Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b58269281 | ||
|
|
a584a6bedd | ||
|
|
a882163e3c | ||
|
|
adab5e1e14 | ||
|
|
387d0c0298 | ||
|
|
ed180e0c62 | ||
|
|
b9290532d5 | ||
|
|
a932d9ab92 | ||
|
|
a0233d8903 | ||
|
|
3d749e40d0 | ||
|
|
90754cad7f | ||
|
|
426c390bfb | ||
|
|
29393bd7af | ||
|
|
e257bf38f0 | ||
|
|
511af7e72b | ||
|
|
e2a5b83873 | ||
|
|
d49c01ac3c | ||
|
|
96b2ecf23f | ||
|
|
3b26513271 | ||
|
|
9b5b9b71f9 | ||
|
|
bf32c16704 | ||
|
|
7c7c313a38 | ||
|
|
2211965618 | ||
|
|
fb9ff55a66 | ||
|
|
3903f0e7f1 | ||
|
|
12cd1ef4be | ||
|
|
9c84cc4f45 | ||
|
|
303256081e | ||
|
|
1c81c35e11 | ||
|
|
8a3840c203 | ||
|
|
816622cd59 | ||
|
|
0ca05771e1 | ||
|
|
733d857d8d | ||
|
|
0357fac250 | ||
|
|
f74380b631 | ||
|
|
c110421bb7 | ||
|
|
28af93ce2c | ||
|
|
062ccb9f25 | ||
|
|
7e3cfe0c5b | ||
|
|
0e724047a4 | ||
|
|
c3358a94ca | ||
|
|
0dfdc7931c | ||
|
|
99cfa69e85 | ||
|
|
ef681838d8 | ||
|
|
a0333a9bfa | ||
|
|
becb96b861 | ||
|
|
4482d78f6e | ||
|
|
45a1d4ccfa | ||
|
|
e041118d78 | ||
|
|
eb16494311 | ||
|
|
3335cfce13 | ||
|
|
195c1cdedb | ||
|
|
6cbabf6bcd | ||
|
|
fd2c68c36c | ||
|
|
2906438b25 | ||
|
|
9175519561 | ||
|
|
6da1c2ed78 | ||
|
|
801257c6eb | ||
|
|
03979e48ee | ||
|
|
7fc87f4050 | ||
|
|
0a19d21036 | ||
|
|
6df6e3658a | ||
|
|
f8725e549c | ||
|
|
8b080a36ae | ||
|
|
43d093535f | ||
|
|
6f50d68c62 | ||
|
|
dedcc8e9f1 | ||
|
|
46da75558b | ||
|
|
28f517b65c | ||
|
|
dbea88ec7e | ||
|
|
3b5061583c | ||
|
|
2cddedff5b | ||
|
|
4ac546962b | ||
|
|
1ec7fb4958 | ||
|
|
c359601517 | ||
|
|
3eddbf230d | ||
|
|
ca39a04ec3 | ||
|
|
6a36198f00 | ||
|
|
5e8fc3913a | ||
|
|
56a9203267 | ||
|
|
d83e682eee | ||
|
|
9a86583e85 | ||
|
|
892b9bcf72 | ||
|
|
f410e09b72 | ||
|
|
d118ca8d7d | ||
|
|
b745f55bd2 | ||
|
|
57bd3cd1f0 | ||
|
|
3c783f8138 | ||
|
|
5c1218ee94 | ||
|
|
b867a0d71b | ||
|
|
c9e8518d83 | ||
|
|
f5d8f06cde | ||
|
|
18c933c3ea | ||
|
|
c65f2a0b31 | ||
|
|
0e2fb41fcc | ||
|
|
e6f887e9a2 | ||
|
|
01ea0e6a0e | ||
|
|
15d3cd5d0c | ||
|
|
86d2ca9680 | ||
|
|
0d687da1c5 | ||
|
|
8fdc5c47e6 | ||
|
|
d71aacbae1 | ||
|
|
31958f0139 | ||
|
|
4d80bb5cee | ||
|
|
625f1e2dff | ||
|
|
2794bf51a3 | ||
|
|
c7dab85b09 | ||
|
|
f2acab6269 | ||
|
|
000123a7ec | ||
|
|
41d3433de2 | ||
|
|
fb76f528a1 | ||
|
|
0acc494b61 | ||
|
|
733aa848ed | ||
|
|
ef770d4edc | ||
|
|
390bb79af7 | ||
|
|
641a59d295 | ||
|
|
de02c4550c | ||
|
|
68224f2355 | ||
|
|
e024aedd5a | ||
|
|
fa59bcd260 | ||
|
|
cb870d6072 | ||
|
|
2a9cf25f28 | ||
|
|
471997e083 | ||
|
|
b9c034bc79 | ||
|
|
12874caced | ||
|
|
580af1004a | ||
|
|
0dfb663ea8 | ||
|
|
200b76f845 | ||
|
|
44e428a69f | ||
|
|
9e56504dbb | ||
|
|
1b06dc90b7 | ||
|
|
62f50dbcf4 | ||
|
|
9031ab26ec | ||
|
|
31ac62142d | ||
|
|
7b461e1208 | ||
|
|
d3e285528e | ||
|
|
a39af037a3 | ||
|
|
73710b4f44 | ||
|
|
87ae5a398f | ||
|
|
f6619233d9 | ||
|
|
fa0d6bdb56 | ||
|
|
883e0c0e51 | ||
|
|
869089fd15 | ||
|
|
012f3ee7a2 | ||
|
|
2cda9ede8d | ||
|
|
3693cec892 | ||
|
|
525b3da3b0 | ||
|
|
920894a85d | ||
|
|
404929e926 | ||
|
|
9ff8259b72 | ||
|
|
242fde5d0f | ||
|
|
d854e1fc06 | ||
|
|
20e46b179c | ||
|
|
b9345fe942 | ||
|
|
b99c9ec82f | ||
|
|
7fd43762af | ||
|
|
fdd747de9a | ||
|
|
db30fd696a | ||
|
|
a80718f7bf | ||
|
|
adc00aa0df | ||
|
|
dcb247a053 | ||
|
|
e6f5bb86da | ||
|
|
485402c408 | ||
|
|
2cf3c6dd14 | ||
|
|
2f1aa730db | ||
|
|
a417daa7fc | ||
|
|
1d6a915e4a | ||
|
|
67fab4ed33 | ||
|
|
5b7bcde487 | ||
|
|
7b72b9ffee | ||
|
|
5e7ea9b470 | ||
|
|
d02dc83247 | ||
|
|
45c67eb744 | ||
|
|
21c48c503f | ||
|
|
063e8a736c | ||
|
|
7d12571ef6 | ||
|
|
3f23c088cb | ||
|
|
87a7959b48 | ||
|
|
5420bad9cb | ||
|
|
8034443dd0 | ||
|
|
279ae2c446 | ||
|
|
c4752cfb18 | ||
|
|
14945e7e5d | ||
|
|
9e45a7bf3b | ||
|
|
5ecda3338f | ||
|
|
07c56ca6f8 | ||
|
|
80c8756e52 | ||
|
|
7d01243b4e | ||
|
|
269abda0dd | ||
|
|
d32a53ff28 | ||
|
|
2a7cd55c04 | ||
|
|
194f846d48 | ||
|
|
1a799bc60a | ||
|
|
08425887f6 | ||
|
|
d7d0822bc5 | ||
|
|
62cab15643 | ||
|
|
757885a7b6 | ||
|
|
ab17d5860b | ||
|
|
dae1df1f23 | ||
|
|
dfcbfd38a0 | ||
|
|
a0cff43cc6 | ||
|
|
0e59050c38 | ||
|
|
7a0fbde263 | ||
|
|
920a76ac5c | ||
|
|
1f6a27cde7 | ||
|
|
1d659fda65 | ||
|
|
a02dea46df | ||
|
|
6a11c26684 | ||
|
|
9ffda77728 | ||
|
|
2f5d663d50 | ||
|
|
cd259a7068 | ||
|
|
077f03a5f7 | ||
|
|
8c1e8f9427 | ||
|
|
ab2ce33789 | ||
|
|
df61c069a0 | ||
|
|
679244766a | ||
|
|
5ee5871d9d | ||
|
|
1b2998aa96 | ||
|
|
a2e6a71cf1 | ||
|
|
6d353c86af | ||
|
|
2af0b43a46 | ||
|
|
0882453746 | ||
|
|
73d0831617 | ||
|
|
0fcad3e022 | ||
|
|
c416318fc9 | ||
|
|
11436d36f9 | ||
|
|
6413ba63cc | ||
|
|
f70bf3dce5 | ||
|
|
59c7b6b748 | ||
|
|
d2daaf4ee4 | ||
|
|
1785f49830 | ||
|
|
f2e4bb7769 | ||
|
|
e13d3b73cc | ||
|
|
d3fd42c98e | ||
|
|
5bffa51846 | ||
|
|
37de9ba4ad | ||
|
|
63f63a54d4 | ||
|
|
ccf8a27d7a | ||
|
|
c6d7a8d603 | ||
|
|
41352f9943 | ||
|
|
8d6277b99e | ||
|
|
1df06e9d68 | ||
|
|
b7e06155c1 | ||
|
|
92e115e3e6 | ||
|
|
069b059af8 | ||
|
|
ccf9ac8630 | ||
|
|
5f6b3c11b2 | ||
|
|
3904c037cf | ||
|
|
28806d3b14 | ||
|
|
794f8787dc | ||
|
|
06e31122fc | ||
|
|
d487234fa6 | ||
|
|
b1a8bc8465 | ||
|
|
cb4eeab9a9 | ||
|
|
d17811753c | ||
|
|
736c787dcc | ||
|
|
7fc217eb2d | ||
|
|
ab6584975c | ||
|
|
fe0ae3aba3 | ||
|
|
05917530f6 | ||
|
|
a6a43d9baa | ||
|
|
1900347260 | ||
|
|
cca6fddd7d | ||
|
|
a3bf2cf65d | ||
|
|
2d2827f36c | ||
|
|
976de28045 | ||
|
|
d26f25ecd1 | ||
|
|
65dccea0e7 | ||
|
|
39f87572f7 | ||
|
|
847b0efd9e | ||
|
|
e306658276 | ||
|
|
00e2601c9f | ||
|
|
2c0b87ceeb | ||
|
|
6367b694a9 | ||
|
|
558c2741ca | ||
|
|
ba2e392265 | ||
|
|
6d61bb4ef4 | ||
|
|
846717632a | ||
|
|
c39a7ad0a4 | ||
|
|
7527deec09 | ||
|
|
cdea9cddea | ||
|
|
56054087d8 | ||
|
|
897076862b | ||
|
|
a6dbc34ec5 | ||
|
|
5b9f88dc5c | ||
|
|
b58873d8f1 | ||
|
|
0df1f36744 | ||
|
|
8d7aa0fc4b | ||
|
|
d1d8cd1d87 | ||
|
|
af3715429e | ||
|
|
72a73de6e6 | ||
|
|
ce8f5d6653 | ||
|
|
ec76f5e1ec | ||
|
|
6d7c3e38e3 | ||
|
|
54b9847ae4 | ||
|
|
9761aa76c6 | ||
|
|
3df8744037 | ||
|
|
ca1529cbad | ||
|
|
72267b6d1d | ||
|
|
cf399f6090 | ||
|
|
90bfc3bb2b | ||
|
|
6961f83067 | ||
|
|
9c778de818 | ||
|
|
32f57212d9 | ||
|
|
df76db40a4 | ||
|
|
3681e05499 | ||
|
|
27c94f804e | ||
|
|
9a88df0b03 | ||
|
|
e22480029f | ||
|
|
4bb49ef0a7 | ||
|
|
d40b91e460 | ||
|
|
e23804ec6c | ||
|
|
d331e4f839 | ||
|
|
8364799eef | ||
|
|
c9d02f6a5e | ||
|
|
c86b92b34b | ||
|
|
ca091d55e6 | ||
|
|
7a98ff9971 | ||
|
|
ca086237da | ||
|
|
2d795b1e95 | ||
|
|
120c9fef82 | ||
|
|
ec34a10c71 | ||
|
|
1095b75f49 | ||
|
|
15bf575e36 | ||
|
|
eae21744fc | ||
|
|
d26a6bbf94 | ||
|
|
1dded89b7b | ||
|
|
aac87cfcee | ||
|
|
72a7eaf0bf | ||
|
|
31500bcd28 | ||
|
|
46490aded8 | ||
|
|
9347b44e95 | ||
|
|
f81107fc0d | ||
|
|
07427b4a77 | ||
|
|
5c7c633857 | ||
|
|
bd610b9a0e | ||
|
|
f6d1564163 | ||
|
|
a6c02c3819 | ||
|
|
59576c4250 | ||
|
|
e5f71eb624 | ||
|
|
4c9f893c0b | ||
|
|
c6ce186a7f | ||
|
|
bcddb3c5ce | ||
|
|
67204ab800 | ||
|
|
a6e0bd67cb | ||
|
|
8850de5ab1 | ||
|
|
78fcf181d0 | ||
|
|
72ca37ca76 | ||
|
|
cd1e132da7 | ||
|
|
c656547ada | ||
|
|
b7fc92cca2 | ||
|
|
5221b13d3e | ||
|
|
3e05ddbdba | ||
|
|
b1071445fa | ||
|
|
8e25e4abd1 | ||
|
|
0c5d4d7495 | ||
|
|
4ae2cea129 | ||
|
|
a634da9c20 | ||
|
|
c1b391be40 | ||
|
|
aac2b69d70 | ||
|
|
cb5ef18006 | ||
|
|
bd0ffff441 | ||
|
|
4cb1c03e4e | ||
|
|
ac1535b552 | ||
|
|
490e6e329f | ||
|
|
77278008f4 | ||
|
|
02da6106c3 | ||
|
|
2b9f6b0cb5 | ||
|
|
6afbb561e3 | ||
|
|
be19a9306d | ||
|
|
2938870cbc | ||
|
|
00abda735b | ||
|
|
feb9d01a9d | ||
|
|
4a75f67911 | ||
|
|
b55821ed7e | ||
|
|
f92c796c7e | ||
|
|
e18d77395e | ||
|
|
91e041c583 | ||
|
|
cf6bc8afa7 | ||
|
|
59b0ca3660 | ||
|
|
163b108e23 | ||
|
|
9276757a92 | ||
|
|
a64b243d0d | ||
|
|
ae3bc847be | ||
|
|
01a2d3339d | ||
|
|
013b4a46c1 | ||
|
|
3ecbc2a3dd | ||
|
|
f08218e77d | ||
|
|
2f9d0d64a1 | ||
|
|
f2dbda6350 | ||
|
|
8cb4f6798a | ||
|
|
641be23eed | ||
|
|
bf99ff0898 | ||
|
|
cd9f06b232 | ||
|
|
3b9e179427 | ||
|
|
641a11ee07 | ||
|
|
8ba2b38dad | ||
|
|
40ae3bda19 | ||
|
|
c00ab2e141 | ||
|
|
a7ff1fc6be | ||
|
|
6df90d9854 | ||
|
|
d6948dbe26 | ||
|
|
657384bc24 | ||
|
|
299e352d76 | ||
|
|
8c4d698c9f | ||
|
|
2711fc5745 | ||
|
|
3564c137a4 | ||
|
|
614061b743 | ||
|
|
0ec6d35b83 | ||
|
|
a64fec7880 | ||
|
|
dc89548d3a | ||
|
|
3c16c42c04 | ||
|
|
2ebf52fc43 | ||
|
|
f1d0b0a8e5 | ||
|
|
7b01fe291f | ||
|
|
82c37ed39f | ||
|
|
4c0edf8561 | ||
|
|
a02027951b | ||
|
|
042d9b7f46 | ||
|
|
23dfee74c2 | ||
|
|
d167d1ea78 | ||
|
|
84be8866d5 | ||
|
|
809af0a581 | ||
|
|
49d2ed576a | ||
|
|
7716b05b9a | ||
|
|
ebaf5255f2 | ||
|
|
42899c0e24 | ||
|
|
ed1b00540b | ||
|
|
8ee04b386f | ||
|
|
12144ba6e9 | ||
|
|
1cfb48fca8 | ||
|
|
597cac1387 | ||
|
|
288cb407a0 | ||
|
|
79eb0b11a8 | ||
|
|
7286bbff6e | ||
|
|
8828e9f4ac | ||
|
|
f92c09175f | ||
|
|
cf6ba3517a | ||
|
|
445a31e630 | ||
|
|
a3d5a4f3f0 | ||
|
|
fcbba19ce2 | ||
|
|
399fbfcff6 | ||
|
|
a3d9fc18f9 | ||
|
|
d094d4daf7 | ||
|
|
8a77d6cae2 | ||
|
|
054786ccfb | ||
|
|
4a1b3d85cc |
@@ -17,7 +17,7 @@ You are an expert technical writer specializing in creating clear, user-focused
|
||||
5. Determine which parts of the codebase were affected (frontend, backend, API, database, etc.)
|
||||
|
||||
### Step 2: Study Recent Changelog Patterns
|
||||
1. Read 3-5 of the most recent changelog posts in `../langfuse-docs/pages/changelog`
|
||||
1. Read 3-5 of the most recent changelog posts in `../hanzo-docs/pages/changelog`
|
||||
2. Analyze their structure, tone, and formatting conventions
|
||||
3. Note how they:
|
||||
- Title features (concise, benefit-focused)
|
||||
@@ -28,7 +28,7 @@ You are an expert technical writer specializing in creating clear, user-focused
|
||||
- Format code examples or technical details
|
||||
|
||||
### Step 3: Identify Documentation Links
|
||||
1. Check if there is relevant documentation in `../langfuse-docs/pages` that relates to this feature
|
||||
1. Check if there is relevant documentation in `../hanzo-docs/pages` that relates to this feature
|
||||
2. If the feature is new, note that documentation may need to be created
|
||||
3. If the feature extends existing functionality, identify which docs pages should be referenced
|
||||
|
||||
@@ -80,7 +80,7 @@ Present your work in this order:
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The changelog lives in `../langfuse-docs/pages/changelog`
|
||||
- The changelog lives in `../hanzo-docs/pages/changelog`
|
||||
- Always check the Linear issue via the branch name (lfe-XXXX format) for context
|
||||
- Compare against main branch to understand the full scope of changes
|
||||
- Study recent changelogs before writing to maintain consistency
|
||||
|
||||
@@ -20,9 +20,7 @@ interface SessionTracking {
|
||||
edited_files: EditedFile[];
|
||||
}
|
||||
|
||||
function getFileCategory(
|
||||
filePath: string,
|
||||
): "backend" | "frontend" | "database" | "other" {
|
||||
function getFileCategory(filePath: string): "backend" | "frontend" | "database" | "other" {
|
||||
// Frontend detection
|
||||
if (
|
||||
filePath.includes("/frontend/") ||
|
||||
@@ -43,11 +41,7 @@ function getFileCategory(
|
||||
return "backend";
|
||||
|
||||
// Database detection
|
||||
if (
|
||||
filePath.includes("/database/") ||
|
||||
filePath.includes("/prisma/") ||
|
||||
filePath.includes("/migrations/")
|
||||
)
|
||||
if (filePath.includes("/database/") || filePath.includes("/prisma/") || filePath.includes("/migrations/"))
|
||||
return "database";
|
||||
|
||||
return "other";
|
||||
@@ -86,14 +80,8 @@ function analyzeFileContent(filePath: string): {
|
||||
return {
|
||||
hasTryCatch: /try\s*\{/.test(content),
|
||||
hasAsync: /async\s+/.test(content),
|
||||
hasPrisma:
|
||||
/prisma\.|PrismaService|findMany|findUnique|create\(|update\(|delete\(/i.test(
|
||||
content,
|
||||
),
|
||||
hasController:
|
||||
/export class.*Controller|router\.|app\.(get|post|put|delete|patch)/.test(
|
||||
content,
|
||||
),
|
||||
hasPrisma: /prisma\.|PrismaService|findMany|findUnique|create\(|update\(|delete\(/i.test(content),
|
||||
hasController: /export class.*Controller|router\.|app\.(get|post|put|delete|patch)/.test(content),
|
||||
hasApiCall: /fetch\(|axios\.|apiClient\./i.test(content),
|
||||
};
|
||||
}
|
||||
@@ -108,12 +96,7 @@ async function main() {
|
||||
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
||||
|
||||
// Check for edited files tracking
|
||||
const cacheDir = join(
|
||||
process.env.HOME || "/root",
|
||||
".claude",
|
||||
"tsc-cache",
|
||||
session_id,
|
||||
);
|
||||
const cacheDir = join(process.env.HOME || "/root", ".claude", "tsc-cache", session_id);
|
||||
const trackingFile = join(cacheDir, "edited-files.log");
|
||||
|
||||
if (!existsSync(trackingFile)) {
|
||||
@@ -182,9 +165,7 @@ async function main() {
|
||||
|
||||
// Backend reminders
|
||||
if (categories.backend.length > 0) {
|
||||
const backendFiles = analysisResults.filter(
|
||||
(f) => f.category === "backend",
|
||||
);
|
||||
const backendFiles = analysisResults.filter((f) => f.category === "backend");
|
||||
const hasTryCatch = backendFiles.some((f) => f.analysis.hasTryCatch);
|
||||
const hasPrisma = backendFiles.some((f) => f.analysis.hasPrisma);
|
||||
const hasController = backendFiles.some((f) => f.analysis.hasController);
|
||||
@@ -193,9 +174,7 @@ async function main() {
|
||||
console.log(` ${categories.backend.length} file(s) edited\n`);
|
||||
|
||||
if (hasTryCatch) {
|
||||
console.log(
|
||||
" ❓ Did you add Sentry.captureException() in catch blocks?",
|
||||
);
|
||||
console.log(" ❓ Did you add Sentry.captureException() in catch blocks?");
|
||||
}
|
||||
if (hasPrisma) {
|
||||
console.log(" ❓ Are Prisma operations wrapped in error handling?");
|
||||
@@ -212,9 +191,7 @@ async function main() {
|
||||
|
||||
// Frontend reminders
|
||||
if (categories.frontend.length > 0) {
|
||||
const frontendFiles = analysisResults.filter(
|
||||
(f) => f.category === "frontend",
|
||||
);
|
||||
const frontendFiles = analysisResults.filter((f) => f.category === "frontend");
|
||||
const hasApiCall = frontendFiles.some((f) => f.analysis.hasApiCall);
|
||||
const hasTryCatch = frontendFiles.some((f) => f.analysis.hasTryCatch);
|
||||
|
||||
|
||||
@@ -56,9 +56,7 @@ async function main() {
|
||||
|
||||
// Keyword matching
|
||||
if (triggers.keywords) {
|
||||
const keywordMatch = triggers.keywords.some((kw) =>
|
||||
prompt.includes(kw.toLowerCase()),
|
||||
);
|
||||
const keywordMatch = triggers.keywords.some((kw) => prompt.includes(kw.toLowerCase()));
|
||||
if (keywordMatch) {
|
||||
matchedSkills.push({ name: skillName, matchType: "keyword", config });
|
||||
continue;
|
||||
@@ -84,13 +82,9 @@ async function main() {
|
||||
output += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
|
||||
|
||||
// Group by priority
|
||||
const critical = matchedSkills.filter(
|
||||
(s) => s.config.priority === "critical",
|
||||
);
|
||||
const critical = matchedSkills.filter((s) => s.config.priority === "critical");
|
||||
const high = matchedSkills.filter((s) => s.config.priority === "high");
|
||||
const medium = matchedSkills.filter(
|
||||
(s) => s.config.priority === "medium",
|
||||
);
|
||||
const medium = matchedSkills.filter((s) => s.config.priority === "medium");
|
||||
const low = matchedSkills.filter((s) => s.config.priority === "low");
|
||||
|
||||
if (critical.length > 0) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: add-model-price
|
||||
description: Add new LLM model pricing entries to Langfuse's default-model-prices.json. Use when adding model prices, updating model pricing, creating model entries, adding Claude/OpenAI/Anthropic/Google/Gemini/AWS Bedrock/Azure/Vertex AI model pricing, working with matchPattern regex, pricingTiers, or model cost configuration. Covers model price JSON structure, regex patterns for multi-provider matching, tiered pricing with conditions, cache pricing, and validation rules.
|
||||
description: Add new LLM model pricing entries to Console's default-model-prices.json. Use when adding model prices, updating model pricing, creating model entries, adding Claude/OpenAI/Anthropic/Google/Gemini/AWS Bedrock/Azure/Vertex AI model pricing, working with matchPattern regex, pricingTiers, or model cost configuration. Covers model price JSON structure, regex patterns for multi-provider matching, tiered pricing with conditions, cache pricing, and validation rules.
|
||||
---
|
||||
|
||||
# Add Model Price
|
||||
|
||||
## Purpose
|
||||
|
||||
Guide for adding new LLM model pricing entries to Langfuse's default model prices configuration. This enables accurate cost tracking across different model providers and deployment platforms.
|
||||
Guide for adding new LLM model pricing entries to Console's default model prices configuration. This enables accurate cost tracking across different model providers and deployment platforms.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
@@ -332,7 +332,7 @@ Add the entry to the JSON array in `/worker/src/constants/default-model-prices.j
|
||||
|
||||
### Step 5: Add to LLM Types (for Playground & LLM-as-Judge)
|
||||
|
||||
To make the model available in the Langfuse playground and for LLM-as-a-judge evaluations, add it to the appropriate model array in `/packages/shared/src/server/llm/types.ts`.
|
||||
To make the model available in the Console playground and for LLM-as-a-judge evaluations, add it to the appropriate model array in `/packages/shared/src/server/llm/types.ts`.
|
||||
|
||||
**File**: `/packages/shared/src/server/llm/types.ts`
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: backend-dev-guidelines
|
||||
description: Comprehensive backend development guide for Langfuse's Next.js 14/tRPC/Express/TypeScript monorepo. Use when creating tRPC routers, public API endpoints, BullMQ queue processors, services, or working with tRPC procedures, Next.js API routes, Prisma database access, ClickHouse analytics queries, Redis queues, OpenTelemetry instrumentation, Zod v4 validation, env.mjs configuration, tenant isolation patterns, or async patterns. Covers layered architecture (tRPC procedures → services, queue processors → services), dual database system (PostgreSQL + ClickHouse), projectId filtering for multi-tenant isolation, traceException error handling, observability patterns, and testing strategies (Jest for web, vitest for worker).
|
||||
description: Comprehensive backend development guide for Hanzo's Next.js 14/tRPC/Express/TypeScript monorepo. Use when creating tRPC routers, public API endpoints, BullMQ queue processors, services, or working with tRPC procedures, Next.js API routes, Prisma database access, Datastore analytics queries, Redis queues, OpenTelemetry instrumentation, Zod v4 validation, env.mjs configuration, tenant isolation patterns, or async patterns. Covers layered architecture (tRPC procedures → services, queue processors → services), dual database system (PostgreSQL + Datastore), projectId filtering for multi-tenant isolation, traceException error handling, observability patterns, and testing strategies (Jest for web, vitest for worker).
|
||||
---
|
||||
|
||||
# Backend Development Guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
Establish consistency and best practices across Langfuse's backend packages (web, worker, packages/shared) using Next.js 14, tRPC, BullMQ, and TypeScript patterns.
|
||||
Establish consistency and best practices across Hanzo's backend packages (web, worker, packages/shared) using Next.js 14, tRPC, BullMQ, and TypeScript patterns.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
@@ -20,7 +20,7 @@ Automatically activates when working on:
|
||||
- Authenticating API requests
|
||||
- Accessing resources based on entitlements
|
||||
- Implementing middleware (tRPC, NextAuth, public API)
|
||||
- Database operations with Prisma (PostgreSQL) or ClickHouse
|
||||
- Database operations with Prisma (PostgreSQL) or Datastore
|
||||
- Observability with OpenTelemetry, DataDog, logger, and traceException
|
||||
- Input validation with Zod v4
|
||||
- Environment configuration from env variables
|
||||
@@ -80,7 +80,7 @@ Automatically activates when working on:
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Service (business logic) │ │ Service (business logic) │
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Prisma / ClickHouse │ │ Prisma / ClickHouse │
|
||||
│ Prisma / Datastore │ │ Prisma / Datastore │
|
||||
│ │ │ │
|
||||
└─────────────────────────────┘ └─────────────────────────────┘
|
||||
↓
|
||||
@@ -94,7 +94,7 @@ Automatically activates when working on:
|
||||
│ ↓ │
|
||||
│ Service (business logic) │
|
||||
│ ↓ │
|
||||
│ Prisma / ClickHouse │
|
||||
│ Prisma / Datastore │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
@@ -163,7 +163,7 @@ worker/src/
|
||||
shared/src/
|
||||
├── server/ # Server utilities
|
||||
│ ├── auth/ # Authentication helpers
|
||||
│ ├── clickhouse/ # ClickHouse client & schema
|
||||
│ ├── datastore/ # Datastore client & schema
|
||||
│ ├── instrumentation/ # OpenTelemetry helpers
|
||||
│ ├── llm/ # LLM integration utilities
|
||||
│ ├── redis/ # Redis queues & cache
|
||||
@@ -188,11 +188,11 @@ The shared package exposes specific import paths for different use cases:
|
||||
|
||||
| Import Path | Maps To | Use For |
|
||||
| ------------------------------------------ | --------------------------------- | --------------------------------------------------------------- |
|
||||
| `@langfuse/shared` | `dist/src/index.js` | General types, schemas, utilities, constants |
|
||||
| `@langfuse/shared/src/db` | `dist/src/db.js` | Prisma client and database types |
|
||||
| `@langfuse/shared/src/server` | `dist/src/server/index.js` | Server-side utilities (queues, auth, services, instrumentation) |
|
||||
| `@langfuse/shared/src/server/auth/apiKeys` | `dist/src/server/auth/apiKeys.js` | API key management utilities |
|
||||
| `@langfuse/shared/encryption` | `dist/src/encryption/index.js` | Encryption and signature utilities |
|
||||
| `@hanzo/console` | `dist/src/index.js` | General types, schemas, utilities, constants |
|
||||
| `@hanzo/console-core/src/db` | `dist/src/db.js` | Prisma client and database types |
|
||||
| `@hanzo/console-core/src/server` | `dist/src/server/index.js` | Server-side utilities (queues, auth, services, instrumentation) |
|
||||
| `@hanzo/console-core/src/server/auth/apiKeys` | `dist/src/server/auth/apiKeys.js` | API key management utilities |
|
||||
| `@hanzo/console-core/encryption` | `dist/src/encryption/index.js` | Encryption and signature utilities |
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
@@ -205,11 +205,11 @@ import {
|
||||
type APIScoreV2,
|
||||
type ColumnDefinition,
|
||||
Role,
|
||||
} from "@langfuse/shared";
|
||||
} from "@hanzo/console";
|
||||
|
||||
// Database - Prisma client and types
|
||||
import { prisma, Prisma, JobExecutionStatus } from "@langfuse/shared/src/db";
|
||||
import { type DB as Database } from "@langfuse/shared";
|
||||
import { prisma, Prisma, JobExecutionStatus } from "@hanzo/console-core/src/db";
|
||||
import { type DB as Database } from "@hanzo/console";
|
||||
|
||||
// Server utilities - queues, services, auth, instrumentation
|
||||
import {
|
||||
@@ -223,13 +223,13 @@ import {
|
||||
invalidateApiKeysForProject,
|
||||
recordIncrement,
|
||||
recordHistogram,
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
// API key management (specific path)
|
||||
import { createAndAddApiKeysToDb } from "@langfuse/shared/src/server/auth/apiKeys";
|
||||
import { createAndAddApiKeysToDb } from "@hanzo/console-core/src/server/auth/apiKeys";
|
||||
|
||||
// Encryption utilities
|
||||
import { encrypt, decrypt, sign, verify } from "@langfuse/shared/encryption";
|
||||
import { encrypt, decrypt, sign, verify } from "@hanzo/console-core/encryption";
|
||||
```
|
||||
|
||||
**What Goes Where:**
|
||||
@@ -238,11 +238,11 @@ The shared package provides types, utilities, and server code used by both web a
|
||||
|
||||
| Import Path | Usage | What's Included |
|
||||
| ------------------------------------------ | --------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `@langfuse/shared` | ✅ Frontend + Backend | Prisma types, Zod schemas, constants, table definitions, domain models, utilities |
|
||||
| `@langfuse/shared/src/db` | 🔒 Backend only | Prisma client instance |
|
||||
| `@langfuse/shared/src/server` | 🔒 Backend only | Services, repositories, queues, auth, ClickHouse, LLM integration, instrumentation |
|
||||
| `@langfuse/shared/src/server/auth/apiKeys` | 🔒 Backend only | API key management (separated to avoid circular deps) |
|
||||
| `@langfuse/shared/encryption` | 🔒 Backend only | Database field encryption/decryption |
|
||||
| `@hanzo/console` | ✅ Frontend + Backend | Prisma types, Zod schemas, constants, table definitions, domain models, utilities |
|
||||
| `@hanzo/console-core/src/db` | 🔒 Backend only | Prisma client instance |
|
||||
| `@hanzo/console-core/src/server` | 🔒 Backend only | Services, repositories, queues, auth, Datastore, LLM integration, instrumentation |
|
||||
| `@hanzo/console-core/src/server/auth/apiKeys` | 🔒 Backend only | API key management (separated to avoid circular deps) |
|
||||
| `@hanzo/console-core/encryption` | 🔒 Backend only | Database field encryption/decryption |
|
||||
|
||||
**Naming Conventions:**
|
||||
|
||||
@@ -304,14 +304,14 @@ const validated = schema.parse(input);
|
||||
|
||||
```typescript
|
||||
// Services use Prisma directly for simple CRUD
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
|
||||
const dataset = await prisma.dataset.findUnique({
|
||||
where: { id: datasetId, projectId }, // Always filter by projectId for tenant isolation
|
||||
});
|
||||
|
||||
// Or use repositories for complex queries (traces, observations, scores)
|
||||
import { getTracesTable } from "@langfuse/shared/src/server";
|
||||
import { getTracesTable } from "@hanzo/console-core/src/server";
|
||||
|
||||
const traces = await getTracesTable({
|
||||
projectId,
|
||||
@@ -322,7 +322,7 @@ const traces = await getTracesTable({
|
||||
|
||||
### 6. Observability: OpenTelemetry + DataDog (Not Sentry for Backend)
|
||||
|
||||
**Langfuse uses OpenTelemetry for backend observability, with traces and logs sent to DataDog.**
|
||||
**Hanzo uses OpenTelemetry for backend observability, with traces and logs sent to DataDog.**
|
||||
|
||||
```typescript
|
||||
// Import observability utilities
|
||||
@@ -330,7 +330,7 @@ import {
|
||||
logger, // Winston logger with OpenTelemetry/DataDog context
|
||||
traceException, // Record exceptions to OpenTelemetry spans
|
||||
instrumentAsync, // Create instrumented spans
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
// Structured logging (includes trace_id, span_id, dd.trace_id)
|
||||
logger.info("Processing dataset", { datasetId, projectId });
|
||||
@@ -413,8 +413,8 @@ const trace = await prisma.trace.findUnique({
|
||||
where: { id: traceId, projectId }, // Required for multi-tenant data isolation
|
||||
});
|
||||
|
||||
// ✅ CORRECT: ClickHouse queries also require projectId
|
||||
const traces = await queryClickhouse({
|
||||
// ✅ CORRECT: Datastore queries also require projectId
|
||||
const traces = await queryDatastore({
|
||||
query: `
|
||||
SELECT * FROM traces
|
||||
WHERE project_id = {projectId: String}
|
||||
@@ -464,22 +464,22 @@ import {
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
// Database
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
|
||||
// ClickHouse
|
||||
// Datastore
|
||||
import {
|
||||
queryClickhouse,
|
||||
queryClickhouseStream,
|
||||
upsertClickhouse,
|
||||
} from "@langfuse/shared/src/server";
|
||||
queryDatastore,
|
||||
queryDatastoreStream,
|
||||
upsertDatastore,
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
// Observability - OpenTelemetry + DataDog (NOT Sentry for backend)
|
||||
import {
|
||||
logger, // Winston logger with OTEL/DataDog trace context
|
||||
traceException, // Record exceptions to OpenTelemetry spans
|
||||
instrumentAsync, // Create instrumented spans for operations
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
// Config
|
||||
import { env } from "@/src/env.mjs"; // web
|
||||
@@ -492,7 +492,7 @@ import { createAuthedProjectAPIRoute } from "@/src/features/public-api/server/cr
|
||||
|
||||
// Queue Processing (Worker)
|
||||
import { Job } from "bullmq";
|
||||
import { QueueName, TQueueJobTypes } from "@langfuse/shared/src/server";
|
||||
import { QueueName, TQueueJobTypes } from "@hanzo/console-core/src/server";
|
||||
```
|
||||
|
||||
---
|
||||
@@ -513,7 +513,7 @@ import { QueueName, TQueueJobTypes } from "@langfuse/shared/src/server";
|
||||
|
||||
### Example Features to Reference
|
||||
|
||||
Reference existing Langfuse features for implementation patterns:
|
||||
Reference existing Hanzo features for implementation patterns:
|
||||
- **Datasets** (`web/src/features/datasets/`) - Complete feature with tRPC router, public API, and service
|
||||
- **Prompts** (`web/src/features/prompts/`) - Feature with versioning and templates
|
||||
- **Evaluations** (`web/src/features/evals/`) - Complex feature with worker integration
|
||||
@@ -550,7 +550,7 @@ Reference existing Langfuse features for implementation patterns:
|
||||
|
||||
### [architecture-overview.md](resources/architecture-overview.md)
|
||||
|
||||
Three-layer architecture (tRPC/Public API → Services → Data Access), request lifecycle for tRPC/Public API/Worker, Next.js 14 directory structure, dual database system (PostgreSQL + ClickHouse), separation of concerns, repository pattern for complex queries
|
||||
Three-layer architecture (tRPC/Public API → Services → Data Access), request lifecycle for tRPC/Public API/Worker, Next.js 14 directory structure, dual database system (PostgreSQL + Datastore), separation of concerns, repository pattern for complex queries
|
||||
|
||||
### [routing-and-controllers.md](resources/routing-and-controllers.md)
|
||||
|
||||
@@ -566,11 +566,11 @@ tRPC middleware (withErrorHandling, withOtelInstrumentation, enforceUserIsAuthed
|
||||
|
||||
### [database-patterns.md](resources/database-patterns.md)
|
||||
|
||||
Dual database architecture (PostgreSQL via Prisma + ClickHouse via direct client), PostgreSQL CRUD operations, ClickHouse query patterns (queryClickhouse, queryClickhouseStream, upsertClickhouse), repository pattern for complex queries, tenant isolation with projectId filtering, when to use which database
|
||||
Dual database architecture (PostgreSQL via Prisma + Datastore via direct client), PostgreSQL CRUD operations, Datastore query patterns (queryDatastore, queryDatastoreStream, upsertDatastore), repository pattern for complex queries, tenant isolation with projectId filtering, when to use which database
|
||||
|
||||
### [configuration.md](resources/configuration.md)
|
||||
|
||||
Environment variable validation with Zod, package-specific configs (web/env.mjs with t3-oss/env-nextjs, worker/env.ts, shared/env.ts), NEXT_PUBLIC_LANGFUSE_CLOUD_REGION usage, LANGFUSE_EE_LICENSE_KEY for enterprise features, best practices for env management
|
||||
Environment variable validation with Zod, package-specific configs (web/env.mjs with t3-oss/env-nextjs, worker/env.ts, shared/env.ts), NEXT_PUBLIC_HANZO_CLOUD_REGION usage, HANZO_EE_LICENSE_KEY for enterprise features, best practices for env management
|
||||
|
||||
### [testing-guide.md](resources/testing-guide.md)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Architecture Overview - Langfuse Backend
|
||||
# Architecture Overview - Hanzo Backend
|
||||
|
||||
Complete guide to the layered architecture pattern used in Langfuse's Next.js 14/tRPC/Express monorepo.
|
||||
Complete guide to the layered architecture pattern used in Hanzo's Next.js 14/tRPC/Express monorepo.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -15,7 +15,7 @@ Complete guide to the layered architecture pattern used in Langfuse's Next.js 14
|
||||
|
||||
## Layered Architecture Pattern
|
||||
|
||||
Langfuse uses a **three-layer architecture** with two primary entry points (tRPC and Public API) plus async processing via Worker.
|
||||
Hanzo uses a **three-layer architecture** with two primary entry points (tRPC and Public API) plus async processing via Worker.
|
||||
|
||||
### The Three Layers
|
||||
|
||||
@@ -31,7 +31,7 @@ Langfuse uses a **three-layer architecture** with two primary entry points (tRPC
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Service (business logic) │ │ Service (business logic) │
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Prisma / ClickHouse │ │ Prisma / ClickHouse │
|
||||
│ Prisma / Datastore │ │ Prisma / Datastore │
|
||||
│ │ │ │
|
||||
└─────────────────────────────┘ └─────────────────────────────┘
|
||||
↓
|
||||
@@ -45,7 +45,7 @@ Langfuse uses a **three-layer architecture** with two primary entry points (tRPC
|
||||
│ ↓ │
|
||||
│ Service (business logic) │
|
||||
│ ↓ │
|
||||
│ Prisma / ClickHouse │
|
||||
│ Prisma / Datastore │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
@@ -79,7 +79,7 @@ Two types of entry points:
|
||||
- **Repositories** for complex data access patterns (traces, observations, scores, events)
|
||||
- **Direct Prisma** for simple CRUD operations in services
|
||||
- PostgreSQL for transactional data
|
||||
- ClickHouse for analytics/traces (accessed via repositories)
|
||||
- Datastore for analytics/traces (accessed via repositories)
|
||||
- Redis for caching/queues
|
||||
|
||||
**Async Processing Layer: Worker**
|
||||
@@ -148,11 +148,11 @@ Two types of entry points:
|
||||
6. Service executes business logic:
|
||||
- Validate business rules
|
||||
- Use repositories for complex queries or Prisma directly
|
||||
- ClickHouse queries via repositories if needed
|
||||
- Datastore queries via repositories if needed
|
||||
↓
|
||||
7. Database operations:
|
||||
- prisma.dataset.create({ data })
|
||||
- clickhouse queries via getTracesTable()
|
||||
- datastore queries via getTracesTable()
|
||||
↓
|
||||
8. Response flows back:
|
||||
Database → Service → Procedure → tRPC → Client
|
||||
@@ -208,7 +208,7 @@ Two types of entry points:
|
||||
↓
|
||||
5. Service performs operations:
|
||||
- Prisma transactions
|
||||
- ClickHouse queries
|
||||
- Datastore queries
|
||||
- External API calls (LLMs)
|
||||
↓
|
||||
6. Job completes or fails:
|
||||
@@ -298,11 +298,11 @@ The shared package provides types, utilities, and server code used by both web a
|
||||
|
||||
| Import Path | Usage | What's Included |
|
||||
| ------------------------------------------ | --------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `@langfuse/shared` | ✅ Frontend + Backend | Prisma types, Zod schemas, constants, table definitions, domain models, utilities |
|
||||
| `@langfuse/shared/src/db` | 🔒 Backend only | Prisma client instance |
|
||||
| `@langfuse/shared/src/server` | 🔒 Backend only | Services, repositories, queues, auth, ClickHouse, LLM integration, instrumentation |
|
||||
| `@langfuse/shared/src/server/auth/apiKeys` | 🔒 Backend only | API key management (separated to avoid circular deps) |
|
||||
| `@langfuse/shared/encryption` | 🔒 Backend only | Database field encryption/decryption |
|
||||
| `@hanzo/console` | ✅ Frontend + Backend | Prisma types, Zod schemas, constants, table definitions, domain models, utilities |
|
||||
| `@hanzo/console-core/src/db` | 🔒 Backend only | Prisma client instance |
|
||||
| `@hanzo/console-core/src/server` | 🔒 Backend only | Services, repositories, queues, auth, Datastore, LLM integration, instrumentation |
|
||||
| `@hanzo/console-core/src/server/auth/apiKeys` | 🔒 Backend only | API key management (separated to avoid circular deps) |
|
||||
| `@hanzo/console-core/encryption` | 🔒 Backend only | Database field encryption/decryption |
|
||||
|
||||
**Key Structure:**
|
||||
|
||||
@@ -310,7 +310,7 @@ The shared package provides types, utilities, and server code used by both web a
|
||||
packages/shared/src/
|
||||
├── server/ # 🔒 All server-only code
|
||||
│ ├── auth/ # Authentication & authorization
|
||||
│ ├── clickhouse/ # ClickHouse client & queries
|
||||
│ ├── datastore/ # Datastore client & queries
|
||||
│ ├── redis/ # Redis client & 30+ queue types
|
||||
│ ├── repositories/ # Data access (traces, observations, scores, events)
|
||||
│ ├── services/ # Business services (Storage, Email, Slack, etc.)
|
||||
@@ -336,10 +336,10 @@ import {
|
||||
Role,
|
||||
type Dataset,
|
||||
CloudConfigSchema,
|
||||
} from "@langfuse/shared";
|
||||
} from "@hanzo/console";
|
||||
|
||||
// 🔒 Database - Backend only
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
|
||||
// 🔒 Server utilities - Backend only
|
||||
import {
|
||||
@@ -347,17 +347,17 @@ import {
|
||||
instrumentAsync,
|
||||
traceException,
|
||||
redis,
|
||||
clickhouseClient,
|
||||
datastoreClient,
|
||||
StorageService,
|
||||
fetchLLMCompletion,
|
||||
filterToPrisma,
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
// 🔒 API keys - Backend only
|
||||
import { createAndAddApiKeysToDb } from "@langfuse/shared/src/server/auth/apiKeys";
|
||||
import { createAndAddApiKeysToDb } from "@hanzo/console-core/src/server/auth/apiKeys";
|
||||
|
||||
// 🔒 Encryption - Backend only
|
||||
import { encrypt, decrypt } from "@langfuse/shared/encryption";
|
||||
import { encrypt, decrypt } from "@hanzo/console-core/encryption";
|
||||
```
|
||||
|
||||
---
|
||||
@@ -465,7 +465,7 @@ src/server/api/routers/
|
||||
- ✅ Transaction orchestration
|
||||
- ✅ Repository calls for complex queries
|
||||
- ✅ Direct Prisma operations for simple CRUD
|
||||
- ✅ ClickHouse queries (via repositories)
|
||||
- ✅ Datastore queries (via repositories)
|
||||
- ✅ Redis cache access
|
||||
- ✅ External API calls (LLMs, etc.)
|
||||
- ❌ HTTP concerns (Request/Response)
|
||||
@@ -526,8 +526,8 @@ export const datasetRouter = createTRPCRouter({
|
||||
|
||||
```typescript
|
||||
// web/src/features/datasets/server/service.ts
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { instrumentAsync, traceException } from "@langfuse/shared/src/server";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
import { instrumentAsync, traceException } from "@hanzo/console-core/src/server";
|
||||
|
||||
export async function createDataset(data: {
|
||||
name: string;
|
||||
@@ -640,14 +640,14 @@ export async function processDatasetExport(
|
||||
|
||||
### Dual Database System
|
||||
|
||||
Langfuse uses two databases with different purposes:
|
||||
Hanzo uses two databases with different purposes:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Application │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ PostgreSQL │ │ ClickHouse │ │
|
||||
│ │ PostgreSQL │ │ Datastore │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Transactional│ │ Analytics │ │
|
||||
│ │ Data │ │ Data │ │
|
||||
@@ -667,13 +667,13 @@ Langfuse uses two databases with different purposes:
|
||||
- Schema managed via `prisma migrate`
|
||||
- Located in `packages/shared/prisma/`
|
||||
|
||||
**ClickHouse (Analytics Database):**
|
||||
**Datastore (Analytics Database):**
|
||||
|
||||
- Accessed via direct SQL queries
|
||||
- High-volume trace/observation data
|
||||
- Columnar storage for analytics
|
||||
- Optimized for aggregations
|
||||
- Schema in `packages/shared/src/server/clickhouse/`
|
||||
- Schema in `packages/shared/src/server/datastore/`
|
||||
- Schema managed via `golang-migrate`
|
||||
|
||||
**Redis (Cache & Queues):**
|
||||
@@ -689,12 +689,12 @@ Langfuse uses two databases with different purposes:
|
||||
|
||||
```typescript
|
||||
// PostgreSQL via Prisma
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
|
||||
const dataset = await prisma.dataset.create({ data });
|
||||
|
||||
// ClickHouse via helper functions
|
||||
import { getTracesTable } from "@langfuse/shared/src/server";
|
||||
// Datastore via helper functions
|
||||
import { getTracesTable } from "@hanzo/console-core/src/server";
|
||||
|
||||
const traces = await getTracesTable({
|
||||
projectId,
|
||||
@@ -703,18 +703,18 @@ const traces = await getTracesTable({
|
||||
});
|
||||
|
||||
// Redis via queue/cache utilities
|
||||
import { redis } from "@langfuse/shared/src/server";
|
||||
import { redis } from "@hanzo/console-core/src/server";
|
||||
|
||||
await redis.set(`cache:${key}`, value, "EX", 3600);
|
||||
```
|
||||
|
||||
**Repository Pattern:**
|
||||
|
||||
Langfuse uses repositories in `packages/shared/src/server/repositories/` for complex data access patterns. Repositories provide:
|
||||
Hanzo uses repositories in `packages/shared/src/server/repositories/` for complex data access patterns. Repositories provide:
|
||||
|
||||
- Abstraction over complex queries (traces, observations, scores, events)
|
||||
- Data converters for transforming database models to application models
|
||||
- ClickHouse query builders and stream processing
|
||||
- Datastore query builders and stream processing
|
||||
- Reusable query logic across services
|
||||
|
||||
Services can use repositories for complex operations OR Prisma directly for simple CRUD operations.
|
||||
@@ -771,7 +771,7 @@ export async function createDataset(ctx: TRPCContext) {
|
||||
|
||||
### 3. Observability with OpenTelemetry + DataDog
|
||||
|
||||
**Langfuse uses OpenTelemetry for backend observability, with traces and logs sent to DataDog.**
|
||||
**Hanzo uses OpenTelemetry for backend observability, with traces and logs sent to DataDog.**
|
||||
|
||||
Use structured logging and instrumentation:
|
||||
|
||||
@@ -780,7 +780,7 @@ import {
|
||||
logger,
|
||||
traceException,
|
||||
instrumentAsync,
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
export async function processEvaluation(evalId: string) {
|
||||
return await instrumentAsync(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Configuration Management - Environment Variables
|
||||
|
||||
Complete guide to managing configuration across Langfuse's monorepo packages.
|
||||
Complete guide to managing configuration across Hanzo's monorepo packages.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -38,7 +38,7 @@ Complete guide to managing configuration across Langfuse's monorepo packages.
|
||||
Each package has its own `env.ts` or `env.mjs` file that validates and exports environment variables:
|
||||
|
||||
```
|
||||
langfuse/
|
||||
hanzo/
|
||||
├── web/src/env.mjs # Next.js app (t3-env pattern)
|
||||
├── worker/src/env.ts # Worker service (Zod schema)
|
||||
├── packages/shared/src/env.ts # Shared config (Zod schema)
|
||||
@@ -68,13 +68,13 @@ export const env = createEnv({
|
||||
DATABASE_URL: z.string().url(),
|
||||
NEXTAUTH_SECRET: z.string().min(1),
|
||||
SALT: z.string(),
|
||||
CLICKHOUSE_URL: z.string().url(),
|
||||
DATASTORE_URL: z.string().url(),
|
||||
// ... 100+ server variables
|
||||
},
|
||||
|
||||
// Client-side variables (exposed to browser)
|
||||
client: {
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION: z
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: z
|
||||
.enum(["US", "EU", "STAGING", "DEV", "HIPAA"])
|
||||
.optional(),
|
||||
NEXT_PUBLIC_SIGN_UP_DISABLED: z.enum(["true", "false"]).default("false"),
|
||||
@@ -85,8 +85,8 @@ export const env = createEnv({
|
||||
runtimeEnv: {
|
||||
DATABASE_URL: process.env.DATABASE_URL,
|
||||
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION:
|
||||
process.env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION,
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION:
|
||||
process.env.NEXT_PUBLIC_HANZO_CLOUD_REGION,
|
||||
// ... must map ALL variables
|
||||
},
|
||||
|
||||
@@ -108,7 +108,7 @@ const salt = env.SALT;
|
||||
// In client-side code (React components)
|
||||
import { env } from "@/src/env.mjs";
|
||||
|
||||
const region = env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION;
|
||||
const region = env.NEXT_PUBLIC_HANZO_CLOUD_REGION;
|
||||
```
|
||||
|
||||
### Worker Package (`worker/src/env.ts`)
|
||||
@@ -119,7 +119,7 @@ Uses **plain Zod schema** for Express.js worker service.
|
||||
|
||||
```typescript
|
||||
import { z } from "zod/v4";
|
||||
import { removeEmptyEnvVariables } from "@langfuse/shared";
|
||||
import { removeEmptyEnvVariables } from "@hanzo/console";
|
||||
|
||||
const EnvSchema = z.object({
|
||||
BUILD_ID: z.string().optional(),
|
||||
@@ -129,22 +129,22 @@ const EnvSchema = z.object({
|
||||
DATABASE_URL: z.string(),
|
||||
PORT: z.coerce.number().positive().max(65536).default(3030),
|
||||
|
||||
// ClickHouse
|
||||
CLICKHOUSE_URL: z.string().url(),
|
||||
CLICKHOUSE_USER: z.string(),
|
||||
CLICKHOUSE_PASSWORD: z.string(),
|
||||
// Datastore
|
||||
DATASTORE_URL: z.string().url(),
|
||||
DATASTORE_USER: z.string(),
|
||||
DATASTORE_PASSWORD: z.string(),
|
||||
|
||||
// S3 Event Upload (required)
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: z.string({
|
||||
error: "Langfuse requires a bucket name for S3 Event Uploads.",
|
||||
S3_EVENT_UPLOAD_BUCKET: z.string({
|
||||
error: "Hanzo requires a bucket name for S3 Event Uploads.",
|
||||
}),
|
||||
|
||||
// Queue concurrency settings
|
||||
LANGFUSE_INGESTION_QUEUE_PROCESSING_CONCURRENCY: z.coerce
|
||||
HANZO_INGESTION_QUEUE_PROCESSING_CONCURRENCY: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(20),
|
||||
LANGFUSE_EVAL_EXECUTION_WORKER_CONCURRENCY: z.coerce
|
||||
HANZO_EVAL_EXECUTION_WORKER_CONCURRENCY: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(5),
|
||||
@@ -171,8 +171,8 @@ export const env: z.infer<typeof EnvSchema> =
|
||||
```typescript
|
||||
import { env } from "./env";
|
||||
|
||||
const concurrency = env.LANGFUSE_INGESTION_QUEUE_PROCESSING_CONCURRENCY;
|
||||
const s3Bucket = env.LANGFUSE_S3_EVENT_UPLOAD_BUCKET;
|
||||
const concurrency = env.HANZO_INGESTION_QUEUE_PROCESSING_CONCURRENCY;
|
||||
const s3Bucket = env.S3_EVENT_UPLOAD_BUCKET;
|
||||
```
|
||||
|
||||
### Shared Package (`packages/shared/src/env.ts`)
|
||||
@@ -197,21 +197,21 @@ const EnvSchema = z.object({
|
||||
REDIS_CONNECTION_STRING: z.string().nullish(),
|
||||
REDIS_CLUSTER_ENABLED: z.enum(["true", "false"]).default("false"),
|
||||
|
||||
// ClickHouse
|
||||
CLICKHOUSE_URL: z.string().url(),
|
||||
CLICKHOUSE_USER: z.string(),
|
||||
CLICKHOUSE_PASSWORD: z.string(),
|
||||
CLICKHOUSE_MAX_OPEN_CONNECTIONS: z.coerce.number().int().default(25),
|
||||
// Datastore
|
||||
DATASTORE_URL: z.string().url(),
|
||||
DATASTORE_USER: z.string(),
|
||||
DATASTORE_PASSWORD: z.string(),
|
||||
DATASTORE_MAX_OPEN_CONNECTIONS: z.coerce.number().int().default(25),
|
||||
|
||||
// S3 Event Upload
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: z.string(),
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION: z.string().optional(),
|
||||
S3_EVENT_UPLOAD_BUCKET: z.string(),
|
||||
S3_EVENT_UPLOAD_REGION: z.string().optional(),
|
||||
|
||||
// Logging
|
||||
LANGFUSE_LOG_LEVEL: z
|
||||
HANZO_LOG_LEVEL: z
|
||||
.enum(["trace", "debug", "info", "warn", "error", "fatal"])
|
||||
.optional(),
|
||||
LANGFUSE_LOG_FORMAT: z.enum(["text", "json"]).default("text"),
|
||||
HANZO_LOG_FORMAT: z.enum(["text", "json"]).default("text"),
|
||||
|
||||
// Encryption
|
||||
ENCRYPTION_KEY: z
|
||||
@@ -234,10 +234,10 @@ export const env: z.infer<typeof EnvSchema> =
|
||||
**Usage:**
|
||||
|
||||
```typescript
|
||||
import { env } from "@langfuse/shared/src/env";
|
||||
import { env } from "@hanzo/console-core/src/env";
|
||||
|
||||
const redisHost = env.REDIS_HOST;
|
||||
const clickhouseUrl = env.CLICKHOUSE_URL;
|
||||
const datastoreUrl = env.DATASTORE_URL;
|
||||
```
|
||||
|
||||
### Enterprise Edition Package (`ee/src/env.ts`)
|
||||
@@ -248,11 +248,11 @@ Minimal Zod schema for EE-specific variables.
|
||||
|
||||
```typescript
|
||||
import { z } from "zod/v4";
|
||||
import { removeEmptyEnvVariables } from "@langfuse/shared";
|
||||
import { removeEmptyEnvVariables } from "@hanzo/console";
|
||||
|
||||
const EnvSchema = z.object({
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION: z.string().optional(),
|
||||
LANGFUSE_EE_LICENSE_KEY: z.string().optional(),
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: z.string().optional(),
|
||||
HANZO_EE_LICENSE_KEY: z.string().optional(),
|
||||
});
|
||||
|
||||
export const env = EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
@@ -261,18 +261,18 @@ export const env = EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
**Usage:**
|
||||
|
||||
```typescript
|
||||
import { env } from "@langfuse/ee/src/env";
|
||||
import { env } from "@hanzo/ee/src/env";
|
||||
|
||||
const licenseKey = env.LANGFUSE_EE_LICENSE_KEY;
|
||||
const licenseKey = env.HANZO_EE_LICENSE_KEY;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Special Environment Variables
|
||||
|
||||
### NEXT_PUBLIC_LANGFUSE_CLOUD_REGION
|
||||
### NEXT_PUBLIC_HANZO_CLOUD_REGION
|
||||
|
||||
**Purpose:** Identifies the cloud deployment region for Langfuse Cloud.
|
||||
**Purpose:** Identifies the cloud deployment region for Hanzo Cloud.
|
||||
|
||||
**Type:** `"US" | "EU" | "STAGING" | "DEV" | "HIPAA" | undefined`
|
||||
|
||||
@@ -288,16 +288,16 @@ const licenseKey = env.LANGFUSE_EE_LICENSE_KEY;
|
||||
| Environment | Value | Purpose |
|
||||
| ------------------------ | ---------------------- | ---------------------------------------------- |
|
||||
| **Developer Laptop** | `"DEV"` or `"STAGING"` | Local development against cloud infrastructure |
|
||||
| **Langfuse Cloud US** | `"US"` | Production US region |
|
||||
| **Langfuse Cloud EU** | `"EU"` | Production EU region |
|
||||
| **Langfuse Cloud HIPAA** | `"HIPAA"` | HIPAA-compliant region |
|
||||
| **Hanzo Cloud US** | `"US"` | Production US region |
|
||||
| **Hanzo Cloud EU** | `"EU"` | Production EU region |
|
||||
| **Hanzo Cloud HIPAA** | `"HIPAA"` | HIPAA-compliant region |
|
||||
| **OSS Self-Hosted** | `undefined` (not set) | Self-hosted deployments don't have region |
|
||||
|
||||
**Use Cases:**
|
||||
|
||||
```typescript
|
||||
// Check if running in cloud
|
||||
if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION) {
|
||||
if (env.NEXT_PUBLIC_HANZO_CLOUD_REGION) {
|
||||
// Enable cloud-specific features
|
||||
- Usage metering and billing
|
||||
- Cloud spend alerts
|
||||
@@ -307,12 +307,12 @@ if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION) {
|
||||
}
|
||||
|
||||
// Region-specific behavior
|
||||
if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION === "HIPAA") {
|
||||
if (env.NEXT_PUBLIC_HANZO_CLOUD_REGION === "HIPAA") {
|
||||
// HIPAA compliance features
|
||||
}
|
||||
|
||||
// Development/staging checks
|
||||
if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION === "DEV") {
|
||||
if (env.NEXT_PUBLIC_HANZO_CLOUD_REGION === "DEV") {
|
||||
// Enable debug features
|
||||
}
|
||||
```
|
||||
@@ -321,16 +321,16 @@ if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION === "DEV") {
|
||||
|
||||
```bash
|
||||
# .env file on developer laptop
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=DEV
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION=DEV
|
||||
|
||||
# Cloud US deployment
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=US
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION=US
|
||||
|
||||
# Self-hosted OSS deployment
|
||||
# (variable not set)
|
||||
```
|
||||
|
||||
### LANGFUSE_EE_LICENSE_KEY
|
||||
### HANZO_EE_LICENSE_KEY
|
||||
|
||||
**Purpose:** Enables Enterprise Edition features in self-hosted deployments.
|
||||
|
||||
@@ -345,13 +345,13 @@ NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=US
|
||||
|
||||
| Deployment | Value | Features Enabled |
|
||||
| ------------------- | ------------------ | ---------------------------------------------------------------- |
|
||||
| **Langfuse Cloud** | Not set | Cloud features controlled by `NEXT_PUBLIC_LANGFUSE_CLOUD_REGION` |
|
||||
| **Hanzo Cloud** | Not set | Cloud features controlled by `NEXT_PUBLIC_HANZO_CLOUD_REGION` |
|
||||
| **OSS Self-Hosted** | Not set | Core open-source features only |
|
||||
| **EE Self-Hosted** | License key string | Enterprise features enabled |
|
||||
|
||||
**Enterprise Features Controlled:**
|
||||
|
||||
When `LANGFUSE_EE_LICENSE_KEY` is set and valid:
|
||||
When `HANZO_EE_LICENSE_KEY` is set and valid:
|
||||
|
||||
- SSO integrations (custom OIDC, SAML)
|
||||
- Advanced RBAC
|
||||
@@ -366,9 +366,9 @@ When `LANGFUSE_EE_LICENSE_KEY` is set and valid:
|
||||
import { env } from "@/src/env.mjs";
|
||||
|
||||
// Check if EE license is present
|
||||
if (env.LANGFUSE_EE_LICENSE_KEY) {
|
||||
if (env.HANZO_EE_LICENSE_KEY) {
|
||||
// Validate license
|
||||
const isValidLicense = await validateEELicense(env.LANGFUSE_EE_LICENSE_KEY);
|
||||
const isValidLicense = await validateEELicense(env.HANZO_EE_LICENSE_KEY);
|
||||
|
||||
if (isValidLicense) {
|
||||
// Enable EE features
|
||||
@@ -382,14 +382,14 @@ if (env.LANGFUSE_EE_LICENSE_KEY) {
|
||||
|
||||
```bash
|
||||
# OSS self-hosted (no license)
|
||||
# LANGFUSE_EE_LICENSE_KEY not set
|
||||
# HANZO_EE_LICENSE_KEY not set
|
||||
|
||||
# EE self-hosted
|
||||
LANGFUSE_EE_LICENSE_KEY=ee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
HANZO_EE_LICENSE_KEY=ee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# Langfuse Cloud (uses region instead)
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=US
|
||||
# LANGFUSE_EE_LICENSE_KEY not used
|
||||
# Hanzo Cloud (uses region instead)
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION=US
|
||||
# HANZO_EE_LICENSE_KEY not used
|
||||
```
|
||||
|
||||
### Other Important Variables
|
||||
@@ -448,7 +448,7 @@ import { env } from "@/src/env.mjs";
|
||||
import { env } from "./env";
|
||||
|
||||
// In shared package
|
||||
import { env } from "@langfuse/shared/src/env";
|
||||
import { env } from "@hanzo/console-core/src/env";
|
||||
```
|
||||
|
||||
### 3. Client Variables Must Start with NEXT*PUBLIC*
|
||||
@@ -480,12 +480,12 @@ PORT: z.coerce.number(); // Converts "3000" to 3000
|
||||
|
||||
```typescript
|
||||
// Split comma-separated values
|
||||
LANGFUSE_LOG_PROPAGATED_HEADERS: z.string().optional().transform((s) =>
|
||||
HANZO_LOG_PROPAGATED_HEADERS: z.string().optional().transform((s) =>
|
||||
s ? s.split(",").map((s) => s.toLowerCase().trim()) : []
|
||||
),
|
||||
|
||||
// Parse project:rate pairs
|
||||
LANGFUSE_INGESTION_PROCESSING_SAMPLED_PROJECTS: z.string().optional().transform((val) => {
|
||||
HANZO_INGESTION_PROCESSING_SAMPLED_PROJECTS: z.string().optional().transform((val) => {
|
||||
const map = new Map<string, number>();
|
||||
val?.split(",").forEach(part => {
|
||||
const [projectId, rate] = part.split(":");
|
||||
@@ -502,7 +502,7 @@ All environment variables are validated when the application starts. Invalid con
|
||||
```bash
|
||||
❌ Validation error:
|
||||
- SALT: Required
|
||||
- CLICKHOUSE_URL: Invalid url
|
||||
- DATASTORE_URL: Invalid url
|
||||
- PORT: Number must be less than or equal to 65536
|
||||
```
|
||||
|
||||
@@ -522,7 +522,7 @@ export const env =
|
||||
Treats empty strings as undefined:
|
||||
|
||||
```typescript
|
||||
import { removeEmptyEnvVariables } from "@langfuse/shared";
|
||||
import { removeEmptyEnvVariables } from "@hanzo/console";
|
||||
|
||||
EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
```
|
||||
@@ -539,7 +539,7 @@ OPTIONAL_VAR= # Treated as undefined, not empty string
|
||||
## Configuration File Locations
|
||||
|
||||
```
|
||||
langfuse/
|
||||
hanzo/
|
||||
├── .env # Local development overrides
|
||||
├── .env.dev.example # Example dev configuration
|
||||
├── web/src/env.mjs # Web app env validation
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Database Patterns - PostgreSQL & ClickHouse
|
||||
# Database Patterns - PostgreSQL & Datastore
|
||||
|
||||
Complete guide to database access patterns in Langfuse using PostgreSQL (Prisma ORM) and ClickHouse (direct client).
|
||||
Complete guide to database access patterns in Hanzo using PostgreSQL (Prisma ORM) and Datastore (direct client).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Database Architecture Overview](#database-architecture-overview)
|
||||
- [PostgreSQL with Prisma](#postgresql-with-prisma)
|
||||
- [ClickHouse with Direct Client](#clickhouse-with-direct-client)
|
||||
- [Datastore with Direct Client](#datastore-with-direct-client)
|
||||
- [Repository Pattern](#repository-pattern)
|
||||
- [When to Use Which Database](#when-to-use-which-database)
|
||||
- [Error Handling](#error-handling)
|
||||
@@ -15,15 +15,15 @@ Complete guide to database access patterns in Langfuse using PostgreSQL (Prisma
|
||||
|
||||
## Database Architecture Overview
|
||||
|
||||
Langfuse uses a **dual database architecture**:
|
||||
Hanzo uses a **dual database architecture**:
|
||||
|
||||
| Database | Technology | Purpose | Access Pattern |
|
||||
| -------------- | ----------------- | ------------------------------------------------------------- | -------------------------------------- |
|
||||
| **PostgreSQL** | Prisma ORM | Transactional data, relational data, CRUD operations | Type-safe ORM with migrations |
|
||||
| **ClickHouse** | Direct SQL client | Analytics data, high-volume traces/observations, aggregations | Raw SQL queries with streaming support |
|
||||
| **Datastore** | Direct SQL client | Analytics data, high-volume traces/observations, aggregations | Raw SQL queries with streaming support |
|
||||
| **Redis** | ioredis | Queues (BullMQ), caching, rate limiting | Direct client access |
|
||||
|
||||
**Key Principle**: Use PostgreSQL for transactional data and relationships. Use ClickHouse for high-volume analytics and time-series data.
|
||||
**Key Principle**: Use PostgreSQL for transactional data and relationships. Use Datastore for high-volume analytics and time-series data.
|
||||
|
||||
**⚠️ Important**: All queries must filter by `project_id` (or `projectId`) to ensure proper data isolation between tenants. This is essential for the multi-tenant architecture.
|
||||
|
||||
@@ -34,13 +34,13 @@ Langfuse uses a **dual database architecture**:
|
||||
### Import Pattern
|
||||
|
||||
```typescript
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
|
||||
// Direct access to Prisma client
|
||||
const user = await prisma.user.findUnique({ where: { id } });
|
||||
```
|
||||
|
||||
**Important**: Always import from `@langfuse/shared/src/db`, not `@prisma/client` directly.
|
||||
**Important**: Always import from `@hanzo/console-core/src/db`, not `@prisma/client` directly.
|
||||
|
||||
### Common CRUD Operations
|
||||
|
||||
@@ -180,42 +180,42 @@ const traces = await prisma.trace.findMany({
|
||||
});
|
||||
```
|
||||
|
||||
## ClickHouse with Direct Client
|
||||
## Datastore with Direct Client
|
||||
|
||||
### Import Pattern
|
||||
|
||||
```typescript
|
||||
import { queryClickhouse } from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
import { clickhouseClient } from "@langfuse/shared/src/server/clickhouse/client";
|
||||
import { queryDatastore } from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
import { datastoreClient } from "@hanzo/console-core/src/server/datastore/client";
|
||||
```
|
||||
|
||||
### ClickHouse Client Singleton
|
||||
### Datastore Client Singleton
|
||||
|
||||
ClickHouse uses a singleton client manager that reuses connections:
|
||||
Datastore uses a singleton client manager that reuses connections:
|
||||
|
||||
```typescript
|
||||
import { clickhouseClient } from "@langfuse/shared/src/server/clickhouse/client";
|
||||
import { datastoreClient } from "@hanzo/console-core/src/server/datastore/client";
|
||||
|
||||
// Get client (automatically reuses existing connection)
|
||||
const client = clickhouseClient();
|
||||
const client = datastoreClient();
|
||||
|
||||
// For read-only queries (uses read replica if configured)
|
||||
const client = clickhouseClient(undefined, "ReadOnly");
|
||||
const client = datastoreClient(undefined, "ReadOnly");
|
||||
```
|
||||
|
||||
### Query Patterns
|
||||
|
||||
ClickHouse queries use **raw SQL** with parameterized queries. Parameters use `{paramName: Type}` syntax:
|
||||
Datastore queries use **raw SQL** with parameterized queries. Parameters use `{paramName: Type}` syntax:
|
||||
|
||||
**⚠️ Important**: All ClickHouse queries must include `project_id` filter to ensure proper tenant isolation.
|
||||
**⚠️ Important**: All Datastore queries must include `project_id` filter to ensure proper tenant isolation.
|
||||
|
||||
**Simple query:**
|
||||
|
||||
```typescript
|
||||
import { queryClickhouse } from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
import { queryDatastore } from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
// ✅ GOOD: Always filter by project_id
|
||||
const rows = await queryClickhouse<{ id: string; name: string }>({
|
||||
const rows = await queryDatastore<{ id: string; name: string }>({
|
||||
query: `
|
||||
SELECT id, name, timestamp
|
||||
FROM traces
|
||||
@@ -226,14 +226,14 @@ const rows = await queryClickhouse<{ id: string; name: string }>({
|
||||
`,
|
||||
params: {
|
||||
projectId, // ← Required for tenant isolation
|
||||
startTime: convertDateToClickhouseDateTime(startDate),
|
||||
startTime: convertDateToDatastoreDateTime(startDate),
|
||||
limit: 100,
|
||||
},
|
||||
tags: { feature: "tracing", type: "trace" },
|
||||
});
|
||||
|
||||
// ❌ BAD: Missing project_id filter
|
||||
// const rows = await queryClickhouse({
|
||||
// const rows = await queryDatastore({
|
||||
// query: `SELECT * FROM traces WHERE timestamp >= {startTime: DateTime64(3)}`,
|
||||
// params: { startTime },
|
||||
// });
|
||||
@@ -242,10 +242,10 @@ const rows = await queryClickhouse<{ id: string; name: string }>({
|
||||
**Streaming query (for large result sets):**
|
||||
|
||||
```typescript
|
||||
import { queryClickhouseStream } from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
import { queryDatastoreStream } from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
// Stream results to avoid loading all rows in memory
|
||||
for await (const row of queryClickhouseStream<ObservationRecordReadType>({
|
||||
for await (const row of queryDatastoreStream<ObservationRecordReadType>({
|
||||
query: `
|
||||
SELECT *
|
||||
FROM observations
|
||||
@@ -262,9 +262,9 @@ for await (const row of queryClickhouseStream<ObservationRecordReadType>({
|
||||
**Upsert (insert) operation:**
|
||||
|
||||
```typescript
|
||||
import { upsertClickhouse } from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
import { upsertDatastore } from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
await upsertClickhouse({
|
||||
await upsertDatastore({
|
||||
table: "traces",
|
||||
records: [
|
||||
{
|
||||
@@ -289,10 +289,10 @@ await upsertClickhouse({
|
||||
**DDL/Administrative commands:**
|
||||
|
||||
```typescript
|
||||
import { commandClickhouse } from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
import { commandDatastore } from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
// Create table, alter schema, etc.
|
||||
await commandClickhouse({
|
||||
await commandDatastore({
|
||||
query: `
|
||||
ALTER TABLE traces
|
||||
ADD COLUMN IF NOT EXISTS new_field String
|
||||
@@ -301,27 +301,27 @@ await commandClickhouse({
|
||||
});
|
||||
```
|
||||
|
||||
### ClickHouse Type Mapping
|
||||
### Datastore Type Mapping
|
||||
|
||||
| JavaScript Type | ClickHouse Param Type |
|
||||
| JavaScript Type | Datastore Param Type |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
| `string` | `String` |
|
||||
| `number` | `UInt32`, `Int64`, `Float64` |
|
||||
| `Date` | `DateTime64(3)` (use `convertDateToClickhouseDateTime()`) |
|
||||
| `Date` | `DateTime64(3)` (use `convertDateToDatastoreDateTime()`) |
|
||||
| `boolean` | `UInt8` (0 or 1) |
|
||||
| `string[]` | `Array(String)` |
|
||||
|
||||
**Date handling:**
|
||||
|
||||
```typescript
|
||||
import { convertDateToClickhouseDateTime } from "@langfuse/shared/src/server/clickhouse/client";
|
||||
import { convertDateToDatastoreDateTime } from "@hanzo/console-core/src/server/datastore/client";
|
||||
|
||||
const params = {
|
||||
startTime: convertDateToClickhouseDateTime(new Date()),
|
||||
startTime: convertDateToDatastoreDateTime(new Date()),
|
||||
};
|
||||
```
|
||||
|
||||
### ClickHouse Query Best Practices
|
||||
### Datastore Query Best Practices
|
||||
|
||||
**1. Always filter by `project_id` for tenant isolation:**
|
||||
|
||||
@@ -341,7 +341,7 @@ const query = `
|
||||
```
|
||||
|
||||
**Why this is important:**
|
||||
- Langfuse is multi-tenant - each project's data must be isolated
|
||||
- Hanzo is multi-tenant - each project's data must be isolated
|
||||
- The `project_id` filter ensures queries only access data from the intended tenant
|
||||
- All queries on project-scoped tables (traces, observations, scores, sessions, etc.) must filter by `project_id`
|
||||
|
||||
@@ -399,20 +399,20 @@ const query = `
|
||||
|
||||
**Error handling with retries:**
|
||||
|
||||
ClickHouse queries automatically retry on network errors (socket hang up). Custom error handling for resource limits:
|
||||
Datastore queries automatically retry on network errors (socket hang up). Custom error handling for resource limits:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
queryClickhouse,
|
||||
ClickHouseResourceError,
|
||||
} from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
queryDatastore,
|
||||
DatastoreResourceError,
|
||||
} from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
try {
|
||||
const rows = await queryClickhouse({ query, params });
|
||||
const rows = await queryDatastore({ query, params });
|
||||
} catch (error) {
|
||||
if (error instanceof ClickHouseResourceError) {
|
||||
if (error instanceof DatastoreResourceError) {
|
||||
// Memory limit, timeout, or overcommit error
|
||||
throw new Error(ClickHouseResourceError.ERROR_ADVICE_MESSAGE);
|
||||
throw new Error(DatastoreResourceError.ERROR_ADVICE_MESSAGE);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@@ -422,18 +422,18 @@ try {
|
||||
|
||||
## Repository Pattern
|
||||
|
||||
Langfuse uses repositories in `packages/shared/src/server/repositories/` for complex data access patterns.
|
||||
Hanzo uses repositories in `packages/shared/src/server/repositories/` for complex data access patterns.
|
||||
|
||||
### When to Use Repositories
|
||||
|
||||
✅ **Use repositories when:**
|
||||
|
||||
- Complex ClickHouse queries with CTEs, aggregations, or joins
|
||||
- Complex Datastore queries with CTEs, aggregations, or joins
|
||||
- Query used in multiple places (DRY principle)
|
||||
- Need data transformation/converters (DB → domain models)
|
||||
- Building reusable query logic with filters
|
||||
|
||||
❌ **Use direct Prisma/ClickHouse for:**
|
||||
❌ **Use direct Prisma/Datastore for:**
|
||||
|
||||
- Simple CRUD operations
|
||||
- One-off queries
|
||||
@@ -441,7 +441,7 @@ Langfuse uses repositories in `packages/shared/src/server/repositories/` for com
|
||||
|
||||
### Repository Examples
|
||||
|
||||
**Trace repository (ClickHouse):**
|
||||
**Trace repository (Datastore):**
|
||||
|
||||
```typescript
|
||||
// packages/shared/src/server/repositories/traces.ts
|
||||
@@ -449,7 +449,7 @@ export const getTracesByIds = async (
|
||||
projectId: string,
|
||||
traceIds: string[],
|
||||
): Promise<TraceRecordReadType[]> => {
|
||||
const rows = await queryClickhouse<TraceRecordReadType>({
|
||||
const rows = await queryDatastore<TraceRecordReadType>({
|
||||
query: `
|
||||
SELECT *
|
||||
FROM traces
|
||||
@@ -462,11 +462,11 @@ export const getTracesByIds = async (
|
||||
tags: { feature: "tracing", type: "trace" },
|
||||
});
|
||||
|
||||
return rows.map(convertClickhouseToDomain);
|
||||
return rows.map(convertDatastoreToDomain);
|
||||
};
|
||||
```
|
||||
|
||||
**Score repository (PostgreSQL + ClickHouse):**
|
||||
**Score repository (PostgreSQL + Datastore):**
|
||||
|
||||
```typescript
|
||||
// Repositories can query both databases
|
||||
@@ -474,8 +474,8 @@ export const getScoresByTraceId = async (
|
||||
projectId: string,
|
||||
traceId: string,
|
||||
) => {
|
||||
// Use ClickHouse for analytics
|
||||
const clickhouseScores = await queryClickhouse<ScoreRecordReadType>({
|
||||
// Use Datastore for analytics
|
||||
const datastoreScores = await queryDatastore<ScoreRecordReadType>({
|
||||
query: `
|
||||
SELECT *
|
||||
FROM scores
|
||||
@@ -490,7 +490,7 @@ export const getScoresByTraceId = async (
|
||||
where: { projectId },
|
||||
});
|
||||
|
||||
return enrichScoresWithConfigs(clickhouseScores, scoreConfigs);
|
||||
return enrichScoresWithConfigs(datastoreScores, scoreConfigs);
|
||||
};
|
||||
```
|
||||
|
||||
@@ -503,19 +503,19 @@ export const getScoresByTraceId = async (
|
||||
| User accounts, projects, API keys | PostgreSQL | Transactional data with strong consistency |
|
||||
| Prompt management, dataset definitions | PostgreSQL | Configuration data with relations |
|
||||
| Project settings, RBAC permissions | PostgreSQL | Small, frequently updated data |
|
||||
| Traces, observations, events | ClickHouse | High-volume time-series data |
|
||||
| Score aggregations, analytics queries | ClickHouse | Fast aggregations over millions of rows |
|
||||
| Usage metrics, cost calculations | ClickHouse | Analytical queries with GROUP BY |
|
||||
| Exports, large dataset queries | ClickHouse | Streaming support for large result sets |
|
||||
| Traces, observations, events | Datastore | High-volume time-series data |
|
||||
| Score aggregations, analytics queries | Datastore | Fast aggregations over millions of rows |
|
||||
| Usage metrics, cost calculations | Datastore | Analytical queries with GROUP BY |
|
||||
| Exports, large dataset queries | Datastore | Streaming support for large result sets |
|
||||
|
||||
**Decision flow:**
|
||||
|
||||
1. Is it high-volume time-series data? → **ClickHouse**
|
||||
2. Does it need aggregation over millions of rows? → **ClickHouse**
|
||||
1. Is it high-volume time-series data? → **Datastore**
|
||||
2. Does it need aggregation over millions of rows? → **Datastore**
|
||||
3. Is it transactional data with relationships? → **PostgreSQL**
|
||||
4. Is it configuration or user data? → **PostgreSQL**
|
||||
5. Is it frequently updated? → **PostgreSQL**
|
||||
6. Is it append-only analytics data? → **ClickHouse**
|
||||
6. Is it append-only analytics data? → **Datastore**
|
||||
|
||||
### Project-Scoped vs Global Tables
|
||||
|
||||
@@ -535,7 +535,7 @@ export const getScoresByTraceId = async (
|
||||
|
||||
```typescript
|
||||
// ✅ CORRECT: Project-scoped query
|
||||
const traces = await queryClickhouse({
|
||||
const traces = await queryDatastore({
|
||||
query: `
|
||||
SELECT * FROM traces
|
||||
WHERE project_id = {projectId: String}
|
||||
@@ -550,7 +550,7 @@ const user = await prisma.user.findUnique({
|
||||
});
|
||||
|
||||
// ❌ WRONG: Project-scoped query without project_id filter
|
||||
// const traces = await queryClickhouse({
|
||||
// const traces = await queryDatastore({
|
||||
// query: `SELECT * FROM traces WHERE timestamp >= {startTime: DateTime64(3)}`,
|
||||
// });
|
||||
```
|
||||
@@ -563,7 +563,7 @@ const user = await prisma.user.findUnique({
|
||||
|
||||
```typescript
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
|
||||
try {
|
||||
await prisma.user.create({ data: userData });
|
||||
@@ -606,35 +606,35 @@ try {
|
||||
| `P2025` | Record not found | Update/delete of non-existent record |
|
||||
| `P2018` | Required relation not found | Connect to non-existent related record |
|
||||
|
||||
### ClickHouse Errors
|
||||
### Datastore Errors
|
||||
|
||||
```typescript
|
||||
import {
|
||||
queryClickhouse,
|
||||
ClickHouseResourceError,
|
||||
} from "@langfuse/shared/src/server/repositories/clickhouse";
|
||||
queryDatastore,
|
||||
DatastoreResourceError,
|
||||
} from "@hanzo/console-core/src/server/repositories/datastore";
|
||||
|
||||
try {
|
||||
const rows = await queryClickhouse({ query, params });
|
||||
const rows = await queryDatastore({ query, params });
|
||||
} catch (error) {
|
||||
// ClickHouse resource errors (memory limit, timeout, overcommit)
|
||||
if (error instanceof ClickHouseResourceError) {
|
||||
logger.warn("ClickHouse resource error", {
|
||||
// Datastore resource errors (memory limit, timeout, overcommit)
|
||||
if (error instanceof DatastoreResourceError) {
|
||||
logger.warn("Datastore resource error", {
|
||||
errorType: error.errorType, // "MEMORY_LIMIT" | "OVERCOMMIT" | "TIMEOUT"
|
||||
message: error.message,
|
||||
});
|
||||
|
||||
// User-friendly error message
|
||||
throw new BadRequestError(ClickHouseResourceError.ERROR_ADVICE_MESSAGE);
|
||||
throw new BadRequestError(DatastoreResourceError.ERROR_ADVICE_MESSAGE);
|
||||
}
|
||||
|
||||
// Network/connection errors are automatically retried
|
||||
logger.error("ClickHouse error", { error });
|
||||
logger.error("Datastore error", { error });
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
|
||||
**ClickHouse error types:**
|
||||
**Datastore error types:**
|
||||
|
||||
| Error Type | Discriminator | Meaning | Solution |
|
||||
| --------------- | ----------------------- | ---------------------------- | -------------------------------------------------- |
|
||||
@@ -642,13 +642,13 @@ try {
|
||||
| `OVERCOMMIT` | "OvercommitTracker" | Memory overcommit limit hit | Reduce query complexity or result set size |
|
||||
| `TIMEOUT` | "Timeout", "timed out" | Query took too long | Add filters, reduce time range, or optimize query |
|
||||
|
||||
**ClickHouse retries:**
|
||||
**Datastore retries:**
|
||||
|
||||
ClickHouse queries automatically retry network errors (socket hang up) with exponential backoff. Configure retry behavior:
|
||||
Datastore queries automatically retry network errors (socket hang up) with exponential backoff. Configure retry behavior:
|
||||
|
||||
```typescript
|
||||
// In packages/shared/src/env.ts
|
||||
LANGFUSE_CLICKHOUSE_QUERY_MAX_ATTEMPTS: z.coerce.number().positive().default(3)
|
||||
HANZO_DATASTORE_QUERY_MAX_ATTEMPTS: z.coerce.number().positive().default(3)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Middleware Guide - tRPC & Public API Patterns
|
||||
|
||||
Complete guide to middleware patterns in Langfuse's Next.js + tRPC architecture.
|
||||
Complete guide to middleware patterns in Hanzo's Next.js + tRPC architecture.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -17,7 +17,7 @@ Complete guide to middleware patterns in Langfuse's Next.js + tRPC architecture.
|
||||
|
||||
**File:** `web/src/server/api/trpc.ts`
|
||||
|
||||
tRPC middleware in Langfuse is composable and type-safe. Each middleware enriches the context and provides guarantees to subsequent middleware.
|
||||
tRPC middleware in Hanzo is composable and type-safe. Each middleware enriches the context and provides guarantees to subsequent middleware.
|
||||
|
||||
### Core tRPC Middlewares
|
||||
|
||||
@@ -30,11 +30,11 @@ const withErrorHandling = t.middleware(async ({ ctx, next }) => {
|
||||
const res = await next({ ctx });
|
||||
|
||||
if (!res.ok) {
|
||||
if (res.error.cause instanceof ClickHouseResourceError) {
|
||||
// Surface ClickHouse resource errors with advice message
|
||||
if (res.error.cause instanceof DatastoreResourceError) {
|
||||
// Surface Datastore resource errors with advice message
|
||||
res.error = new TRPCError({
|
||||
code: "SERVICE_UNAVAILABLE",
|
||||
message: ClickHouseResourceError.ERROR_ADVICE_MESSAGE,
|
||||
message: DatastoreResourceError.ERROR_ADVICE_MESSAGE,
|
||||
});
|
||||
} else {
|
||||
// Transform 5xx errors to not expose internals
|
||||
@@ -57,13 +57,13 @@ const withErrorHandling = t.middleware(async ({ ctx, next }) => {
|
||||
|
||||
**2. OpenTelemetry Instrumentation (`withOtelInstrumentation`)**
|
||||
|
||||
Propagates OpenTelemetry context with Langfuse-specific baggage:
|
||||
Propagates OpenTelemetry context with Hanzo-specific baggage:
|
||||
|
||||
```typescript
|
||||
const withOtelInstrumentation = t.middleware(async (opts) => {
|
||||
const actualInput = await opts.getRawInput();
|
||||
|
||||
const baggageCtx = contextWithLangfuseProps({
|
||||
const baggageCtx = contextWithHanzoProps({
|
||||
headers: opts.ctx.headers,
|
||||
userId: opts.ctx.session?.user?.id,
|
||||
projectId: (actualInput as Record<string, string>)?.projectId,
|
||||
@@ -236,7 +236,7 @@ const enforceTraceAccess = t.middleware(async (opts) => {
|
||||
|
||||
### tRPC Procedure Types
|
||||
|
||||
Langfuse exports composed procedures with middleware chains:
|
||||
Hanzo exports composed procedures with middleware chains:
|
||||
|
||||
```typescript
|
||||
// 1. Public procedure (no auth required)
|
||||
@@ -286,7 +286,7 @@ Wraps all public API routes with CORS, error handling, and OpenTelemetry:
|
||||
```typescript
|
||||
export function withMiddlewares(handlers: Handlers) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const ctx = contextWithLangfuseProps({ headers: req.headers });
|
||||
const ctx = contextWithHanzoProps({ headers: req.headers });
|
||||
|
||||
return opentelemetry.context.with(ctx, async () => {
|
||||
try {
|
||||
@@ -310,9 +310,9 @@ export function withMiddlewares(handlers: Handlers) {
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof ClickHouseResourceError) {
|
||||
if (error instanceof DatastoreResourceError) {
|
||||
return res.status(524).json({
|
||||
message: ClickHouseResourceError.ERROR_ADVICE_MESSAGE,
|
||||
message: DatastoreResourceError.ERROR_ADVICE_MESSAGE,
|
||||
error: "Request is taking too long to process.",
|
||||
});
|
||||
}
|
||||
@@ -380,7 +380,7 @@ export const createAuthedProjectAPIRoute = <TQuery, TBody, TResponse>(
|
||||
: {};
|
||||
|
||||
// 4. Execute with OpenTelemetry context
|
||||
const ctx = contextWithLangfuseProps({
|
||||
const ctx = contextWithHanzoProps({
|
||||
headers: req.headers,
|
||||
projectId: auth.scope.projectId,
|
||||
});
|
||||
@@ -495,16 +495,16 @@ async function verifyBasicAuth(authHeader: string | undefined) {
|
||||
async function verifyAdminApiKeyAuth(req: NextApiRequest) {
|
||||
// Requires:
|
||||
// 1. Authorization: Bearer <ADMIN_API_KEY>
|
||||
// 2. x-langfuse-admin-api-key: <ADMIN_API_KEY>
|
||||
// 3. x-langfuse-project-id: <project-id>
|
||||
// 2. x-hanzo-admin-api-key: <ADMIN_API_KEY>
|
||||
// 3. x-hanzo-project-id: <project-id>
|
||||
|
||||
if (env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION) {
|
||||
throw { status: 403, message: "Admin API key auth not available on Langfuse Cloud" };
|
||||
if (env.NEXT_PUBLIC_HANZO_CLOUD_REGION) {
|
||||
throw { status: 403, message: "Admin API key auth not available on Hanzo Cloud" };
|
||||
}
|
||||
|
||||
const adminApiKey = env.ADMIN_API_KEY;
|
||||
const bearerToken = req.headers.authorization?.replace("Bearer ", "");
|
||||
const adminApiKeyHeader = req.headers["x-langfuse-admin-api-key"];
|
||||
const adminApiKeyHeader = req.headers["x-hanzo-admin-api-key"];
|
||||
|
||||
// Timing-safe comparison
|
||||
const isValid =
|
||||
@@ -513,7 +513,7 @@ async function verifyAdminApiKeyAuth(req: NextApiRequest) {
|
||||
|
||||
if (!isValid) throw { status: 401, message: "Invalid admin API key" };
|
||||
|
||||
const projectId = req.headers["x-langfuse-project-id"];
|
||||
const projectId = req.headers["x-hanzo-project-id"];
|
||||
const project = await prisma.project.findUnique({ where: { id: projectId } });
|
||||
|
||||
if (!project) throw { status: 404, message: "Project not found" };
|
||||
@@ -532,7 +532,7 @@ All tRPC errors go through `withErrorHandling` middleware:
|
||||
|
||||
**Error types handled:**
|
||||
|
||||
1. **ClickHouseResourceError** → `SERVICE_UNAVAILABLE` (524)
|
||||
1. **DatastoreResourceError** → `SERVICE_UNAVAILABLE` (524)
|
||||
2. **BaseError** → Preserves httpCode and message
|
||||
3. **5xx errors** → Sanitized as "Internal error" (hides stack traces)
|
||||
4. **4xx errors** → Original error message preserved
|
||||
@@ -541,10 +541,10 @@ All tRPC errors go through `withErrorHandling` middleware:
|
||||
|
||||
```typescript
|
||||
if (!res.ok) {
|
||||
if (res.error.cause instanceof ClickHouseResourceError) {
|
||||
if (res.error.cause instanceof DatastoreResourceError) {
|
||||
res.error = new TRPCError({
|
||||
code: "SERVICE_UNAVAILABLE",
|
||||
message: ClickHouseResourceError.ERROR_ADVICE_MESSAGE,
|
||||
message: DatastoreResourceError.ERROR_ADVICE_MESSAGE,
|
||||
});
|
||||
} else {
|
||||
const { code, httpStatus } = resolveError(res.error);
|
||||
@@ -574,10 +574,10 @@ catch (error) {
|
||||
});
|
||||
}
|
||||
|
||||
// 2. ClickHouseResourceError (query timeouts, memory limits)
|
||||
if (error instanceof ClickHouseResourceError) {
|
||||
// 2. DatastoreResourceError (query timeouts, memory limits)
|
||||
if (error instanceof DatastoreResourceError) {
|
||||
return res.status(524).json({
|
||||
message: ClickHouseResourceError.ERROR_ADVICE_MESSAGE,
|
||||
message: DatastoreResourceError.ERROR_ADVICE_MESSAGE,
|
||||
error: "Request is taking too long to process.",
|
||||
});
|
||||
}
|
||||
@@ -612,16 +612,16 @@ catch (error) {
|
||||
|
||||
## OpenTelemetry Instrumentation
|
||||
|
||||
All requests (tRPC and public API) propagate OpenTelemetry context with Langfuse-specific baggage.
|
||||
All requests (tRPC and public API) propagate OpenTelemetry context with Hanzo-specific baggage.
|
||||
|
||||
### Context Propagation Pattern
|
||||
|
||||
```typescript
|
||||
import { contextWithLangfuseProps } from "@langfuse/shared/src/server";
|
||||
import { contextWithHanzoProps } from "@hanzo/console-core/src/server";
|
||||
import * as opentelemetry from "@opentelemetry/api";
|
||||
|
||||
// Create context with Langfuse baggage
|
||||
const ctx = contextWithLangfuseProps({
|
||||
// Create context with Hanzo baggage
|
||||
const ctx = contextWithHanzoProps({
|
||||
headers: req.headers,
|
||||
userId: session?.user?.id,
|
||||
projectId: input?.projectId,
|
||||
@@ -645,7 +645,7 @@ return opentelemetry.context.with(ctx, async () => {
|
||||
const withOtelInstrumentation = t.middleware(async (opts) => {
|
||||
const actualInput = await opts.getRawInput();
|
||||
|
||||
const baggageCtx = contextWithLangfuseProps({
|
||||
const baggageCtx = contextWithHanzoProps({
|
||||
headers: opts.ctx.headers,
|
||||
userId: opts.ctx.session?.user?.id,
|
||||
projectId: (actualInput as Record<string, string>)?.projectId,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Routing Patterns - Next.js & tRPC
|
||||
|
||||
Complete guide to routing and separation of concerns in Langfuse's Next.js + tRPC architecture.
|
||||
Complete guide to routing and separation of concerns in Hanzo's Next.js + tRPC architecture.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -16,7 +16,7 @@ Complete guide to routing and separation of concerns in Langfuse's Next.js + tRP
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Langfuse uses a **layered architecture** with clear separation of concerns:
|
||||
Hanzo uses a **layered architecture** with clear separation of concerns:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
@@ -41,7 +41,7 @@ Langfuse uses a **layered architecture** with clear separation of concerns:
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DATABASE LAYER │
|
||||
│ PostgreSQL (Prisma) + ClickHouse (Direct Client) │
|
||||
│ PostgreSQL (Prisma) + Datastore (Direct Client) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -63,14 +63,14 @@ Langfuse uses a **layered architecture** with clear separation of concerns:
|
||||
**Services:**
|
||||
- ✅ Contain business logic
|
||||
- ✅ Orchestrate multiple operations
|
||||
- ✅ Call repositories or Prisma/ClickHouse
|
||||
- ✅ Call repositories or Prisma/Datastore
|
||||
- ✅ Handle complex workflows
|
||||
- ❌ Should NOT know about HTTP, tRPC, or request/response objects
|
||||
|
||||
**Repositories:**
|
||||
- ✅ Complex database queries
|
||||
- ✅ Data transformation (DB → domain models)
|
||||
- ✅ ClickHouse query builders
|
||||
- ✅ Datastore query builders
|
||||
- ✅ Reusable query logic
|
||||
- ❌ Should NOT contain business logic
|
||||
|
||||
@@ -89,12 +89,12 @@ tRPC routers define type-safe procedures for the internal UI. Each router groups
|
||||
```typescript
|
||||
import { z } from "zod/v4";
|
||||
import { createTRPCRouter, protectedProjectProcedure } from "@/src/server/api/trpc";
|
||||
import { paginationZod, singleFilter, orderBy } from "@langfuse/shared";
|
||||
import { paginationZod, singleFilter, orderBy } from "@hanzo/console";
|
||||
import {
|
||||
getScoresUiTable,
|
||||
getScoresUiCount,
|
||||
upsertScore,
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
|
||||
const ScoreAllOptions = z.object({
|
||||
projectId: z.string(),
|
||||
@@ -111,7 +111,7 @@ export const scoresRouter = createTRPCRouter({
|
||||
.input(ScoreAllOptions)
|
||||
.query(async ({ input, ctx }) => {
|
||||
// Delegate to repository for data fetching
|
||||
const clickhouseScoreData = await getScoresUiTable({
|
||||
const datastoreScoreData = await getScoresUiTable({
|
||||
projectId: input.projectId,
|
||||
filter: input.filter ?? [],
|
||||
orderBy: input.orderBy,
|
||||
@@ -124,14 +124,14 @@ export const scoresRouter = createTRPCRouter({
|
||||
ctx.prisma.jobExecution.findMany({
|
||||
where: {
|
||||
jobOutputScoreId: {
|
||||
in: clickhouseScoreData.map((score) => score.id),
|
||||
in: datastoreScoreData.map((score) => score.id),
|
||||
},
|
||||
},
|
||||
}),
|
||||
ctx.prisma.user.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: clickhouseScoreData
|
||||
in: datastoreScoreData
|
||||
.map((s) => s.authorUserId)
|
||||
.filter((id): id is string => id !== null),
|
||||
},
|
||||
@@ -140,7 +140,7 @@ export const scoresRouter = createTRPCRouter({
|
||||
]);
|
||||
|
||||
// Transform and combine data
|
||||
return clickhouseScoreData.map((score) => ({
|
||||
return datastoreScoreData.map((score) => ({
|
||||
...score,
|
||||
jobConfigurationId:
|
||||
jobExecutions.find((j) => j.jobOutputScoreId === score.id)
|
||||
@@ -271,8 +271,8 @@ import {
|
||||
GetScoresResponseV1,
|
||||
PostScoresBodyV1,
|
||||
PostScoresResponseV1,
|
||||
} from "@langfuse/shared";
|
||||
import { eventTypes, processEventBatch } from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console";
|
||||
import { eventTypes, processEventBatch } from "@hanzo/console-core/src/server";
|
||||
import { ScoresApiService } from "@/src/features/public-api/server/scores-api-service";
|
||||
|
||||
export default withMiddlewares({
|
||||
@@ -384,7 +384,7 @@ import {
|
||||
_handleGetScoresCountForPublicApi,
|
||||
type ScoreQueryType,
|
||||
} from "@/src/features/public-api/server/scores";
|
||||
import { _handleGetScoreById } from "@langfuse/shared/src/server";
|
||||
import { _handleGetScoreById } from "@hanzo/console-core/src/server";
|
||||
|
||||
export class ScoresApiService {
|
||||
constructor(private readonly apiVersion: "v1" | "v2") {}
|
||||
@@ -406,7 +406,7 @@ export class ScoresApiService {
|
||||
scoreId,
|
||||
source,
|
||||
scoreScope: this.apiVersion === "v1" ? "traces_only" : "all",
|
||||
preferredClickhouseService: "ReadOnly",
|
||||
preferredDatastoreService: "ReadOnly",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ export class ScoresApiService {
|
||||
**Key Points:**
|
||||
- Services contain business logic, not routing logic
|
||||
- Services should NOT import tRPC or Next.js types
|
||||
- Services can call repositories, Prisma, ClickHouse directly
|
||||
- Services can call repositories, Prisma, Datastore directly
|
||||
- Services orchestrate multiple operations
|
||||
- Services are reusable across tRPC and public API
|
||||
|
||||
@@ -476,10 +476,10 @@ Repositories handle complex database queries, data transformation, and provide r
|
||||
|
||||
```
|
||||
packages/shared/src/server/repositories/
|
||||
├── traces.ts # Trace queries (ClickHouse)
|
||||
├── observations.ts # Observation queries (ClickHouse)
|
||||
├── scores.ts # Score queries (ClickHouse)
|
||||
├── clickhouse.ts # Core ClickHouse helpers
|
||||
├── traces.ts # Trace queries (Datastore)
|
||||
├── observations.ts # Observation queries (Datastore)
|
||||
├── scores.ts # Score queries (Datastore)
|
||||
├── datastore.ts # Core Datastore helpers
|
||||
└── definitions.ts # Type definitions
|
||||
```
|
||||
|
||||
@@ -488,9 +488,9 @@ packages/shared/src/server/repositories/
|
||||
**File:** `packages/shared/src/server/repositories/traces.ts`
|
||||
|
||||
```typescript
|
||||
import { queryClickhouse, upsertClickhouse } from "./clickhouse";
|
||||
import { queryDatastore, upsertDatastore } from "./datastore";
|
||||
import { TraceRecordReadType } from "./definitions";
|
||||
import { convertClickhouseToDomain } from "./traces_converters";
|
||||
import { convertDatastoreToDomain } from "./traces_converters";
|
||||
|
||||
/**
|
||||
* Get traces by IDs
|
||||
@@ -499,7 +499,7 @@ export const getTracesByIds = async (
|
||||
projectId: string,
|
||||
traceIds: string[]
|
||||
): Promise<TraceRecordReadType[]> => {
|
||||
const rows = await queryClickhouse<TraceRecordReadType>({
|
||||
const rows = await queryDatastore<TraceRecordReadType>({
|
||||
query: `
|
||||
SELECT *
|
||||
FROM traces
|
||||
@@ -512,16 +512,16 @@ export const getTracesByIds = async (
|
||||
tags: { feature: "tracing", type: "trace" },
|
||||
});
|
||||
|
||||
return rows.map(convertClickhouseToDomain);
|
||||
return rows.map(convertDatastoreToDomain);
|
||||
};
|
||||
|
||||
/**
|
||||
* Upsert trace to ClickHouse
|
||||
* Upsert trace to Datastore
|
||||
*/
|
||||
export const upsertTrace = async (
|
||||
trace: TraceRecordInsertType
|
||||
): Promise<void> => {
|
||||
await upsertClickhouse({
|
||||
await upsertDatastore({
|
||||
table: "traces",
|
||||
records: [trace],
|
||||
eventBodyMapper: (body) => ({
|
||||
@@ -536,22 +536,22 @@ export const upsertTrace = async (
|
||||
```
|
||||
|
||||
**Key Points:**
|
||||
- Use `queryClickhouse` for SELECT queries
|
||||
- Use `upsertClickhouse` for INSERT/UPDATE
|
||||
- Use `commandClickhouse` for DDL (ALTER TABLE, etc.)
|
||||
- Include data converters (`convertClickhouseToDomain`)
|
||||
- Use `queryDatastore` for SELECT queries
|
||||
- Use `upsertDatastore` for INSERT/UPDATE
|
||||
- Use `commandDatastore` for DDL (ALTER TABLE, etc.)
|
||||
- Include data converters (`convertDatastoreToDomain`)
|
||||
- Add OpenTelemetry tags for observability
|
||||
- Repositories should NOT contain business logic
|
||||
|
||||
### When to Use Repositories
|
||||
|
||||
✅ **Use repositories for:**
|
||||
- Complex ClickHouse queries with CTEs, joins, aggregations
|
||||
- Complex Datastore queries with CTEs, joins, aggregations
|
||||
- Queries used in multiple places (DRY principle)
|
||||
- Data transformation from DB types to domain models
|
||||
- Streaming large result sets
|
||||
|
||||
❌ **Use direct Prisma/ClickHouse for:**
|
||||
❌ **Use direct Prisma/Datastore for:**
|
||||
- Simple CRUD operations
|
||||
- One-off queries
|
||||
- Prototyping (can refactor to repository later)
|
||||
@@ -610,7 +610,7 @@ export async function createScoreWithValidation({
|
||||
});
|
||||
|
||||
if (!config) {
|
||||
throw new LangfuseNotFoundError("Score config not found");
|
||||
throw new HanzoNotFoundError("Score config not found");
|
||||
}
|
||||
|
||||
validateConfigAgainstBody(config, scoreData);
|
||||
@@ -619,7 +619,7 @@ export async function createScoreWithValidation({
|
||||
const scoreId = randomUUID();
|
||||
|
||||
await Promise.all([
|
||||
// Create score in ClickHouse
|
||||
// Create score in Datastore
|
||||
upsertScore({
|
||||
id: scoreId,
|
||||
projectId,
|
||||
@@ -649,7 +649,7 @@ export const upsertScore = async (
|
||||
score: ScoreInsertType
|
||||
): Promise<void> => {
|
||||
// ✅ Pure data access - no business logic
|
||||
await upsertClickhouse({
|
||||
await upsertDatastore({
|
||||
table: "scores",
|
||||
records: [score],
|
||||
eventBodyMapper: (body) => ({
|
||||
@@ -751,8 +751,8 @@ export default withMiddlewares({
|
||||
GET: createAuthedProjectAPIRoute({
|
||||
name: "Get Scores",
|
||||
fn: async ({ auth }) => {
|
||||
// ❌ Direct ClickHouse query in route
|
||||
const scores = await queryClickhouse({
|
||||
// ❌ Direct Datastore query in route
|
||||
const scores = await queryDatastore({
|
||||
query: "SELECT * FROM scores WHERE project_id = {projectId: String}",
|
||||
params: { projectId: auth.scope.projectId },
|
||||
});
|
||||
@@ -809,7 +809,7 @@ export const upsertScore = async (
|
||||
// ❌ Side effects in repository
|
||||
await auditLog({ ... });
|
||||
|
||||
await upsertClickhouse({ ... });
|
||||
await upsertDatastore({ ... });
|
||||
};
|
||||
```
|
||||
|
||||
@@ -820,7 +820,7 @@ export const upsertScore = async (
|
||||
export const upsertScore = async (
|
||||
score: ScoreInsertType
|
||||
): Promise<void> => {
|
||||
await upsertClickhouse({
|
||||
await upsertDatastore({
|
||||
table: "scores",
|
||||
records: [score],
|
||||
eventBodyMapper: (body) => ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Testing Guide - Backend Testing Strategies
|
||||
|
||||
Complete guide to testing Langfuse backend services across web, worker, and shared packages.
|
||||
Complete guide to testing Hanzo backend services across web, worker, and shared packages.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -16,7 +16,7 @@ Complete guide to testing Langfuse backend services across web, worker, and shar
|
||||
|
||||
## Test Types Overview
|
||||
|
||||
Langfuse uses multiple testing strategies for different layers:
|
||||
Hanzo uses multiple testing strategies for different layers:
|
||||
|
||||
| Test Type | Framework | Location | Purpose |
|
||||
|-----------|-----------|----------|---------|
|
||||
@@ -80,8 +80,8 @@ import {
|
||||
createEvent,
|
||||
createEventsCh,
|
||||
getObservationsWithModelDataFromEventsTable,
|
||||
} from "@langfuse/shared/src/server";
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
describe("Event Repository Tests", () => {
|
||||
@@ -176,7 +176,7 @@ describe("Event Repository Tests", () => {
|
||||
|
||||
**Key Points:**
|
||||
- Tests service/repository functions directly
|
||||
- Uses ClickHouse and Prisma test data
|
||||
- Uses Datastore and Prisma test data
|
||||
- Always cleanup test data after tests
|
||||
- Use unique IDs to avoid test interference
|
||||
|
||||
@@ -191,11 +191,11 @@ Test tRPC procedures with caller pattern and auth context.
|
||||
```typescript
|
||||
import { appRouter } from "@/src/server/api/root";
|
||||
import { createInnerTRPCContext } from "@/src/server/api/trpc";
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { createOrgProjectAndApiKey } from "@langfuse/shared/src/server";
|
||||
import { prisma } from "@hanzo/console-core/src/db";
|
||||
import { createOrgProjectAndApiKey } from "@hanzo/console-core/src/server";
|
||||
import type { Session } from "next-auth";
|
||||
import { v4 } from "uuid";
|
||||
import { JobConfigState } from "@langfuse/shared";
|
||||
import { JobConfigState } from "@hanzo/console";
|
||||
|
||||
async function prepare() {
|
||||
const { project, org } = await createOrgProjectAndApiKey();
|
||||
@@ -349,7 +349,7 @@ import {
|
||||
createScoresCh,
|
||||
createTrace,
|
||||
createTracesCh,
|
||||
} from "@langfuse/shared/src/server";
|
||||
} from "@hanzo/console-core/src/server";
|
||||
import { getObservationStream } from "../features/database-read-stream/observation-stream";
|
||||
|
||||
describe("batch export test suite", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description: How to manage authorization and RBAC within full-stack langfuse features
|
||||
description: How to manage authorization and RBAC within full-stack hanzo features
|
||||
globs: web/
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
@@ -15,7 +15,7 @@ alwaysApply: true
|
||||
|
||||
## API for frontend features
|
||||
|
||||
- We use TRPC.io to power full-stack features of the Langfuse Frontend
|
||||
- We use TRPC.io to power full-stack features of the Hanzo Frontend
|
||||
- Entry point for all trpc routes: [root.ts](mdc:web/src/server/api/root.ts)
|
||||
- Authentication, see [authorization-and-rbac.mdc](mdc:.cursor/rules/authorization-and-rbac.mdc)
|
||||
- Entitlements, see [entitlements.mdc](mdc:.cursor/rules/entitlements.mdc)
|
||||
|
||||
@@ -16,10 +16,10 @@ The most important domain objects are in [observations.ts](mdc:packages/shared/s
|
||||
|
||||
## Database schema
|
||||
|
||||
We use Postgres and Clickhouse.
|
||||
We use Postgres and Datastore.
|
||||
|
||||
- The postgres schema is in [schema.prisma](mdc:packages/shared/prisma/schema.prisma)
|
||||
- The clickhouse schema is in [0001_traces.up.sql](mdc:packages/shared/clickhouse/migrations/clustered/0001_traces.up.sql), [0002_observations.up.sql](mdc:packages/shared/clickhouse/migrations/clustered/0002_observations.up.sql), [0003_scores.up.sql](mdc:packages/shared/clickhouse/migrations/clustered/0003_scores.up.sql)
|
||||
- The datastore schema is in [0001_traces.up.sql](mdc:packages/shared/datastore/migrations/clustered/0001_traces.up.sql), [0002_observations.up.sql](mdc:packages/shared/datastore/migrations/clustered/0002_observations.up.sql), [0003_scores.up.sql](mdc:packages/shared/datastore/migrations/clustered/0003_scores.up.sql)
|
||||
|
||||
## Cursor Background/Cloud Agent
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description: How to create new public api routes for Langfuse
|
||||
description: How to create new public api routes for Hanzo
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Dev container Dockerfile
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:20-bookworm
|
||||
|
||||
# Install golang-migrate for database migrations
|
||||
RUN curl -L https://github.com/golang-migrate/migrate/releases/download/v4.19.1/migrate.linux-amd64.tar.gz | tar xvz && \
|
||||
# Install golang-migrate with Hanzo Datastore driver support
|
||||
RUN curl -L https://github.com/hanzoai/migrate/releases/download/v4.19.2/migrate.linux-amd64.tar.gz | tar xvz && \
|
||||
chmod +x migrate && \
|
||||
mv migrate /usr/local/bin/migrate
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "langfuse-development",
|
||||
"name": "hanzo-development",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
|
||||
+115
-6
@@ -1,8 +1,117 @@
|
||||
Dockerfile
|
||||
# Dependencies
|
||||
node_modules/
|
||||
**/node_modules/
|
||||
.pnpm-store/
|
||||
.npm/
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
**/.next/
|
||||
.next/
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# IDE files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Testing
|
||||
coverage/
|
||||
.nyc_output/
|
||||
*.lcov
|
||||
test-results/
|
||||
playwright-report/
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.*.local
|
||||
local.env
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Docker
|
||||
.dockerignore
|
||||
node_modules
|
||||
npm-debug.log
|
||||
Dockerfile*
|
||||
docker-compose*.yml
|
||||
compose*.yaml
|
||||
|
||||
# CI/CD
|
||||
.github/
|
||||
.gitlab-ci.yml
|
||||
.travis.yml
|
||||
.circleci/
|
||||
|
||||
# Cache directories
|
||||
.cache/
|
||||
.turbo/
|
||||
.parcel-cache/
|
||||
.eslintcache
|
||||
.yarn-integrity
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Runtime data
|
||||
pids/
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Husky
|
||||
.husky/
|
||||
|
||||
# Documentation
|
||||
README.md
|
||||
**/.next
|
||||
.git
|
||||
**/node_modules
|
||||
CHANGELOG.md
|
||||
*.md
|
||||
|
||||
# Temporary files
|
||||
.tmp/
|
||||
temp/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Fern
|
||||
fern/
|
||||
generated/
|
||||
|
||||
# Monitoring
|
||||
monitoring/
|
||||
|
||||
# Scripts
|
||||
scripts/
|
||||
|
||||
# Tests
|
||||
tests/
|
||||
|
||||
# Misc
|
||||
*.tar.gz
|
||||
*.zip
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Build-time placeholder values for Docker builds
|
||||
# Real values are provided at runtime via environment variables
|
||||
DATABASE_URL=postgresql://placeholder:placeholder@localhost:5432/placeholder
|
||||
NEXTAUTH_SECRET=build-time-placeholder-secret-32chars
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
SALT=build-time-placeholder-salt-32chars
|
||||
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
# Datastore (analytics DB)
|
||||
# Values must pass env.mjs validation at build time. Using defaults that match
|
||||
# docker-compose so sourcing this file at runtime (up.sh) won't break auth.
|
||||
DATASTORE_URL=http://localhost:8123
|
||||
DATASTORE_USER=hanzo
|
||||
DATASTORE_PASSWORD=hanzo
|
||||
DATASTORE_CLUSTER_ENABLED=false
|
||||
# Redis
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
+38
-38
@@ -6,12 +6,12 @@
|
||||
DIRECT_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
|
||||
# Clickhouse
|
||||
CLICKHOUSE_MIGRATION_URL="clickhouse://localhost:9000"
|
||||
CLICKHOUSE_URL="http://localhost:8123"
|
||||
CLICKHOUSE_USER="clickhouse"
|
||||
CLICKHOUSE_PASSWORD="clickhouse"
|
||||
CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
# Datastore (analytics database)
|
||||
DATASTORE_MIGRATION_URL="datastore://localhost:9000"
|
||||
DATASTORE_URL="http://localhost:8123"
|
||||
DATASTORE_USER="hanzo"
|
||||
DATASTORE_PASSWORD="hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED="false"
|
||||
|
||||
# Next Auth
|
||||
# You can generate a new secret on the command line with:
|
||||
@@ -21,11 +21,11 @@ CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
NEXTAUTH_SECRET="secret"
|
||||
|
||||
# Langfuse Cloud Environment
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION="DEV"
|
||||
# Hanzo Cloud Environment
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION="DEV"
|
||||
|
||||
# Langfuse experimental features
|
||||
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
# Console experimental features
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
|
||||
# Salt for API key hashing
|
||||
SALT="salt"
|
||||
@@ -36,39 +36,39 @@ SMTP_CONNECTION_URL="" # Defines the connection url for smtp server.
|
||||
|
||||
# DON'T PANIC: The Azurite Secrets are well-known and meant to be hard-coded
|
||||
# S3 Batch Exports
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENABLED=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_BUCKET=langfuse
|
||||
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=devstoreaccount1
|
||||
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
LANGFUSE_S3_BATCH_EXPORT_REGION=auto
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_PREFIX=exports/
|
||||
S3_BATCH_EXPORT_ENABLED=true
|
||||
S3_BATCH_EXPORT_BUCKET=hanzo
|
||||
S3_BATCH_EXPORT_ACCESS_KEY_ID=devstoreaccount1
|
||||
S3_BATCH_EXPORT_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
S3_BATCH_EXPORT_REGION=auto
|
||||
S3_BATCH_EXPORT_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
S3_BATCH_EXPORT_PREFIX=exports/
|
||||
|
||||
# S3 Media Upload LOCAL
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID=devstoreaccount1
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_REGION=auto
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
S3_MEDIA_UPLOAD_BUCKET=hanzo
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID=devstoreaccount1
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
S3_MEDIA_UPLOAD_REGION=auto
|
||||
S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
|
||||
# S3 Event Bucket Upload
|
||||
## Set to true to test uploading all events to S3
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=devstoreaccount1
|
||||
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION=auto
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||
S3_EVENT_UPLOAD_BUCKET=hanzo
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID=devstoreaccount1
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
|
||||
S3_EVENT_UPLOAD_REGION=auto
|
||||
S3_EVENT_UPLOAD_ENDPOINT=http://localhost:10000/devstoreaccount1
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_EVENT_UPLOAD_PREFIX=events/
|
||||
|
||||
LANGFUSE_USE_AZURE_BLOB=true
|
||||
LANGFUSE_AZURE_SKIP_CONTAINER_CHECK=false
|
||||
HANZO_USE_AZURE_BLOB=true
|
||||
HANZO_AZURE_SKIP_CONTAINER_CHECK=false
|
||||
|
||||
# Set during docker build of application
|
||||
# Used to disable environment verification at build time
|
||||
@@ -82,4 +82,4 @@ REDIS_AUTH="myredissecret"
|
||||
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# speeds up local development by not executing init scripts on server startup
|
||||
NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT="false"
|
||||
NEXT_PUBLIC_HANZO_RUN_NEXT_INIT="false"
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
DIRECT_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
|
||||
# Clickhouse
|
||||
CLICKHOUSE_MIGRATION_URL="clickhouse://localhost:9000"
|
||||
CLICKHOUSE_URL="http://localhost:8123"
|
||||
CLICKHOUSE_USER="clickhouse"
|
||||
CLICKHOUSE_PASSWORD="clickhouse"
|
||||
CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
# Datastore (analytics database)
|
||||
DATASTORE_MIGRATION_URL="datastore://localhost:9000"
|
||||
DATASTORE_URL="http://localhost:8123"
|
||||
DATASTORE_USER="hanzo"
|
||||
DATASTORE_PASSWORD="hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED="false"
|
||||
|
||||
# Next Auth
|
||||
# You can generate a new secret on the command line with:
|
||||
@@ -21,11 +21,11 @@ CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
NEXTAUTH_SECRET="secret"
|
||||
|
||||
# Langfuse Cloud Environment
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION="DEV"
|
||||
# Hanzo Cloud Environment
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION="DEV"
|
||||
|
||||
# Langfuse experimental features
|
||||
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
# Console experimental features
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
|
||||
# Salt for API key hashing
|
||||
SALT="salt"
|
||||
@@ -35,36 +35,36 @@ EMAIL_FROM_ADDRESS="" # Defines the email address to use as the from address.
|
||||
SMTP_CONNECTION_URL="" # Defines the connection url for smtp server.
|
||||
|
||||
# S3 Batch Exports
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENABLED=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_BUCKET=langfuse
|
||||
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_BATCH_EXPORT_REGION=us-east-1
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_PREFIX=exports/
|
||||
S3_BATCH_EXPORT_ENABLED=true
|
||||
S3_BATCH_EXPORT_BUCKET=hanzo
|
||||
S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||
S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_BATCH_EXPORT_REGION=us-east-1
|
||||
S3_BATCH_EXPORT_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
S3_BATCH_EXPORT_PREFIX=exports/
|
||||
|
||||
# S3 Media Upload LOCAL
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_REGION=us-east-1
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
S3_MEDIA_UPLOAD_BUCKET=hanzo
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_MEDIA_UPLOAD_REGION=us-east-1
|
||||
S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
|
||||
# S3 Event Bucket Upload
|
||||
## Set to true to test uploading all events to S3
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION=us-east-1
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||
S3_EVENT_UPLOAD_BUCKET=hanzo
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_EVENT_UPLOAD_REGION=us-east-1
|
||||
S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_EVENT_UPLOAD_PREFIX=events/
|
||||
|
||||
# Set during docker build of application
|
||||
# Used to disable environment verification at build time
|
||||
@@ -75,13 +75,13 @@ REDIS_PORT=6379
|
||||
REDIS_AUTH="bitnami"
|
||||
REDIS_CLUSTER_ENABLED="true"
|
||||
REDIS_CLUSTER_NODES="127.0.0.1:6370,127.0.0.1:6371,127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374,127.0.0.1:6375"
|
||||
LANGFUSE_INGESTION_QUEUE_SHARD_COUNT=8
|
||||
LANGFUSE_OTEL_INGESTION_QUEUE_SHARD_COUNT=4
|
||||
LANGFUSE_TRACE_UPSERT_QUEUE_SHARD_COUNT=4
|
||||
HANZO_INGESTION_QUEUE_SHARD_COUNT=8
|
||||
HANZO_OTEL_INGESTION_QUEUE_SHARD_COUNT=4
|
||||
HANZO_TRACE_UPSERT_QUEUE_SHARD_COUNT=4
|
||||
|
||||
# openssl rand -hex 32 used only here
|
||||
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# speeds up local development by not executing init scripts on server startup
|
||||
NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT="false"
|
||||
NEXT_PUBLIC_HANZO_RUN_NEXT_INIT="false"
|
||||
|
||||
|
||||
+68
-68
@@ -10,29 +10,29 @@
|
||||
# Host Ports
|
||||
# POSTGRES_HOST_PORT=5432
|
||||
# REDIS_HOST_PORT=6379
|
||||
# CLICKHOUSE_HTTP_PORT=8123
|
||||
# CLICKHOUSE_NATIVE_PORT=9000
|
||||
# MINIO_API_PORT=9090
|
||||
# MINIO_CONSOLE_PORT=9091
|
||||
# DATASTORE_HTTP_PORT=8123
|
||||
# DATASTORE_NATIVE_PORT=9000
|
||||
# S3_API_PORT=9090
|
||||
# S3_CONSOLE_PORT=9091
|
||||
# WEB_HOST_PORT=3000
|
||||
# WORKER_HOST_PORT=3030
|
||||
|
||||
# Container Names
|
||||
# POSTGRES_CONTAINER_NAME=langfuse-postgres
|
||||
# CLICKHOUSE_CONTAINER_NAME=langfuse-clickhouse
|
||||
# REDIS_CONTAINER_NAME=langfuse-redis
|
||||
# MINIO_CONTAINER_NAME=langfuse-minio
|
||||
# WEB_CONTAINER_NAME=langfuse-web
|
||||
# WORKER_CONTAINER_NAME=langfuse-worker
|
||||
# POSTGRES_CONTAINER_NAME=hanzo-postgres
|
||||
# DATASTORE_CONTAINER_NAME=hanzo-datastore
|
||||
# REDIS_CONTAINER_NAME=hanzo-redis
|
||||
# S3_CONTAINER_NAME=hanzo-s3
|
||||
# WEB_CONTAINER_NAME=hanzo-web
|
||||
# WORKER_CONTAINER_NAME=hanzo-worker
|
||||
|
||||
# Volumes
|
||||
# POSTGRES_VOLUME_NAME=langfuse_postgres_data
|
||||
# CLICKHOUSE_DATA_VOLUME_NAME=langfuse_clickhouse_data
|
||||
# CLICKHOUSE_LOGS_VOLUME_NAME=langfuse_clickhouse_logs
|
||||
# MINIO_VOLUME_NAME=langfuse_minio_data
|
||||
# POSTGRES_VOLUME_NAME=hanzo_postgres_data
|
||||
# DATASTORE_DATA_VOLUME_NAME=hanzo_datastore_data
|
||||
# DATASTORE_LOGS_VOLUME_NAME=hanzo_datastore_logs
|
||||
# S3_VOLUME_NAME=hanzo_s3_data
|
||||
|
||||
# Network
|
||||
# DOCKER_NETWORK_NAME=langfuse-network
|
||||
# DOCKER_NETWORK_NAME=hanzo-network
|
||||
|
||||
# ============================================================================
|
||||
# APPLICATION CONFIGURATION
|
||||
@@ -43,14 +43,14 @@
|
||||
DIRECT_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
||||
|
||||
# Clickhouse
|
||||
CLICKHOUSE_MIGRATION_URL="clickhouse://localhost:9000"
|
||||
CLICKHOUSE_URL="http://localhost:8123"
|
||||
# CLICKHOUSE_READ_ONLY_URL="http://localhost:8123" # Optional: read replica for legacy tables
|
||||
# CLICKHOUSE_EVENTS_READ_ONLY_URL="http://localhost:8123" # Optional: read replica for events table queries
|
||||
CLICKHOUSE_USER="clickhouse"
|
||||
CLICKHOUSE_PASSWORD="clickhouse"
|
||||
CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
# Datastore (analytics database)
|
||||
DATASTORE_MIGRATION_URL="datastore://127.0.0.1:9000"
|
||||
DATASTORE_URL="http://127.0.0.1:8123"
|
||||
# DATASTORE_READ_ONLY_URL="http://localhost:8123" # Optional: read replica for legacy tables
|
||||
# DATASTORE_EVENTS_READ_ONLY_URL="http://localhost:8123" # Optional: read replica for events table queries
|
||||
DATASTORE_USER="hanzo"
|
||||
DATASTORE_PASSWORD="hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED="false"
|
||||
|
||||
# Next Auth
|
||||
# You can generate a new secret on the command line with:
|
||||
@@ -60,11 +60,11 @@ CLICKHOUSE_CLUSTER_ENABLED="false"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
NEXTAUTH_SECRET="secret"
|
||||
|
||||
# Langfuse Cloud Environment
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION="DEV"
|
||||
# Hanzo Cloud Environment
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION="DEV"
|
||||
|
||||
# Langfuse experimental features
|
||||
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
# Console experimental features
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES="false"
|
||||
|
||||
# Salt for API key hashing
|
||||
SALT="salt"
|
||||
@@ -75,36 +75,36 @@ SMTP_CONNECTION_URL="" # Defines the connection url for smtp server.
|
||||
CLOUD_CRM_EMAIL="" # Optional BCC address for usage threshold emails (e.g., for CRM integration like HubSpot)
|
||||
|
||||
# S3 Batch Exports
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENABLED=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_BUCKET=langfuse
|
||||
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_BATCH_EXPORT_REGION=us-east-1
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_BATCH_EXPORT_PREFIX=exports/
|
||||
S3_BATCH_EXPORT_ENABLED=true
|
||||
S3_BATCH_EXPORT_BUCKET=hanzo
|
||||
S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||
S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_BATCH_EXPORT_REGION=us-east-1
|
||||
S3_BATCH_EXPORT_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||
S3_BATCH_EXPORT_PREFIX=exports/
|
||||
|
||||
# S3 Media Upload LOCAL
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_REGION=us-east-1
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
S3_MEDIA_UPLOAD_BUCKET=hanzo
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_MEDIA_UPLOAD_REGION=us-east-1
|
||||
S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_MEDIA_UPLOAD_PREFIX=media/
|
||||
|
||||
# S3 Event Bucket Upload
|
||||
## Set to true to test uploading all events to S3
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION=us-east-1
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for minio compatibility
|
||||
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||
S3_EVENT_UPLOAD_BUCKET=hanzo
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||
S3_EVENT_UPLOAD_REGION=us-east-1
|
||||
S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9090
|
||||
## Necessary for S3-compatible storage (path style)
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||
S3_EVENT_UPLOAD_PREFIX=events/
|
||||
|
||||
# Set during docker build of application
|
||||
# Used to disable environment verification at build time
|
||||
@@ -123,33 +123,33 @@ REDIS_AUTH="myredissecret"
|
||||
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# speeds up local development by not executing init scripts on server startup
|
||||
NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT="false"
|
||||
NEXT_PUBLIC_HANZO_RUN_NEXT_INIT="false"
|
||||
|
||||
# For SDK integration tests to pass, decrease the ingestion queue delay by uncommenting the env vars:
|
||||
# LANGFUSE_INGESTION_QUEUE_DELAY_MS=10
|
||||
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=10
|
||||
# HANZO_INGESTION_QUEUE_DELAY_MS=10
|
||||
# DATASTORE_INGESTION_WRITE_INTERVAL_MS=10
|
||||
|
||||
# Slack credentials for development
|
||||
SLACK_CLIENT_ID=your_slack_client_id
|
||||
SLACK_CLIENT_SECRET=your_slack_client_secret
|
||||
SLACK_STATE_SECRET=your_slack_state_secret
|
||||
|
||||
# Langfuse AI instance for tracing, prompts
|
||||
LANGFUSE_AI_FEATURES_PUBLIC_KEY="pk-lf-1234567890"
|
||||
LANGFUSE_AI_FEATURES_SECRET_KEY="sk-lf-1234567890"
|
||||
LANGFUSE_AI_FEATURES_HOST="http://localhost:3000"
|
||||
LANGFUSE_AI_FEATURES_PROJECT_ID=7a88fb47-b4e2-43b8-a06c-a5ce950dc53a
|
||||
# Hanzo AI instance for tracing, prompts
|
||||
HANZO_AI_FEATURES_PUBLIC_KEY="pk-hz-1234567890"
|
||||
HANZO_AI_FEATURES_SECRET_KEY="sk-hz-1234567890"
|
||||
HANZO_AI_FEATURES_HOST="http://localhost:3000"
|
||||
HANZO_AI_FEATURES_PROJECT_ID=7a88fb47-b4e2-43b8-a06c-a5ce950dc53a
|
||||
|
||||
# Langfuse AI Bedrock credentials
|
||||
# Hanzo AI Bedrock credentials
|
||||
AWS_ACCESS_KEY_ID="A123456789"
|
||||
AWS_SECRET_ACCESS_KEY="SAK123456789"
|
||||
LANGFUSE_AWS_BEDROCK_REGION="eu-west-1"
|
||||
LANGFUSE_AWS_BEDROCK_MODEL="eu.anthropic.claude-3-haiku-20240307-v1:0"
|
||||
HANZO_AWS_BEDROCK_REGION="eu-west-1"
|
||||
HANZO_AWS_BEDROCK_MODEL="eu.anthropic.claude-3-haiku-20240307-v1:0"
|
||||
|
||||
# Events table migration
|
||||
LANGFUSE_ENABLE_EVENTS_TABLE_OBSERVATIONS=true
|
||||
LANGFUSE_ENABLE_EVENTS_TABLE_FLAGS=true
|
||||
LANGFUSE_ENABLE_EVENTS_TABLE_V2_APIS=true
|
||||
LANGFUSE_EXPERIMENT_INSERT_INTO_EVENTS_TABLE=true
|
||||
HANZO_ENABLE_EVENTS_TABLE_OBSERVATIONS=true
|
||||
HANZO_ENABLE_EVENTS_TABLE_FLAGS=true
|
||||
HANZO_ENABLE_EVENTS_TABLE_V2_APIS=true
|
||||
HANZO_EXPERIMENT_INSERT_INTO_EVENTS_TABLE=true
|
||||
|
||||
CLICKHOUSE_USE_LIGHTWEIGHT_UPDATE="true"
|
||||
DATASTORE_USE_LIGHTWEIGHT_UPDATE="true"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Console Frontend-Only Mode
|
||||
# Usage: cd web && pnpm dev:frontend
|
||||
# No Docker, no databases, no Redis — just the UI proxied to production APIs.
|
||||
|
||||
SKIP_ENV_VALIDATION=1
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION=DEV
|
||||
NEXT_PUBLIC_HANZO_RUN_NEXT_INIT=false
|
||||
|
||||
# Override if you want to proxy to a different console backend
|
||||
# CONSOLE_API_URL=https://console.hanzo.ai
|
||||
+89
-81
@@ -1,4 +1,4 @@
|
||||
# More information: https://langfuse.com/docs/deployment/self-host
|
||||
# More information: https://hanzo.com/docs/deployment/self-host
|
||||
|
||||
# When adding additional environment variables, the schema in "/src/env.mjs"
|
||||
# should be updated accordingly.
|
||||
@@ -10,7 +10,7 @@ DATABASE_URL="postgresql://postgres:postgres@db:5432/postgres"
|
||||
# DIRECT_URL="postgresql://postgres:postgres@db:5432/postgres"
|
||||
# SHADOW_DATABASE_URL=
|
||||
# optional, set to true to disable automated database migrations on Docker start
|
||||
# LANGFUSE_AUTO_POSTGRES_MIGRATION_DISABLED=
|
||||
# HANZO_AUTO_POSTGRES_MIGRATION_DISABLED=
|
||||
|
||||
# Next Auth
|
||||
# NEXTAUTH_URL does not need to be set when deploying on Vercel
|
||||
@@ -26,7 +26,7 @@ SALT="salt" # salt used to hash api keys
|
||||
ENCRYPTION_KEY="0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
# Use CSP headers to enforce HTTPS, optional
|
||||
# LANGFUSE_CSP_ENFORCE_HTTPS="true"
|
||||
# HANZO_CSP_ENFORCE_HTTPS="true"
|
||||
|
||||
# Configure base path for self-hosting, optional
|
||||
# Note: You need to build the docker image with the base path set and cannot use the pre-built docker image if you set this.
|
||||
@@ -38,22 +38,22 @@ ENCRYPTION_KEY="0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# Opentelemetry, optional
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
|
||||
OTEL_SERVICE_NAME="langfuse"
|
||||
OTEL_SERVICE_NAME="hanzo"
|
||||
|
||||
# Default role for users who sign up, optional, can be org or org+project
|
||||
# Supports comma-separated IDs for multiple orgs (e.g., "org1,org2,org3")
|
||||
# LANGFUSE_DEFAULT_ORG_ID=
|
||||
# LANGFUSE_DEFAULT_ORG_ROLE=
|
||||
# HANZO_DEFAULT_ORG_ID=
|
||||
# HANZO_DEFAULT_ORG_ROLE=
|
||||
# Supports comma-separated IDs for multiple projects (e.g., "proj1,proj2,proj3")
|
||||
# LANGFUSE_DEFAULT_PROJECT_ID=
|
||||
# LANGFUSE_DEFAULT_PROJECT_ROLE=
|
||||
# HANZO_DEFAULT_PROJECT_ID=
|
||||
# HANZO_DEFAULT_PROJECT_ROLE=
|
||||
|
||||
# Logging, optional
|
||||
# LANGFUSE_LOG_LEVEL=info
|
||||
# LANGFUSE_LOG_FORMAT=text
|
||||
# HANZO_LOG_LEVEL=info
|
||||
# HANZO_LOG_FORMAT=text
|
||||
|
||||
# Enable experimental features, optional
|
||||
# LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES=false
|
||||
# HANZO_ENABLE_EXPERIMENTAL_FEATURES=false
|
||||
|
||||
# Auth, optional configuration
|
||||
# AUTH_DOMAINS_WITH_SSO_ENFORCEMENT=domain1.com,domain2.com
|
||||
@@ -66,7 +66,7 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
# AUTH_GOOGLE_CLIENT_ID=
|
||||
# AUTH_GOOGLE_CLIENT_SECRET=
|
||||
# AUTH_GOOGLE_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_GOOGLE_ALLOWED_DOMAINS=langfuse.com,google.com # optional allowlist of workspace domains that can sign in via Google
|
||||
# AUTH_GOOGLE_ALLOWED_DOMAINS=hanzo.ai,google.com # optional allowlist of workspace domains that can sign in via Google
|
||||
# AUTH_GOOGLE_CLIENT_AUTH_METHOD=
|
||||
# AUTH_GOOGLE_CHECKS=
|
||||
# AUTH_GITHUB_CLIENT_ID=
|
||||
@@ -148,38 +148,41 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
# SMTP_CONNECTION_URL=
|
||||
|
||||
# S3 Batch Exports
|
||||
# LANGFUSE_S3_BATCH_EXPORT_ENABLED=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_BUCKET=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_REGION=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=
|
||||
# LANGFUSE_S3_BATCH_EXPORT_PREFIX=
|
||||
# S3_BATCH_EXPORT_ENABLED=
|
||||
# S3_BATCH_EXPORT_BUCKET=
|
||||
# S3_BATCH_EXPORT_ACCESS_KEY_ID=
|
||||
# S3_BATCH_EXPORT_SECRET_ACCESS_KEY=
|
||||
# S3_BATCH_EXPORT_REGION=
|
||||
# S3_BATCH_EXPORT_ENDPOINT=
|
||||
# S3_BATCH_EXPORT_PREFIX=
|
||||
|
||||
# S3 storage for events, optional, used to persist all incoming events
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_BUCKET=
|
||||
# S3_EVENT_UPLOAD_BUCKET=
|
||||
# Optional prefix to be used within the bucket. Must end with `/` if set
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||
# S3_EVENT_UPLOAD_PREFIX=events/
|
||||
# The following four options are optional and fallback to the normal SDK credential provider chain if omitted
|
||||
# See https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_REGION=
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=
|
||||
# LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=
|
||||
# S3_EVENT_UPLOAD_ENDPOINT=
|
||||
# S3_EVENT_UPLOAD_REGION=
|
||||
# S3_EVENT_UPLOAD_ACCESS_KEY_ID=
|
||||
# S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=
|
||||
# Whether to use blob_storage_file_log table to manage blob storage events
|
||||
# Can be set to `false` if `event` entities are managed using lifecycle policies in the blob storage bucket.
|
||||
LANGFUSE_ENABLE_BLOB_STORAGE_FILE_LOG=true
|
||||
HANZO_ENABLE_BLOB_STORAGE_FILE_LOG=true
|
||||
|
||||
# Automated provisioning of default resources
|
||||
# LANGFUSE_INIT_ORG_ID=org-id
|
||||
# LANGFUSE_INIT_ORG_NAME=org-name
|
||||
# LANGFUSE_INIT_PROJECT_ID=project-id
|
||||
# LANGFUSE_INIT_PROJECT_NAME=project-name
|
||||
# LANGFUSE_INIT_PROJECT_PUBLIC_KEY=pk-1234567890
|
||||
# LANGFUSE_INIT_PROJECT_SECRET_KEY=sk-1234567890
|
||||
# LANGFUSE_INIT_USER_EMAIL=user@example.com
|
||||
# LANGFUSE_INIT_USER_NAME=User Name
|
||||
# LANGFUSE_INIT_USER_PASSWORD=password
|
||||
# INIT_ORG_ID=org-id
|
||||
# INIT_ORG_NAME=org-name
|
||||
# INIT_ORG_IDS=hanzo,lux,zoo,pars
|
||||
# INIT_ORG_NAMES=Hanzo,Lux,Zoo,Pars
|
||||
# INIT_PROJECT_ID=project-id
|
||||
# INIT_PROJECT_ORG_ID=org-id # recommended when INIT_ORG_IDS sets multiple orgs
|
||||
# INIT_PROJECT_NAME=project-name
|
||||
# INIT_PROJECT_PUBLIC_KEY=pk-1234567890
|
||||
# INIT_PROJECT_SECRET_KEY=sk-1234567890
|
||||
# INIT_USER_EMAIL=user@example.com # adds OWNER membership to init orgs; creates user if password is also set
|
||||
# INIT_USER_NAME=User Name
|
||||
# INIT_USER_PASSWORD=password
|
||||
|
||||
# Redis configuration
|
||||
# REDIS_HOST=
|
||||
@@ -201,72 +204,77 @@ LANGFUSE_ENABLE_BLOB_STORAGE_FILE_LOG=true
|
||||
# REDIS_SENTINEL_PASSWORD=
|
||||
|
||||
# Cache configuration
|
||||
# LANGFUSE_CACHE_API_KEY_ENABLED=
|
||||
# LANGFUSE_CACHE_API_KEY_TTL_SECONDS=
|
||||
# LANGFUSE_CACHE_PROMPT_ENABLED=
|
||||
# LANGFUSE_CACHE_PROMPT_TTL_SECONDS=
|
||||
# HANZO_CACHE_API_KEY_ENABLED=
|
||||
# HANZO_CACHE_API_KEY_TTL_SECONDS=
|
||||
# HANZO_CACHE_PROMPT_ENABLED=
|
||||
# HANZO_CACHE_PROMPT_TTL_SECONDS=
|
||||
|
||||
# Clickhouse configuration
|
||||
# CLICKHOUSE_URL=
|
||||
# CLICKHOUSE_CLUSTER_NAME=default
|
||||
# CLICKHOUSE_DB=default
|
||||
# CLICKHOUSE_USER=
|
||||
# CLICKHOUSE_PASSWORD=
|
||||
# CLICKHOUSE_CLUSTER_ENABLED=true
|
||||
# Datastore configuration
|
||||
# DATASTORE_URL=
|
||||
# DATASTORE_CLUSTER_NAME=default
|
||||
# DATASTORE_DB=default
|
||||
# DATASTORE_USER=
|
||||
# DATASTORE_PASSWORD=
|
||||
# DATASTORE_CLUSTER_ENABLED=true
|
||||
|
||||
# Ingestion configuration
|
||||
# LANGFUSE_INGESTION_QUEUE_DELAY_MS=
|
||||
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_BATCH_SIZE=
|
||||
# LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=
|
||||
# LANGFUSE_INGESTION_CLICKHOUSE_MAX_ATTEMPTS=
|
||||
# HANZO_INGESTION_QUEUE_DELAY_MS=
|
||||
# DATASTORE_INGESTION_WRITE_BATCH_SIZE=
|
||||
# DATASTORE_INGESTION_WRITE_INTERVAL_MS=
|
||||
# DATASTORE_INGESTION_MAX_ATTEMPTS=
|
||||
|
||||
# API Traces endpoint controls (may induce breaking changes on API when changed!)
|
||||
# Reject GET /api/public/traces requests that do not include a fromTimestamp parameter (returns 400)
|
||||
# LANGFUSE_API_TRACES_REJECT_NO_DATE_RANGE=false
|
||||
# HANZO_API_TRACES_REJECT_NO_DATE_RANGE=false
|
||||
# Apply a default date range (in days) to GET /api/public/traces when no fromTimestamp is provided
|
||||
# LANGFUSE_API_TRACES_DEFAULT_DATE_RANGE_DAYS=
|
||||
# HANZO_API_TRACES_DEFAULT_DATE_RANGE_DAYS=
|
||||
# Comma-separated default field groups for GET /api/public/traces when no fields param is provided
|
||||
# Valid values: core, io, scores, observations, metrics
|
||||
# LANGFUSE_API_TRACES_DEFAULT_FIELDS=
|
||||
# HANZO_API_TRACES_DEFAULT_FIELDS=
|
||||
|
||||
### START Enterprise Edition Configuration
|
||||
|
||||
# Allowlisted users that can create new organizations, by default all users can create organizations
|
||||
# LANGFUSE_ALLOWED_ORGANIZATION_CREATORS=user1@langfuse.com,user2@langfuse.com
|
||||
# HANZO_ALLOWED_ORGANIZATION_CREATORS=user1@hanzo.com,user2@hanzo.com
|
||||
|
||||
# UI Customization Options
|
||||
# LANGFUSE_UI_API_HOST=https://api.example.com
|
||||
# LANGFUSE_UI_DOCUMENTATION_HREF=https://docs.example.com
|
||||
# LANGFUSE_UI_SUPPORT_HREF=https://support.example.com
|
||||
# LANGFUSE_UI_FEEDBACK_HREF=https://feedback.example.com
|
||||
# LANGFUSE_UI_LOGO_LIGHT_MODE_HREF=https://static.langfuse.com/langfuse-dev/example-logo-light-mode.png
|
||||
# LANGFUSE_UI_LOGO_DARK_MODE_HREF=https://static.langfuse.com/langfuse-dev/example-logo-dark-mode.png
|
||||
# LANGFUSE_UI_DEFAULT_MODEL_ADAPTER=Anthropic # OpenAI, Anthropic, Azure
|
||||
# LANGFUSE_UI_DEFAULT_BASE_URL_OPENAI=https://api.openai.com/v1
|
||||
# LANGFUSE_UI_DEFAULT_BASE_URL_ANTHROPIC=https://api.anthropic.com
|
||||
# LANGFUSE_UI_DEFAULT_BASE_URL_AZURE_OPENAI=https://{instanceName}.openai.azure.com/openai/deployments
|
||||
# LANGFUSE_UI_VISIBLE_PRODUCT_MODULES=
|
||||
# LANGFUSE_UI_HIDDEN_PRODUCT_MODULES=
|
||||
# HANZO_UI_API_HOST=https://api.example.com
|
||||
# HANZO_UI_DOCUMENTATION_HREF=https://docs.example.com
|
||||
# HANZO_UI_SUPPORT_HREF=https://support.example.com
|
||||
# HANZO_UI_FEEDBACK_HREF=https://feedback.example.com
|
||||
# HANZO_UI_LOGO_LIGHT_MODE_HREF=https://static.hanzo.com/hanzo-dev/example-logo-light-mode.png
|
||||
# HANZO_UI_LOGO_DARK_MODE_HREF=https://static.hanzo.com/hanzo-dev/example-logo-dark-mode.png
|
||||
# HANZO_UI_DEFAULT_MODEL_ADAPTER=Anthropic # OpenAI, Anthropic, Azure
|
||||
# HANZO_UI_DEFAULT_BASE_URL_OPENAI=https://api.openai.com/v1
|
||||
# HANZO_UI_DEFAULT_BASE_URL_ANTHROPIC=https://api.anthropic.com
|
||||
# HANZO_UI_DEFAULT_BASE_URL_AZURE_OPENAI=https://{instanceName}.openai.azure.com/openai/deployments
|
||||
# HANZO_UI_VISIBLE_PRODUCT_MODULES=
|
||||
# HANZO_UI_HIDDEN_PRODUCT_MODULES=
|
||||
|
||||
### END Enterprise Edition Configuration
|
||||
|
||||
|
||||
### START Langfuse Cloud Config
|
||||
# Used for Langfuse Cloud deployments
|
||||
### START Commerce / Billing Config
|
||||
# Commerce API for billing, subscriptions, payments, credits
|
||||
COMMERCE_API_URL="http://commerce.hanzo.svc.cluster.local:8001"
|
||||
COMMERCE_SERVICE_TOKEN="your-commerce-service-token"
|
||||
|
||||
### START Hanzo Cloud Config
|
||||
# Used for Hanzo Cloud deployments
|
||||
# Not recommended for self-hosted deployments as these are NOT COVERED BY SEMANTIC VERSIONING
|
||||
|
||||
# NEXT_PUBLIC_LANGFUSE_CLOUD_REGION="US"
|
||||
# NEXTAUTH_COOKIE_DOMAIN=".langfuse.com"
|
||||
# NEXT_PUBLIC_HANZO_CLOUD_REGION="US"
|
||||
# NEXTAUTH_COOKIE_DOMAIN=".hanzo.com"
|
||||
|
||||
# LANGFUSE_TEAM_SLACK_WEBHOOK=
|
||||
# LANGFUSE_NEW_USER_SIGNUP_WEBHOOK=
|
||||
# HANZO_TEAM_SLACK_WEBHOOK=
|
||||
# HANZO_NEW_USER_SIGNUP_WEBHOOK=
|
||||
|
||||
# Posthog (optional for analytics of web ui)
|
||||
# NEXT_PUBLIC_POSTHOG_HOST=
|
||||
# NEXT_PUBLIC_POSTHOG_KEY=
|
||||
|
||||
# Sentry
|
||||
# NEXT_PUBLIC_LANGFUSE_TRACING_SAMPLE_RATE
|
||||
# NEXT_PUBLIC_HANZO_TRACING_SAMPLE_RATE
|
||||
# NEXT_PUBLIC_SENTRY_DSN=
|
||||
# NEXT_SENTRY_ORG=
|
||||
# NEXT_SENTRY_PROJECT=
|
||||
@@ -286,17 +294,17 @@ LANGFUSE_ENABLE_BLOB_STORAGE_FILE_LOG=true
|
||||
|
||||
# Admin API
|
||||
# ADMIN_API_KEY=
|
||||
# LANGFUSE_CACHE_MODEL_MATCH_ENABLED=
|
||||
# LANGFUSE_CACHE_MODEL_MATCH_TTL_SECONDS=
|
||||
# HANZO_CACHE_MODEL_MATCH_ENABLED=
|
||||
# HANZO_CACHE_MODEL_MATCH_TTL_SECONDS=
|
||||
|
||||
# Rate limiting
|
||||
# LANGFUSE_RATE_LIMITS_ENABLED=
|
||||
# HANZO_RATE_LIMITS_ENABLED=
|
||||
|
||||
# Free tier usage thresholds (Cloud deployments only)
|
||||
# Enable the queue consumer that monitors free tier usage (default: true, but requires cloud region)
|
||||
# QUEUE_CONSUMER_FREE_TIER_USAGE_THRESHOLD_QUEUE_IS_ENABLED=true
|
||||
# Enable enforcement: send emails and block orgs that exceed free tier limits (default: false)
|
||||
# LANGFUSE_FREE_TIER_USAGE_THRESHOLD_ENFORCEMENT_ENABLED=false
|
||||
# HANZO_FREE_TIER_USAGE_THRESHOLD_ENFORCEMENT_ENABLED=false
|
||||
# Optional BCC address for usage threshold emails (e.g., for CRM integration like HubSpot)
|
||||
# CLOUD_CRM_EMAIL=
|
||||
|
||||
@@ -308,11 +316,11 @@ LANGFUSE_ENABLE_BLOB_STORAGE_FILE_LOG=true
|
||||
# BETTERSTACK_UPTIME_API_KEY=
|
||||
# BETTERSTACK_UPTIME_STATUS_PAGE_ID=
|
||||
|
||||
### END Langfuse Cloud Config
|
||||
### END Hanzo Cloud Config
|
||||
|
||||
|
||||
### START Langfuse CI Config
|
||||
### START Hanzo CI Config
|
||||
|
||||
# LANGFUSE_INIT_ORG_CLOUD_PLAN=
|
||||
# INIT_ORG_CLOUD_PLAN=
|
||||
|
||||
### END Langfuse CI Config
|
||||
### END Hanzo CI Config
|
||||
|
||||
+3
-3
@@ -3,10 +3,10 @@
|
||||
# Only overrides specific test variables - other values inherited from .env
|
||||
|
||||
# PostgreSQL - Test Database
|
||||
DIRECT_URL="postgresql://postgres:postgres@localhost:5432/langfuse_test"
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/langfuse_test"
|
||||
DIRECT_URL="postgresql://postgres:postgres@localhost:5432/hanzo_test"
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/hanzo_test"
|
||||
|
||||
# ClickHouse - Use Default Database for now, nothing set
|
||||
# Datastore - Use Default Database for now, nothing set
|
||||
|
||||
# Redis - Test Database (database 1 for isolation)
|
||||
REDIS_CONNECTION_STRING="redis://:myredissecret@127.0.0.1:6379/1"
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
# Currently inactive
|
||||
# * @langfuse/maintainers
|
||||
# * @hanzo/maintainers
|
||||
|
||||
@@ -7,9 +7,9 @@ body:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Langfuse Cloud or Self-Hosted?
|
||||
label: Hanzo Cloud or Self-Hosted?
|
||||
options:
|
||||
- "Langfuse Cloud"
|
||||
- "Hanzo Cloud"
|
||||
- "Self-Hosted"
|
||||
validations:
|
||||
required: true
|
||||
@@ -19,8 +19,8 @@ body:
|
||||
description: What version are you running? We may ask you to upgrade to the latest version, as many issues are continuously being fixed.
|
||||
- type: input
|
||||
attributes:
|
||||
label: If Langfuse Cloud
|
||||
description: Please share the link to your Langfuse project or the specific view you have a question about. This helps us resolve requests faster.
|
||||
label: If Hanzo Cloud
|
||||
description: Please share the link to your Hanzo project or the specific view you have a question about. This helps us resolve requests faster.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: SDK and integration versions
|
||||
@@ -28,9 +28,9 @@ body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Pre-Submission Checklist
|
||||
description: Please check for existing [issues](https://github.com/langfuse/langfuse/issues) and [discussions](https://github.com/orgs/langfuse/discussions) and ask the [Langfuse AI chatbot](https://langfuse.com/docs/ask-ai).
|
||||
description: Please check for existing [issues](https://github.com/hanzo/hanzo/issues) and [discussions](https://github.com/orgs/hanzo/discussions) and ask the [Hanzo AI chatbot](https://hanzo.com/docs/ask-ai).
|
||||
options:
|
||||
- label: I have checked for existing issues/discussions and consulted Langfuse AI.
|
||||
- label: I have checked for existing issues/discussions and consulted Hanzo AI.
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -17,9 +17,9 @@ body:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Langfuse Cloud or self-hosted?
|
||||
label: Hanzo Cloud or self-hosted?
|
||||
options:
|
||||
- "Langfuse Cloud"
|
||||
- "Hanzo Cloud"
|
||||
- "Self-hosted"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
contact_links:
|
||||
- name: 💡 Feature Request
|
||||
url: https://github.com/orgs/langfuse/discussions/new?category=ideas
|
||||
url: https://github.com/orgs/hanzoai/discussions/new?category=ideas
|
||||
about: Suggest any ideas you have using our discussion forums.
|
||||
- name: 🤗 Get Help
|
||||
url: https://github.com/orgs/langfuse/discussions/new?category=support
|
||||
url: https://github.com/orgs/hanzoai/discussions/new?category=support
|
||||
about: If you can’t get something to work the way you expect, open a question in our discussion forums.
|
||||
|
||||
@@ -27,7 +27,7 @@ Fixes # (issue)
|
||||
|
||||
<!-- Remove bullet points below that don't apply to you -->
|
||||
|
||||
- I haven't read the [contributing guide](https://github.com/langfuse/langfuse/blob/main/CONTRIBUTING.md)
|
||||
- I haven't read the [contributing guide](https://github.com/hanzo/hanzo/blob/main/CONTRIBUTING.md)
|
||||
- My code doesn't follow the style guidelines of this project (`pnpm run format`)
|
||||
- I haven't commented my code, particularly in hard-to-understand areas
|
||||
- I haven't checked if my PR needs changes to the documentation
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
name: WorkflowCall - Deploy to ECS Service
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
environment:
|
||||
type: string
|
||||
description: Deployment environment
|
||||
required: true
|
||||
service:
|
||||
type: string
|
||||
description: Name of the service to be deployed, e.g. web-ingestion, web, or worker.
|
||||
required: true
|
||||
jobs:
|
||||
ecs-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ inputs.environment }}
|
||||
steps:
|
||||
- name: Get app name
|
||||
uses: winterjung/split@v2
|
||||
id: split
|
||||
with:
|
||||
msg: ${{ inputs.service }}
|
||||
separator: "-"
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Authenticate with AWS
|
||||
# GitHub/AWS recommend to use OIDC here: https://github.com/aws-actions/configure-aws-credentials?tab=readme-ov-file#oidc
|
||||
# Probably more painful to configure, but would remove all long-lived credentials.
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
- name: Login to AWS ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: Build, tag, and push Docker image
|
||||
env:
|
||||
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: ${{ steps.split.outputs._0 }}
|
||||
IMAGE_TAG: ${{ github.sha }}
|
||||
run: |
|
||||
docker build \
|
||||
-t $REGISTRY/$REPOSITORY:$IMAGE_TAG \
|
||||
-f ./${{ steps.split.outputs._0 }}/Dockerfile \
|
||||
--build-arg NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=${{ vars.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION }} \
|
||||
--build-arg NEXT_LANGFUSE_TRACING_SAMPLE_RATE=${{ vars.NEXT_LANGFUSE_TRACING_SAMPLE_RATE }} \
|
||||
--build-arg NEXT_PUBLIC_SENTRY_ENVIRONMENT=${{ vars.NEXT_PUBLIC_SENTRY_ENVIRONMENT }} \
|
||||
--build-arg NEXT_PUBLIC_DEMO_ORG_ID=${{ vars.NEXT_PUBLIC_DEMO_ORG_ID }} \
|
||||
--build-arg NEXT_PUBLIC_DEMO_PROJECT_ID=${{ vars.NEXT_PUBLIC_DEMO_PROJECT_ID }} \
|
||||
--build-arg NEXT_PUBLIC_SENTRY_DSN=${{ vars.NEXT_PUBLIC_SENTRY_DSN }} \
|
||||
--build-arg NEXT_PUBLIC_BUILD_ID=${{ github.sha }} \
|
||||
--build-arg NEXT_PUBLIC_POSTHOG_KEY=${{ vars.NEXT_PUBLIC_POSTHOG_KEY }} \
|
||||
--build-arg NEXT_PUBLIC_POSTHOG_HOST=${{ vars.NEXT_PUBLIC_POSTHOG_HOST }} \
|
||||
--build-arg NEXT_PUBLIC_PLAIN_APP_ID=${{ vars.NEXT_PUBLIC_PLAIN_APP_ID }} \
|
||||
--build-arg SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} \
|
||||
--build-arg SENTRY_ORG=${{ vars.SENTRY_ORG }} \
|
||||
--build-arg SENTRY_PROJECT=${{ vars.SENTRY_PROJECT }} \
|
||||
--build-arg NEXT_PUBLIC_LANGFUSE_TRACING_SAMPLE_RATE=${{ vars.NEXT_PUBLIC_LANGFUSE_TRACING_SAMPLE_RATE }} \
|
||||
.
|
||||
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
|
||||
- name: Render AWS ECS Task Definition
|
||||
id: render-task-definition
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
container-name: ${{ inputs.service }}
|
||||
image: ${{ steps.login-ecr.outputs.registry }}/${{ steps.split.outputs._0 }}:${{ github.sha }}
|
||||
task-definition-family: ${{ inputs.environment }}-${{ inputs.service }}
|
||||
- name: Update AWS ECS Service
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
|
||||
with:
|
||||
task-definition: ${{ steps.render-task-definition.outputs.task-definition }}
|
||||
service: ${{ inputs.environment }}-${{ inputs.service }}
|
||||
cluster: ${{ inputs.environment }}-cluster
|
||||
wait-for-service-stability: true
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Docker Release
|
||||
|
||||
on:
|
||||
# Only deploy after CI/CD pipeline passes on main
|
||||
workflow_run:
|
||||
workflows: ["CI/CD"]
|
||||
types: [completed]
|
||||
branches: [main]
|
||||
# Tags deploy directly (release cuts)
|
||||
push:
|
||||
tags: ["v*"]
|
||||
# Manual override
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: docker-${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
# Gate: only proceed if CI passed (skip check for tags/manual)
|
||||
gate:
|
||||
runs-on: ubuntu-latest
|
||||
if: >-
|
||||
github.event_name != 'workflow_run' ||
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
steps:
|
||||
- run: echo "CI passed — proceeding with Docker build and deploy"
|
||||
|
||||
web:
|
||||
needs: gate
|
||||
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository_owner }}/console
|
||||
dockerfile: web/Dockerfile
|
||||
build-args: |
|
||||
NEXT_PUBLIC_BUILD_ID=${{ github.event.workflow_run.head_sha || github.sha }}
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION=US
|
||||
deploy: true
|
||||
deploy-deployment: console
|
||||
deploy-namespace: hanzo
|
||||
secrets: inherit
|
||||
|
||||
worker:
|
||||
needs: gate
|
||||
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository_owner }}/console-worker
|
||||
dockerfile: worker/Dockerfile
|
||||
deploy: true
|
||||
deploy-deployment: console-worker
|
||||
deploy-namespace: hanzo
|
||||
secrets: inherit
|
||||
@@ -30,10 +30,10 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
|
||||
- name: Setup Node 18
|
||||
- name: Setup Node 23
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 23
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
name: Hanzo Cloud CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
paths:
|
||||
- 'cloud/**'
|
||||
- '.github/workflows/cloud-ci.yml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'cloud/**'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/hanzo-cloud
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: cloud
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:18-alpine
|
||||
env:
|
||||
POSTGRES_USER: hanzo
|
||||
POSTGRES_PASSWORD: hanzo123
|
||||
POSTGRES_DB: cloud_test
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
ports:
|
||||
- 8123:8123
|
||||
- 9000:9000
|
||||
options: >-
|
||||
--health-cmd "wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
redis:
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Create test env file
|
||||
run: |
|
||||
cat > .env.test << EOF
|
||||
DATABASE_URL=postgresql://hanzo:hanzo123@localhost:5432/cloud_test
|
||||
DIRECT_URL=postgresql://hanzo:hanzo123@localhost:5432/cloud_test
|
||||
DATASTORE_URL=http://localhost:8123
|
||||
DATASTORE_USER=hanzo
|
||||
DATASTORE_PASSWORD=hanzo
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_SECRET=test-secret-change-in-production
|
||||
SALT=test-salt-change-in-production
|
||||
ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
HANZO_CLOUD_INTEGRATION=true
|
||||
HANZO_ROUTER_URL=http://localhost:4000
|
||||
HANZO_SERVICES_URL=http://localhost:3001
|
||||
EOF
|
||||
|
||||
- name: Run database migrations
|
||||
run: |
|
||||
cd web
|
||||
pnpm prisma generate
|
||||
pnpm prisma migrate deploy
|
||||
env:
|
||||
DATABASE_URL: postgresql://hanzo:hanzo123@localhost:5432/cloud_test
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
env:
|
||||
NODE_ENV: test
|
||||
|
||||
- name: Type check
|
||||
run: pnpm type-check
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Web image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ./cloud
|
||||
file: ./cloud/web/Dockerfile
|
||||
target: runner
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
NEXT_PUBLIC_HANZO_CLOUD=true
|
||||
|
||||
- name: Build and push Worker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ./cloud
|
||||
file: ./cloud/worker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-worker:latest
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
integration-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Start services
|
||||
run: |
|
||||
cd ..
|
||||
docker compose -f services/docker-compose.mothership.yml up -d \
|
||||
postgres datastore redis
|
||||
|
||||
# Wait for services
|
||||
sleep 10
|
||||
|
||||
- name: Run Cloud container
|
||||
run: |
|
||||
docker run -d \
|
||||
--name hanzo-cloud-test \
|
||||
--network host \
|
||||
-e DATABASE_URL="postgresql://hanzo:hanzo123@localhost:5432/cloud" \
|
||||
-e DATASTORE_URL="http://localhost:8123" \
|
||||
-e REDIS_HOST="localhost" \
|
||||
-e NEXTAUTH_URL="http://localhost:3000" \
|
||||
-e NEXTAUTH_SECRET="test-secret" \
|
||||
-e SALT="test-salt" \
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
# Wait for startup
|
||||
sleep 15
|
||||
|
||||
- name: Test Cloud API
|
||||
run: |
|
||||
# Check health
|
||||
curl -f http://localhost:3000/api/health || exit 1
|
||||
|
||||
# Check auth endpoint
|
||||
curl -f http://localhost:3000/api/auth/providers || exit 1
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
docker stop hanzo-cloud-test || true
|
||||
docker rm hanzo-cloud-test || true
|
||||
@@ -25,3 +25,6 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Codespell
|
||||
uses: codespell-project/actions-codespell@v2
|
||||
with:
|
||||
skip: "*.lock,*.svg,./web/.next,./node_modules,./web/node_modules,./worker/node_modules,./packages/*/node_modules,./packages/*/dist,./worker/dist,./pnpm-lock.yaml"
|
||||
ignore_words_list: "te,dateA"
|
||||
|
||||
@@ -14,5 +14,5 @@ jobs:
|
||||
- name: "Rebase open Dependabot PR"
|
||||
uses: orange-buffalo/dependabot-auto-rebase@v1
|
||||
with:
|
||||
api-token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
api-token: ${{ secrets.GH_PAT }}
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- production
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
service:
|
||||
description: "Service to be deployed"
|
||||
type: choice
|
||||
options:
|
||||
- all
|
||||
- web
|
||||
- web-ingestion
|
||||
- web-iso
|
||||
- worker
|
||||
- worker-cpu
|
||||
required: true
|
||||
environment:
|
||||
description: "Environment to deploy to"
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- prod-eu
|
||||
- prod-us
|
||||
- prod-hipaa
|
||||
required: true
|
||||
|
||||
concurrency:
|
||||
# Support concurrent `push` and `workflow_dispatch`` actions
|
||||
group: deploy-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
name: Deploy to ECS
|
||||
jobs:
|
||||
affected-services:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
services: ${{ steps.affected-services.outputs.result }}
|
||||
steps:
|
||||
- name: Get affected services
|
||||
id: affected-services
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
if (context.eventName === "workflow_dispatch") {
|
||||
if (context.payload.inputs.service === "all") {
|
||||
return `["web", "web-ingestion", "web-iso", "worker", "worker-cpu"]`
|
||||
}
|
||||
return `["${context.payload.inputs.service}"]`
|
||||
}
|
||||
if (context.eventName === "push") {
|
||||
return `["web", "web-ingestion", "web-iso", "worker", "worker-cpu"]`
|
||||
}
|
||||
return "[]"
|
||||
result-encoding: string
|
||||
- name: Print services to build
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
services: ${{ steps.affected-services.outputs.result }}
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
console.log('Services', `${process.env.services}` ?? 'n/a');
|
||||
|
||||
affected-environments:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
environments: ${{ steps.affected-environments.outputs.result }}
|
||||
steps:
|
||||
- name: Get affected environments
|
||||
id: affected-environments
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
if (context.eventName === "workflow_dispatch") {
|
||||
return `["${context.payload.inputs.environment}"]`
|
||||
}
|
||||
if (context.eventName === "push") {
|
||||
if (context.ref === "refs/heads/main") {
|
||||
return `["staging"]`
|
||||
}
|
||||
if (context.ref === "refs/heads/production") {
|
||||
return `["prod-eu", "prod-us", "prod-hipaa"]`
|
||||
}
|
||||
}
|
||||
return "[]"
|
||||
result-encoding: string
|
||||
- name: Print environments to build
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
environments: ${{ steps.affected-environments.outputs.result }}
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
console.log('Environments', `${process.env.environments}` ?? 'n/a');
|
||||
|
||||
ecs-deploy:
|
||||
uses: ./.github/workflows/_deploy_ecs_service.yml
|
||||
needs: [affected-services, affected-environments]
|
||||
secrets: inherit
|
||||
strategy:
|
||||
matrix:
|
||||
service: ${{ fromJson(needs.affected-services.outputs.services) }}
|
||||
environment: ${{ fromJson(needs.affected-environments.outputs.environments) }}
|
||||
with:
|
||||
service: ${{ matrix.service }}
|
||||
environment: ${{ matrix.environment }}
|
||||
@@ -0,0 +1,52 @@
|
||||
name: E2E Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'web/**'
|
||||
- 'packages/**'
|
||||
|
||||
concurrency:
|
||||
group: e2e-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
name: Playwright E2E
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Install Playwright
|
||||
working-directory: web
|
||||
run: npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run E2E tests
|
||||
working-directory: web
|
||||
run: npx playwright test
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: web/playwright-report/
|
||||
retention-days: 14
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 23
|
||||
|
||||
- name: Install license-checker
|
||||
run: npm install -g license-checker
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
external: "npm-license-checker.csv"
|
||||
external-format: "csv"
|
||||
external-options: "{:skip-header true}"
|
||||
fail: "WeakCopyleft,StrongCopyleft,NetworkCopyleft"
|
||||
fail: "StrongCopyleft,NetworkCopyleft"
|
||||
fails-only: true
|
||||
totals: true
|
||||
verbose: 1
|
||||
|
||||
+423
-255
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
name: PR Preview
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, closed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
uses: hanzoai/.github/.github/workflows/pr-preview.yml@main
|
||||
with:
|
||||
service: console
|
||||
image: ghcr.io/hanzoai/console
|
||||
port: "3000"
|
||||
health-path: /api/public/health
|
||||
e2e-dir: web
|
||||
secrets: inherit
|
||||
@@ -42,29 +42,29 @@ jobs:
|
||||
env:
|
||||
GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
run: |
|
||||
# Clone langfuse-python repository
|
||||
git clone https://github.com/langfuse/langfuse-python.git ../langfuse-python
|
||||
cd ../langfuse-python
|
||||
# Clone hanzo-python repository
|
||||
git clone https://github.com/hanzo/hanzo-python.git ../hanzo-python
|
||||
cd ../hanzo-python
|
||||
|
||||
git config user.name "langfuse-bot"
|
||||
git config user.email "langfuse-bot@langfuse.com"
|
||||
git config user.name "hanzo-bot"
|
||||
git config user.email "hanzo-bot@hanzo.com"
|
||||
echo "$GH_ACCESS_TOKEN" | gh auth login --with-token
|
||||
gh auth setup-git
|
||||
|
||||
# Delete existing API contents
|
||||
rm -rf langfuse/api/*
|
||||
rm -rf hanzo/api/*
|
||||
|
||||
# Copy generated Python SDK files
|
||||
cp -r ../langfuse/generated/python/* langfuse/api/
|
||||
cp -r ../hanzo/generated/python/* hanzo/api/
|
||||
|
||||
# Remove unnecessary integration tests created by Fern
|
||||
# (could not find the right option to prevent this in generation step)
|
||||
rm -rf langfuse/api/tests
|
||||
rm -rf hanzo/api/tests
|
||||
|
||||
# Install poetry and format
|
||||
pip install poetry
|
||||
poetry install --all-extras
|
||||
poetry run ruff format langfuse/api
|
||||
poetry run ruff format hanzo/api
|
||||
|
||||
# Check for changes and show diff for debugging
|
||||
if git diff --quiet; then
|
||||
@@ -73,34 +73,34 @@ jobs:
|
||||
fi
|
||||
|
||||
# Close existing api-spec-bot PRs
|
||||
gh pr list --author langfuse-bot --state open --json number --jq '.[].number' | xargs -I {} gh pr close {}
|
||||
gh pr list --author hanzo-bot --state open --json number --jq '.[].number' | xargs -I {} gh pr close {}
|
||||
|
||||
# Get the GitHub username of the original commit author
|
||||
cd ../langfuse
|
||||
ORIGINAL_AUTHOR=$(gh api repos/langfuse/langfuse/commits/${GITHUB_SHA} --jq '.author.login')
|
||||
cd ../langfuse-python
|
||||
cd ../hanzo
|
||||
ORIGINAL_AUTHOR=$(gh api repos/hanzo/hanzo/commits/${GITHUB_SHA} --jq '.author.login')
|
||||
cd ../hanzo-python
|
||||
|
||||
# Create new branch and push changes
|
||||
BRANCH_NAME="api-spec-bot-${GITHUB_SHA::7}"
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
git add .
|
||||
git commit -m "feat(api): update API spec from langfuse/langfuse ${GITHUB_SHA::7}"
|
||||
git commit -m "feat(api): update API spec from hanzo/hanzo ${GITHUB_SHA::7}"
|
||||
git push origin "$BRANCH_NAME"
|
||||
|
||||
# Create PR with original author as reviewer
|
||||
gh pr create --title "feat(api): update API spec from langfuse/langfuse ${GITHUB_SHA::7}" --body "" --reviewer "$ORIGINAL_AUTHOR"
|
||||
gh pr create --title "feat(api): update API spec from hanzo/hanzo ${GITHUB_SHA::7}" --body "" --reviewer "$ORIGINAL_AUTHOR"
|
||||
|
||||
- name: Update TypeScript SDK
|
||||
env:
|
||||
GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
run: |
|
||||
# Clone langfuse-js repository
|
||||
git clone https://github.com/langfuse/langfuse-js.git ../langfuse-js
|
||||
cd ../langfuse-js
|
||||
# Clone hanzo-js repository
|
||||
git clone https://github.com/hanzo/hanzo-js.git ../hanzo-js
|
||||
cd ../hanzo-js
|
||||
|
||||
# Configure git
|
||||
git config user.name "langfuse-bot"
|
||||
git config user.email "langfuse-bot@langfuse.com"
|
||||
git config user.name "hanzo-bot"
|
||||
git config user.email "hanzo-bot@hanzo.com"
|
||||
echo "$GH_ACCESS_TOKEN" | gh auth login --with-token
|
||||
gh auth setup-git
|
||||
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
rm -rf packages/core/src/api/*
|
||||
|
||||
# Copy generated TypeScript SDK files
|
||||
cp -r ../langfuse/generated/typescript/* packages/core/src/api/
|
||||
cp -r ../hanzo/generated/typescript/* packages/core/src/api/
|
||||
|
||||
# Patch compilation error inducing output
|
||||
# Without this patch, the JS SDK will not build due to
|
||||
@@ -131,19 +131,19 @@ jobs:
|
||||
fi
|
||||
|
||||
# Close existing api-spec-bot PRs
|
||||
gh pr list --author langfuse-bot --state open --json number --jq '.[].number' | xargs -I {} gh pr close {}
|
||||
gh pr list --author hanzo-bot --state open --json number --jq '.[].number' | xargs -I {} gh pr close {}
|
||||
|
||||
# Get the GitHub username of the original commit author
|
||||
cd ../langfuse
|
||||
ORIGINAL_AUTHOR=$(gh api repos/langfuse/langfuse/commits/${GITHUB_SHA} --jq '.author.login')
|
||||
cd ../langfuse-js
|
||||
cd ../hanzo
|
||||
ORIGINAL_AUTHOR=$(gh api repos/hanzo/hanzo/commits/${GITHUB_SHA} --jq '.author.login')
|
||||
cd ../hanzo-js
|
||||
|
||||
# Create new branch and push changes
|
||||
BRANCH_NAME="api-spec-bot-${GITHUB_SHA::7}"
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
git add .
|
||||
git commit -m "feat(api): update API spec from langfuse/langfuse ${GITHUB_SHA::7}" --no-verify
|
||||
git commit -m "feat(api): update API spec from hanzo/hanzo ${GITHUB_SHA::7}" --no-verify
|
||||
git push origin "$BRANCH_NAME"
|
||||
|
||||
# Create PR with original author as reviewer
|
||||
gh pr create --title "feat(api): update API spec from langfuse/langfuse ${GITHUB_SHA::7}" --body "" --reviewer "$ORIGINAL_AUTHOR"
|
||||
gh pr create --title "feat(api): update API spec from hanzo/hanzo ${GITHUB_SHA::7}" --body "" --reviewer "$ORIGINAL_AUTHOR"
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
# or you can sign up for free at https://snyk.io/login
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
image: langfuse/langfuse
|
||||
image: hanzoai/console
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Fix SARIF file
|
||||
if: always()
|
||||
@@ -43,6 +43,6 @@ jobs:
|
||||
fi
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
if: always()
|
||||
if: always() && hashFiles('snyk.sarif') != ''
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
# or you can sign up for free at https://snyk.io/login
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
image: langfuse/langfuse-worker
|
||||
image: hanzoai/console-worker
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Fix SARIF file
|
||||
if: always()
|
||||
@@ -43,6 +43,6 @@ jobs:
|
||||
fi
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
if: always()
|
||||
if: always() && hashFiles('snyk.sarif') != ''
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
||||
+12
-1
@@ -41,15 +41,23 @@ yarn-error.log*
|
||||
# local env files
|
||||
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
|
||||
.env*
|
||||
local.env
|
||||
!.env.build
|
||||
!.env.dev.example
|
||||
!.env.dev-azure.example
|
||||
!.env.dev-redis-cluster.example
|
||||
!.env.prod.example
|
||||
!.env.test.example
|
||||
!.env.frontend
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
#aider
|
||||
.aider
|
||||
/aider-cache
|
||||
/myenv
|
||||
.aider.*
|
||||
/.aider.tags.chache.v3
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
@@ -81,3 +89,6 @@ web/test-results/*
|
||||
|
||||
# Refactoring planning files (local only)
|
||||
**/.refactor/
|
||||
console-standalone.tar.gz
|
||||
|
||||
CLAUDE.md
|
||||
|
||||
+1
-22
@@ -1,23 +1,2 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Get the current branch
|
||||
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# Define the protected branch
|
||||
protected_branch="main"
|
||||
|
||||
# Check if the current branch is the protected branch
|
||||
if [ "$current_branch" = "$protected_branch" ]; then
|
||||
echo "🚨 You are about to commit to the $protected_branch branch. Are you sure? (y/n)"
|
||||
read -r answer < /dev/tty
|
||||
if [ "$answer" != "${answer#[Yy]}" ]; then
|
||||
# Commit approved, check formatting. On files changed, block commit
|
||||
pnpm run format:check
|
||||
else
|
||||
echo "Commit to $protected_branch branch has been canceled."
|
||||
exit 1 # Commit will be blocked
|
||||
fi
|
||||
fi
|
||||
|
||||
# If not the protected branch, check formatting (on changed files, block)
|
||||
pnpm run format:check
|
||||
pnpm exec lint-staged
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "always",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Codex Guidelines for Langfuse
|
||||
# Codex Guidelines for Hanzo
|
||||
|
||||
Langfuse is an **open source LLM engineering** platform for developing, monitoring, evaluating and debugging AI applications. See the README for more details.
|
||||
Hanzo is an **open source LLM engineering** platform for developing, monitoring, evaluating and debugging AI applications. See the README for more details.
|
||||
|
||||
## Linting
|
||||
- Run `pnpm run lint` to lint all packages.
|
||||
|
||||
+41
-41
@@ -1,43 +1,43 @@
|
||||

|
||||

|
||||
|
||||
# Contributing to Langfuse
|
||||
# Contributing to Hanzo
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
The best ways to contribute to Langfuse:
|
||||
The best ways to contribute to Hanzo:
|
||||
|
||||
- Submit and vote on [Ideas](https://github.com/orgs/langfuse/discussions/categories/ideas)
|
||||
- Create and comment on [Issues](https://github.com/langfuse/langfuse/issues)
|
||||
- Submit and vote on [Ideas](https://github.com/orgs/hanzoai/discussions/categories/ideas)
|
||||
- Create and comment on [Issues](https://github.com/hanzoai/cloud/issues)
|
||||
- Open a PR.
|
||||
|
||||
We welcome contributions through GitHub pull requests. This document outlines our conventions regarding development workflow, commit message formatting, contact points, and other resources. Our goal is to simplify the process and ensure that your contributions are easily accepted.
|
||||
|
||||
We gratefully welcome improvements to documentation ([docs repo](https://github.com/langfuse/langfuse-docs)), the core application (this repo) and the SDKs ([Python](https://github.com/langfuse/langfuse-python), [JS](https://github.com/langfuse/langfuse-js)).
|
||||
We gratefully welcome improvements to documentation ([docs repo](https://github.com/hanzoai/cloud-docs)), the core application (this repo) and the SDKs ([Python](https://github.com/hanzoai/cloud-python), [JS](https://github.com/hanzoai/cloud-js)).
|
||||
|
||||
The maintainers are available on [Discord](https://langfuse.com/discord) in case you have any questions.
|
||||
The maintainers are available on [Discord](https://hanzo.ai/discord) in case you have any questions.
|
||||
|
||||
> And if you like the project, but just don't have time to contribute code, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
>
|
||||
> - Star the project;
|
||||
> - Tweet about it;
|
||||
> - Refer to this project in your project's readme;
|
||||
> - Submit and vote on [Ideas](https://github.com/orgs/langfuse/discussions/categories/ideas);
|
||||
> - Create and comment on [Issues](https://github.com/langfuse/langfuse/issues);
|
||||
> - Submit and vote on [Ideas](https://github.com/orgs/hanzoai/discussions/categories/ideas);
|
||||
> - Create and comment on [Issues](https://github.com/hanzoai/cloud/issues);
|
||||
> - Mention the project at local meetups and tell your friends/colleagues.
|
||||
|
||||
## Making a change
|
||||
|
||||
_Before making any significant changes, please [open an issue](https://github.com/langfuse/langfuse/issues)._ Discussing your proposed changes ahead of time will make the contribution process smooth for everyone. Changes that were not discussed in an issue may be rejected.
|
||||
_Before making any significant changes, please [open an issue](https://github.com/hanzo/hanzo/issues)._ Discussing your proposed changes ahead of time will make the contribution process smooth for everyone. Changes that were not discussed in an issue may be rejected.
|
||||
|
||||
Once we've discussed your changes and you've got your code ready, make sure that tests are passing and open your pull request.
|
||||
|
||||
A good first step is to search for open [issues](https://github.com/langfuse/langfuse/issues). Issues are labeled, and some good issues to start with are labeled: [good first issue](https://github.com/langfuse/langfuse/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
||||
A good first step is to search for open [issues](https://github.com/hanzoai/cloud/issues). Issues are labeled, and some good issues to start with are labeled: [good first issue](https://github.com/hanzoai/cloud/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
||||
|
||||
## Project Overview
|
||||
|
||||
We recommend checking out DeepWiki to familiarize yourself with the project:
|
||||
|
||||
[](https://deepwiki.com/langfuse/langfuse)
|
||||
[](https://deepwiki.com/hanzo/hanzo)
|
||||
|
||||
### Technologies we use
|
||||
|
||||
@@ -50,14 +50,14 @@ We recommend checking out DeepWiki to familiarize yourself with the project:
|
||||
- Tailwind CSS
|
||||
- shadcn/ui tailwind components (using Radix and tanstack)
|
||||
- Fern: generate OpenAPI spec and Pydantic models
|
||||
- JS SDK ([langfuse/langfuse-js](https://github.com/langfuse/langfuse-js))
|
||||
- JS SDK ([hanzoai/cloud-js](https://github.com/hanzoai/cloud-js))
|
||||
- openapi-typescript to generated types based on OpenAPI spec
|
||||
- Python SDK ([langfuse/langfuse-python](https://github.com/langfuse/langfuse-python))
|
||||
- Python SDK ([hanzoai/cloud-python](https://github.com/hanzoai/cloud-python))
|
||||
- Pydantic for input validation, models generated by fern
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
See this [diagram](https://langfuse.com/self-hosting#architecture) for an overview of the architecture.
|
||||
See this [diagram](https://hanzo.ai/self-hosting#architecture) for an overview of the architecture.
|
||||
|
||||
### Network Overview
|
||||
|
||||
@@ -65,11 +65,11 @@ See this [diagram](https://langfuse.com/self-hosting#architecture) for an overvi
|
||||
flowchart TB
|
||||
User["UI, API, SDKs"]
|
||||
subgraph vpc["VPC"]
|
||||
Web["Web Server<br/>(langfuse/langfuse)"]
|
||||
Worker["Async Worker<br/>(langfuse/worker)"]
|
||||
Web["Web Server<br/>(hanzo/hanzo)"]
|
||||
Worker["Async Worker<br/>(hanzo/worker)"]
|
||||
Postgres["Postgres - OLTP<br/>(Transactional Data)"]
|
||||
Cache["Redis/Valkey<br/>(Cache, Queue)"]
|
||||
Clickhouse["Clickhouse - OLAP<br/>(Observability Data)"]
|
||||
Datastore["Datastore - OLAP<br/>(Observability Data)"]
|
||||
S3["S3 / Blob Storage<br/>(Raw events, multi-modal attachments)"]
|
||||
end
|
||||
LLM["LLM API/Gateway<br/>(optional)"]
|
||||
@@ -78,11 +78,11 @@ flowchart TB
|
||||
Web --> S3
|
||||
Web --> Postgres
|
||||
Web --> Cache
|
||||
Web --> Clickhouse
|
||||
Web --> Datastore
|
||||
Web -.->|"optional for playground"| LLM
|
||||
|
||||
Cache --> Worker
|
||||
Worker --> Clickhouse
|
||||
Worker --> Datastore
|
||||
Worker --> Postgres
|
||||
Worker --> S3
|
||||
Worker -.->|"optional for evals"| LLM
|
||||
@@ -98,7 +98,7 @@ Full database schema: [packages/shared/prisma/schema.prisma](packages/shared/pri
|
||||
|
||||
We built a monorepo using [pnpm](https://pnpm.io/motivation) and [turbo](https://turbo.build/repo/docs) to manage the dependencies and build process. The monorepo contains the following packages:
|
||||
|
||||
- `web`: is the main application package providing Frontend and Backend APIs for Langfuse.
|
||||
- `web`: is the main application package providing Frontend and Backend APIs for Hanzo.
|
||||
- `worker`: contains an application for asynchronous processing of tasks.
|
||||
- `packages`:
|
||||
- `shared`: contains shared code between the above packages.
|
||||
@@ -113,21 +113,21 @@ Requirements
|
||||
- Node.js 24 as specified in the [.nvmrc](.nvmrc)
|
||||
- Pnpm v.9.5.0
|
||||
- Docker to run the database locally
|
||||
- Clickhouse client
|
||||
- Datastore client
|
||||
|
||||
**Note:** You can also simply run Langfuse in a **GitHub Codespace** via the provided devcontainer. To do this, click on the green "Code" button in the top right corner of the repository and select "Open with Codespaces".
|
||||
**Note:** You can also simply run Hanzo in a **GitHub Codespace** via the provided devcontainer. To do this, click on the green "Code" button in the top right corner of the repository and select "Open with Codespaces".
|
||||
|
||||
**Steps**
|
||||
|
||||
1. Install development dependencies:
|
||||
- [golang-migrate](https://github.com/golang-migrate/migrate/tree/master/cmd/migrate#migrate-cli) as CLI
|
||||
- [clickhouse binary](https://clickhouse.com/docs/install) on macOS with brew: `brew install --cask clickhouse`
|
||||
- [datastore binary](https://datastore.com/docs/install) on macOS with brew: `brew install --cask datastore`
|
||||
|
||||
2. Fork the repository and clone it locally
|
||||
|
||||
```bash
|
||||
git clone https://github.com/langfuse/langfuse.git
|
||||
cd langfuse
|
||||
git clone https://github.com/hanzoai/cloud.git
|
||||
cd hanzo
|
||||
```
|
||||
|
||||
3. Install dependencies and set up pre-commit hooks
|
||||
@@ -150,14 +150,14 @@ Requirements
|
||||
pnpm run dev # any subsequent runs
|
||||
```
|
||||
|
||||
You will be asked whether you want to reset Postgres and ClickHouse. Confirm both with 'Y' and press enter.
|
||||
You will be asked whether you want to reset Postgres and Datastore. Confirm both with 'Y' and press enter.
|
||||
|
||||
6. Open the web app in your browser to start using Langfuse:
|
||||
6. Open the web app in your browser to start using Hanzo:
|
||||
- [Sign up page, http://localhost:3000](http://localhost:3000)
|
||||
- [Demo project, http://localhost:3000/project/7a88fb47-b4e2-43b8-a06c-a5ce950dc53a](http://localhost:3000/project/7a88fb47-b4e2-43b8-a06c-a5ce950dc53a)
|
||||
|
||||
7. Log in as a test user:
|
||||
- Username: `demo@langfuse.com`
|
||||
- Username: `demo@hanzo.com`
|
||||
- Password: `password`
|
||||
|
||||
To get comprehensive example data, you can use the `seed` command:
|
||||
@@ -170,7 +170,7 @@ pnpm run db:seed:examples
|
||||
|
||||
- Available packages and their dependencies
|
||||
|
||||
Packages are included in the monorepo according to the `pnpm-workspace.yaml` file. Each package maintains its own dependencies defined in the `package.json`. Internal dependencies can be added as well by adding them to the package dependencies: `"@langfuse/shared": "workspace:*"`.
|
||||
Packages are included in the monorepo according to the `pnpm-workspace.yaml` file. Each package maintains its own dependencies defined in the `package.json`. Internal dependencies can be added as well by adding them to the package dependencies: `"@hanzo/console": "workspace:*"`.
|
||||
|
||||
- Executing commands
|
||||
|
||||
@@ -220,7 +220,7 @@ On the main branch, we adhere to the best practices of [conventional commits](ht
|
||||
## Running Unit Tests
|
||||
|
||||
All tests run in the CI and must pass before merging.
|
||||
All tests run against a running langfuse instance and **write/delete real data from the database**.
|
||||
All tests run against a running hanzo instance and **write/delete real data from the database**.
|
||||
|
||||
### Test Database Setup
|
||||
|
||||
@@ -234,8 +234,8 @@ cp .env.test.example .env.test
|
||||
Then, a different PostgreSQL and Redis are used for the tests.
|
||||
The `.env.test` file only overrides the set values and falls back on `.env` for all undefined values.
|
||||
|
||||
- **PostgreSQL**: Uses separate `langfuse_test` database for isolation
|
||||
- **ClickHouse**: Uses shared `default` database for now
|
||||
- **PostgreSQL**: Uses separate `hanzo_test` database for isolation
|
||||
- **Datastore**: Uses shared `default` database for now
|
||||
- **Redis**: Uses database 1 instead of 0 for isolation (Redis data is not cleaned between tests)
|
||||
|
||||
Tests automatically create the PostgreSQL test database if it doesn't exist and clean up data between runs.
|
||||
@@ -295,25 +295,25 @@ CD on `main`
|
||||
|
||||
## Staging environment
|
||||
|
||||
We run a staging environment at [https://staging.langfuse.com](https://staging.langfuse.com) that is automatically deployed on every push to `main` branch.
|
||||
We run a staging environment at [https://staging.hanzo.ai](https://staging.hanzo.ai) that is automatically deployed on every push to `main` branch.
|
||||
|
||||
The same environment is also used for preview deployments of pull requests. Limitations:
|
||||
|
||||
- SSO is not available as dynamic domains are not supported by most SSO providers.
|
||||
- When making changes to the database, migrations to the staging database need to be applied manually by a maintainer. If you want to interactively test database changes in the staging environment, please reach out.
|
||||
|
||||
You can use the staging environment end-to-end with the Langfuse integrations or SDKs (host: `https://staging.langfuse.com`). However, please note that the staging environment is not intended for production use and may be reset at any time.
|
||||
You can use the staging environment end-to-end with the Hanzo integrations or SDKs (host: `https://staging.hanzo.ai`). However, please note that the staging environment is not intended for production use and may be reset at any time.
|
||||
|
||||
## Production environment
|
||||
|
||||
When a new release is tagged on the `main` branch (excluding prereleases), it triggers a production deployment. The deployment process consists of two steps:
|
||||
|
||||
1. The Docker image is published to GitHub Packages with the version number and `latest` tag.
|
||||
2. The deployment is carried out on Langfuse Cloud. This is done by force pushing the `main` branch to the `production` branch during every release, using the [`release.yml`](.github/workflows/release.yml) GitHub Action.
|
||||
2. The deployment is carried out on Hanzo Cloud. This is done by force pushing the `main` branch to the `production` branch during every release, using the [`release.yml`](.github/workflows/release.yml) GitHub Action.
|
||||
|
||||
## Theming
|
||||
|
||||
At Langfuse, we utilize CSS variables to manage our theme settings across the platform.
|
||||
At Hanzo, we utilize CSS variables to manage our theme settings across the platform.
|
||||
|
||||
Our approach leverages separate CSS variables for backgrounds (--background) and foregrounds (--foreground), fully adhering to the [shadcn/ui](https://ui.shadcn.com/docs/theming) color conventions. The background suffix can be omitted if the variable is used for the background color of the component. We recommend using HSL values for these colors to enhance consistency and customization. There is no need to manually handle dark mode styling with "dark:" prefixes, as next-themes automatically manages the theme switching.
|
||||
|
||||
@@ -367,8 +367,8 @@ The background color of the following component will be `hsl(var(--primary))` an
|
||||
| --dark-yellow | Dark yellow for warning text | LevelColor |
|
||||
| --light-green | Light green for success status badge background | StatusBadge |
|
||||
| --dark-green | Dark green for success status badge text and dot | StatusBadge |
|
||||
| --light-blue | Light blue for background of Staging label | LangfuseLogo |
|
||||
| --dark-blue | Dark blue for text and border of Staging label | LangfuseLogo |
|
||||
| --light-blue | Light blue for background of Staging label | HanzoLogo |
|
||||
| --dark-blue | Dark blue for text and border of Staging label | HanzoLogo |
|
||||
| --accent-light-blue | Light blue accent for table link hover effect | TableLink |
|
||||
| --accent-dark-blue | Dark blue accent for table link text | TableLink |
|
||||
|
||||
@@ -421,6 +421,6 @@ npx fern-api generate --api organizations # for the organizations API
|
||||
|
||||
## License
|
||||
|
||||
Langfuse is MIT licensed, except for `ee/` folder. See [LICENSE](LICENSE) and [docs](https://langfuse.com/docs/open-source) for more details.
|
||||
Hanzo is MIT licensed, except for `ee/` folder. See [LICENSE](LICENSE) and [docs](https://hanzo.ai/docs/open-source) for more details.
|
||||
|
||||
When contributing to the Langfuse codebase, you need to agree to the [Contributor License Agreement](https://cla-assistant.io/langfuse/langfuse). You only need to do this once and the CLA bot will remind you if you haven't signed it yet.
|
||||
When contributing to the Hanzo codebase, you need to agree to the [Contributor License Agreement](https://cla-assistant.io/hanzoai/cloud). You only need to do this once and the CLA bot will remind you if you haven't signed it yet.
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
# Production-ready Dockerfile for Hanzo Cloud Dashboard
|
||||
# Multi-stage build optimized for Next.js applications
|
||||
|
||||
# ===== Base Stage =====
|
||||
FROM node:24-alpine@sha256:cd6fb7efa6490f039f3471a189214d5f548c11df1ff9e5b181aa49e22c14383e AS base
|
||||
|
||||
# Install system dependencies and security updates
|
||||
RUN apk update && apk upgrade && \
|
||||
apk add --no-cache \
|
||||
libc6-compat \
|
||||
dumb-init \
|
||||
tini \
|
||||
ca-certificates && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Enable Corepack for pnpm (pinned version for reliability)
|
||||
RUN corepack enable && corepack prepare pnpm@9.5.0 --activate
|
||||
|
||||
# Create app directory with proper permissions
|
||||
WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs && \
|
||||
chown -R nextjs:nodejs /app
|
||||
|
||||
# ===== Dependencies Stage =====
|
||||
FROM base AS deps
|
||||
|
||||
# Copy package files
|
||||
COPY --chown=nextjs:nodejs package.json pnpm-lock.yaml* pnpm-workspace.yaml* ./
|
||||
COPY --chown=nextjs:nodejs .npmrc* ./
|
||||
COPY --chown=nextjs:nodejs turbo.json* ./
|
||||
COPY --chown=nextjs:nodejs patches/ ./patches/
|
||||
|
||||
# Copy workspace package files
|
||||
COPY --chown=nextjs:nodejs web/package.json ./web/
|
||||
COPY --chown=nextjs:nodejs worker/package.json ./worker/
|
||||
COPY --chown=nextjs:nodejs packages/shared/package.json ./packages/shared/
|
||||
COPY --chown=nextjs:nodejs packages/config-eslint/package.json ./packages/config-eslint/
|
||||
COPY --chown=nextjs:nodejs packages/config-typescript/package.json ./packages/config-typescript/
|
||||
COPY --chown=nextjs:nodejs packages/console-js/package.json ./packages/console-js/
|
||||
COPY --chown=nextjs:nodejs packages/datastore/package.json ./packages/datastore/
|
||||
COPY --chown=nextjs:nodejs packages/langchain/package.json ./packages/langchain/
|
||||
|
||||
# Switch to nextjs user for security
|
||||
USER nextjs
|
||||
|
||||
# Install dependencies with frozen lockfile
|
||||
RUN --mount=type=cache,id=pnpm,target=/app/.pnpm-store pnpm install --frozen-lockfile
|
||||
|
||||
# ===== Builder Stage =====
|
||||
FROM deps AS builder
|
||||
|
||||
# Copy source code
|
||||
COPY --chown=nextjs:nodejs . .
|
||||
|
||||
# Set build environment variables
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Skip env.mjs validation during Docker build
|
||||
ENV DOCKER_BUILD=1
|
||||
|
||||
# Ensure .next dir is owned by nextjs before cache mount creates subdirectory
|
||||
RUN mkdir -p /app/web/.next
|
||||
|
||||
# Build the application (adaptive memory to avoid OOM)
|
||||
RUN --mount=type=cache,target=/app/web/.next/cache,uid=1001,gid=1001 \
|
||||
NODE_OPTIONS='--max-old-space-size-percentage=75' pnpm build
|
||||
|
||||
# ===== Development Stage =====
|
||||
FROM deps AS development
|
||||
|
||||
# Copy source code
|
||||
COPY --chown=nextjs:nodejs . .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Set environment
|
||||
ENV NODE_ENV=development
|
||||
ENV PORT=3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node -e "const http = require('http'); \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/api/health', method: 'GET'}, \
|
||||
(res) => process.exit(res.statusCode === 200 ? 0 : 1)); \
|
||||
req.on('error', () => process.exit(1)); \
|
||||
req.end();" || exit 1
|
||||
|
||||
# Development command with hot reload
|
||||
CMD ["pnpm", "dev"]
|
||||
|
||||
# ===== Production Stage =====
|
||||
FROM base AS production
|
||||
|
||||
# Copy built application from builder
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/web/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/web/.next/static ./web/.next/static
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/web/public ./web/public
|
||||
|
||||
# Copy worker if it exists
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/worker/dist ./worker/dist
|
||||
|
||||
# Switch to nextjs user for security
|
||||
USER nextjs
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Set environment variables
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node -e "const http = require('http'); \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/api/health', method: 'GET'}, \
|
||||
(res) => process.exit(res.statusCode === 200 ? 0 : 1)); \
|
||||
req.on('error', () => process.exit(1)); \
|
||||
req.end();" || exit 1
|
||||
|
||||
# Use tini for proper signal handling
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
|
||||
# Production command
|
||||
CMD ["node", "web/server.js"]
|
||||
|
||||
# ===== Default to production =====
|
||||
FROM production
|
||||
@@ -0,0 +1,58 @@
|
||||
# Dockerfile.runtime - Runtime image for pre-built Hanzo Console
|
||||
# Requires local build first: NODE_OPTIONS="--max-old-space-size=8192" pnpm build
|
||||
|
||||
FROM node:24-alpine@sha256:cd6fb7efa6490f039f3471a189214d5f548c11df1ff9e5b181aa49e22c14383e
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk update && apk upgrade && \
|
||||
apk add --no-cache \
|
||||
libc6-compat \
|
||||
tini \
|
||||
ca-certificates && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs && \
|
||||
chown -R nextjs:nodejs /app
|
||||
|
||||
# Copy the entire standalone output with proper structure
|
||||
# The standalone build is nested under the original path
|
||||
COPY --chown=nextjs:nodejs web/.next/standalone/ ./standalone/
|
||||
|
||||
# Copy static files to the correct location
|
||||
COPY --chown=nextjs:nodejs web/.next/static ./standalone/work/hanzo/console/web/.next/static
|
||||
COPY --chown=nextjs:nodejs web/public ./standalone/work/hanzo/console/web/public
|
||||
|
||||
# Set working directory to where server.js is located
|
||||
WORKDIR /app/standalone/work/hanzo/console/web
|
||||
|
||||
# Switch to nextjs user
|
||||
USER nextjs
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3001
|
||||
|
||||
# Set environment variables
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3001
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD node -e "const http = require('http'); \
|
||||
const req = http.request({hostname: 'localhost', port: 3001, path: '/api/public/health', method: 'GET'}, \
|
||||
(res) => process.exit(res.statusCode === 200 ? 0 : 1)); \
|
||||
req.on('error', () => process.exit(1)); \
|
||||
req.end();" || exit 1
|
||||
|
||||
# Use tini for proper signal handling
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
|
||||
# Start the server
|
||||
CMD ["node", "server.js"]
|
||||
@@ -1,9 +1,9 @@
|
||||
Copyright (c) 2023-2025 Langfuse GmbH
|
||||
Copyright (c) 2023-2025 Hanzo GmbH
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
- All content that resides under the "ee/", "web/src/ee/", and/or "worker/src/ee/" directories of this repository, if these directories exist, is licensed under the license defined in "ee/LICENSE".
|
||||
- All third party components incorporated into the Langfuse Software are licensed under the original license provided by the owner of the applicable component.
|
||||
- All third party components incorporated into the Hanzo Software are licensed under the original license provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
||||
+9
-9
@@ -2,14 +2,14 @@
|
||||
|
||||
## Project Overview
|
||||
|
||||
Langfuse is an open-source LLM engineering platform that helps teams collaboratively develop, monitor, evaluate, and debug AI applications.
|
||||
The main feature areas are tracing, evals and prompt management. Langfuse consists of the web application (this repo), documentation, python SDK and javascript/typescript SDK.
|
||||
Hanzo Console is an open-source LLM engineering platform that helps teams collaboratively develop, monitor, evaluate, and debug AI applications.
|
||||
The main feature areas are tracing, evals and prompt management. Console consists of the web application (this repo), documentation, python SDK and javascript/typescript SDK.
|
||||
This repo contains the web application, worker, and supporting packages but notably not the JS nor Python client SDKs.
|
||||
|
||||
## Repository Structure
|
||||
High level structure. There are more folders (eg for hooks etc).
|
||||
```
|
||||
langfuse/
|
||||
console/
|
||||
├── web/ # Next.js 14 frontend/backend application
|
||||
│ ├── src/
|
||||
│ │ ├── components/ # Reusable UI components (shadcn/ui)
|
||||
@@ -68,7 +68,7 @@ pnpm run db:seed # Seed with example data
|
||||
|
||||
### Infrastructure
|
||||
```sh
|
||||
pnpm run infra:dev:up # Start Docker services (PostgreSQL, ClickHouse, Redis, MinIO)
|
||||
pnpm run infra:dev:up # Start Docker services (PostgreSQL, Datastore, Redis, MinIO)
|
||||
pnpm run infra:dev:down # Stop Docker services
|
||||
```
|
||||
|
||||
@@ -110,7 +110,7 @@ pnpm run nuke # Remove all node_modules, build files, wipe database
|
||||
- **APIs**: tRPC (type-safe client-server communication) + REST APIs for public access
|
||||
- **Authentication**: NextAuth.js/Auth.js
|
||||
- **Database**: Prisma ORM with PostgreSQL
|
||||
- **Analytics Database**: ClickHouse (high-volume trace data)
|
||||
- **Analytics Database**: Datastore (high-volume trace data)
|
||||
- **Validation**: Zod schemas, we use zodv4 (always import from `zod/v4`)
|
||||
- **Styling**: Tailwind CSS with CSS variables for theming
|
||||
- **Components**: shadcn/ui (Radix UI primitives)
|
||||
@@ -124,7 +124,7 @@ pnpm run nuke # Remove all node_modules, build files, wipe database
|
||||
|
||||
### Infrastructure
|
||||
- **Primary Database**: PostgreSQL (via Prisma ORM)
|
||||
- **Analytics Database**: ClickHouse
|
||||
- **Analytics Database**: Datastore
|
||||
- **Cache/Queues**: Redis
|
||||
- **Blob Storage**: MinIO/S3
|
||||
|
||||
@@ -149,7 +149,7 @@ pnpm run nuke # Remove all node_modules, build files, wipe database
|
||||
- Implement proper entitlements checking (see `/web/src/features/entitlements/README.md`)
|
||||
|
||||
### Database
|
||||
- **Dual database system**: PostgreSQL (primary) + ClickHouse (analytics)
|
||||
- **Dual database system**: PostgreSQL (primary) + Datastore (analytics)
|
||||
- Use `golang-migrate` CLI for database migrations
|
||||
- All database operations go through Prisma ORM for PostgreSQL
|
||||
- Foreign key relationships may not be enforced in schema to allow unordered ingestion
|
||||
@@ -172,13 +172,13 @@ pnpm run nuke # Remove all node_modules, build files, wipe database
|
||||
|
||||
- **Node.js**: Version 24 (specified in `.nvmrc`)
|
||||
- **Package Manager**: pnpm v9.5.0
|
||||
- **Database Dependencies**: Docker for local PostgreSQL, ClickHouse, Redis, MinIO
|
||||
- **Database Dependencies**: Docker for local PostgreSQL, Datastore, Redis, MinIO
|
||||
- **Environment**: Copy `.env.dev.example` to `.env`
|
||||
|
||||
## Login for Development
|
||||
|
||||
When running locally with seed data:
|
||||
- Username: `demo@langfuse.com`
|
||||
- Username: `demo@hanzo.ai`
|
||||
- Password: `password`
|
||||
- Demo project URL: `http://localhost:3000/project/7a88fb47-b4e2-43b8-a06c-a5ce950dc53a`
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Hanzo Cloud Platform Makefile
|
||||
|
||||
# Get version from package.json
|
||||
VERSION := $(shell node -p "require('./package.json').version")
|
||||
REGISTRY := hanzoai
|
||||
COMMIT_SHA := $(shell git rev-parse --short HEAD)
|
||||
|
||||
# Default target
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Hanzo Cloud Platform Build Tools"
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make build-images Build multi-platform Docker images and push to registry"
|
||||
@echo " make build-local Build single-platform Docker images for local testing"
|
||||
@echo " make push-images Push Docker images to registry (redundant with build-images)"
|
||||
@echo " make build-push-images Build and push Docker images"
|
||||
@echo " make update-compose Update docker-compose files to use new images"
|
||||
@echo " make deploy Build, push images and update compose files"
|
||||
@echo " make version Display current version information"
|
||||
@echo ""
|
||||
@echo "Current version: $(VERSION) ($(COMMIT_SHA))"
|
||||
|
||||
# Build Docker images
|
||||
.PHONY: build-images
|
||||
build-images:
|
||||
@echo "Building Hanzo Cloud images v$(VERSION) ($(COMMIT_SHA))"
|
||||
docker buildx create --name cloud-builder --use --bootstrap || true
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
-f worker/Dockerfile \
|
||||
-t $(REGISTRY)/cloud-worker:$(VERSION) \
|
||||
-t $(REGISTRY)/cloud-worker:latest \
|
||||
--push .
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
-f web/Dockerfile \
|
||||
-t $(REGISTRY)/cloud-web:$(VERSION) \
|
||||
-t $(REGISTRY)/cloud-web:latest \
|
||||
--push .
|
||||
@echo "Successfully built images:"
|
||||
@echo " - $(REGISTRY)/cloud-worker:$(VERSION) (multi-platform)"
|
||||
@echo " - $(REGISTRY)/cloud-web:$(VERSION) (multi-platform)"
|
||||
|
||||
# Push Docker images (now handled by buildx with --push flag)
|
||||
.PHONY: push-images
|
||||
push-images:
|
||||
@echo "Images v$(VERSION) already pushed during build with buildx"
|
||||
@echo "If you need to push again, run build-images"
|
||||
|
||||
# Build local images for testing (single platform)
|
||||
.PHONY: build-local
|
||||
build-local:
|
||||
@echo "Building local Hanzo Cloud images v$(VERSION) ($(COMMIT_SHA))"
|
||||
docker build -f worker/Dockerfile -t $(REGISTRY)/cloud-worker:local .
|
||||
docker build -f web/Dockerfile -t $(REGISTRY)/cloud-web:local .
|
||||
@echo "Successfully built local images:"
|
||||
@echo " - $(REGISTRY)/cloud-worker:local"
|
||||
@echo " - $(REGISTRY)/cloud-web:local"
|
||||
|
||||
# Build and push images
|
||||
.PHONY: build-push-images
|
||||
build-push-images: build-images
|
||||
|
||||
# Update docker-compose files
|
||||
.PHONY: update-compose
|
||||
update-compose:
|
||||
@echo "Updating docker-compose files to use version $(VERSION)"
|
||||
@for file in docker-compose.yml docker-compose.dev.yml docker-compose.prod.yml docker-compose.build.yml docker-compose.dev-azure.yml; do \
|
||||
if [ -f "$$file" ]; then \
|
||||
echo "Updating $$file..."; \
|
||||
sed -i.bak -E "s|image: .*ai-platform-worker:.*|image: $(REGISTRY)/cloud-worker:$(VERSION)|g" "$$file"; \
|
||||
if grep -q "image: .*ai-platform" "$$file"; then \
|
||||
sed -i.bak -E "s|image: .*ai-platform(-web)?:.*|image: $(REGISTRY)/cloud-web:$(VERSION)|g" "$$file"; \
|
||||
fi; \
|
||||
rm -f "$$file.bak"; \
|
||||
echo "Successfully updated $$file"; \
|
||||
else \
|
||||
echo "File $$file not found, skipping"; \
|
||||
fi; \
|
||||
done
|
||||
@echo "All docker-compose files updated successfully!"
|
||||
|
||||
# Full deployment process
|
||||
.PHONY: deploy
|
||||
deploy: build-push-images update-compose
|
||||
@echo "Deployment completed successfully!"
|
||||
|
||||
# Display version information
|
||||
.PHONY: version
|
||||
version:
|
||||
@echo "Hanzo Cloud Platform"
|
||||
@echo "Version: $(VERSION)"
|
||||
@echo "Commit: $(COMMIT_SHA)"
|
||||
@echo "Registry: $(REGISTRY)"
|
||||
+120
-120
@@ -1,34 +1,34 @@
|
||||

|
||||

|
||||
|
||||
<div align="center">
|
||||
<div>
|
||||
<h3>
|
||||
<a href="https://langfuse.com/cn">
|
||||
<a href="https://hanzo.ai/cn">
|
||||
<strong>🇨🇳 🤝 🪢</strong>
|
||||
</a> ·
|
||||
<a href="https://cloud.langfuse.com">
|
||||
<strong>Langfuse Cloud</strong>
|
||||
<a href="https://cloud.hanzo.ai">
|
||||
<strong>Hanzo Cloud</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/docs/deployment/self-host">
|
||||
<a href="https://hanzo.ai/docs/deployment/self-host">
|
||||
<strong>自托管</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/demo">
|
||||
<a href="https://hanzo.ai/demo">
|
||||
<strong>演示</strong>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="https://langfuse.com/docs"><strong>文档</strong></a> ·
|
||||
<a href="https://langfuse.com/issues"><strong>报告问题</strong></a> ·
|
||||
<a href="https://langfuse.com/ideas"><strong>功能请求</strong></a> ·
|
||||
<a href="https://langfuse.com/changelog"><strong>更新日志</strong></a> ·
|
||||
<a href="https://langfuse.com/roadmap"><strong>路线图</strong></a> ·
|
||||
<a href="https://hanzo.ai/docs"><strong>文档</strong></a> ·
|
||||
<a href="https://hanzo.ai/issues"><strong>报告问题</strong></a> ·
|
||||
<a href="https://hanzo.ai/ideas"><strong>功能请求</strong></a> ·
|
||||
<a href="https://hanzo.ai/changelog"><strong>更新日志</strong></a> ·
|
||||
<a href="https://hanzo.ai/roadmap"><strong>路线图</strong></a> ·
|
||||
</div>
|
||||
<br/>
|
||||
<span>Langfuse 使用 <a href="https://github.com/orgs/langfuse/discussions"><strong>GitHub Discussions</strong></a> 作为支持和功能请求的平台。</span>
|
||||
<span>Hanzo 使用 <a href="https://github.com/orgs/hanzo/discussions"><strong>GitHub Discussions</strong></a> 作为支持和功能请求的平台。</span>
|
||||
<br/>
|
||||
<span><b>我们正在招聘。</b> <a href="https://langfuse.com/careers"><strong>加入我们</strong></a>,从事产品工程和技术市场职位。</span>
|
||||
<span><b>我们正在招聘。</b> <a href="https://hanzo.ai/careers"><strong>加入我们</strong></a>,从事产品工程和技术市场职位。</span>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
@@ -36,42 +36,42 @@
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/langfuse/langfuse/blob/main/LICENSE">
|
||||
<a href="https://github.com/hanzoai/cloud/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-MIT-E11311.svg" alt="MIT License">
|
||||
</a>
|
||||
<a href="https://www.ycombinator.com/companies/langfuse">
|
||||
<a href="https://www.ycombinator.com/companies/hanzo">
|
||||
<img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/u/langfuse" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/langfuse/langfuse?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff">
|
||||
<a href="https://hub.docker.com/u/hanzo" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/hanzoai/cloud?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff">
|
||||
</a>
|
||||
<a href="https://pypi.python.org/pypi/langfuse">
|
||||
<img src="https://img.shields.io/pypi/dm/langfuse?logo=python&logoColor=white&label=pypi%20langfuse&color=blue" alt="langfuse Python package on PyPi">
|
||||
<a href="https://pypi.python.org/pypi/hanzo">
|
||||
<img src="https://img.shields.io/pypi/dm/hanzo?logo=python&logoColor=white&label=pypi%20hanzo&color=blue" alt="hanzo Python package on PyPi">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/langfuse">
|
||||
<img src="https://img.shields.io/npm/dm/langfuse?logo=npm&logoColor=white&label=npm%20langfuse&color=blue" alt="langfuse npm package">
|
||||
<a href="https://www.npmjs.com/package/hanzo">
|
||||
<img src="https://img.shields.io/npm/dm/hanzo?logo=npm&logoColor=white&label=npm%20hanzo&color=blue" alt="hanzo npm package">
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://discord.com/invite/7NXusRtqYU" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1111061815649124414?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="在 Discord 上聊天">
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=langfuse" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/langfuse?logo=X&color=%20%23f5f5f5"
|
||||
<a href="https://twitter.com/intent/follow?screen_name=hanzo" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/hanzo?logo=X&color=%20%23f5f5f5"
|
||||
alt="在 X (Twitter) 上关注">
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/company/langfuse/" target="_blank">
|
||||
<a href="https://www.linkedin.com/company/hanzo/" target="_blank">
|
||||
<img src="https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff"
|
||||
alt="在 LinkedIn 上关注">
|
||||
</a>
|
||||
<a href="https://github.com/langfuse/langfuse/graphs/commit-activity" target="_blank">
|
||||
<img alt="过去一个月的提交" src="https://img.shields.io/github/commit-activity/m/langfuse/langfuse?labelColor=%20%2332b583&color=%20%2312b76a">
|
||||
<a href="https://github.com/hanzoai/cloud/graphs/commit-activity" target="_blank">
|
||||
<img alt="过去一个月的提交" src="https://img.shields.io/github/commit-activity/m/hanzoai/cloud?labelColor=%20%2332b583&color=%20%2312b76a">
|
||||
</a>
|
||||
<a href="https://github.com/langfuse/langfuse/" target="_blank">
|
||||
<img alt="已关闭的问题" src="https://img.shields.io/github/issues-search?query=repo%3Alangfuse%2Flangfuse%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98">
|
||||
<a href="https://github.com/hanzoai/cloud/" target="_blank">
|
||||
<img alt="已关闭的问题" src="https://img.shields.io/github/issues-search?query=repo%3Ahanzo%2Fhanzo%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98">
|
||||
</a>
|
||||
<a href="https://github.com/langfuse/langfuse/discussions/" target="_blank">
|
||||
<img alt="讨论帖数量" src="https://img.shields.io/github/discussions/langfuse/langfuse?labelColor=%20%239b8afb&color=%20%237a5af8">
|
||||
<a href="https://github.com/hanzoai/cloud/discussions/" target="_blank">
|
||||
<img alt="讨论帖数量" src="https://img.shields.io/github/discussions/hanzoai/cloud?labelColor=%20%239b8afb&color=%20%237a5af8">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -82,146 +82,146 @@
|
||||
<a href="./README.kr.md"><img alt="README in Korean" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||
</p>
|
||||
|
||||
Langfuse 是一个 **开源 LLM 工程** 平台。它帮助团队协作 **开发、监控、评估** 以及 **调试** AI 应用。Langfuse 可在几分钟内 **自托管**,并且经过 **实战考验**。
|
||||
Hanzo 是一个 **开源 LLM 工程** 平台。它帮助团队协作 **开发、监控、评估** 以及 **调试** AI 应用。Hanzo 可在几分钟内 **自托管**,并且经过 **实战考验**。
|
||||
|
||||
[](https://langfuse.com/watch-demo)
|
||||
[](https://hanzo.ai/watch-demo)
|
||||
|
||||
## ✨ 核心特性
|
||||
|
||||

|
||||

|
||||
|
||||
- [LLM 应用可观察性](https://langfuse.com/docs/tracing):为你的应用插入仪表代码,并开始将追踪数据传送到 Langfuse,从而追踪 LLM 调用及应用中其他相关逻辑(如检索、嵌入或代理操作)。检查并调试复杂日志及用户会话。试试互动的 [演示](https://langfuse.com/docs/demo) 看看效果。
|
||||
- [提示管理](https://langfuse.com/docs/prompt-management/get-started) 帮助你集中管理、版本控制并协作迭代提示。得益于服务器和客户端的高效缓存,你可以在不增加延迟的情况下反复迭代提示。
|
||||
- [LLM 应用可观察性](https://hanzo.com/docs/tracing):为你的应用插入仪表代码,并开始将追踪数据传送到 Hanzo,从而追踪 LLM 调用及应用中其他相关逻辑(如检索、嵌入或代理操作)。检查并调试复杂日志及用户会话。试试互动的 [演示](https://hanzo.com/docs/demo) 看看效果。
|
||||
- [提示管理](https://hanzo.com/docs/prompt-management/get-started) 帮助你集中管理、版本控制并协作迭代提示。得益于服务器和客户端的高效缓存,你可以在不增加延迟的情况下反复迭代提示。
|
||||
|
||||
- [评估](https://langfuse.com/docs/evaluation/overview) 是 LLM 应用开发流程的关键组成部分,Langfuse 能够满足你的多样需求。它支持 LLM 作为"裁判"、用户反馈收集、手动标注以及通过 API/SDK 实现自定义评估流程。
|
||||
- [评估](https://hanzo.com/docs/evaluation/overview) 是 LLM 应用开发流程的关键组成部分,Hanzo 能够满足你的多样需求。它支持 LLM 作为"裁判"、用户反馈收集、手动标注以及通过 API/SDK 实现自定义评估流程。
|
||||
|
||||
- [数据集](https://langfuse.com/docs/evaluation/dataset-runs/datasets) 为评估你的 LLM 应用提供测试集和基准。它们支持持续改进、部署前测试、结构化实验、灵活评估,并能与 LangChain、LlamaIndex 等框架无缝整合。
|
||||
- [数据集](https://hanzo.com/docs/evaluation/dataset-runs/datasets) 为评估你的 LLM 应用提供测试集和基准。它们支持持续改进、部署前测试、结构化实验、灵活评估,并能与 LangChain、LlamaIndex 等框架无缝整合。
|
||||
|
||||
- [LLM 试玩平台](https://langfuse.com/docs/playground) 是用于测试和迭代提示及模型配置的工具,缩短反馈周期,加速开发。当你在追踪中发现异常结果时,可以直接跳转至试玩平台进行调整。
|
||||
- [LLM 试玩平台](https://hanzo.ai/docs/playground) 是用于测试和迭代提示及模型配置的工具,缩短反馈周期,加速开发。当你在追踪中发现异常结果时,可以直接跳转至试玩平台进行调整。
|
||||
|
||||
- [综合 API](https://langfuse.com/docs/api):Langfuse 常用于驱动定制化的 LLMOps 工作流程,同时利用 Langfuse 提供的构建模块和 API。我们提供 OpenAPI 规格、Postman 集合以及针对 Python 和 JS/TS 的类型化 SDK。
|
||||
- [综合 API](https://hanzo.ai/docs/api):Hanzo 常用于驱动定制化的 LLMOps 工作流程,同时利用 Hanzo 提供的构建模块和 API。我们提供 OpenAPI 规格、Postman 集合以及针对 Python 和 JS/TS 的类型化 SDK。
|
||||
|
||||
## 📦 部署 Langfuse
|
||||
## 📦 部署 Hanzo
|
||||
|
||||

|
||||

|
||||
|
||||
### Langfuse Cloud
|
||||
### Hanzo Cloud
|
||||
|
||||
由 Langfuse 团队管理的部署,提供慷慨的免费额度(爱好者计划),无需信用卡。
|
||||
由 Hanzo 团队管理的部署,提供慷慨的免费额度(爱好者计划),无需信用卡。
|
||||
|
||||
<div align="center">
|
||||
<a href="https://cloud.langfuse.com" target="_blank">
|
||||
<img alt="注册 Langfuse Cloud" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Langfuse%20Cloud-8A2BE2?&color=orange">
|
||||
<a href="https://cloud.hanzo.ai" target="_blank">
|
||||
<img alt="注册 Hanzo Cloud" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Hanzo%20Cloud-8A2BE2?&color=orange">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### 自托管 Langfuse
|
||||
### 自托管 Hanzo
|
||||
|
||||
在你自己的基础设施上运行 Langfuse:
|
||||
在你自己的基础设施上运行 Hanzo:
|
||||
|
||||
- [本地(docker compose)](https://langfuse.com/self-hosting/local):使用 Docker Compose 在你的机器上于 5 分钟内运行 Langfuse。
|
||||
- [本地(docker compose)](https://hanzo.ai/self-hosting/local):使用 Docker Compose 在你的机器上于 5 分钟内运行 Hanzo。
|
||||
|
||||
```bash:README.md/docker-compose
|
||||
# 获取最新的 Langfuse 仓库副本
|
||||
git clone https://github.com/langfuse/langfuse.git
|
||||
cd langfuse
|
||||
# 获取最新的 Hanzo 仓库副本
|
||||
git clone https://github.com/hanzo/hanzo.git
|
||||
cd hanzo
|
||||
|
||||
# 运行 Langfuse 的 docker compose
|
||||
# 运行 Hanzo 的 docker compose
|
||||
docker compose up
|
||||
```
|
||||
|
||||
- [Kubernetes(Helm)](https://langfuse.com/self-hosting/kubernetes-helm):使用 Helm 在 Kubernetes 集群上部署 Langfuse。这是推荐的生产环境部署方式。
|
||||
- [Kubernetes(Helm)](https://hanzo.ai/self-hosting/kubernetes-helm):使用 Helm 在 Kubernetes 集群上部署 Hanzo。这是推荐的生产环境部署方式。
|
||||
|
||||
- [虚拟机](https://langfuse.com/self-hosting/docker-compose):使用 Docker Compose 在单台虚拟机上部署 Langfuse。
|
||||
- [虚拟机](https://hanzo.ai/self-hosting/docker-compose):使用 Docker Compose 在单台虚拟机上部署 Hanzo。
|
||||
|
||||
- Terraform 模板: [AWS](https://langfuse.com/self-hosting/aws)、[Azure](https://langfuse.com/self-hosting/azure)、[GCP](https://langfuse.com/self-hosting/gcp)
|
||||
- Terraform 模板: [AWS](https://hanzo.com/self-hosting/aws)、[Azure](https://hanzo.com/self-hosting/azure)、[GCP](https://hanzo.com/self-hosting/gcp)
|
||||
|
||||
请参阅 [自托管文档](https://langfuse.com/self-hosting) 了解更多关于架构和配置选项的信息。
|
||||
请参阅 [自托管文档](https://hanzo.ai/self-hosting) 了解更多关于架构和配置选项的信息。
|
||||
|
||||
## 🔌 集成
|
||||
|
||||

|
||||

|
||||
|
||||
### 主要集成:
|
||||
|
||||
| 集成 | 支持语言/平台 | 描述 |
|
||||
| ------------------------------------------------------------------------------------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [SDK](https://langfuse.com/docs/sdk) | Python, JS/TS | 使用 SDK 进行手动仪表化,实现全面灵活性。 |
|
||||
| [OpenAI](https://langfuse.com/integrations/model-providers/openai-py) | Python, JS/TS | 通过直接替换 OpenAI SDK 实现自动仪表化。 |
|
||||
| [Langchain](https://langfuse.com/docs/integrations/langchain) | Python, JS/TS | 通过传入回调处理器至 Langchain 应用实现自动仪表化。 |
|
||||
| [LlamaIndex](https://langfuse.com/docs/integrations/llama-index/get-started) | Python | 通过 LlamaIndex 回调系统实现自动仪表化。 |
|
||||
| [Haystack](https://langfuse.com/docs/integrations/haystack) | Python | 通过 Haystack 内容追踪系统实现自动仪表化。 |
|
||||
| [LiteLLM](https://langfuse.com/docs/integrations/litellm) | Python, JS/TS (仅代理) | 允许使用任何 LLM 替代 GPT。支持 Azure、OpenAI、Cohere、Anthropic、Ollama、VLLM、Sagemaker、HuggingFace、Replicate(100+ LLMs)。 |
|
||||
| [Vercel AI SDK](https://langfuse.com/docs/integrations/vercel-ai-sdk) | JS/TS | 基于 TypeScript 的工具包,帮助开发者使用 React、Next.js、Vue、Svelte 和 Node.js 构建 AI 驱动的应用。 |
|
||||
| [API](https://langfuse.com/docs/api) | | 直接调用公共 API。提供 OpenAPI 规格。 |
|
||||
| [Google VertexAI 和 Gemini](https://langfuse.com/docs/integrations/google-vertex-ai) | 模型 | 在 Google 上运行基础模型和微调模型。 |
|
||||
| [SDK](https://hanzo.com/docs/sdk) | Python, JS/TS | 使用 SDK 进行手动仪表化,实现全面灵活性。 |
|
||||
| [OpenAI](https://hanzo.com/integrations/model-providers/openai-py) | Python, JS/TS | 通过直接替换 OpenAI SDK 实现自动仪表化。 |
|
||||
| [Langchain](https://hanzo.com/docs/integrations/langchain) | Python, JS/TS | 通过传入回调处理器至 Langchain 应用实现自动仪表化。 |
|
||||
| [LlamaIndex](https://hanzo.com/docs/integrations/llama-index/get-started) | Python | 通过 LlamaIndex 回调系统实现自动仪表化。 |
|
||||
| [Haystack](https://hanzo.com/docs/integrations/haystack) | Python | 通过 Haystack 内容追踪系统实现自动仪表化。 |
|
||||
| [LiteLLM](https://hanzo.com/docs/integrations/litellm) | Python, JS/TS (仅代理) | 允许使用任何 LLM 替代 GPT。支持 Azure、OpenAI、Cohere、Anthropic、Ollama、VLLM、Sagemaker、HuggingFace、Replicate(100+ LLMs)。 |
|
||||
| [Vercel AI SDK](https://hanzo.com/docs/integrations/vercel-ai-sdk) | JS/TS | 基于 TypeScript 的工具包,帮助开发者使用 React、Next.js、Vue、Svelte 和 Node.js 构建 AI 驱动的应用。 |
|
||||
| [API](https://hanzo.com/docs/api) | | 直接调用公共 API。提供 OpenAPI 规格。 |
|
||||
| [Google VertexAI 和 Gemini](https://hanzo.com/docs/integrations/google-vertex-ai) | 模型 | 在 Google 上运行基础模型和微调模型。 |
|
||||
|
||||
### 与 Langfuse 集成的软件包:
|
||||
### 与 Hanzo 集成的软件包:
|
||||
|
||||
| 名称 | 类型 | 描述 |
|
||||
| ----------------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------- |
|
||||
| [Instructor](https://langfuse.com/docs/integrations/instructor) | 库 | 用于获取结构化 LLM 输出(JSON、Pydantic)的库。 |
|
||||
| [DSPy](https://langfuse.com/docs/integrations/dspy) | 库 | 一个系统性优化语言模型提示和权重的框架。 |
|
||||
| [Amazon Bedrock](https://langfuse.com/docs/integrations/amazon-bedrock) | 模型 | 在 AWS 上运行基础模型和微调模型。 |
|
||||
| [Mirascope](https://langfuse.com/docs/integrations/mirascope) | 库 | 构建 LLM 应用的 Python 工具包。 |
|
||||
| [Ollama](https://langfuse.com/docs/integrations/ollama) | 模型(本地) | 在你的机器上轻松运行开源 LLM。 |
|
||||
| [AutoGen](https://langfuse.com/docs/integrations/autogen) | 代理框架 | 用于构建分布式代理的开源 LLM 平台。 |
|
||||
| [Flowise](https://langfuse.com/docs/integrations/flowise) | 聊天/代理界面 | 基于 JS/TS 的无代码构建器,用于定制化 LLM 流程。 |
|
||||
| [Langflow](https://langfuse.com/docs/integrations/langflow) | 聊天/代理界面 | 基于 Python 的 LangChain 用户界面,采用 react-flow 设计,提供便捷的实验与原型构建体验。 |
|
||||
| [Dify](https://langfuse.com/docs/integrations/dify) | 聊天/代理界面 | 带有无代码构建器的开源 LLM 应用开发平台。 |
|
||||
| [OpenWebUI](https://langfuse.com/docs/integrations/openwebui) | 聊天/代理界面 | 自托管的 LLM 聊天网页界面,支持包括自托管和本地模型在内的多种 LLM 运行器。 |
|
||||
| [Promptfoo](https://langfuse.com/docs/integrations/promptfoo) | 工具 | 开源 LLM 测试平台。 |
|
||||
| [LobeChat](https://langfuse.com/docs/integrations/lobechat) | 聊天/代理界面 | 开源聊天机器人平台。 |
|
||||
| [Vapi](https://langfuse.com/docs/integrations/vapi) | 平台 | 开源语音 AI 平台。 |
|
||||
| [Inferable](https://langfuse.com/docs/integrations/other/inferable) | 代理 | 构建分布式代理的开源 LLM 平台。 |
|
||||
| [Gradio](https://langfuse.com/docs/integrations/other/gradio) | 聊天/代理界面 | 开源 Python 库,可用于构建类似聊天 UI 的网页界面。 |
|
||||
| [Goose](https://langfuse.com/docs/integrations/goose) | 代理 | 构建分布式代理的开源 LLM 平台。 |
|
||||
| [smolagents](https://langfuse.com/docs/integrations/smolagents) | 代理 | 开源 AI 代理框架。 |
|
||||
| [CrewAI](https://langfuse.com/docs/integrations/crewai) | 代理 | 多代理框架,用于实现代理之间的协作与工具调用。 |
|
||||
| [Instructor](https://hanzo.com/docs/integrations/instructor) | 库 | 用于获取结构化 LLM 输出(JSON、Pydantic)的库。 |
|
||||
| [DSPy](https://hanzo.com/docs/integrations/dspy) | 库 | 一个系统性优化语言模型提示和权重的框架。 |
|
||||
| [Amazon Bedrock](https://hanzo.com/docs/integrations/amazon-bedrock) | 模型 | 在 AWS 上运行基础模型和微调模型。 |
|
||||
| [Mirascope](https://hanzo.com/docs/integrations/mirascope) | 库 | 构建 LLM 应用的 Python 工具包。 |
|
||||
| [Ollama](https://hanzo.com/docs/integrations/ollama) | 模型(本地) | 在你的机器上轻松运行开源 LLM。 |
|
||||
| [AutoGen](https://hanzo.com/docs/integrations/autogen) | 代理框架 | 用于构建分布式代理的开源 LLM 平台。 |
|
||||
| [Flowise](https://hanzo.com/docs/integrations/flowise) | 聊天/代理界面 | 基于 JS/TS 的无代码构建器,用于定制化 LLM 流程。 |
|
||||
| [Langflow](https://hanzo.com/docs/integrations/langflow) | 聊天/代理界面 | 基于 Python 的 LangChain 用户界面,采用 react-flow 设计,提供便捷的实验与原型构建体验。 |
|
||||
| [Dify](https://hanzo.com/docs/integrations/dify) | 聊天/代理界面 | 带有无代码构建器的开源 LLM 应用开发平台。 |
|
||||
| [OpenWebUI](https://hanzo.com/docs/integrations/openwebui) | 聊天/代理界面 | 自托管的 LLM 聊天网页界面,支持包括自托管和本地模型在内的多种 LLM 运行器。 |
|
||||
| [Promptfoo](https://hanzo.com/docs/integrations/promptfoo) | 工具 | 开源 LLM 测试平台。 |
|
||||
| [LobeChat](https://hanzo.com/docs/integrations/lobechat) | 聊天/代理界面 | 开源聊天机器人平台。 |
|
||||
| [Vapi](https://hanzo.com/docs/integrations/vapi) | 平台 | 开源语音 AI 平台。 |
|
||||
| [Inferable](https://hanzo.com/docs/integrations/other/inferable) | 代理 | 构建分布式代理的开源 LLM 平台。 |
|
||||
| [Gradio](https://hanzo.com/docs/integrations/other/gradio) | 聊天/代理界面 | 开源 Python 库,可用于构建类似聊天 UI 的网页界面。 |
|
||||
| [Goose](https://hanzo.com/docs/integrations/goose) | 代理 | 构建分布式代理的开源 LLM 平台。 |
|
||||
| [smolagents](https://hanzo.com/docs/integrations/smolagents) | 代理 | 开源 AI 代理框架。 |
|
||||
| [CrewAI](https://hanzo.com/docs/integrations/crewai) | 代理 | 多代理框架,用于实现代理之间的协作与工具调用。 |
|
||||
|
||||
## 🚀 快速入门
|
||||
|
||||
为你的应用增加仪表代码,并开始将追踪数据上传到 Langfuse,从而记录 LLM 调用及应用中其他相关逻辑(如检索、嵌入或代理操作)。
|
||||
为你的应用增加仪表代码,并开始将追踪数据上传到 Hanzo,从而记录 LLM 调用及应用中其他相关逻辑(如检索、嵌入或代理操作)。
|
||||
|
||||
### 1️⃣ 创建新项目
|
||||
|
||||
1. [创建 Langfuse 账户](https://cloud.langfuse.com/auth/sign-up) 或 [自托管](https://langfuse.com/self-hosting)
|
||||
1. [创建 Hanzo 账户](https://cloud.hanzo.ai/auth/sign-up) 或 [自托管](https://hanzo.ai/self-hosting)
|
||||
2. 创建一个新项目
|
||||
3. 在项目设置中创建新的 API 凭证
|
||||
|
||||
### 2️⃣ 记录你的第一个 LLM 调用
|
||||
|
||||
使用 [<code>@observe()</code> 装饰器](https://langfuse.com/docs/sdk/python/decorators) 可轻松跟踪任何 Python LLM 应用。在本快速入门中,我们还使用了 Langfuse 的 [OpenAI 集成](https://langfuse.com/integrations/model-providers/openai-py) 来自动捕获所有模型参数。
|
||||
使用 [<code>@observe()</code> 装饰器](https://hanzo.com/docs/sdk/python/decorators) 可轻松跟踪任何 Python LLM 应用。在本快速入门中,我们还使用了 Hanzo 的 [OpenAI 集成](https://hanzo.com/integrations/model-providers/openai-py) 来自动捕获所有模型参数。
|
||||
|
||||
> [!提示]
|
||||
> 不使用 OpenAI?请访问 [我们的文档](https://langfuse.com/docs/get-started#log-your-first-llm-call-to-langfuse) 了解如何记录其他模型和框架。
|
||||
> 不使用 OpenAI?请访问 [我们的文档](https://hanzo.ai/docs/get-started#log-your-first-llm-call-to-hanzo) 了解如何记录其他模型和框架。
|
||||
|
||||
安装依赖:
|
||||
|
||||
```bash
|
||||
pip install langfuse openai
|
||||
pip install hanzo openai
|
||||
```
|
||||
|
||||
配置环境变量(创建名为 **.env** 的文件):
|
||||
|
||||
```bash:.env
|
||||
LANGFUSE_SECRET_KEY="sk-lf-..."
|
||||
LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
||||
LANGFUSE_BASE_URL="https://cloud.langfuse.com" # 🇪🇺 欧盟区域
|
||||
# LANGFUSE_BASE_URL="https://us.cloud.langfuse.com" # 🇺🇸 美洲区域
|
||||
HANZO_SECRET_KEY="sk-lf-..."
|
||||
HANZO_PUBLIC_KEY="pk-lf-..."
|
||||
HANZO_BASE_URL="https://cloud.hanzo.com" # 🇪🇺 欧盟区域
|
||||
# HANZO_BASE_URL="https://us.cloud.hanzo.com" # 🇺🇸 美洲区域
|
||||
```
|
||||
|
||||
创建示例代码(文件名:**main.py**):
|
||||
|
||||
```python:main.py
|
||||
from langfuse import observe
|
||||
from langfuse.openai import openai # OpenAI 集成
|
||||
from hanzo import observe
|
||||
from hanzo.openai import openai # OpenAI 集成
|
||||
|
||||
@observe()
|
||||
def story():
|
||||
return openai.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": "What is Langfuse?"}],
|
||||
messages=[{"role": "user", "content": "What is Hanzo?"}],
|
||||
).choices[0].message.content
|
||||
|
||||
@observe()
|
||||
@@ -231,62 +231,62 @@ def main():
|
||||
main()
|
||||
```
|
||||
|
||||
### 3️⃣ 在 Langfuse 中查看追踪记录
|
||||
### 3️⃣ 在 Hanzo 中查看追踪记录
|
||||
|
||||
在 Langfuse 中查看你的语言模型调用及其他应用逻辑。
|
||||
在 Hanzo 中查看你的语言模型调用及其他应用逻辑。
|
||||
|
||||

|
||||

|
||||
|
||||
_[Langfuse 中的公共示例追踪](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
_[Hanzo 中的公共示例追踪](https://cloud.hanzo.ai/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
|
||||
> [!提示]
|
||||
>
|
||||
> [了解更多](https://langfuse.com/docs/tracing) 关于 Langfuse 中的追踪,或试试 [互动演示](https://langfuse.com/docs/demo)。
|
||||
> [了解更多](https://hanzo.ai/docs/tracing) 关于 Hanzo 中的追踪,或试试 [互动演示](https://hanzo.ai/docs/demo)。
|
||||
|
||||
## ⭐️ 给我们加星
|
||||
|
||||

|
||||

|
||||
|
||||
## 💭 支持
|
||||
|
||||
查找问题答案:
|
||||
|
||||
- 我们的 [文档](https://langfuse.com/docs) 是查找答案的最佳起点。内容全面,我们投入大量时间进行维护。你也可以通过 GitHub 提出文档修改建议。
|
||||
- [Langfuse 常见问题](https://langfuse.com/faq) 解答了最常见的问题。
|
||||
- 我们的 [文档](https://hanzo.com/docs) 是查找答案的最佳起点。内容全面,我们投入大量时间进行维护。你也可以通过 GitHub 提出文档修改建议。
|
||||
- [Hanzo 常见问题](https://hanzo.com/faq) 解答了最常见的问题。
|
||||
- 使用 "Ask AI" 立即获取问题答案。
|
||||
|
||||
支持渠道:
|
||||
|
||||
- **在 GitHub Discussions 的 [公共问答](https://github.com/orgs/langfuse/discussions/categories/support) 中提出任何问题。** 请尽量提供详细信息(如代码片段、截图、背景信息)以帮助我们理解你的问题。
|
||||
- 在 GitHub Discussions 中 [提出功能请求](https://github.com/orgs/langfuse/discussions/categories/ideas)。
|
||||
- 在 GitHub Issues 中 [报告 Bug](https://github.com/langfuse/langfuse/issues)。
|
||||
- **在 GitHub Discussions 的 [公共问答](https://github.com/orgs/hanzoai/discussions/categories/support) 中提出任何问题。** 请尽量提供详细信息(如代码片段、截图、背景信息)以帮助我们理解你的问题。
|
||||
- 在 GitHub Discussions 中 [提出功能请求](https://github.com/orgs/hanzoai/discussions/categories/ideas)。
|
||||
- 在 GitHub Issues 中 [报告 Bug](https://github.com/hanzoai/cloud/issues)。
|
||||
- 对于时效性较强的问题,请通过应用内聊天小部件联系我们。
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎你的贡献!
|
||||
|
||||
- 在 GitHub Discussions 中为 [想法](https://github.com/orgs/langfuse/discussions/categories/ideas)投票。
|
||||
- 提出并评论 [问题](https://github.com/langfuse/langfuse/issues)。
|
||||
- 在 GitHub Discussions 中为 [想法](https://github.com/orgs/hanzoai/discussions/categories/ideas)投票。
|
||||
- 提出并评论 [问题](https://github.com/hanzoai/cloud/issues)。
|
||||
- 提交 PR —— 详情请参见 [CONTRIBUTING.md](CONTRIBUTING.md),了解如何搭建开发环境。
|
||||
|
||||
## 🥇 许可证
|
||||
|
||||
除 `ee` 文件夹外,本仓库采用 MIT 许可证。详情请参见 [LICENSE](LICENSE) 以及 [文档](https://langfuse.com/docs/open-source)。
|
||||
除 `ee` 文件夹外,本仓库采用 MIT 许可证。详情请参见 [LICENSE](LICENSE) 以及 [文档](https://hanzo.ai/docs/open-source)。
|
||||
|
||||
## ⭐️ 星标历史
|
||||
|
||||
<a href="https://star-history.com/#langfuse/langfuse&Date">
|
||||
<a href="https://star-history.com/#hanzoai/cloud&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" />
|
||||
<img alt="星标历史图表" src="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" style="border-radius: 15px;" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" />
|
||||
<img alt="星标历史图表" src="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" style="border-radius: 15px;" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## ❤️ 使用 Langfuse 的开源项目
|
||||
## ❤️ 使用 Hanzo 的开源项目
|
||||
|
||||
以下是使用 Langfuse 的顶级开源 Python 项目,按星标数排名([来源](https://github.com/langfuse/langfuse-docs/blob/main/components-mdx/dependents)):
|
||||
以下是使用 Hanzo 的顶级开源 Python 项目,按星标数排名([来源](https://github.com/hanzoai/cloud-docs/blob/main/components-mdx/dependents)):
|
||||
|
||||
| 仓库 | 星数 |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----: |
|
||||
@@ -337,15 +337,15 @@ _[Langfuse 中的公共示例追踪](https://cloud.langfuse.com/project/cloramnk
|
||||
|
||||
## 🔒 安全与隐私
|
||||
|
||||
我们非常重视数据安全和隐私。更多信息请参阅我们的 [安全与隐私](https://langfuse.com/security) 页面。
|
||||
我们非常重视数据安全和隐私。更多信息请参阅我们的 [安全与隐私](https://hanzo.ai/security) 页面。
|
||||
|
||||
### 遥测
|
||||
|
||||
默认情况下,Langfuse 会自动将自托管实例的基础使用统计数据上传至集中服务器(PostHog)。
|
||||
默认情况下,Hanzo 会自动将自托管实例的基础使用统计数据上传至集中服务器(PostHog)。
|
||||
|
||||
这有助于我们:
|
||||
|
||||
1. 了解 Langfuse 的使用情况,并改进最关键的功能。
|
||||
1. 了解 Hanzo 的使用情况,并改进最关键的功能。
|
||||
2. 跟踪整体使用数据,以便内部及外部(例如筹款)报告。
|
||||
|
||||
所有数据均不会与第三方共享,也不包含任何敏感信息。我们对这一过程保持高度透明,你可以在 [此处](/web/src/features/telemetry/index.ts) 查看我们收集的具体数据。
|
||||
|
||||
+130
-130
@@ -1,34 +1,34 @@
|
||||

|
||||

|
||||
|
||||
<div align="center">
|
||||
<div>
|
||||
<h3>
|
||||
<a href="https://langfuse.com/jp">
|
||||
<a href="https://hanzo.ai/jp">
|
||||
<strong>🇯🇵 🤝 🪢</strong>
|
||||
</a> ·
|
||||
<a href="https://cloud.langfuse.com">
|
||||
<strong>Langfuse Cloud</strong>
|
||||
<a href="https://cloud.hanzo.ai">
|
||||
<strong>Hanzo Cloud</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/docs/deployment/self-host">
|
||||
<a href="https://hanzo.ai/docs/deployment/self-host">
|
||||
<strong>セルフホスティング</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/demo">
|
||||
<a href="https://hanzo.ai/demo">
|
||||
<strong>デモ</strong>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="https://langfuse.com/docs"><strong>ドキュメント</strong></a> ·
|
||||
<a href="https://langfuse.com/issues"><strong>バグ報告</strong></a> ·
|
||||
<a href="https://langfuse.com/ideas"><strong>機能リクエスト</strong></a> ·
|
||||
<a href="https://langfuse.com/changelog"><strong>変更履歴</strong></a> ·
|
||||
<a href="https://langfuse.com/roadmap"><strong>ロードマップ</strong></a> ·
|
||||
<a href="https://hanzo.ai/docs"><strong>ドキュメント</strong></a> ·
|
||||
<a href="https://hanzo.ai/issues"><strong>バグ報告</strong></a> ·
|
||||
<a href="https://hanzo.ai/ideas"><strong>機能リクエスト</strong></a> ·
|
||||
<a href="https://hanzo.ai/changelog"><strong>変更履歴</strong></a> ·
|
||||
<a href="https://hanzo.ai/roadmap"><strong>ロードマップ</strong></a> ·
|
||||
</div>
|
||||
<br/>
|
||||
<span>Langfuseは、サポートと機能リクエストのために <a href="https://github.com/orgs/langfuse/discussions"><strong>GitHub Discussions</strong></a> を利用しています。</span>
|
||||
<span>Hanzoは、サポートと機能リクエストのために <a href="https://github.com/orgs/hanzo/discussions"><strong>GitHub Discussions</strong></a> を利用しています。</span>
|
||||
<br/>
|
||||
<span><b>We're hiring.</b> <a href="https://langfuse.com/careers"><strong>チームに加わる</strong></a> (製品エンジニアリングおよびテクニカルGTMのポジション)への応募をお待ちしています。</span>
|
||||
<span><b>We're hiring.</b> <a href="https://hanzo.ai/careers"><strong>チームに加わる</strong></a> (製品エンジニアリングおよびテクニカルGTMのポジション)への応募をお待ちしています。</span>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
@@ -36,30 +36,30 @@
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/langfuse/langfuse/blob/main/LICENSE">
|
||||
<a href="https://github.com/hanzoai/cloud/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-MIT-E11311.svg" alt="MIT License">
|
||||
</a>
|
||||
<a href="https://www.ycombinator.com/companies/langfuse"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/langfuse" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/langfuse/langfuse?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/langfuse"><img src="https://img.shields.io/pypi/dm/langfuse?logo=python&logoColor=white&label=pypi%20langfuse&color=blue" alt="langfuse Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/langfuse"><img src="https://img.shields.io/npm/dm/langfuse?logo=npm&logoColor=white&label=npm%20langfuse&color=blue" alt="langfuse npm package"></a>
|
||||
<a href="https://www.ycombinator.com/companies/hanzo"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/hanzo" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/hanzoai/cloud?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/hanzo"><img src="https://img.shields.io/pypi/dm/hanzo?logo=python&logoColor=white&label=pypi%20hanzo&color=blue" alt="hanzo Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/hanzo"><img src="https://img.shields.io/npm/dm/hanzo?logo=npm&logoColor=white&label=npm%20hanzo&color=blue" alt="hanzo npm package"></a>
|
||||
<br/>
|
||||
<a href="https://discord.com/invite/7NXusRtqYU" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1111061815649124414?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=langfuse" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/langfuse?logo=X&color=%20%23f5f5f5"
|
||||
<a href="https://twitter.com/intent/follow?screen_name=hanzo" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/hanzo?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
<a href="https://www.linkedin.com/company/langfuse/" target="_blank">
|
||||
<a href="https://www.linkedin.com/company/hanzo/" target="_blank">
|
||||
<img src="https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff"
|
||||
alt="follow on LinkedIn"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/langfuse/langfuse?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Alangfuse%2Flangfuse%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/langfuse/langfuse?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/hanzoai/cloud?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Ahanzo%2Fhanzo%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/hanzoai/cloud?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -69,162 +69,162 @@
|
||||
<a href="./README.kr.md"><img alt="README in Korean" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||
</p>
|
||||
|
||||
Langfuseは**オープンソースのLLMエンジニアリング**プラットフォームです。
|
||||
Hanzoは**オープンソースのLLMエンジニアリング**プラットフォームです。
|
||||
チームが共同でAIアプリケーションを**開発、監視、評価**、および**デバッグ**するのを支援します。
|
||||
Langfuseは**数分でセルフホスト可能**で、**多くの実績を持つ**システムです。
|
||||
Hanzoは**数分でセルフホスト可能**で、**多くの実績を持つ**システムです。
|
||||
|
||||
[](https://langfuse.com/watch-demo)
|
||||
[](https://hanzo.ai/watch-demo)
|
||||
|
||||
## ✨ コア機能
|
||||
|
||||

|
||||

|
||||
|
||||
- **[LLMアプリケーションの可観測性](https://langfuse.com/docs/tracing):**
|
||||
アプリケーションにインストゥルメンテーションを導入し、Langfuseへトレースを取り込むことで、LLM呼び出しやリトリーバル、埋め込み、エージェントアクションなどの関連ロジックを追跡できます。
|
||||
- **[LLMアプリケーションの可観測性](https://hanzo.ai/docs/tracing):**
|
||||
アプリケーションにインストゥルメンテーションを導入し、Hanzoへトレースを取り込むことで、LLM呼び出しやリトリーバル、埋め込み、エージェントアクションなどの関連ロジックを追跡できます。
|
||||
複雑なログやユーザーセッションを解析・デバッグできます。
|
||||
インタラクティブな[デモ](https://langfuse.com/docs/demo)で動作を確認してください。
|
||||
インタラクティブな[デモ](https://hanzo.ai/docs/demo)で動作を確認してください。
|
||||
|
||||
- **[プロンプト管理](https://langfuse.com/docs/prompt-management/get-started):**
|
||||
- **[プロンプト管理](https://hanzo.com/docs/prompt-management/get-started):**
|
||||
プロンプトを一元管理し、バージョン管理しながら共同で改善を行えます。
|
||||
サーバーおよびクライアント側で強力なキャッシングを行うため、アプリケーションのレイテンシを増やすことなくプロンプトの改良が可能です。
|
||||
|
||||
- **[評価](https://langfuse.com/docs/evaluation/overview):**
|
||||
評価はLLMアプリケーション開発ワークフローの要であり、Langfuseは多様なニーズに対応します。
|
||||
- **[評価](https://hanzo.com/docs/evaluation/overview):**
|
||||
評価はLLMアプリケーション開発ワークフローの要であり、Hanzoは多様なニーズに対応します。
|
||||
LLMを判定者として用いる方法、ユーザーフィードバックの収集、手動によるラベリング、API/SDKを通じたカスタム評価パイプラインをサポートします。
|
||||
|
||||
- **[データセット](https://langfuse.com/docs/evaluation/dataset-runs/datasets):**
|
||||
- **[データセット](https://hanzo.com/docs/evaluation/dataset-runs/datasets):**
|
||||
LLMアプリケーション評価用のテストセットやベンチマークを構築できます。
|
||||
継続的な改善、事前デプロイテスト、構造化された実験、柔軟な評価、さらにLangChainやLlamaIndexなどとのシームレスな統合をサポートします。
|
||||
|
||||
- **[LLMプレイグラウンド](https://langfuse.com/docs/playground):**
|
||||
- **[LLMプレイグラウンド](https://hanzo.ai/docs/playground):**
|
||||
プロンプトやモデル設定のテスト・反復作業を支援するツールで、フィードバックループを短縮し開発を加速します。
|
||||
トレースで不具合が見つかった場合、直接プレイグラウンドへ飛び、迅速に改善できます。
|
||||
|
||||
- **[包括的なAPI](https://langfuse.com/docs/api):**
|
||||
LangfuseはAPIを通じて提供されるビルディングブロックを用い、カスタムLLMOpsワークフローの基盤として頻繁に利用されます。
|
||||
- **[包括的なAPI](https://hanzo.ai/docs/api):**
|
||||
HanzoはAPIを通じて提供されるビルディングブロックを用い、カスタムLLMOpsワークフローの基盤として頻繁に利用されます。
|
||||
OpenAPI仕様、Postmanコレクション、PythonやJS/TS向けの型付きSDKが利用可能です。
|
||||
|
||||
## 📦 Langfuseのデプロイ
|
||||
## 📦 Hanzoのデプロイ
|
||||
|
||||

|
||||

|
||||
|
||||
### Langfuse Cloud
|
||||
### Hanzo Cloud
|
||||
|
||||
Langfuseチームによるマネージドデプロイメント。充実した無料プラン(ホビープラン)で、クレジットカード不要です。
|
||||
Hanzoチームによるマネージドデプロイメント。充実した無料プラン(ホビープラン)で、クレジットカード不要です。
|
||||
|
||||
<div align="center">
|
||||
<a href="https://cloud.langfuse.com" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Langfuse%20Cloud-8A2BE2?&color=orange">
|
||||
<a href="https://cloud.hanzo.ai" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Hanzo%20Cloud-8A2BE2?&color=orange">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### セルフホスティング Langfuse
|
||||
### セルフホスティング Hanzo
|
||||
|
||||
自身のインフラ上でLangfuseを実行できます:
|
||||
自身のインフラ上でHanzoを実行できます:
|
||||
|
||||
- **[Local (docker compose)](https://langfuse.com/self-hosting/local):**
|
||||
Docker Composeを使用して、たった5分で自分のマシン上でLangfuseを実行できます.
|
||||
- **[Local (docker compose)](https://hanzo.ai/self-hosting/local):**
|
||||
Docker Composeを使用して、たった5分で自分のマシン上でHanzoを実行できます.
|
||||
|
||||
```bash
|
||||
# 最新のLangfuseリポジトリのコピーを取得
|
||||
git clone https://github.com/langfuse/langfuse.git
|
||||
cd langfuse
|
||||
# 最新のHanzoリポジトリのコピーを取得
|
||||
git clone https://github.com/hanzoai/cloud.git
|
||||
cd hanzo
|
||||
|
||||
# Langfuseのdocker composeを起動
|
||||
# Hanzoのdocker composeを起動
|
||||
docker compose up
|
||||
```
|
||||
|
||||
- **[Kubernetes (Helm)](https://langfuse.com/self-hosting/kubernetes-helm):**
|
||||
Helmを使用してKubernetesクラスター上でLangfuseを実行します。
|
||||
- **[Kubernetes (Helm)](https://hanzo.ai/self-hosting/kubernetes-helm):**
|
||||
Helmを使用してKubernetesクラスター上でHanzoを実行します。
|
||||
こちらが推奨される本番環境でのデプロイ方法です。
|
||||
|
||||
- **[VM](https://langfuse.com/self-hosting/docker-compose):**
|
||||
Docker Composeを使用して、単一の仮想マシン上でLangfuseを実行します。
|
||||
- **[VM](https://hanzo.ai/self-hosting/docker-compose):**
|
||||
Docker Composeを使用して、単一の仮想マシン上でHanzoを実行します。
|
||||
|
||||
- Terraform テンプレート: [AWS](https://langfuse.com/self-hosting/aws), [Azure](https://langfuse.com/self-hosting/azure), [GCP](https://langfuse.com/self-hosting/gcp)
|
||||
- Terraform テンプレート: [AWS](https://hanzo.com/self-hosting/aws), [Azure](https://hanzo.com/self-hosting/azure), [GCP](https://hanzo.com/self-hosting/gcp)
|
||||
|
||||
[セルフホスティングのドキュメント](https://langfuse.com/self-hosting)を参照し、アーキテクチャや設定オプションの詳細をご確認ください。
|
||||
[セルフホスティングのドキュメント](https://hanzo.ai/self-hosting)を参照し、アーキテクチャや設定オプションの詳細をご確認ください。
|
||||
|
||||
## 🔌 インテグレーション
|
||||
|
||||

|
||||

|
||||
|
||||
### 主なインテグレーション:
|
||||
|
||||
| インテグレーション | 対応言語・環境 | 説明 |
|
||||
| ---------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [SDK](https://langfuse.com/docs/sdk) | Python, JS/TS | SDKを利用して手動でインストゥルメンテーションを実装し、完全な柔軟性を提供します。 |
|
||||
| [OpenAI](https://langfuse.com/integrations/model-providers/openai-py) | Python, JS/TS | OpenAI SDKのドロップイン置換による自動インストゥルメンテーションを実現します。 |
|
||||
| [Langchain](https://langfuse.com/docs/integrations/langchain) | Python, JS/TS | Langchainアプリケーションにコールバックハンドラーを渡すことで自動的に計測します。 |
|
||||
| [LlamaIndex](https://langfuse.com/docs/integrations/llama-index/get-started) | Python | LlamaIndexのコールバックシステムを介して自動的にインストゥルメントします。 |
|
||||
| [Haystack](https://langfuse.com/docs/integrations/haystack) | Python | Haystackのコンテンツトレースシステムを利用した自動インストゥルメンテーションを実現します。 |
|
||||
| [LiteLLM](https://langfuse.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | GPTのドロップイン置換として任意のLLMを使用できます。Azure、OpenAI、Cohere、Anthropic、Ollama、VLLM、Sagemaker、HuggingFace、Replicate(100+ LLM)に対応。 |
|
||||
| [Vercel AI SDK](https://langfuse.com/docs/integrations/vercel-ai-sdk) | JS/TS | React、Next.js、Vue、Svelte、Node.jsを使用してAI搭載アプリケーションの構築を支援するTypeScriptツールキットです。 |
|
||||
| [API](https://langfuse.com/docs/api) | | 公開APIを直接呼び出すことが可能です。OpenAPI仕様も利用できます。 |
|
||||
| [SDK](https://hanzo.com/docs/sdk) | Python, JS/TS | SDKを利用して手動でインストゥルメンテーションを実装し、完全な柔軟性を提供します。 |
|
||||
| [OpenAI](https://hanzo.com/integrations/model-providers/openai-py) | Python, JS/TS | OpenAI SDKのドロップイン置換による自動インストゥルメンテーションを実現します。 |
|
||||
| [Langchain](https://hanzo.com/docs/integrations/langchain) | Python, JS/TS | Langchainアプリケーションにコールバックハンドラーを渡すことで自動的に計測します。 |
|
||||
| [LlamaIndex](https://hanzo.com/docs/integrations/llama-index/get-started) | Python | LlamaIndexのコールバックシステムを介して自動的にインストゥルメントします。 |
|
||||
| [Haystack](https://hanzo.com/docs/integrations/haystack) | Python | Haystackのコンテンツトレースシステムを利用した自動インストゥルメンテーションを実現します。 |
|
||||
| [LiteLLM](https://hanzo.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | GPTのドロップイン置換として任意のLLMを使用できます。Azure、OpenAI、Cohere、Anthropic、Ollama、VLLM、Sagemaker、HuggingFace、Replicate(100+ LLM)に対応。 |
|
||||
| [Vercel AI SDK](https://hanzo.com/docs/integrations/vercel-ai-sdk) | JS/TS | React、Next.js、Vue、Svelte、Node.jsを使用してAI搭載アプリケーションの構築を支援するTypeScriptツールキットです。 |
|
||||
| [API](https://hanzo.com/docs/api) | | 公開APIを直接呼び出すことが可能です。OpenAPI仕様も利用できます。 |
|
||||
|
||||
### Langfuseと統合されているパッケージ:
|
||||
### Hanzoと統合されているパッケージ:
|
||||
|
||||
| 名前 | タイプ | 説明 |
|
||||
| ------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| [Instructor](https://langfuse.com/docs/integrations/instructor) | ライブラリ | 構造化されたLLM出力(JSON、Pydantic)を取得するためのライブラリ |
|
||||
| [DSPy](https://langfuse.com/docs/integrations/dspy) | ライブラリ | LLMプロンプトや重み付けを体系的に最適化するためのフレームワーク |
|
||||
| [Mirascope](https://langfuse.com/docs/integrations/mirascope) | ライブラリ | LLMアプリケーション構築用のPythonツールキット |
|
||||
| [Ollama](https://langfuse.com/docs/integrations/ollama) | モデル(ローカル) | オープンソースLLMを手軽にローカルで実行するためのツール |
|
||||
| [Amazon Bedrock](https://langfuse.com/docs/integrations/amazon-bedrock) | モデル | AWS上でファウンデーションモデルやファインチューニング済みモデルを実行 |
|
||||
| [Google VertexAI and Gemini](https://langfuse.com/docs/integrations/google-vertex-ai) | モデル | Google上でファウンデーションモデルやファインチューニング済みモデルを実行 |
|
||||
| [AutoGen](https://langfuse.com/docs/integrations/autogen) | エージェントフレームワーク | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [Flowise](https://langfuse.com/docs/integrations/flowise) | チャット/エージェント UI | JS/TSのノーコードビルダーで、カスタマイズ可能なLLMフローを構築 |
|
||||
| [Langflow](https://langfuse.com/docs/integrations/langflow) | チャット/エージェント UI | PythonベースのUIで、react-flowを用いてLangChainの実験やプロトタイピングを容易に実現 |
|
||||
| [Dify](https://langfuse.com/docs/integrations/dify) | チャット/エージェント UI | ノーコードでLLMアプリ開発が可能なオープンソースプラットフォーム |
|
||||
| [OpenWebUI](https://langfuse.com/docs/integrations/openwebui) | チャット/エージェント UI | 自前ホストおよびローカルモデルに対応するLLMチャットWeb UI |
|
||||
| [Promptfoo](https://langfuse.com/docs/integrations/promptfoo) | ツール | オープンソースのLLMテストプラットフォーム |
|
||||
| [LobeChat](https://langfuse.com/docs/integrations/lobechat) | チャット/エージェント UI | オープンソースのチャットボットプラットフォーム |
|
||||
| [Vapi](https://langfuse.com/docs/integrations/vapi) | プラットフォーム | オープンソースの音声AIプラットフォーム |
|
||||
| [Inferable](https://langfuse.com/docs/integrations/other/inferable) | エージェント | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [Gradio](https://langfuse.com/docs/integrations/other/gradio) | チャット/エージェント UI | チャットUIなどのWebインターフェース構築のためのオープンソースPythonライブラリ |
|
||||
| [Goose](https://langfuse.com/docs/integrations/goose) | エージェント | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [smolagents](https://langfuse.com/docs/integrations/smolagents) | エージェント | オープンソースのAIエージェントフレームワーク |
|
||||
| [CrewAI](https://langfuse.com/docs/integrations/crewai) | エージェント | エージェントの協調とツール利用を実現するマルチエージェントフレームワーク |
|
||||
| [Instructor](https://hanzo.com/docs/integrations/instructor) | ライブラリ | 構造化されたLLM出力(JSON、Pydantic)を取得するためのライブラリ |
|
||||
| [DSPy](https://hanzo.com/docs/integrations/dspy) | ライブラリ | LLMプロンプトや重み付けを体系的に最適化するためのフレームワーク |
|
||||
| [Mirascope](https://hanzo.com/docs/integrations/mirascope) | ライブラリ | LLMアプリケーション構築用のPythonツールキット |
|
||||
| [Ollama](https://hanzo.com/docs/integrations/ollama) | モデル(ローカル) | オープンソースLLMを手軽にローカルで実行するためのツール |
|
||||
| [Amazon Bedrock](https://hanzo.com/docs/integrations/amazon-bedrock) | モデル | AWS上でファウンデーションモデルやファインチューニング済みモデルを実行 |
|
||||
| [Google VertexAI and Gemini](https://hanzo.com/docs/integrations/google-vertex-ai) | モデル | Google上でファウンデーションモデルやファインチューニング済みモデルを実行 |
|
||||
| [AutoGen](https://hanzo.com/docs/integrations/autogen) | エージェントフレームワーク | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [Flowise](https://hanzo.com/docs/integrations/flowise) | チャット/エージェント UI | JS/TSのノーコードビルダーで、カスタマイズ可能なLLMフローを構築 |
|
||||
| [Langflow](https://hanzo.com/docs/integrations/langflow) | チャット/エージェント UI | PythonベースのUIで、react-flowを用いてLangChainの実験やプロトタイピングを容易に実現 |
|
||||
| [Dify](https://hanzo.com/docs/integrations/dify) | チャット/エージェント UI | ノーコードでLLMアプリ開発が可能なオープンソースプラットフォーム |
|
||||
| [OpenWebUI](https://hanzo.com/docs/integrations/openwebui) | チャット/エージェント UI | 自前ホストおよびローカルモデルに対応するLLMチャットWeb UI |
|
||||
| [Promptfoo](https://hanzo.com/docs/integrations/promptfoo) | ツール | オープンソースのLLMテストプラットフォーム |
|
||||
| [LobeChat](https://hanzo.com/docs/integrations/lobechat) | チャット/エージェント UI | オープンソースのチャットボットプラットフォーム |
|
||||
| [Vapi](https://hanzo.com/docs/integrations/vapi) | プラットフォーム | オープンソースの音声AIプラットフォーム |
|
||||
| [Inferable](https://hanzo.com/docs/integrations/other/inferable) | エージェント | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [Gradio](https://hanzo.com/docs/integrations/other/gradio) | チャット/エージェント UI | チャットUIなどのWebインターフェース構築のためのオープンソースPythonライブラリ |
|
||||
| [Goose](https://hanzo.com/docs/integrations/goose) | エージェント | 分散型エージェント構築のためのオープンソースLLMプラットフォーム |
|
||||
| [smolagents](https://hanzo.com/docs/integrations/smolagents) | エージェント | オープンソースのAIエージェントフレームワーク |
|
||||
| [CrewAI](https://hanzo.com/docs/integrations/crewai) | エージェント | エージェントの協調とツール利用を実現するマルチエージェントフレームワーク |
|
||||
|
||||
## 🚀 クイックスタート
|
||||
|
||||
アプリケーションにインストゥルメンテーションを導入し、LLM呼び出しやリトリーバル、埋め込み、エージェントアクションなどの動作をLangfuseに記録しましょう。
|
||||
アプリケーションにインストゥルメンテーションを導入し、LLM呼び出しやリトリーバル、埋め込み、エージェントアクションなどの動作をHanzoに記録しましょう。
|
||||
複雑なログやユーザーセッションの解析・デバッグが可能になります。
|
||||
|
||||
### 1️⃣ 新規プロジェクトの作成
|
||||
|
||||
1. [Langfuseアカウント作成](https://cloud.langfuse.com/auth/sign-up) または [セルフホスト](https://langfuse.com/self-hosting)
|
||||
1. [Hanzoアカウント作成](https://cloud.hanzo.ai/auth/sign-up) または [セルフホスト](https://hanzo.ai/self-hosting)
|
||||
2. 新規プロジェクトを作成
|
||||
3. プロジェクト設定で新しいAPIクレデンシャルを作成
|
||||
|
||||
### 2️⃣ 初めてのLLM呼び出しのログ記録
|
||||
|
||||
[`@observe()` デコレーター](https://langfuse.com/docs/sdk/python/decorators)を利用することで、任意のPython製LLMアプリケーションのトレースが簡単に行えます。
|
||||
このクイックスタートでは、Langfuseの[OpenAI統合](https://langfuse.com/integrations/model-providers/openai-py)を使用して、全てのモデルパラメータを自動で取得します。
|
||||
[`@observe()` デコレーター](https://hanzo.com/docs/sdk/python/decorators)を利用することで、任意のPython製LLMアプリケーションのトレースが簡単に行えます。
|
||||
このクイックスタートでは、Hanzoの[OpenAI統合](https://hanzo.com/integrations/model-providers/openai-py)を使用して、全てのモデルパラメータを自動で取得します。
|
||||
|
||||
> [!TIP]
|
||||
> OpenAIを利用していない場合は、[こちらのドキュメント](https://langfuse.com/docs/get-started#log-your-first-llm-call-to-langfuse)で、他のモデルやフレームワークのログ記録方法をご確認ください。
|
||||
> OpenAIを利用していない場合は、[こちらのドキュメント](https://hanzo.ai/docs/get-started#log-your-first-llm-call-to-hanzo)で、他のモデルやフレームワークのログ記録方法をご確認ください。
|
||||
|
||||
```bash
|
||||
pip install langfuse openai
|
||||
pip install hanzo openai
|
||||
```
|
||||
|
||||
```bash filename=".env"
|
||||
LANGFUSE_SECRET_KEY="sk-lf-..."
|
||||
LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
||||
LANGFUSE_BASE_URL="https://cloud.langfuse.com" # 🇪🇺 EUリージョン
|
||||
# LANGFUSE_BASE_URL="https://us.cloud.langfuse.com" # 🇺🇸 USリージョン
|
||||
HANZO_SECRET_KEY="sk-lf-..."
|
||||
HANZO_PUBLIC_KEY="pk-lf-..."
|
||||
HANZO_BASE_URL="https://cloud.hanzo.com" # 🇪🇺 EUリージョン
|
||||
# HANZO_BASE_URL="https://us.cloud.hanzo.com" # 🇺🇸 USリージョン
|
||||
```
|
||||
|
||||
```python:/@observe()/ /from langfuse.openai import openai/ filename="main.py"
|
||||
from langfuse import observe
|
||||
from langfuse.openai import openai # OpenAI統合
|
||||
```python:/@observe()/ /from hanzo.openai import openai/ filename="main.py"
|
||||
from hanzo import observe
|
||||
from hanzo.openai import openai # OpenAI統合
|
||||
|
||||
@observe()
|
||||
def story():
|
||||
return openai.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": "What is Langfuse?"}],
|
||||
messages=[{"role": "user", "content": "What is Hanzo?"}],
|
||||
).choices[0].message.content
|
||||
|
||||
@observe()
|
||||
@@ -234,65 +234,65 @@ def main():
|
||||
main()
|
||||
```
|
||||
|
||||
### 3️⃣ Langfuseでトレースを確認する
|
||||
### 3️⃣ Hanzoでトレースを確認する
|
||||
|
||||
Langfuse上で、LLM呼び出しおよびその他のアプリケーションロジックのトレースを確認できます。
|
||||
Hanzo上で、LLM呼び出しおよびその他のアプリケーションロジックのトレースを確認できます。
|
||||
|
||||

|
||||

|
||||
|
||||
_[Langfuseの公開トレース例](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
_[Hanzoの公開トレース例](https://cloud.hanzo.ai/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Langfuseでのトレースの詳細については、[こちら](https://langfuse.com/docs/tracing)をご参照いただくか、[インタラクティブデモ](https://langfuse.com/docs/demo)でお試しください。
|
||||
> Hanzoでのトレースの詳細については、[こちら](https://hanzo.ai/docs/tracing)をご参照いただくか、[インタラクティブデモ](https://hanzo.ai/docs/demo)でお試しください。
|
||||
|
||||
## ⭐️ Star Langfuse
|
||||
## ⭐️ Star Hanzo
|
||||
|
||||

|
||||

|
||||
|
||||
## 💭 サポート
|
||||
|
||||
質問の回答をお探しの場合は:
|
||||
|
||||
- 当社の[ドキュメント](https://langfuse.com/docs)は、回答を探すための最良の出発点です。内容が充実しており、継続的なメンテナンスに努めています。GitHubを通じてドキュメントへの修正提案も可能です。
|
||||
- よくある質問は[Langfuse FAQ](https://langfuse.com/faq)にまとめられています。
|
||||
- [Ask AI](https://langfuse.com/docs/ask-ai)を利用すれば、質問に対して即座に回答を得ることができます。
|
||||
- 当社の[ドキュメント](https://hanzo.ai/docs)は、回答を探すための最良の出発点です。内容が充実しており、継続的なメンテナンスに努めています。GitHubを通じてドキュメントへの修正提案も可能です。
|
||||
- よくある質問は[Hanzo FAQ](https://hanzo.ai/faq)にまとめられています。
|
||||
- [Ask AI](https://hanzo.ai/docs/ask-ai)を利用すれば、質問に対して即座に回答を得ることができます。
|
||||
- 日本語のサポートや決済, 請求書払いなどをお求めの場合は、日本のリセラー (https://gao-ai.com) にご相談ください。
|
||||
|
||||
サポートチャネル:
|
||||
|
||||
- **GitHub Discussionsの[パブリックQ&A](https://github.com/orgs/langfuse/discussions/categories/support)で質問してください。**
|
||||
- **GitHub Discussionsの[パブリックQ&A](https://github.com/orgs/hanzoai/discussions/categories/support)で質問してください。**
|
||||
質問には、コードスニペット、スクリーンショット、背景情報など、できるだけ詳細な情報を含めるとスムーズな対応が可能です。
|
||||
- GitHub Discussionsで[機能リクエスト](https://github.com/orgs/langfuse/discussions/categories/ideas)を投稿してください。
|
||||
- GitHub Issuesにて[バグ報告](https://github.com/langfuse/langfuse/issues)を行ってください。
|
||||
- GitHub Discussionsで[機能リクエスト](https://github.com/orgs/hanzoai/discussions/categories/ideas)を投稿してください。
|
||||
- GitHub Issuesにて[バグ報告](https://github.com/hanzoai/cloud/issues)を行ってください。
|
||||
- 緊急の問い合わせの場合は、アプリ内チャットウィジェットでご連絡ください。
|
||||
|
||||
## 🤝 貢献
|
||||
|
||||
皆様からの貢献を歓迎します!
|
||||
|
||||
- GitHub Discussionsの[アイデア](https://github.com/orgs/langfuse/discussions/categories/ideas)に投票してください。
|
||||
- [Issues](https://github.com/langfuse/langfuse/issues)を作成・コメントしてください。
|
||||
- GitHub Discussionsの[アイデア](https://github.com/orgs/hanzoai/discussions/categories/ideas)に投票してください。
|
||||
- [Issues](https://github.com/hanzoai/cloud/issues)を作成・コメントしてください。
|
||||
- プルリクエストを送信してください。開発環境のセットアップ方法については[CONTRIBUTING.md](CONTRIBUTING.md)をご参照ください。
|
||||
|
||||
## 🥇 ライセンス
|
||||
|
||||
このリポジトリは、`ee`フォルダを除き、MITライセンスの下で公開されています。
|
||||
詳細は[LICENSE](LICENSE)および[オープンソースに関するドキュメント](https://langfuse.com/docs/open-source)をご確認ください。
|
||||
詳細は[LICENSE](LICENSE)および[オープンソースに関するドキュメント](https://hanzo.ai/docs/open-source)をご確認ください。
|
||||
|
||||
## ⭐️ スターの履歴
|
||||
|
||||
<a href="https://star-history.com/#langfuse/langfuse&Date">
|
||||
<a href="https://star-history.com/#hanzoai/cloud&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" style="border-radius: 15px;" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" style="border-radius: 15px;" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## ❤️ Langfuseを利用しているオープンソースプロジェクト
|
||||
## ❤️ Hanzoを利用しているオープンソースプロジェクト
|
||||
|
||||
Langfuseを利用している主要なオープンソースPythonプロジェクト(スター数順): ([出典](https://github.com/langfuse/langfuse-docs/blob/main/components-mdx/dependents))
|
||||
Hanzoを利用している主要なオープンソースPythonプロジェクト(スター数順): ([出典](https://github.com/hanzoai/cloud-docs/blob/main/components-mdx/dependents))
|
||||
|
||||
| リポジトリ | スター |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -----: |
|
||||
@@ -344,13 +344,13 @@ Langfuseを利用している主要なオープンソースPythonプロジェク
|
||||
## 🔒 セキュリティとプライバシー
|
||||
|
||||
データのセキュリティとプライバシーは非常に重要です。
|
||||
詳細につきましては、[セキュリティとプライバシー](https://langfuse.com/security)ページをご参照ください。
|
||||
詳細につきましては、[セキュリティとプライバシー](https://hanzo.ai/security)ページをご参照ください。
|
||||
|
||||
### テレメトリー
|
||||
|
||||
デフォルトでは、Langfuseは以下の目的でセルフホストされたインスタンスの基本的な使用統計情報を中央サーバ(PostHog)へ自動的に報告します。
|
||||
デフォルトでは、Hanzoは以下の目的でセルフホストされたインスタンスの基本的な使用統計情報を中央サーバ(PostHog)へ自動的に報告します。
|
||||
|
||||
1. Langfuseの利用状況を把握し、最も重要な機能の改善に役立てる
|
||||
1. Hanzoの利用状況を把握し、最も重要な機能の改善に役立てる
|
||||
2. 内部および外部(例:資金調達)のレポートのために全体の利用状況を追跡する
|
||||
|
||||
収集されたデータは第三者と共有されず、機微な情報は一切含まれていません。
|
||||
|
||||
+116
-116
@@ -1,34 +1,34 @@
|
||||

|
||||

|
||||
|
||||
<div align="center">
|
||||
<div>
|
||||
<h3>
|
||||
<a href="https://langfuse.com/kr">
|
||||
<a href="https://hanzo.ai/kr">
|
||||
<strong>🇰🇷 🤝 🪢</strong>
|
||||
</a> ·
|
||||
<a href="https://cloud.langfuse.com">
|
||||
<strong>Langfuse Cloud</strong>
|
||||
<a href="https://cloud.hanzo.ai">
|
||||
<strong>Hanzo Cloud</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/docs/deployment/self-host">
|
||||
<a href="https://hanzo.ai/docs/deployment/self-host">
|
||||
<strong>셀프 호스트</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/demo">
|
||||
<a href="https://hanzo.ai/demo">
|
||||
<strong>데모</strong>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="https://langfuse.com/docs"><strong>문서</strong></a> ·
|
||||
<a href="https://langfuse.com/issues"><strong>버그 신고</strong></a> ·
|
||||
<a href="https://langfuse.com/ideas"><strong>기능 요청</strong></a> ·
|
||||
<a href="https://langfuse.com/changelog"><strong>변경 내역</strong></a> ·
|
||||
<a href="https://langfuse.com/roadmap"><strong>로드맵</strong></a> ·
|
||||
<a href="https://hanzo.ai/docs"><strong>문서</strong></a> ·
|
||||
<a href="https://hanzo.ai/issues"><strong>버그 신고</strong></a> ·
|
||||
<a href="https://hanzo.ai/ideas"><strong>기능 요청</strong></a> ·
|
||||
<a href="https://hanzo.ai/changelog"><strong>변경 내역</strong></a> ·
|
||||
<a href="https://hanzo.ai/roadmap"><strong>로드맵</strong></a> ·
|
||||
</div>
|
||||
<br/>
|
||||
<span>Langfuse는 지원 및 기능 요청을 위해 <a href="https://github.com/orgs/langfuse/discussions"><strong>GitHub Discussions</strong></a>를 사용합니다.</span>
|
||||
<span>Hanzo는 지원 및 기능 요청을 위해 <a href="https://github.com/orgs/hanzoai/discussions"><strong>GitHub Discussions</strong></a>를 사용합니다.</span>
|
||||
<br/>
|
||||
<span><b>채용 중입니다.</b> <a href="https://langfuse.com/careers"><strong>함께 하세요</strong></a> – 제품 엔지니어링 및 기술 go-to-market 역할의 인재를 찾고 있습니다.</span>
|
||||
<span><b>채용 중입니다.</b> <a href="https://hanzo.ai/careers"><strong>함께 하세요</strong></a> – 제품 엔지니어링 및 기술 go-to-market 역할의 인재를 찾고 있습니다.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
@@ -36,30 +36,30 @@
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/langfuse/langfuse/blob/main/LICENSE">
|
||||
<a href="https://github.com/hanzoai/cloud/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-MIT-E11311.svg" alt="MIT License">
|
||||
</a>
|
||||
<a href="https://www.ycombinator.com/companies/langfuse"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/langfuse" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/langfuse/langfuse?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/langfuse"><img src="https://img.shields.io/pypi/dm/langfuse?logo=python&logoColor=white&label=pypi%20langfuse&color=blue" alt="langfuse Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/langfuse"><img src="https://img.shields.io/npm/dm/langfuse?logo=npm&logoColor=white&label=npm%20langfuse&color=blue" alt="langfuse npm package"></a>
|
||||
<a href="https://www.ycombinator.com/companies/hanzo"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/hanzo" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/hanzoai/cloud?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/hanzo"><img src="https://img.shields.io/pypi/dm/hanzo?logo=python&logoColor=white&label=pypi%20hanzo&color=blue" alt="hanzo Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/hanzo"><img src="https://img.shields.io/npm/dm/hanzo?logo=npm&logoColor=white&label=npm%20hanzo&color=blue" alt="hanzo npm package"></a>
|
||||
<br/>
|
||||
<a href="https://discord.com/invite/7NXusRtqYU" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1111061815649124414?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=langfuse" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/langfuse?logo=X&color=%20%23f5f5f5"
|
||||
<a href="https://twitter.com/intent/follow?screen_name=hanzo" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/hanzo?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
<a href="https://www.linkedin.com/company/langfuse/" target="_blank">
|
||||
<a href="https://www.linkedin.com/company/hanzo/" target="_blank">
|
||||
<img src="https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff"
|
||||
alt="follow on LinkedIn"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/langfuse/langfuse?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Alangfuse%2Flangfuse%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/langfuse/langfuse?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/hanzoai/cloud?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Ahanzo%2Fhanzo%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/hanzoai/cloud/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/hanzoai/cloud?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -69,24 +69,24 @@
|
||||
<a href="./README.kr.md"><img alt="README in Korean" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||
</p>
|
||||
|
||||
Langfuse는 **오픈 소스 LLM 엔지니어링** 플랫폼입니다.
|
||||
Hanzo는 **오픈 소스 LLM 엔지니어링** 플랫폼입니다.
|
||||
팀이 협업하여 AI 애플리케이션을 **개발, 모니터링, 평가** 및 **디버그**할 수 있도록 도와줍니다.
|
||||
Langfuse는 몇 분 안에 셀프 호스팅할 수 있으며, 검증된(battle-tested) 솔루션입니다.
|
||||
Hanzo는 몇 분 안에 셀프 호스팅할 수 있으며, 검증된(battle-tested) 솔루션입니다.
|
||||
|
||||
[](https://langfuse.com/watch-demo)
|
||||
[](https://hanzo.ai/watch-demo)
|
||||
|
||||
## ✨ 주요 기능
|
||||
|
||||

|
||||

|
||||
|
||||
- **LLM 애플리케이션 관측**
|
||||
앱에 계측(instrumentation)을 추가하여 Langfuse로 trace 데이터를 수집함으로써, 검색, 임베딩, 또는 에이전트 동작과 같은 LLM 호출 및 기타 관련 로직을 추적할 수 있습니다. 복잡한 로그와 사용자 세션을 확인 및 디버깅 해보세요. 인터랙티브 데모를 통해 실제 작동 예를 확인할 수 있습니다.
|
||||
앱에 계측(instrumentation)을 추가하여 Hanzo로 trace 데이터를 수집함으로써, 검색, 임베딩, 또는 에이전트 동작과 같은 LLM 호출 및 기타 관련 로직을 추적할 수 있습니다. 복잡한 로그와 사용자 세션을 확인 및 디버깅 해보세요. 인터랙티브 데모를 통해 실제 작동 예를 확인할 수 있습니다.
|
||||
|
||||
- **프롬프트 관리**
|
||||
프롬프트를 중앙에서 관리하고 버전 관리하며 협업으로 수정할 수 있도록 도와줍니다. 서버와 클라이언트 측의 강력한 캐싱 덕분에 애플리케이션에 지연(latency)을 추가하지 않고도 프롬프트를 반복 개선할 수 있습니다.
|
||||
|
||||
- **평가**
|
||||
LLM 애플리케이션 개발 워크플로우에서 핵심적인 역할을 하며, Langfuse는 여러분의 필요에 맞게 유연하게 대응합니다. LLM을 심사자로 활용하는 기능, 사용자 피드백 수집, 수동 라벨링 및 API/SDK를 통한 맞춤 평가 파이프라인을 지원합니다.
|
||||
LLM 애플리케이션 개발 워크플로우에서 핵심적인 역할을 하며, Hanzo는 여러분의 필요에 맞게 유연하게 대응합니다. LLM을 심사자로 활용하는 기능, 사용자 피드백 수집, 수동 라벨링 및 API/SDK를 통한 맞춤 평가 파이프라인을 지원합니다.
|
||||
|
||||
- **데이터셋**
|
||||
LLM 애플리케이션 평가를 위한 테스트 세트와 벤치마크를 제공하여, 지속적인 개선, 배포 전 테스트, 구조화된 실험, 유연한 평가 및 LangChain과 LlamaIndex와 같은 프레임워크와의 원활한 통합을 지원합니다.
|
||||
@@ -95,121 +95,121 @@ Langfuse는 몇 분 안에 셀프 호스팅할 수 있으며, 검증된(battle-t
|
||||
프롬프트와 모델 구성에 대해 테스트 및 반복 개선할 수 있는 도구로, 피드백 루프를 단축하여 개발 속도를 높여줍니다. trace에서 이상한 결과가 발생하면 플레이그라운드로 바로 이동해 개선할 수 있습니다.
|
||||
|
||||
- **종합 API**
|
||||
Langfuse는 API를 통해 제공되는 구성 요소들을 활용하여 맞춤형 LLMOps 워크플로우를 강화하는 데 자주 사용됩니다. OpenAPI 명세, Postman 컬렉션, Python 및 JS/TS용 타입드 SDK가 제공됩니다.
|
||||
Hanzo는 API를 통해 제공되는 구성 요소들을 활용하여 맞춤형 LLMOps 워크플로우를 강화하는 데 자주 사용됩니다. OpenAPI 명세, Postman 컬렉션, Python 및 JS/TS용 타입드 SDK가 제공됩니다.
|
||||
|
||||
## 📦 Langfuse 배포
|
||||
## 📦 Hanzo 배포
|
||||
|
||||

|
||||

|
||||
|
||||
### Langfuse Cloud
|
||||
### Hanzo Cloud
|
||||
|
||||
Langfuse 팀이 관리하는 배포 방식으로, 후한 무료 플랜(취미 플랜)을 제공하며 신용카드가 필요하지 않습니다.
|
||||
Hanzo 팀이 관리하는 배포 방식으로, 후한 무료 플랜(취미 플랜)을 제공하며 신용카드가 필요하지 않습니다.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://cloud.langfuse.com" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Langfuse%20Cloud-8A2BE2?&color=orange">
|
||||
<a href="https://cloud.hanzo.ai" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Hanzo%20Cloud-8A2BE2?&color=orange">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Langfuse 셀프 호스트
|
||||
### Hanzo 셀프 호스트
|
||||
|
||||
자체 인프라에서 Langfuse를 실행하세요:
|
||||
자체 인프라에서 Hanzo를 실행하세요:
|
||||
|
||||
- [로컬 (docker compose)](https://langfuse.com/self-hosting/local): Docker Compose를 사용하여 본인의 컴퓨터에서 5분 안에 Langfuse를 실행할 수 있습니다.
|
||||
- [로컬 (docker compose)](https://hanzo.ai/self-hosting/local): Docker Compose를 사용하여 본인의 컴퓨터에서 5분 안에 Hanzo를 실행할 수 있습니다.
|
||||
|
||||
```bash
|
||||
# 최신 Langfuse 저장소 클론
|
||||
git clone https://github.com/langfuse/langfuse.git
|
||||
cd langfuse
|
||||
# 최신 Hanzo 저장소 클론
|
||||
git clone https://github.com/hanzoai/cloud.git
|
||||
cd hanzo
|
||||
|
||||
# langfuse docker compose 실행
|
||||
# hanzo docker compose 실행
|
||||
docker compose up
|
||||
```
|
||||
|
||||
- [Kubernetes (Helm)](https://langfuse.com/self-hosting/kubernetes-helm): Helm을 사용해 Kubernetes 클러스터에서 Langfuse를 실행합니다. 이는 권장되는 프로덕션 배포 방식입니다.
|
||||
- [VM](https://langfuse.com/self-hosting/docker-compose): Docker Compose를 사용해 단일 가상 머신에서 Langfuse를 실행합니다.
|
||||
- Terraform 템플릿: [AWS](https://langfuse.com/self-hosting/aws), [Azure](https://langfuse.com/self-hosting/azure), [GCP](https://langfuse.com/self-hosting/gcp)
|
||||
- [Kubernetes (Helm)](https://hanzo.com/self-hosting/kubernetes-helm): Helm을 사용해 Kubernetes 클러스터에서 Hanzo를 실행합니다. 이는 권장되는 프로덕션 배포 방식입니다.
|
||||
- [VM](https://hanzo.com/self-hosting/docker-compose): Docker Compose를 사용해 단일 가상 머신에서 Hanzo를 실행합니다.
|
||||
- Terraform 템플릿: [AWS](https://hanzo.com/self-hosting/aws), [Azure](https://hanzo.com/self-hosting/azure), [GCP](https://hanzo.com/self-hosting/gcp)
|
||||
|
||||
자세한 내용은 [자체 호스팅 문서](https://langfuse.com/self-hosting)를 참조하세요.
|
||||
자세한 내용은 [자체 호스팅 문서](https://hanzo.ai/self-hosting)를 참조하세요.
|
||||
|
||||
## 🔌 통합 기능
|
||||
|
||||

|
||||

|
||||
|
||||
### 주요 통합:
|
||||
|
||||
| 통합 | 지원 | 설명 |
|
||||
| ---------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [SDK](https://langfuse.com/docs/sdk) | Python, JS/TS | SDK를 사용하여 완전한 유연성을 갖춘 수동 계측(manual instrumentation)을 수행합니다. |
|
||||
| [OpenAI](https://langfuse.com/integrations/model-providers/openai-py) | Python, JS/TS | OpenAI SDK의 드롭인 대체(drop-in replacement)를 통해 자동 계측(automated instrumentation)을 수행합니다. |
|
||||
| [Langchain](https://langfuse.com/docs/integrations/langchain) | Python, JS/TS | Langchain 애플리케이션에 callback 핸들러를 전달하여 자동 계측합니다. |
|
||||
| [LlamaIndex](https://langfuse.com/docs/integrations/llama-index/get-started) | Python | LlamaIndex 콜백 시스템을 통한 자동 계측을 지원합니다. |
|
||||
| [Haystack](https://langfuse.com/docs/integrations/haystack) | Python | Haystack 콘텐츠 추적 시스템을 통한 자동 계측을 지원합니다. |
|
||||
| [LiteLLM](https://langfuse.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | GPT의 드롭인 대체품으로 어떤 LLM도 사용할 수 있습니다. Azure, OpenAI, Cohere, Anthropic, Ollama, VLLM, Sagemaker, HuggingFace, Replicate 등 100개 이상의 LLM 지원. |
|
||||
| [Vercel AI SDK](https://langfuse.com/docs/integrations/vercel-ai-sdk) | JS/TS | React, Next.js, Vue, Svelte, Node.js와 함께 AI 기반 애플리케이션 구축을 돕는 TypeScript 툴킷입니다. |
|
||||
| [API](https://langfuse.com/docs/api) | | 공개 API를 직접 호출합니다. OpenAPI 명세가 제공됩니다. |
|
||||
| [SDK](https://hanzo.com/docs/sdk) | Python, JS/TS | SDK를 사용하여 완전한 유연성을 갖춘 수동 계측(manual instrumentation)을 수행합니다. |
|
||||
| [OpenAI](https://hanzo.com/integrations/model-providers/openai-py) | Python, JS/TS | OpenAI SDK의 드롭인 대체(drop-in replacement)를 통해 자동 계측(automated instrumentation)을 수행합니다. |
|
||||
| [Langchain](https://hanzo.com/docs/integrations/langchain) | Python, JS/TS | Langchain 애플리케이션에 callback 핸들러를 전달하여 자동 계측합니다. |
|
||||
| [LlamaIndex](https://hanzo.com/docs/integrations/llama-index/get-started) | Python | LlamaIndex 콜백 시스템을 통한 자동 계측을 지원합니다. |
|
||||
| [Haystack](https://hanzo.com/docs/integrations/haystack) | Python | Haystack 콘텐츠 추적 시스템을 통한 자동 계측을 지원합니다. |
|
||||
| [LiteLLM](https://hanzo.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | GPT의 드롭인 대체품으로 어떤 LLM도 사용할 수 있습니다. Azure, OpenAI, Cohere, Anthropic, Ollama, VLLM, Sagemaker, HuggingFace, Replicate 등 100개 이상의 LLM 지원. |
|
||||
| [Vercel AI SDK](https://hanzo.com/docs/integrations/vercel-ai-sdk) | JS/TS | React, Next.js, Vue, Svelte, Node.js와 함께 AI 기반 애플리케이션 구축을 돕는 TypeScript 툴킷입니다. |
|
||||
| [API](https://hanzo.com/docs/api) | | 공개 API를 직접 호출합니다. OpenAPI 명세가 제공됩니다. |
|
||||
|
||||
### Langfuse와 통합된 패키지:
|
||||
### Hanzo와 통합된 패키지:
|
||||
|
||||
| 이름 | 유형 | 설명 |
|
||||
| ------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| [Instructor](https://langfuse.com/docs/integrations/instructor) | 라이브러리 | 구조화된 LLM 출력을(JSON, Pydantic) 얻기 위한 라이브러리입니다. |
|
||||
| [DSPy](https://langfuse.com/docs/integrations/dspy) | 라이브러리 | 언어 모델 프롬프트와 가중치를 체계적으로 최적화하는 프레임워크입니다. |
|
||||
| [Mirascope](https://langfuse.com/docs/integrations/mirascope) | 라이브러리 | LLM 애플리케이션 구축을 위한 Python 툴킷입니다. |
|
||||
| [Ollama](https://langfuse.com/docs/integrations/ollama) | 모델 (로컬) | 자신의 컴퓨터에서 오픈 소스 LLM을 손쉽게 실행할 수 있습니다. |
|
||||
| [Amazon Bedrock](https://langfuse.com/docs/integrations/amazon-bedrock) | 모델 | AWS에서 기본 및 파인튜닝된 모델을 실행합니다. |
|
||||
| [Google VertexAI and Gemini](https://langfuse.com/docs/integrations/google-vertex-ai) | 모델 | Google에서 기본 및 파인튜닝된 모델을 실행합니다. |
|
||||
| [AutoGen](https://langfuse.com/docs/integrations/autogen) | 에이전트 프레임워크 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [Flowise](https://langfuse.com/docs/integrations/flowise) | 채팅/에이전트 UI | 맞춤형 LLM 플로우를 위한 JS/TS 코드 없는(no-code) 빌더입니다. |
|
||||
| [Langflow](https://langfuse.com/docs/integrations/langflow) | 채팅/에이전트 UI | react-flow를 활용하여 실험 및 프로토타이핑을 손쉽게 할 수 있도록 디자인된 LangChain용 Python 기반 UI입니다. |
|
||||
| [Dify](https://langfuse.com/docs/integrations/dify) | 채팅/에이전트 UI | 코드 없는 빌더와 함께 제공되는 오픈 소스 LLM 애플리케이션 개발 플랫폼입니다. |
|
||||
| [OpenWebUI](https://langfuse.com/docs/integrations/openwebui) | 채팅/에이전트 UI | 셀프 호스팅 및 로컬 모델 등 다양한 LLM 실행기를 지원하는 셀프 호스팅 LLM 채팅 웹 UI입니다. |
|
||||
| [Promptfoo](https://langfuse.com/docs/integrations/promptfoo) | 도구 | 오픈 소스 LLM 테스트 플랫폼입니다. |
|
||||
| [LobeChat](https://langfuse.com/docs/integrations/lobechat) | 채팅/에이전트 UI | 오픈 소스 챗봇 플랫폼입니다. |
|
||||
| [Vapi](https://langfuse.com/docs/integrations/vapi) | 플랫폼 | 오픈 소스 음성 AI 플랫폼입니다. |
|
||||
| [Inferable](https://langfuse.com/docs/integrations/other/inferable) | 에이전트 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [Gradio](https://langfuse.com/docs/integrations/other/gradio) | 채팅/에이전트 UI | 채팅 UI와 같은 웹 인터페이스 구축을 위한 오픈 소스 Python 라이브러리입니다. |
|
||||
| [Goose](https://langfuse.com/docs/integrations/goose) | 에이전트 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [smolagents](https://langfuse.com/docs/integrations/smolagents) | 에이전트 | 오픈 소스 AI 에이전트 프레임워크입니다. |
|
||||
| [CrewAI](https://langfuse.com/docs/integrations/crewai) | 에이전트 | 에이전트 간 협업 및 도구 사용을 위한 다중 에이전트 프레임워크입니다. |
|
||||
| [Instructor](https://hanzo.com/docs/integrations/instructor) | 라이브러리 | 구조화된 LLM 출력을(JSON, Pydantic) 얻기 위한 라이브러리입니다. |
|
||||
| [DSPy](https://hanzo.com/docs/integrations/dspy) | 라이브러리 | 언어 모델 프롬프트와 가중치를 체계적으로 최적화하는 프레임워크입니다. |
|
||||
| [Mirascope](https://hanzo.com/docs/integrations/mirascope) | 라이브러리 | LLM 애플리케이션 구축을 위한 Python 툴킷입니다. |
|
||||
| [Ollama](https://hanzo.com/docs/integrations/ollama) | 모델 (로컬) | 자신의 컴퓨터에서 오픈 소스 LLM을 손쉽게 실행할 수 있습니다. |
|
||||
| [Amazon Bedrock](https://hanzo.com/docs/integrations/amazon-bedrock) | 모델 | AWS에서 기본 및 파인튜닝된 모델을 실행합니다. |
|
||||
| [Google VertexAI and Gemini](https://hanzo.com/docs/integrations/google-vertex-ai) | 모델 | Google에서 기본 및 파인튜닝된 모델을 실행합니다. |
|
||||
| [AutoGen](https://hanzo.com/docs/integrations/autogen) | 에이전트 프레임워크 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [Flowise](https://hanzo.com/docs/integrations/flowise) | 채팅/에이전트 UI | 맞춤형 LLM 플로우를 위한 JS/TS 코드 없는(no-code) 빌더입니다. |
|
||||
| [Langflow](https://hanzo.com/docs/integrations/langflow) | 채팅/에이전트 UI | react-flow를 활용하여 실험 및 프로토타이핑을 손쉽게 할 수 있도록 디자인된 LangChain용 Python 기반 UI입니다. |
|
||||
| [Dify](https://hanzo.com/docs/integrations/dify) | 채팅/에이전트 UI | 코드 없는 빌더와 함께 제공되는 오픈 소스 LLM 애플리케이션 개발 플랫폼입니다. |
|
||||
| [OpenWebUI](https://hanzo.com/docs/integrations/openwebui) | 채팅/에이전트 UI | 셀프 호스팅 및 로컬 모델 등 다양한 LLM 실행기를 지원하는 셀프 호스팅 LLM 채팅 웹 UI입니다. |
|
||||
| [Promptfoo](https://hanzo.com/docs/integrations/promptfoo) | 도구 | 오픈 소스 LLM 테스트 플랫폼입니다. |
|
||||
| [LobeChat](https://hanzo.com/docs/integrations/lobechat) | 채팅/에이전트 UI | 오픈 소스 챗봇 플랫폼입니다. |
|
||||
| [Vapi](https://hanzo.com/docs/integrations/vapi) | 플랫폼 | 오픈 소스 음성 AI 플랫폼입니다. |
|
||||
| [Inferable](https://hanzo.com/docs/integrations/other/inferable) | 에이전트 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [Gradio](https://hanzo.com/docs/integrations/other/gradio) | 채팅/에이전트 UI | 채팅 UI와 같은 웹 인터페이스 구축을 위한 오픈 소스 Python 라이브러리입니다. |
|
||||
| [Goose](https://hanzo.com/docs/integrations/goose) | 에이전트 | 분산 에이전트 구축을 위한 오픈 소스 LLM 플랫폼입니다. |
|
||||
| [smolagents](https://hanzo.com/docs/integrations/smolagents) | 에이전트 | 오픈 소스 AI 에이전트 프레임워크입니다. |
|
||||
| [CrewAI](https://hanzo.com/docs/integrations/crewai) | 에이전트 | 에이전트 간 협업 및 도구 사용을 위한 다중 에이전트 프레임워크입니다. |
|
||||
|
||||
## 🚀 빠른 시작
|
||||
|
||||
앱에 계측을 추가하고 Langfuse에 trace 데이터를 수집하여, LLM 호출 및 검색, 임베딩, 에이전트 동작과 같은 애플리케이션 로직을 추적해보세요. 복잡한 로그와 사용자 세션을 확인하여 디버깅할 수 있습니다.
|
||||
앱에 계측을 추가하고 Hanzo에 trace 데이터를 수집하여, LLM 호출 및 검색, 임베딩, 에이전트 동작과 같은 애플리케이션 로직을 추적해보세요. 복잡한 로그와 사용자 세션을 확인하여 디버깅할 수 있습니다.
|
||||
|
||||
### 1️⃣ 새 프로젝트 생성
|
||||
|
||||
1. [Langfuse 계정 생성](https://cloud.langfuse.com/auth/sign-up) 또는 [셀프 호스트](https://langfuse.com/self-hosting)
|
||||
1. [Hanzo 계정 생성](https://cloud.hanzo.ai/auth/sign-up) 또는 [셀프 호스트](https://hanzo.ai/self-hosting)
|
||||
2. 새 프로젝트를 생성합니다.
|
||||
3. 프로젝트 설정에서 새로운 API 자격 증명을 생성합니다.
|
||||
|
||||
### 2️⃣ 첫 번째 LLM 호출 기록하기
|
||||
|
||||
[`@observe()` 데코레이터](https://langfuse.com/docs/sdk/python/decorators)를 사용하면 Python LLM 애플리케이션의 추적이 매우 간편해집니다. 이 빠른 시작 예제에서는 Langfuse [OpenAI 통합](https://langfuse.com/integrations/model-providers/openai-py)을 사용하여 모든 모델 파라미터를 자동으로 캡처합니다.
|
||||
[`@observe()` 데코레이터](https://hanzo.com/docs/sdk/python/decorators)를 사용하면 Python LLM 애플리케이션의 추적이 매우 간편해집니다. 이 빠른 시작 예제에서는 Hanzo [OpenAI 통합](https://hanzo.com/integrations/model-providers/openai-py)을 사용하여 모든 모델 파라미터를 자동으로 캡처합니다.
|
||||
|
||||
> [!TIP]
|
||||
> OpenAI를 사용하지 않으시다면, 다른 모델 및 프레임워크의 로그 기록 방법은 [문서](https://langfuse.com/docs/get-started#log-your-first-llm-call-to-langfuse)를 참조하세요.
|
||||
> OpenAI를 사용하지 않으시다면, 다른 모델 및 프레임워크의 로그 기록 방법은 [문서](https://hanzo.ai/docs/get-started#log-your-first-llm-call-to-hanzo)를 참조하세요.
|
||||
|
||||
```bash
|
||||
pip install langfuse openai
|
||||
pip install hanzo openai
|
||||
```
|
||||
|
||||
```bash filename=".env"
|
||||
LANGFUSE_SECRET_KEY="sk-lf-..."
|
||||
LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
||||
LANGFUSE_BASE_URL="https://cloud.langfuse.com" # 🇪🇺 EU region
|
||||
# LANGFUSE_BASE_URL="https://us.cloud.langfuse.com" # 🇺🇸 US region
|
||||
HANZO_SECRET_KEY="sk-lf-..."
|
||||
HANZO_PUBLIC_KEY="pk-lf-..."
|
||||
HANZO_BASE_URL="https://cloud.hanzo.com" # 🇪🇺 EU region
|
||||
# HANZO_BASE_URL="https://us.cloud.hanzo.com" # 🇺🇸 US region
|
||||
```
|
||||
|
||||
```python:main.py
|
||||
from langfuse import observe
|
||||
from langfuse.openai import openai # OpenAI integration
|
||||
from hanzo import observe
|
||||
from hanzo.openai import openai # OpenAI integration
|
||||
|
||||
@observe()
|
||||
def story():
|
||||
return openai.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": "What is Langfuse?"}],
|
||||
messages=[{"role": "user", "content": "What is Hanzo?"}],
|
||||
).choices[0].message.content
|
||||
|
||||
@observe()
|
||||
@@ -219,62 +219,62 @@ def main():
|
||||
main()
|
||||
```
|
||||
|
||||
### 3️⃣ Langfuse에서 trace 확인하기
|
||||
### 3️⃣ Hanzo에서 trace 확인하기
|
||||
|
||||
Langfuse에서 LLM 호출 및 애플리케이션의 기타 로직에 대한 trace를 확인할 수 있습니다.
|
||||
Hanzo에서 LLM 호출 및 애플리케이션의 기타 로직에 대한 trace를 확인할 수 있습니다.
|
||||
|
||||

|
||||

|
||||
|
||||
_[Langfuse의 공개 예제 trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
_[Hanzo의 공개 예제 trace](https://cloud.hanzo.ai/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Langfuse의 trace에 대해 더 알아보거나 [인터랙티브 데모](https://langfuse.com/docs/demo)에서 직접 체험해보세요.
|
||||
> Hanzo의 trace에 대해 더 알아보거나 [인터랙티브 데모](https://hanzo.ai/docs/demo)에서 직접 체험해보세요.
|
||||
|
||||
## ⭐️ 별을 눌러주세요
|
||||
|
||||

|
||||

|
||||
|
||||
## 💭 지원
|
||||
|
||||
질문에 대한 답변을 찾는 방법:
|
||||
|
||||
- 우리의 [문서](https://langfuse.com/docs)는 답을 찾기 위한 최적의 장소입니다. 문서가 매우 포괄적이며, 유지보수에 많은 노력을 기울이고 있습니다. GitHub를 통해 문서 수정 제안도 가능합니다.
|
||||
- [Langfuse FAQ](https://langfuse.com/faq)에서는 가장 흔한 질문에 대해 답변하고 있습니다.
|
||||
- 질문에 즉각적인 답변이 필요하다면 [Ask AI](https://langfuse.com/docs/ask-ai)를 사용해보세요.
|
||||
- 우리의 [문서](https://hanzo.ai/docs)는 답을 찾기 위한 최적의 장소입니다. 문서가 매우 포괄적이며, 유지보수에 많은 노력을 기울이고 있습니다. GitHub를 통해 문서 수정 제안도 가능합니다.
|
||||
- [Hanzo FAQ](https://hanzo.ai/faq)에서는 가장 흔한 질문에 대해 답변하고 있습니다.
|
||||
- 질문에 즉각적인 답변이 필요하다면 [Ask AI](https://hanzo.ai/docs/ask-ai)를 사용해보세요.
|
||||
|
||||
지원 채널:
|
||||
|
||||
- **GitHub Discussions의 [공개 Q&A](https://github.com/orgs/langfuse/discussions/categories/support)** 에 질문을 남겨주세요. 가능한 한 많은 세부 사항(예: 코드 스니펫, 스크린샷, 배경 정보)을 포함해 질문해 주시기 바랍니다.
|
||||
- [기능 요청](https://github.com/orgs/langfuse/discussions/categories/ideas)을 남겨주세요.
|
||||
- [버그 신고](https://github.com/langfuse/langfuse/issues)는 GitHub Issues를 통해 해주세요.
|
||||
- **GitHub Discussions의 [공개 Q&A](https://github.com/orgs/hanzoai/discussions/categories/support)** 에 질문을 남겨주세요. 가능한 한 많은 세부 사항(예: 코드 스니펫, 스크린샷, 배경 정보)을 포함해 질문해 주시기 바랍니다.
|
||||
- [기능 요청](https://github.com/orgs/hanzoai/discussions/categories/ideas)을 남겨주세요.
|
||||
- [버그 신고](https://github.com/hanzoai/cloud/issues)는 GitHub Issues를 통해 해주세요.
|
||||
- 긴급한 문의는 앱 내 채팅 위젯을 통해 연락 바랍니다.
|
||||
|
||||
## 🤝 기여하기
|
||||
|
||||
여러분의 기여를 환영합니다!
|
||||
|
||||
- GitHub Discussions의 [아이디어](https://github.com/orgs/langfuse/discussions/categories/ideas)에 투표해보세요.
|
||||
- GitHub Discussions의 [아이디어](https://github.com/orgs/hanzoai/discussions/categories/ideas)에 투표해보세요.
|
||||
- GitHub Issues에서 이슈를 제기하고 댓글을 남겨주세요.
|
||||
- PR을 제출하세요 – 개발 환경 설정 방법 등 자세한 내용은 [CONTRIBUTING.md](CONTRIBUTING.md)를 참조하세요.
|
||||
|
||||
## 🥇 라이선스
|
||||
|
||||
이 저장소는 `ee` 폴더를 제외하고 MIT 라이선스가 적용됩니다. 자세한 내용은 [LICENSE](LICENSE)와 [문서](https://langfuse.com/docs/open-source)를 확인하세요.
|
||||
이 저장소는 `ee` 폴더를 제외하고 MIT 라이선스가 적용됩니다. 자세한 내용은 [LICENSE](LICENSE)와 [문서](https://hanzo.ai/docs/open-source)를 확인하세요.
|
||||
|
||||
## ⭐️ 별(Star) 히스토리
|
||||
|
||||
<a href="https://star-history.com/#langfuse/langfuse&Date">
|
||||
<a href="https://star-history.com/#hanzoai/cloud&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" style="border-radius: 15px;" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" style="border-radius: 15px;" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## ❤️ Langfuse를 사용하는 오픈 소스 프로젝트
|
||||
## ❤️ Hanzo를 사용하는 오픈 소스 프로젝트
|
||||
|
||||
별(star) 수를 기준으로 순위가 매겨진 Langfuse를 사용하는 상위 오픈 소스 Python 프로젝트들 ([출처](https://github.com/langfuse/langfuse-docs/blob/main/components-mdx/dependents)):
|
||||
별(star) 수를 기준으로 순위가 매겨진 Hanzo를 사용하는 상위 오픈 소스 Python 프로젝트들 ([출처](https://github.com/hanzoai/cloud-docs/blob/main/components-mdx/dependents)):
|
||||
|
||||
| 저장소 | 별 |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----: |
|
||||
@@ -325,15 +325,15 @@ _[Langfuse의 공개 예제 trace](https://cloud.langfuse.com/project/cloramnkj0
|
||||
|
||||
## 🔒 보안 & 개인정보 보호
|
||||
|
||||
우리는 데이터 보안과 개인정보 보호를 매우 중요하게 생각합니다. 자세한 내용은 [Security and Privacy](https://langfuse.com/security) 페이지를 참조하세요.
|
||||
우리는 데이터 보안과 개인정보 보호를 매우 중요하게 생각합니다. 자세한 내용은 [Security and Privacy](https://hanzo.ai/security) 페이지를 참조하세요.
|
||||
|
||||
### 텔레메트리
|
||||
|
||||
기본적으로 Langfuse는 자체 호스팅 인스턴스의 기본 사용 통계를 중앙 서버(PostHog)로 자동 보고합니다.
|
||||
기본적으로 Hanzo는 자체 호스팅 인스턴스의 기본 사용 통계를 중앙 서버(PostHog)로 자동 보고합니다.
|
||||
|
||||
이를 통해:
|
||||
|
||||
1. Langfuse가 어떻게 사용되는지 이해하고, 가장 관련성 높은 기능을 개선할 수 있습니다.
|
||||
1. Hanzo가 어떻게 사용되는지 이해하고, 가장 관련성 높은 기능을 개선할 수 있습니다.
|
||||
2. 내부 및 외부(예: 자금 조달) 보고를 위한 전체 사용량을 추적할 수 있습니다.
|
||||
|
||||
수집된 데이터는 제3자와 공유되지 않으며 민감한 정보를 포함하지 않습니다. 이에 대해 매우 투명하게 공개하고 있으며, 수집되는 정확한 데이터는 [여기](/web/src/features/telemetry/index.ts)에서 확인할 수 있습니다.
|
||||
|
||||
@@ -3,32 +3,32 @@
|
||||
<div align="center">
|
||||
<div>
|
||||
<h3>
|
||||
<a href="https://langfuse.com/blog/2025-06-04-open-sourcing-langfuse-product">
|
||||
<strong>Langfuse Is Doubling Down On Open Source</strong>
|
||||
<a href="https://hanzo.com/blog/2025-06-04-open-sourcing-hanzo-product">
|
||||
<strong>Hanzo Is Doubling Down On Open Source</strong>
|
||||
</a> <br> <br>
|
||||
<a href="https://cloud.langfuse.com">
|
||||
<strong>Langfuse Cloud</strong>
|
||||
<a href="https://cloud.hanzo.com">
|
||||
<strong>Hanzo Cloud</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/docs/deployment/self-host">
|
||||
<a href="https://hanzo.ai/docs/deployment/self-host">
|
||||
<strong>Self Host</strong>
|
||||
</a> ·
|
||||
<a href="https://langfuse.com/demo">
|
||||
<a href="https://hanzo.ai/demo">
|
||||
<strong>Demo</strong>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="https://langfuse.com/docs"><strong>Docs</strong></a> ·
|
||||
<a href="https://langfuse.com/issues"><strong>Report Bug</strong></a> ·
|
||||
<a href="https://langfuse.com/ideas"><strong>Feature Request</strong></a> ·
|
||||
<a href="https://langfuse.com/changelog"><strong>Changelog</strong></a> ·
|
||||
<a href="https://langfuse.com/roadmap"><strong>Roadmap</strong></a> ·
|
||||
<a href="https://hanzo.ai/docs"><strong>Docs</strong></a> ·
|
||||
<a href="https://hanzo.ai/issues"><strong>Report Bug</strong></a> ·
|
||||
<a href="https://hanzo.ai/ideas"><strong>Feature Request</strong></a> ·
|
||||
<a href="https://hanzo.ai/changelog"><strong>Changelog</strong></a> ·
|
||||
<a href="https://hanzo.ai/roadmap"><strong>Roadmap</strong></a> ·
|
||||
</div>
|
||||
<br/>
|
||||
<span>Langfuse uses <a href="https://github.com/orgs/langfuse/discussions"><strong>GitHub Discussions</strong></a> for Support and Feature Requests.</span>
|
||||
<span>Hanzo uses <a href="https://github.com/orgs/hanzo/discussions"><strong>GitHub Discussions</strong></a> for Support and Feature Requests.</span>
|
||||
<br/>
|
||||
<span><b>We're hiring.</b> <a href="https://langfuse.com/careers"><strong>Join us</strong></a> in product engineering and technical go-to-market roles.</span>
|
||||
<span><b>We're hiring.</b> <a href="https://hanzo.ai/careers"><strong>Join us</strong></a> in product engineering and technical go-to-market roles.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
@@ -36,31 +36,31 @@
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/langfuse/langfuse/blob/main/LICENSE">
|
||||
<a href="https://github.com/hanzoai/cloud/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-MIT-E11311.svg" alt="MIT License">
|
||||
</a>
|
||||
<a href="https://www.ycombinator.com/companies/langfuse"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/langfuse" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/langfuse/langfuse?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/langfuse"><img src="https://img.shields.io/pypi/dm/langfuse?logo=python&logoColor=white&label=pypi%20langfuse&color=blue" alt="langfuse Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/langfuse"><img src="https://img.shields.io/npm/dm/langfuse?logo=npm&logoColor=white&label=npm%20langfuse&color=blue" alt="langfuse npm package"></a>
|
||||
<a href="https://www.ycombinator.com/companies/hanzo"><img src="https://img.shields.io/badge/Y%20Combinator-W23-orange" alt="Y Combinator W23"></a>
|
||||
<a href="https://hub.docker.com/u/hanzo" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/hanzoai/cloud?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
|
||||
<a href="https://pypi.python.org/pypi/hanzo"><img src="https://img.shields.io/pypi/dm/hanzo?logo=python&logoColor=white&label=pypi%20hanzo&color=blue" alt="hanzo Python package on PyPi"></a>
|
||||
<a href="https://www.npmjs.com/package/hanzo"><img src="https://img.shields.io/npm/dm/hanzo?logo=npm&logoColor=white&label=npm%20hanzo&color=blue" alt="hanzo npm package"></a>
|
||||
<br/>
|
||||
<a href="https://discord.com/invite/7NXusRtqYU" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1111061815649124414?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=langfuse" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/langfuse?logo=X&color=%20%23f5f5f5"
|
||||
<a href="https://twitter.com/intent/follow?screen_name=hanzo" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/hanzo?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
<a href="https://www.linkedin.com/company/langfuse/" target="_blank">
|
||||
<a href="https://www.linkedin.com/company/hanzo/" target="_blank">
|
||||
<img src="https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff"
|
||||
alt="follow on LinkedIn"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/langfuse/langfuse?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Alangfuse%2Flangfuse%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/langfuse/langfuse/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/langfuse/langfuse?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
<a href="https://deepwiki.com/langfuse/langfuse" target="_blank">
|
||||
<a href="https://github.com/hanzo/hanzo/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/hanzo/hanzo?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/hanzo/hanzo/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Ahanzo%2Fhanzo%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/hanzo/hanzo/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/hanzo/hanzo?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
<a href="https://deepwiki.com/hanzo/hanzo" target="_blank">
|
||||
<img alt="Ask DeepWiki" src="https://deepwiki.com/badge.svg"></a>
|
||||
</p>
|
||||
|
||||
@@ -72,66 +72,66 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/ClickHouse/ClickHouse"><strong>Proudly made with ClickHouse open source database</strong></a>
|
||||
<a href="https://github.com/Datastore/Datastore"><strong>Proudly made with Datastore open source database</strong></a>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
Langfuse is an **open source LLM engineering** platform. It helps teams collaboratively
|
||||
**develop, monitor, evaluate,** and **debug** AI applications. Langfuse can be **self-hosted in minutes** and is **battle-tested**.
|
||||
Hanzo is an **open source LLM engineering** platform. It helps teams collaboratively
|
||||
**develop, monitor, evaluate,** and **debug** AI applications. Hanzo can be **self-hosted in minutes** and is **battle-tested**.
|
||||
|
||||
[](https://langfuse.com/watch-demo)
|
||||
[](https://hanzo.com/watch-demo)
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
<img width="4856" height="1944" alt="Langfuse Overview" src="https://github.com/user-attachments/assets/5dac68ef-d546-49fb-b06f-cfafc19282e3" />
|
||||
<img width="4856" height="1944" alt="Hanzo Overview" src="https://github.com/user-attachments/assets/5dac68ef-d546-49fb-b06f-cfafc19282e3" />
|
||||
|
||||
- [LLM Application Observability](https://langfuse.com/docs/tracing): Instrument your app and start ingesting traces to Langfuse, thereby tracking LLM calls and other relevant logic in your app such as retrieval, embedding, or agent actions. Inspect and debug complex logs and user sessions. Try the interactive [demo](https://langfuse.com/docs/demo) to see this in action.
|
||||
- [LLM Application Observability](https://hanzo.ai/docs/tracing): Instrument your app and start ingesting traces to Hanzo, thereby tracking LLM calls and other relevant logic in your app such as retrieval, embedding, or agent actions. Inspect and debug complex logs and user sessions. Try the interactive [demo](https://hanzo.ai/docs/demo) to see this in action.
|
||||
|
||||
- [Prompt Management](https://langfuse.com/docs/prompt-management/get-started) helps you centrally manage, version control, and collaboratively iterate on your prompts. Thanks to strong caching on server and client side, you can iterate on prompts without adding latency to your application.
|
||||
- [Prompt Management](https://hanzo.com/docs/prompt-management/get-started) helps you centrally manage, version control, and collaboratively iterate on your prompts. Thanks to strong caching on server and client side, you can iterate on prompts without adding latency to your application.
|
||||
|
||||
- [Evaluations](https://langfuse.com/docs/evaluation/overview) are key to the LLM application development workflow, and Langfuse adapts to your needs. It supports LLM-as-a-judge, user feedback collection, manual labeling, and custom evaluation pipelines via APIs/SDKs.
|
||||
- [Evaluations](https://hanzo.com/docs/evaluation/overview) are key to the LLM application development workflow, and Hanzo adapts to your needs. It supports LLM-as-a-judge, user feedback collection, manual labeling, and custom evaluation pipelines via APIs/SDKs.
|
||||
|
||||
- [Datasets](https://langfuse.com/docs/evaluation/dataset-runs/datasets) enable test sets and benchmarks for evaluating your LLM application. They support continuous improvement, pre-deployment testing, structured experiments, flexible evaluation, and seamless integration with frameworks like LangChain and LlamaIndex.
|
||||
- [Datasets](https://hanzo.com/docs/evaluation/dataset-runs/datasets) enable test sets and benchmarks for evaluating your LLM application. They support continuous improvement, pre-deployment testing, structured experiments, flexible evaluation, and seamless integration with frameworks like LangChain and LlamaIndex.
|
||||
|
||||
- [LLM Playground](https://langfuse.com/docs/playground) is a tool for testing and iterating on your prompts and model configurations, shortening the feedback loop and accelerating development. When you see a bad result in tracing, you can directly jump to the playground to iterate on it.
|
||||
- [LLM Playground](https://hanzo.ai/docs/playground) is a tool for testing and iterating on your prompts and model configurations, shortening the feedback loop and accelerating development. When you see a bad result in tracing, you can directly jump to the playground to iterate on it.
|
||||
|
||||
- [Comprehensive API](https://langfuse.com/docs/api): Langfuse is frequently used to power bespoke LLMOps workflows while using the building blocks provided by Langfuse via the API. OpenAPI spec, Postman collection, and typed SDKs for Python, JS/TS are available.
|
||||
- [Comprehensive API](https://hanzo.ai/docs/api): Hanzo is frequently used to power bespoke LLMOps workflows while using the building blocks provided by Hanzo via the API. OpenAPI spec, Postman collection, and typed SDKs for Python, JS/TS are available.
|
||||
|
||||
## 📦 Deploy Langfuse
|
||||
## 📦 Deploy Hanzo
|
||||
|
||||
<img width="4856" height="1322" alt="Langfuse Deployment Options" src="https://github.com/user-attachments/assets/98f020c7-7a20-4264-a201-65c41a52a5d5" />
|
||||
<img width="4856" height="1322" alt="Hanzo Deployment Options" src="https://github.com/user-attachments/assets/98f020c7-7a20-4264-a201-65c41a52a5d5" />
|
||||
|
||||
### Langfuse Cloud
|
||||
### Hanzo Cloud
|
||||
|
||||
Managed deployment by the Langfuse team, generous free-tier, no credit card required.
|
||||
Managed deployment by the Hanzo team, generous free-tier, no credit card required.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://cloud.langfuse.com" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Langfuse%20Cloud-8A2BE2?&color=orange">
|
||||
<a href="https://cloud.hanzo.ai" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/»%20Sign%20up%20for%20Hanzo%20Cloud-8A2BE2?&color=orange">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Self-Host Langfuse
|
||||
### Self-Host Hanzo
|
||||
|
||||
Run Langfuse on your own infrastructure:
|
||||
Run Hanzo on your own infrastructure:
|
||||
|
||||
- [Local (docker compose)](https://langfuse.com/self-hosting/local): Run Langfuse on your own machine in 5 minutes using Docker Compose.
|
||||
- [Local (docker compose)](https://hanzo.ai/self-hosting/local): Run Hanzo on your own machine in 5 minutes using Docker Compose.
|
||||
|
||||
```bash
|
||||
# Get a copy of the latest Langfuse repository
|
||||
git clone https://github.com/langfuse/langfuse.git
|
||||
cd langfuse
|
||||
# Get a copy of the latest Hanzo repository
|
||||
git clone https://github.com/hanzoai/cloud.git
|
||||
cd hanzo
|
||||
|
||||
# Run the langfuse docker compose
|
||||
# Run the hanzo docker compose
|
||||
docker compose up
|
||||
```
|
||||
|
||||
- [VM](https://langfuse.com/self-hosting/docker-compose): Run Langfuse on a single Virtual Machine using Docker Compose.
|
||||
- [Kubernetes (Helm)](https://langfuse.com/self-hosting/kubernetes-helm): Run Langfuse on a Kubernetes cluster using Helm. This is the preferred production deployment.
|
||||
- Terraform Templates: [AWS](https://langfuse.com/self-hosting/aws), [Azure](https://langfuse.com/self-hosting/azure), [GCP](https://langfuse.com/self-hosting/gcp)
|
||||
- [VM](https://hanzo.com/self-hosting/docker-compose): Run Hanzo on a single Virtual Machine using Docker Compose.
|
||||
- [Kubernetes (Helm)](https://hanzo.com/self-hosting/kubernetes-helm): Run Hanzo on a Kubernetes cluster using Helm. This is the preferred production deployment.
|
||||
- Terraform Templates: [AWS](https://hanzo.com/self-hosting/aws), [Azure](https://hanzo.com/self-hosting/azure), [GCP](https://hanzo.com/self-hosting/gcp)
|
||||
|
||||
See [self-hosting documentation](https://langfuse.com/self-hosting) to learn more about architecture and configuration options.
|
||||
See [self-hosting documentation](https://hanzo.com/self-hosting) to learn more about architecture and configuration options.
|
||||
|
||||
## 🔌 Integrations
|
||||
|
||||
@@ -141,76 +141,76 @@ See [self-hosting documentation](https://langfuse.com/self-hosting) to learn mor
|
||||
|
||||
| Integration | Supports | Description |
|
||||
| ---------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [SDK](https://langfuse.com/docs/sdk) | Python, JS/TS | Manual instrumentation using the SDKs for full flexibility. |
|
||||
| [OpenAI](https://langfuse.com/integrations/model-providers/openai-py) | Python, JS/TS | Automated instrumentation using drop-in replacement of OpenAI SDK. |
|
||||
| [Langchain](https://langfuse.com/docs/integrations/langchain) | Python, JS/TS | Automated instrumentation by passing callback handler to Langchain application. |
|
||||
| [LlamaIndex](https://langfuse.com/docs/integrations/llama-index/get-started) | Python | Automated instrumentation via LlamaIndex callback system. |
|
||||
| [Haystack](https://langfuse.com/docs/integrations/haystack) | Python | Automated instrumentation via Haystack content tracing system. |
|
||||
| [LiteLLM](https://langfuse.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | Use any LLM as a drop in replacement for GPT. Use Azure, OpenAI, Cohere, Anthropic, Ollama, VLLM, Sagemaker, HuggingFace, Replicate (100+ LLMs). |
|
||||
| [Vercel AI SDK](https://langfuse.com/docs/integrations/vercel-ai-sdk) | JS/TS | TypeScript toolkit designed to help developers build AI-powered applications with React, Next.js, Vue, Svelte, Node.js. |
|
||||
| [Mastra](https://langfuse.com/docs/integrations/mastra) | JS/TS | Open source framework for building AI agents and multi-agent systems. |
|
||||
| [API](https://langfuse.com/docs/api) | | Directly call the public API. OpenAPI spec available. |
|
||||
| [SDK](https://hanzo.com/docs/sdk) | Python, JS/TS | Manual instrumentation using the SDKs for full flexibility. |
|
||||
| [OpenAI](https://hanzo.com/integrations/model-providers/openai-py) | Python, JS/TS | Automated instrumentation using drop-in replacement of OpenAI SDK. |
|
||||
| [Langchain](https://hanzo.com/docs/integrations/langchain) | Python, JS/TS | Automated instrumentation by passing callback handler to Langchain application. |
|
||||
| [LlamaIndex](https://hanzo.com/docs/integrations/llama-index/get-started) | Python | Automated instrumentation via LlamaIndex callback system. |
|
||||
| [Haystack](https://hanzo.com/docs/integrations/haystack) | Python | Automated instrumentation via Haystack content tracing system. |
|
||||
| [LiteLLM](https://hanzo.com/docs/integrations/litellm) | Python, JS/TS (proxy only) | Use any LLM as a drop in replacement for GPT. Use Azure, OpenAI, Cohere, Anthropic, Ollama, VLLM, Sagemaker, HuggingFace, Replicate (100+ LLMs). |
|
||||
| [Vercel AI SDK](https://hanzo.com/docs/integrations/vercel-ai-sdk) | JS/TS | TypeScript toolkit designed to help developers build AI-powered applications with React, Next.js, Vue, Svelte, Node.js. |
|
||||
| [Mastra](https://hanzo.com/docs/integrations/mastra) | JS/TS | Open source framework for building AI agents and multi-agent systems. |
|
||||
| [API](https://hanzo.com/docs/api) | | Directly call the public API. OpenAPI spec available. |
|
||||
|
||||
### Packages integrated with Langfuse:
|
||||
### Packages integrated with Hanzo:
|
||||
|
||||
| Name | Type | Description |
|
||||
| ----------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Instructor](https://langfuse.com/docs/integrations/instructor) | Library | Library to get structured LLM outputs (JSON, Pydantic) |
|
||||
| [DSPy](https://langfuse.com/docs/integrations/dspy) | Library | Framework that systematically optimizes language model prompts and weights |
|
||||
| [Mirascope](https://langfuse.com/docs/integrations/mirascope) | Library | Python toolkit for building LLM applications. |
|
||||
| [Ollama](https://langfuse.com/docs/integrations/ollama) | Model (local) | Easily run open source LLMs on your own machine. |
|
||||
| [Amazon Bedrock](https://langfuse.com/docs/integrations/amazon-bedrock) | Model | Run foundation and fine-tuned models on AWS. |
|
||||
| [AutoGen](https://langfuse.com/docs/integrations/autogen) | Agent Framework | Open source LLM platform for building distributed agents. |
|
||||
| [Flowise](https://langfuse.com/docs/integrations/flowise) | Chat/Agent UI | JS/TS no-code builder for customized LLM flows. |
|
||||
| [Langflow](https://langfuse.com/docs/integrations/langflow) | Chat/Agent UI | Python-based UI for LangChain, designed with react-flow to provide an effortless way to experiment and prototype flows. |
|
||||
| [Dify](https://langfuse.com/docs/integrations/dify) | Chat/Agent UI | Open source LLM app development platform with no-code builder. |
|
||||
| [OpenWebUI](https://langfuse.com/docs/integrations/openwebui) | Chat/Agent UI | Self-hosted LLM Chat web ui supporting various LLM runners including self-hosted and local models. |
|
||||
| [Promptfoo](https://langfuse.com/docs/integrations/promptfoo) | Tool | Open source LLM testing platform. |
|
||||
| [LobeChat](https://langfuse.com/docs/integrations/lobechat) | Chat/Agent UI | Open source chatbot platform. |
|
||||
| [Vapi](https://langfuse.com/docs/integrations/vapi) | Platform | Open source voice AI platform. |
|
||||
| [Inferable](https://langfuse.com/docs/integrations/other/inferable) | Agents | Open source LLM platform for building distributed agents. |
|
||||
| [Gradio](https://langfuse.com/docs/integrations/other/gradio) | Chat/Agent UI | Open source Python library to build web interfaces like Chat UI. |
|
||||
| [Goose](https://langfuse.com/docs/integrations/goose) | Agents | Open source LLM platform for building distributed agents. |
|
||||
| [smolagents](https://langfuse.com/docs/integrations/smolagents) | Agents | Open source AI agents framework. |
|
||||
| [CrewAI](https://langfuse.com/docs/integrations/crewai) | Agents | Multi agent framework for agent collaboration and tool use. |
|
||||
| [Instructor](https://hanzo.ai/docs/integrations/instructor) | Library | Library to get structured LLM outputs (JSON, Pydantic) |
|
||||
| [DSPy](https://hanzo.ai/docs/integrations/dspy) | Library | Framework that systematically optimizes language model prompts and weights |
|
||||
| [Mirascope](https://hanzo.ai/docs/integrations/mirascope) | Library | Python toolkit for building LLM applications. |
|
||||
| [Ollama](https://hanzo.ai/docs/integrations/ollama) | Model (local) | Easily run open source LLMs on your own machine. |
|
||||
| [Amazon Bedrock](https://hanzo.ai/docs/integrations/amazon-bedrock) | Model | Run foundation and fine-tuned models on AWS. |
|
||||
| [AutoGen](https://hanzo.ai/docs/integrations/autogen) | Agent Framework | Open source LLM platform for building distributed agents. |
|
||||
| [Flowise](https://hanzo.ai/docs/integrations/flowise) | Chat/Agent UI | JS/TS no-code builder for customized LLM flows. |
|
||||
| [Langflow](https://hanzo.ai/docs/integrations/langflow) | Chat/Agent UI | Python-based UI for LangChain, designed with react-flow to provide an effortless way to experiment and prototype flows. |
|
||||
| [Dify](https://hanzo.ai/docs/integrations/dify) | Chat/Agent UI | Open source LLM app development platform with no-code builder. |
|
||||
| [OpenWebUI](https://hanzo.ai/docs/integrations/openwebui) | Chat/Agent UI | Self-hosted LLM Chat web ui supporting various LLM runners including self-hosted and local models. |
|
||||
| [Promptfoo](https://hanzo.ai/docs/integrations/promptfoo) | Tool | Open source LLM testing platform. |
|
||||
| [LobeChat](https://hanzo.ai/docs/integrations/lobechat) | Chat/Agent UI | Open source chatbot platform. |
|
||||
| [Vapi](https://hanzo.ai/docs/integrations/vapi) | Platform | Open source voice AI platform. |
|
||||
| [Inferable](https://hanzo.ai/docs/integrations/other/inferable) | Agents | Open source LLM platform for building distributed agents. |
|
||||
| [Gradio](https://hanzo.ai/docs/integrations/other/gradio) | Chat/Agent UI | Open source Python library to build web interfaces like Chat UI. |
|
||||
| [Goose](https://hanzo.ai/docs/integrations/goose) | Agents | Open source LLM platform for building distributed agents. |
|
||||
| [smolagents](https://hanzo.ai/docs/integrations/smolagents) | Agents | Open source AI agents framework. |
|
||||
| [CrewAI](https://hanzo.ai/docs/integrations/crewai) | Agents | Multi agent framework for agent collaboration and tool use. |
|
||||
|
||||
## 🚀 Quickstart
|
||||
|
||||
Instrument your app and start ingesting traces to Langfuse, thereby tracking LLM calls and other relevant logic in your app such as retrieval, embedding, or agent actions. Inspect and debug complex logs and user sessions.
|
||||
Instrument your app and start ingesting traces to Hanzo, thereby tracking LLM calls and other relevant logic in your app such as retrieval, embedding, or agent actions. Inspect and debug complex logs and user sessions.
|
||||
|
||||
### 1️⃣ Create new project
|
||||
|
||||
1. [Create Langfuse account](https://cloud.langfuse.com/auth/sign-up) or [self-host](https://langfuse.com/self-hosting)
|
||||
1. [Create Hanzo account](https://cloud.hanzo.ai/auth/sign-up) or [self-host](https://hanzo.ai/self-hosting)
|
||||
2. Create a new project
|
||||
3. Create new API credentials in the project settings
|
||||
|
||||
### 2️⃣ Log your first LLM call
|
||||
|
||||
The [`@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators) makes it easy to trace any Python LLM application. In this quickstart we also use the Langfuse [OpenAI integration](https://langfuse.com/integrations/model-providers/openai-py) to automatically capture all model parameters.
|
||||
The [`@observe()` decorator](https://hanzo.com/docs/sdk/python/decorators) makes it easy to trace any Python LLM application. In this quickstart we also use the Hanzo [OpenAI integration](https://hanzo.com/integrations/model-providers/openai-py) to automatically capture all model parameters.
|
||||
|
||||
> [!TIP]
|
||||
> Not using OpenAI? Visit [our documentation](https://langfuse.com/docs/get-started#log-your-first-llm-call-to-langfuse) to learn how to log other models and frameworks.
|
||||
> Not using OpenAI? Visit [our documentation](https://hanzo.ai/docs/get-started#log-your-first-llm-call-to-hanzo) to learn how to log other models and frameworks.
|
||||
|
||||
```bash
|
||||
pip install langfuse openai
|
||||
pip install hanzo openai
|
||||
```
|
||||
|
||||
```bash filename=".env"
|
||||
LANGFUSE_SECRET_KEY="sk-lf-..."
|
||||
LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
||||
LANGFUSE_BASE_URL="https://cloud.langfuse.com" # 🇪🇺 EU region
|
||||
# LANGFUSE_BASE_URL="https://us.cloud.langfuse.com" # 🇺🇸 US region
|
||||
HANZO_SECRET_KEY="sk-lf-..."
|
||||
HANZO_PUBLIC_KEY="pk-lf-..."
|
||||
HANZO_BASE_URL="https://cloud.hanzo.com" # 🇪🇺 EU region
|
||||
# HANZO_BASE_URL="https://us.cloud.hanzo.com" # 🇺🇸 US region
|
||||
```
|
||||
|
||||
```python /@observe()/ /from langfuse.openai import openai/ filename="main.py"
|
||||
from langfuse import observe
|
||||
from langfuse.openai import openai # OpenAI integration
|
||||
```python /@observe()/ /from hanzo.openai import openai/ filename="main.py"
|
||||
from hanzo import observe
|
||||
from hanzo.openai import openai # OpenAI integration
|
||||
|
||||
@observe()
|
||||
def story():
|
||||
return openai.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": "What is Langfuse?"}],
|
||||
messages=[{"role": "user", "content": "What is Hanzo?"}],
|
||||
).choices[0].message.content
|
||||
|
||||
@observe()
|
||||
@@ -220,48 +220,48 @@ def main():
|
||||
main()
|
||||
```
|
||||
|
||||
### 3️⃣ See traces in Langfuse
|
||||
### 3️⃣ See traces in Hanzo
|
||||
|
||||
See your language model calls and other application logic in Langfuse.
|
||||
See your language model calls and other application logic in Hanzo.
|
||||
|
||||
<img width="1787" height="674" alt="Example trace in Langfuse" src="https://github.com/user-attachments/assets/f796eb78-dfb5-4570-b236-bdb4b67d4d55" />
|
||||
<img width="1787" height="674" alt="Example trace in Hanzo" src="https://github.com/user-attachments/assets/f796eb78-dfb5-4570-b236-bdb4b67d4d55" />
|
||||
|
||||
_[Public example trace in Langfuse](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
_[Public example trace in Hanzo](https://cloud.hanzo.ai/project/cloramnkj0002jz088vzn1ja4/traces/2cec01e3-3dc2-472f-afcf-3b968cf0c1f4?timestamp=2025-02-10T14%3A27%3A30.275Z&observation=cb5ff844-07ef-41e6-b8e2-6c64344bc13b)_
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> [Learn more](https://langfuse.com/docs/tracing) about tracing in Langfuse or play with the [interactive demo](https://langfuse.com/docs/demo).
|
||||
> [Learn more](https://hanzo.ai/docs/tracing) about tracing in Hanzo or play with the [interactive demo](https://hanzo.ai/docs/demo).
|
||||
|
||||
## ⭐️ Star Us
|
||||
|
||||

|
||||

|
||||
|
||||
## 💭 Support
|
||||
|
||||
Finding an answer to your question:
|
||||
|
||||
- Our [documentation](https://langfuse.com/docs) is the best place to start looking for answers. It is comprehensive, and we invest significant time into maintaining it. You can also suggest edits to the docs via GitHub.
|
||||
- [Langfuse FAQs](https://langfuse.com/faq) where the most common questions are answered.
|
||||
- Use "[Ask AI](https://langfuse.com/docs/ask-ai)" to get instant answers to your questions.
|
||||
- Our [documentation](https://hanzo.ai/docs) is the best place to start looking for answers. It is comprehensive, and we invest significant time into maintaining it. You can also suggest edits to the docs via GitHub.
|
||||
- [Hanzo FAQs](https://hanzo.ai/faq) where the most common questions are answered.
|
||||
- Use "[Ask AI](https://hanzo.ai/docs/ask-ai)" to get instant answers to your questions.
|
||||
|
||||
Support Channels:
|
||||
|
||||
- **Ask any question in our [public Q&A](https://github.com/orgs/langfuse/discussions/categories/support) on GitHub Discussions.** Please include as much detail as possible (e.g. code snippets, screenshots, background information) to help us understand your question.
|
||||
- [Request a feature](https://github.com/orgs/langfuse/discussions/categories/ideas) on GitHub Discussions.
|
||||
- [Report a Bug](https://github.com/langfuse/langfuse/issues) on GitHub Issues.
|
||||
- **Ask any question in our [public Q&A](https://github.com/orgs/hanzoai/discussions/categories/support) on GitHub Discussions.** Please include as much detail as possible (e.g. code snippets, screenshots, background information) to help us understand your question.
|
||||
- [Request a feature](https://github.com/orgs/hanzoai/discussions/categories/ideas) on GitHub Discussions.
|
||||
- [Report a Bug](https://github.com/hanzoai/cloud/issues) on GitHub Issues.
|
||||
- For time-sensitive queries, ping us via the in-app chat widget.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Your contributions are welcome!
|
||||
|
||||
- Vote on [Ideas](https://github.com/orgs/langfuse/discussions/categories/ideas) in GitHub Discussions.
|
||||
- Raise and comment on [Issues](https://github.com/langfuse/langfuse/issues).
|
||||
- Vote on [Ideas](https://github.com/orgs/hanzoai/discussions/categories/ideas) in GitHub Discussions.
|
||||
- Raise and comment on [Issues](https://github.com/hanzoai/cloud/issues).
|
||||
- Open a PR - see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to setup a development environment.
|
||||
|
||||
## 🥇 License
|
||||
|
||||
This repository is MIT licensed, except for the `ee` folders. See [LICENSE](LICENSE) and [docs](https://langfuse.com/docs/open-source) for more details.
|
||||
This repository is MIT licensed, except for the `ee` folders. See [LICENSE](LICENSE) and [docs](https://hanzo.ai/docs/open-source) for more details.
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -269,17 +269,17 @@ We deploy this code base in Docker containers based on the Linux Alpine Image ([
|
||||
|
||||
## ⭐️ Star History
|
||||
|
||||
<a href="https://star-history.com/#langfuse/langfuse&Date">
|
||||
<a href="https://star-history.com/#hanzoai/cloud&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=langfuse/langfuse&type=Date" style="border-radius: 15px;" />
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hanzoai/cloud&type=Date" style="border-radius: 15px;" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## ❤️ Open Source Projects Using Langfuse
|
||||
## ❤️ Open Source Projects Using Hanzo
|
||||
|
||||
Top open-source Python projects that use Langfuse, ranked by stars ([Source](https://github.com/langfuse/langfuse-docs/blob/main/components-mdx/dependents)):
|
||||
Top open-source Python projects that use Hanzo, ranked by stars ([Source](https://github.com/hanzoai/cloud-docs/blob/main/components-mdx/dependents)):
|
||||
|
||||
| Repository | Stars |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----: |
|
||||
@@ -302,7 +302,7 @@ Top open-source Python projects that use Langfuse, ranked by stars ([Source](htt
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/170767358?s=40&v=4" width="20" height="20" alt=""> [kortix-ai](https://github.com/kortix-ai) / [suna](https://github.com/kortix-ai/suna) | 17976 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/76263028?s=40&v=4" width="20" height="20" alt=""> [anthropics](https://github.com/anthropics) / [courses](https://github.com/anthropics/courses) | 17057 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/149120496?s=40&v=4" width="20" height="20" alt=""> [mastra-ai](https://github.com/mastra-ai) / [mastra](https://github.com/mastra-ai/mastra) | 16484 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/134601687?s=40&v=4" width="20" height="20" alt=""> [langfuse](https://github.com/langfuse) / [langfuse](https://github.com/langfuse/langfuse) | 16054 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/134601687?s=40&v=4" width="20" height="20" alt=""> [hanzo](https://github.com/hanzo) / [hanzo](https://github.com/hanzo/hanzo) | 16054 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/7250217?s=40&v=4" width="20" height="20" alt=""> [Canner](https://github.com/Canner) / [WrenAI](https://github.com/Canner/WrenAI) | 11868 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/137907881?s=40&v=4" width="20" height="20" alt=""> [promptfoo](https://github.com/promptfoo) / [promptfoo](https://github.com/promptfoo/promptfoo) | 8350 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/193350244?s=40&v=4" width="20" height="20" alt=""> [The-Pocket](https://github.com/The-Pocket) / [PocketFlow](https://github.com/The-Pocket/PocketFlow) | 8313 |
|
||||
@@ -374,7 +374,7 @@ Top open-source Python projects that use Langfuse, ranked by stars ([Source](htt
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/1009716?s=40&v=4" width="20" height="20" alt=""> [codecentric](https://github.com/codecentric) / [c4-genai-suite](https://github.com/codecentric/c4-genai-suite) | 152 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/196509932?s=40&v=4" width="20" height="20" alt=""> [XSpoonAi](https://github.com/XSpoonAi) / [spoon-core](https://github.com/XSpoonAi/spoon-core) | 150 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/139558948?s=40&v=4" width="20" height="20" alt=""> [chatchat-space](https://github.com/chatchat-space) / [LangGraph-Chatchat](https://github.com/chatchat-space/LangGraph-Chatchat) | 144 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/134601687?s=40&v=4" width="20" height="20" alt=""> [langfuse](https://github.com/langfuse) / [langfuse-docs](https://github.com/langfuse/langfuse-docs) | 139 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/134601687?s=40&v=4" width="20" height="20" alt=""> [hanzo](https://github.com/hanzo) / [hanzo-docs](https://github.com/hanzo/hanzo-docs) | 139 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/44976328?s=40&v=4" width="20" height="20" alt=""> [piyushgarg-dev](https://github.com/piyushgarg-dev) / [genai-cohort](https://github.com/piyushgarg-dev/genai-cohort) | 135 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/105285801?s=40&v=4" width="20" height="20" alt=""> [i-dot-ai](https://github.com/i-dot-ai) / [redbox](https://github.com/i-dot-ai/redbox) | 132 |
|
||||
| <img class="avatar mr-2" src="https://avatars.githubusercontent.com/u/90423581?s=40&v=4" width="20" height="20" alt=""> [bmd1905](https://github.com/bmd1905) / [ChatOpsLLM](https://github.com/bmd1905/ChatOpsLLM) | 127 |
|
||||
@@ -383,15 +383,15 @@ Top open-source Python projects that use Langfuse, ranked by stars ([Source](htt
|
||||
|
||||
## 🔒 Security & Privacy
|
||||
|
||||
We take data security and privacy seriously. Please refer to our [Security and Privacy](https://langfuse.com/security) page for more information.
|
||||
We take data security and privacy seriously. Please refer to our [Security and Privacy](https://hanzo.ai/security) page for more information.
|
||||
|
||||
### Telemetry
|
||||
|
||||
By default, Langfuse automatically reports basic usage statistics of self-hosted instances to a centralized server (PostHog).
|
||||
By default, Hanzo automatically reports basic usage statistics of self-hosted instances to a centralized server (PostHog).
|
||||
|
||||
This helps us to:
|
||||
|
||||
1. Understand how Langfuse is used and improve the most relevant features.
|
||||
1. Understand how Hanzo is used and improve the most relevant features.
|
||||
2. Track overall usage for internal and external (e.g. fundraising) reporting.
|
||||
|
||||
None of the data is shared with third parties and does not include any sensitive information. We want to be super transparent about this and you can find the exact data we collect [here](/web/src/features/telemetry/index.ts).
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
## Database Migrations
|
||||
|
||||
### ClickHouse
|
||||
### Datastore
|
||||
|
||||
- ClickHouse migrations in the `packages/shared/clickhouse/migrations/clustered` directory should include `ON CLUSTER default` and should use `Replicated` merge tree table types.
|
||||
- Datastore migrations in the `packages/shared/datastore/migrations/clustered` directory should include `ON CLUSTER default` and should use `Replicated` merge tree table types.
|
||||
- E.g. `ReplacingMergeTree` is likely an error while `ReplicatedReplacingMergeTree` would be correct in most cases.
|
||||
- ClickHouse migrations in the `packages/shared/clickhouse/migrations/unclustered` directory must not include `ON CLUSTER` statements and must not use `Replicated` merge tree table types.
|
||||
- Migrations in `packages/shared/clickhouse/migrations/clustered` should match their counterparts in `packages/shared/clickhouse/migrations/unclustered` aside from the restrictions listed above.
|
||||
- When adding new indexes on ClickHouse, ensure that there is a corresponding `MATERIALIZE INDEX` statement in the same migration. The materialization can use `SETTINGS mutations_sync = 2` if they operate on smaller tables, but may timeout otherwise.
|
||||
- All ClickHouse queries on project-scoped tables (traces, observations, scores, events, sessions, etc.) must include `WHERE project_id = {projectId: String}` filter to ensure proper tenant isolation and that queries only access data from the intended project.
|
||||
- Datastore migrations in the `packages/shared/datastore/migrations/unclustered` directory must not include `ON CLUSTER` statements and must not use `Replicated` merge tree table types.
|
||||
- Migrations in `packages/shared/datastore/migrations/clustered` should match their counterparts in `packages/shared/datastore/migrations/unclustered` aside from the restrictions listed above.
|
||||
- When adding new indexes on Datastore, ensure that there is a corresponding `MATERIALIZE INDEX` statement in the same migration. The materialization can use `SETTINGS mutations_sync = 2` if they operate on smaller tables, but may timeout otherwise.
|
||||
- All Datastore queries on project-scoped tables (traces, observations, scores, events, sessions, etc.) must include `WHERE project_id = {projectId: String}` filter to ensure proper tenant isolation and that queries only access data from the intended project.
|
||||
- For operations on the `events` table, you must never use the `FINAL` keyword as it kills performance. `events` is built so that `FINAL` is never required.
|
||||
|
||||
### Postgres
|
||||
@@ -26,9 +26,9 @@
|
||||
- Highlight usage of `redis.call` invocations. Those may have suboptimal redis cluster routing and will raise errors. Instead, use the native call patterns.
|
||||
Example: `await redis?.call("SET", key, "1", "NX", "EX", TTLSeconds);` should use `await redis?.set(key, "1", "EX", TTLSeconds, "NX");` instead.
|
||||
|
||||
## Langfuse Cloud
|
||||
## Hanzo Cloud
|
||||
|
||||
- When attempting to confirm if the current environment is Langfuse Cloud in the frontend, use the `useLangfuseCloudRegion` hook and never environment variables directly.
|
||||
- When attempting to confirm if the current environment is Hanzo Cloud in the frontend, use the `useHanzoCloudRegion` hook and never environment variables directly.
|
||||
|
||||
## Banner Height System
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
## Security Policy
|
||||
We strongly recommend using the latest version of Langfuse to receive all security updates.
|
||||
We strongly recommend using the latest version of Hanzo to receive all security updates.
|
||||
|
||||
For more information, please refer to the [Data Security & Privacy](https://langfuse.com/docs/data-security-privacy) page in the documentation or contact security@langfuse.com.
|
||||
For more information, please refer to the [Data Security & Privacy](https://hanzo.ai/docs/data-security-privacy) page in the documentation or contact security@hanzo.ai.
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
services:
|
||||
hanzo-web:
|
||||
build:
|
||||
dockerfile: ./web/Dockerfile
|
||||
context: .
|
||||
args:
|
||||
- NEXT_PUBLIC_HANZO_CLOUD_REGION=${NEXT_PUBLIC_HANZO_CLOUD_REGION}
|
||||
depends_on: &hanzo-depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment: &hanzo-web-env
|
||||
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
||||
NEXTAUTH_SECRET: mysecret
|
||||
SALT: mysalt
|
||||
ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" # generate via `openssl rand -hex 32`
|
||||
NEXTAUTH_URL: http://localhost:3000
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
DATASTORE_MIGRATION_URL: ${DATASTORE_MIGRATION_URL:-datastore://datastore:9000}
|
||||
DATASTORE_URL: ${DATASTORE_URL:-http://datastore:8123}
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
DATASTORE_CLUSTER_ENABLED: ${DATASTORE_CLUSTER_ENABLED:-false}
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-us-east-1}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/public/health"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 12
|
||||
start_period: 30s
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
hanzo-worker:
|
||||
build:
|
||||
dockerfile: ./worker/Dockerfile
|
||||
context: .
|
||||
args:
|
||||
- NEXT_PUBLIC_HANZO_CLOUD_REGION=${NEXT_PUBLIC_HANZO_CLOUD_REGION}
|
||||
depends_on: *hanzo-depends-on
|
||||
ports:
|
||||
- "3030:3030"
|
||||
environment:
|
||||
<<: *hanzo-web-env
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3030/api/health"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 12
|
||||
start_period: 30s
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: hanzo
|
||||
DATASTORE_PASSWORD: hanzo
|
||||
volumes:
|
||||
- hanzo_datastore_data:/var/lib/datastore
|
||||
- hanzo_datastore_logs:/var/log/datastore
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
entrypoint: sh
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: minio
|
||||
MINIO_ROOT_PASSWORD: miniosecret
|
||||
ports:
|
||||
- "9090:9000"
|
||||
- "9091:9001"
|
||||
volumes:
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
redis:
|
||||
image: redis:7
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
ports:
|
||||
- 6379:6379
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_VERSION:-17}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- local-dev
|
||||
|
||||
volumes:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
hanzo_s3_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
local-dev:
|
||||
@@ -0,0 +1,89 @@
|
||||
services:
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
volumes:
|
||||
- hanzo_datastore_data:/var/lib/datastore
|
||||
- hanzo_datastore_logs:/var/log/datastore
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
azurite:
|
||||
image: mcr.microsoft.com/azure-storage/azurite
|
||||
command: azurite-blob --blobHost 0.0.0.0
|
||||
ports:
|
||||
- "10000:10000"
|
||||
volumes:
|
||||
- hanzo_azurite_data:/data
|
||||
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
container_name: ${S3_CONTAINER_NAME:-hanzo-s3}
|
||||
entrypoint: sh
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret}
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_API_PORT:-9090}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_CONSOLE_PORT:-9091}:9001
|
||||
volumes:
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
networks:
|
||||
- default
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7.2.4
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
--maxmemory-policy noeviction
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
command: ["postgres", "-c", "log_statement=all"]
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-postgres}
|
||||
- TZ=UTC
|
||||
- PGTZ=UTC
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
hanzo_azurite_data:
|
||||
driver: local
|
||||
hanzo_s3_data:
|
||||
name: ${S3_VOLUME_NAME:-hanzo_s3_data}
|
||||
driver: local
|
||||
@@ -0,0 +1,292 @@
|
||||
# Define common dependencies anchor before it's used
|
||||
x-cloud-dev-depends-on: &cloud-depends-on
|
||||
postgres-dev:
|
||||
condition: service_healthy
|
||||
s3-dev:
|
||||
condition: service_healthy
|
||||
redis-dev:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
|
||||
# Define environment variables anchor before it's used
|
||||
x-cloud-dev-environment: &cloud-worker-env
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres-dev:5432/postgres}
|
||||
SALT: ${SALT:-mysalt}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-true}
|
||||
DATASTORE_MIGRATION_URL: "datastore://datastore:9000"
|
||||
DATASTORE_URL: "http://datastore:8123"
|
||||
DATASTORE_USER: "hanzo"
|
||||
DATASTORE_PASSWORD: "hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED: "false"
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis-dev}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
|
||||
services:
|
||||
cloud-dev-web:
|
||||
image: ghcr.io/hanzoai/hanzo-cloud-web:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: web/Dockerfile
|
||||
args:
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: "DEV"
|
||||
STRIPE_SECRET_KEY: "${STRIPE_SECRET_KEY}"
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: "${STRIPE_PUBLISHABLE_KEY}"
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: "${STRIPE_WEBHOOK_SIGNING_SECRET}"
|
||||
restart: always
|
||||
depends_on:
|
||||
postgres-dev:
|
||||
condition: service_healthy
|
||||
s3-dev:
|
||||
condition: service_healthy
|
||||
redis-dev:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
# *cloud-dev-depends-on
|
||||
# ports:
|
||||
# - "3003:3000"
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres-dev:5432/postgres}
|
||||
SALT: ${SALT:-mysalt}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-true}
|
||||
DATASTORE_MIGRATION_URL: "datastore://datastore:9000"
|
||||
DATASTORE_URL: "http://datastore:8123"
|
||||
DATASTORE_USER: "hanzo"
|
||||
DATASTORE_PASSWORD: "hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED: "false"
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis-dev}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: "DEV"
|
||||
STRIPE_SECRET_KEY: "${STRIPE_SECRET_KEY}"
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: "${STRIPE_PUBLISHABLE_KEY}"
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: "${STRIPE_WEBHOOK_SIGNING_SECRET}"
|
||||
NEXTAUTH_URL: https://cloud-dev.hanzo.ai
|
||||
NEXTAUTH_SECRET: mysecret
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
IAM_APP_NAME: ${IAM_APP_NAME:-}
|
||||
IAM_CLIENT_ID: ${IAM_CLIENT_ID:-}
|
||||
IAM_CLIENT_SECRET: ${IAM_CLIENT_SECRET:-}
|
||||
IAM_ORG_NAME: ${IAM_ORG_NAME:-}
|
||||
|
||||
IAM_SERVER_URL: ${IAM_SERVER_URL:-}
|
||||
IAM_ALLOW_ACCOUNT_LINKING: ${IAM_ALLOW_ACCOUNT_LINKING:-}
|
||||
AUTH_DISABLE_USERNAME_PASSWORD: ${AUTH_DISABLE_USERNAME_PASSWORD:-true}
|
||||
networks:
|
||||
- hanzo-network
|
||||
- interal-cloud-dev-network
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
|
||||
# HTTPS Router
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.cloud-dev-https.rule=Host(`cloud-dev.hanzo.ai`)"
|
||||
- "traefik.http.routers.cloud-dev-https.entrypoints=websecure"
|
||||
- "traefik.http.routers.cloud-dev-https.tls=true"
|
||||
- "traefik.http.routers.cloud-dev-https.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.cloud-dev-https.middlewares=well-known"
|
||||
- "traefik.http.routers.cloud-dev-https.service=cloud-dev-service"
|
||||
- "traefik.http.services.cloud-dev-service.loadbalancer.server.port=3000"
|
||||
|
||||
# HTTP Router (redirect to HTTPS)
|
||||
- "traefik.http.routers.cloud-dev-http.rule=Host(`cloud-dev.hanzo.ai`)"
|
||||
- "traefik.http.routers.cloud-dev-http.entrypoints=web"
|
||||
- "traefik.http.routers.cloud-dev-http.middlewares=well-known,redirect-to-https"
|
||||
- "traefik.http.routers.cloud-dev-http.service=cloud-dev-service"
|
||||
|
||||
|
||||
cloud-dev-worker:
|
||||
image: ghcr.io/hanzoai/hanzo-cloud-worker:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
postgres-dev:
|
||||
condition: service_healthy
|
||||
s3-dev:
|
||||
condition: service_healthy
|
||||
redis-dev:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# <<: *cloud-dev-worker-env
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres-dev:5432/postgres}
|
||||
SALT: ${SALT:-mysalt}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-true}
|
||||
DATASTORE_MIGRATION_URL: "datastore://datastore:9000"
|
||||
DATASTORE_URL: "http://datastore:8123"
|
||||
DATASTORE_USER: "hanzo"
|
||||
DATASTORE_PASSWORD: "hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED: "false"
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3-dev:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis-dev}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
networks:
|
||||
- interal-cloud-dev-network
|
||||
|
||||
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
restart: always
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: hanzo
|
||||
DATASTORE_PASSWORD: hanzo
|
||||
DATASTORE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
volumes:
|
||||
- cloud_dev_datastore_data:/var/lib/datastore
|
||||
- cloud_dev_datastore_logs:/var/log/datastore
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
networks:
|
||||
- interal-cloud-dev-network
|
||||
|
||||
|
||||
s3-dev:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
restart: always
|
||||
entrypoint: sh
|
||||
# create the 'cloud-dev' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/cloud-dev && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: minio
|
||||
MINIO_ROOT_PASSWORD: miniosecret
|
||||
volumes:
|
||||
- cloud_dev_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
networks:
|
||||
- interal-cloud-dev-network
|
||||
|
||||
redis-dev:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- interal-cloud-dev-network
|
||||
|
||||
postgres-dev:
|
||||
image: postgres:${POSTGRES_VERSION:-latest}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
volumes:
|
||||
- cloud_dev_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- interal-cloud-dev-network
|
||||
|
||||
networks:
|
||||
interal-cloud-dev-network:
|
||||
hanzo-network:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
cloud_dev_postgres_data:
|
||||
driver: local
|
||||
cloud_dev_datastore_data:
|
||||
driver: local
|
||||
cloud_dev_datastore_logs:
|
||||
driver: local
|
||||
cloud_dev_s3_data:
|
||||
driver: local
|
||||
@@ -0,0 +1,242 @@
|
||||
# Define common dependencies anchor before it's used
|
||||
x-cloud-depends-on: &cloud-depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
redis-cloud:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
|
||||
# Define environment variables anchor before it's used
|
||||
x-cloud-environment: &cloud-worker-env
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/postgres}
|
||||
SALT: ${SALT:-mysalt}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-true}
|
||||
DATASTORE_MIGRATION_URL: "datastore://datastore:9000"
|
||||
DATASTORE_URL: "http://datastore:8123"
|
||||
DATASTORE_USER: "hanzo"
|
||||
DATASTORE_PASSWORD: "hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED: "false"
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
|
||||
services:
|
||||
console:
|
||||
image: hanzoai/console:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: web/Dockerfile
|
||||
args:
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: ${NEXT_PUBLIC_HANZO_CLOUD_REGION:-US}
|
||||
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-sk-live-xxx}
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-pk-live-xxx}
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: ${STRIPE_WEBHOOK_SIGNING_SECRET:-your-secret}
|
||||
restart: always
|
||||
depends_on: *cloud-depends-on
|
||||
#ports:
|
||||
# - "3000:3000"
|
||||
environment:
|
||||
<<: *cloud-worker-env
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: ${NEXT_PUBLIC_HANZO_CLOUD_REGION:-US}
|
||||
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-sk-live-xxx}
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY:-pk-live-xxx}
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: ${STRIPE_WEBHOOK_SIGNING_SECRET:-your-secret}
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:-https://console.hanzo.ai}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-mysecret}
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
IAM_APP_NAME: ${IAM_APP_NAME:-}
|
||||
IAM_CLIENT_ID: ${IAM_CLIENT_ID:-}
|
||||
IAM_CLIENT_SECRET: ${IAM_CLIENT_SECRET:-}
|
||||
IAM_ORG_NAME: ${IAM_ORG_NAME:-}
|
||||
|
||||
IAM_SERVER_URL: ${IAM_SERVER_URL:-}
|
||||
IAM_ALLOW_ACCOUNT_LINKING: ${IAM_ALLOW_ACCOUNT_LINKING:-}
|
||||
AUTH_DISABLE_USERNAME_PASSWORD: ${AUTH_DISABLE_USERNAME_PASSWORD:-true}
|
||||
S3_FREE_PLAN_EXPIRE: ${S3_FREE_PLAN_EXPIRE:-90}
|
||||
SMTP_CONNECTION_URL: ${SMTP_CONNECTION_URL:-smtp://dev@hanzo.ai:md-iOMNRc1olJUrZMSvBaGAbA@smtp.mandrillapp.com:587}
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.middlewares.well-known.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.middlewares.console-csp.headers.customResponseHeaders.Content-Security-Policy=connect-src 'self' https://console.hanzo.ai http://console.hanzo.ai;"
|
||||
- "traefik.http.routers.console-http.rule=Host(`console.hanzo.ai`)"
|
||||
- "traefik.http.routers.console-http.entrypoints=web"
|
||||
- "traefik.http.routers.console-http.middlewares=well-known,console-csp,redirect-to-https"
|
||||
- "traefik.http.routers.console-https.rule=Host(`console.hanzo.ai`)"
|
||||
- "traefik.http.routers.console-https.entrypoints=websecure"
|
||||
- "traefik.http.routers.console-https.middlewares=well-known,console-csp"
|
||||
- "traefik.http.routers.console-https.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.console-service.loadbalancer.server.port=3000"
|
||||
|
||||
console-worker:
|
||||
image: hanzoai/console-worker:latest
|
||||
restart: always
|
||||
depends_on: *cloud-depends-on
|
||||
#ports:
|
||||
# - "3030:3030"
|
||||
environment: *cloud-worker-env
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
restart: always
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: hanzo
|
||||
DATASTORE_PASSWORD: hanzo
|
||||
DATASTORE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
volumes:
|
||||
- cloud-datastore-data:/var/lib/datastore
|
||||
- cloud-datastore-logs:/var/log/datastore
|
||||
#ports:
|
||||
# - "8123:8123"
|
||||
# - "9000:9000"
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
restart: always
|
||||
entrypoint: sh
|
||||
# create the 'cloud' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/cloud && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: minio
|
||||
MINIO_ROOT_PASSWORD: miniosecret
|
||||
#ports:
|
||||
# - "9090:9000"
|
||||
# - "9091:9001"
|
||||
volumes:
|
||||
- cloud-s3-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
networks:
|
||||
- cloud-hanzo-network
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
#ports:
|
||||
# - 6379:6379
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_VERSION:-latest}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
#ports:
|
||||
# - 5432:5432
|
||||
volumes:
|
||||
- cloud-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
|
||||
redis-cloud:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
environment:
|
||||
REDIS_PASSWORD: ${REDIS_AUTH:-myredissecret}
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_AUTH:-myredissecret}", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- hanzo-network
|
||||
- cloud-hanzo-network
|
||||
|
||||
volumes:
|
||||
- cloud-redis-cloud-data:/data
|
||||
|
||||
networks:
|
||||
cloud-hanzo-network:
|
||||
driver: bridge
|
||||
hanzo-network:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
cloud-postgres-data:
|
||||
name: cloud-postgres-data-prod
|
||||
driver: local
|
||||
cloud-datastore-data:
|
||||
driver: local
|
||||
cloud-datastore-logs:
|
||||
driver: local
|
||||
cloud-s3-data:
|
||||
driver: local
|
||||
cloud-redis-cloud-data:
|
||||
driver: local
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
networks:
|
||||
ai-platform_default:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
hanzo-worker:
|
||||
image: hanzoai/cloud-worker:3.38.0
|
||||
restart: always
|
||||
depends_on: &hanzo-depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3030:3030"
|
||||
environment: &hanzo-worker-env
|
||||
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
||||
SALT: "mysalt"
|
||||
ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" # generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-true}
|
||||
DATASTORE_MIGRATION_URL: "datastore://datastore:9000"
|
||||
DATASTORE_URL: "http://datastore:8123"
|
||||
DATASTORE_USER: "hanzo"
|
||||
DATASTORE_PASSWORD: "hanzo"
|
||||
DATASTORE_CLUSTER_ENABLED: "false"
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
networks:
|
||||
- ai-platform_default
|
||||
|
||||
hanzo-web:
|
||||
# image: hanzoai/cloud-web:3.38.0
|
||||
build:
|
||||
context: .
|
||||
dockerfile: web/Dockerfile
|
||||
args:
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: "DEV"
|
||||
STRIPE_SECRET_KEY: "${STRIPE_SECRET_KEY}"
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: "${STRIPE_PUBLISHABLE_KEY}"
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: "${STRIPE_WEBHOOK_SIGNING_SECRET}"
|
||||
restart: always
|
||||
depends_on: *hanzo-depends-on
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
<<: *hanzo-worker-env
|
||||
NEXT_PUBLIC_HANZO_CLOUD_REGION: "DEV"
|
||||
STRIPE_SECRET_KEY: "${STRIPE_SECRET_KEY}"
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: "${STRIPE_PUBLISHABLE_KEY}"
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET: "${STRIPE_WEBHOOK_SIGNING_SECRET}"
|
||||
NEXTAUTH_URL: https://cloud.hanzo.ai
|
||||
NEXTAUTH_SECRET: mysecret
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
networks:
|
||||
- ai-platform_default
|
||||
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
restart: always
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: hanzo
|
||||
DATASTORE_PASSWORD: hanzo
|
||||
DATASTORE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
volumes:
|
||||
- hanzo_datastore_data:/var/lib/datastore
|
||||
- hanzo_datastore_logs:/var/log/datastore
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
networks:
|
||||
- ai-platform_default
|
||||
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
restart: always
|
||||
entrypoint: sh
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: minio
|
||||
MINIO_ROOT_PASSWORD: miniosecret
|
||||
ports:
|
||||
- "9090:9000"
|
||||
- "9091:9001"
|
||||
volumes:
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
ports:
|
||||
- 6379:6379
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- ai-platform_default
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_VERSION:-latest}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- ai-platform_default
|
||||
|
||||
volumes:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
hanzo_s3_data:
|
||||
driver: local
|
||||
@@ -0,0 +1,227 @@
|
||||
# Production deployment stack for console.hanzo.ai
|
||||
#
|
||||
# SUPPLY CHAIN SECURITY: All images are either:
|
||||
# 1. Built from source in this repo (console-web, console-worker)
|
||||
# 2. Built from official source + pinned by SHA256 digest (infra services)
|
||||
# 3. Built from source in our repos (agents, casvisor)
|
||||
#
|
||||
# NO third-party pre-built images are used.
|
||||
#
|
||||
# Usage:
|
||||
# docker compose -f deployments/compose.yml up -d
|
||||
#
|
||||
# Required env vars — set in .env or export:
|
||||
# AGENTS_API_URL, CASVISOR_API_URL, DATABASE_URL, etc.
|
||||
|
||||
x-hanzo-env: &hanzo-env
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:-https://console.hanzo.ai}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:?NEXTAUTH_SECRET required}
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/postgres}
|
||||
SALT: ${SALT:?SALT required}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY required}
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: "true"
|
||||
# Optional org/project bootstrap (single-org and multi-org)
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
# Datastore
|
||||
DATASTORE_MIGRATION_URL: ${DATASTORE_MIGRATION_URL:-datastore://datastore:9000}
|
||||
DATASTORE_URL: ${DATASTORE_URL:-http://datastore:8123}
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:?DATASTORE_PASSWORD required}
|
||||
DATASTORE_CLUSTER_ENABLED: ${DATASTORE_CLUSTER_ENABLED:-false}
|
||||
# S3-compatible storage
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:?S3_SECRET required}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true"
|
||||
S3_EVENT_UPLOAD_PREFIX: "events/"
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: auto
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:?S3_SECRET required}
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: "true"
|
||||
S3_MEDIA_UPLOAD_PREFIX: "media/"
|
||||
# Redis
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: "6379"
|
||||
REDIS_AUTH: ${REDIS_AUTH:?REDIS_AUTH required}
|
||||
# Hanzo Agents + Casvisor (server-side only)
|
||||
AGENTS_API_URL: ${AGENTS_API_URL:-http://agents:8080/api/ui/v1}
|
||||
CASVISOR_API_URL: ${CASVISOR_API_URL:-http://casvisor:14000}
|
||||
|
||||
x-depends-on: &depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
|
||||
services:
|
||||
# =========================================================================
|
||||
# Application services — built from OUR source code
|
||||
# =========================================================================
|
||||
|
||||
console-web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: web/Dockerfile
|
||||
image: ghcr.io/hanzoai/console:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
<<: *depends-on
|
||||
agents:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
<<: *hanzo-env
|
||||
|
||||
console-worker:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: worker/Dockerfile
|
||||
image: ghcr.io/hanzoai/console-worker:latest
|
||||
restart: always
|
||||
depends_on: *depends-on
|
||||
environment:
|
||||
<<: *hanzo-env
|
||||
|
||||
agents:
|
||||
build:
|
||||
context: /Users/z/work/hanzo/agent
|
||||
dockerfile: deployments/docker/Dockerfile.control-plane
|
||||
image: ghcr.io/hanzoai/agent:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
environment:
|
||||
AGENTS_PORT: "8080"
|
||||
AGENTS_STORAGE_MODE: postgresql
|
||||
AGENTS_DATABASE_URL: ${AGENTS_DATABASE_URL:-postgresql://agents:agents@postgres:5432/agents?sslmode=disable}
|
||||
GIN_MODE: release
|
||||
LOG_LEVEL: info
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
casvisor:
|
||||
build:
|
||||
context: /Users/z/work/cas/casvisor
|
||||
dockerfile: Dockerfile
|
||||
target: STANDARD
|
||||
image: ghcr.io/hanzoai/casvisor:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "127.0.0.1:14000:14000"
|
||||
environment:
|
||||
CASVISOR_DB_DRIVER: postgres
|
||||
CASVISOR_DB_CONN: ${CASVISOR_DB_URL:-postgresql://casvisor:casvisor@postgres:5432/casvisor?sslmode=disable}
|
||||
|
||||
# =========================================================================
|
||||
# Infrastructure services — built from official source, pinned digests
|
||||
# =========================================================================
|
||||
|
||||
postgres:
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
TZ: UTC
|
||||
PGTZ: UTC
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
datastore:
|
||||
build:
|
||||
context: images
|
||||
dockerfile: Dockerfile.datastore
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
restart: always
|
||||
user: "101:101"
|
||||
environment:
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:?DATASTORE_PASSWORD required}
|
||||
volumes:
|
||||
- datastore_data:/var/lib/datastore
|
||||
- datastore_logs:/var/log/datastore
|
||||
healthcheck:
|
||||
# Verify BOTH HTTP (8123) and native protocol (9000) are ready.
|
||||
# The native protocol lags behind HTTP; migrations use port 9000.
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8123/ping && datastore client --user ${DATASTORE_USER:-hanzo} --password ${DATASTORE_PASSWORD:-hanzo} --port 9000 --query 'SELECT 1' > /dev/null 2>&1"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 10s
|
||||
|
||||
s3:
|
||||
build:
|
||||
context: images
|
||||
dockerfile: Dockerfile.minio
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
restart: always
|
||||
entrypoint: sh
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD required}
|
||||
volumes:
|
||||
- s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 3s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
build:
|
||||
context: images
|
||||
dockerfile: Dockerfile.redis
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:?REDIS_AUTH required}
|
||||
--maxmemory-policy noeviction
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
datastore_data:
|
||||
datastore_logs:
|
||||
s3_data:
|
||||
@@ -0,0 +1,5 @@
|
||||
# Hanzo Datastore — analytics database
|
||||
# Build: docker build -t ghcr.io/hanzoai/datastore:latest -f Dockerfile.datastore .
|
||||
# Bootstrap: pass --build-arg BASE=<upstream-24-alpine-digest> for initial build
|
||||
ARG BASE=ghcr.io/hanzoai/datastore:24-alpine
|
||||
FROM ${BASE}
|
||||
@@ -0,0 +1,2 @@
|
||||
# S3-compatible storage — Hanzo S3 image (MinIO-based)
|
||||
FROM ghcr.io/hanzoai/s3:latest
|
||||
@@ -0,0 +1,5 @@
|
||||
# PostgreSQL 17 — rebuilt from official source, pinned by digest
|
||||
# To update: docker pull postgres:17-alpine && docker inspect --format='{{index .RepoDigests 0}}' postgres:17-alpine
|
||||
FROM postgres:17-alpine@sha256:bb377b7239d2774ac8cc76f481596ce96c5a6b5e9d141f6d0a0ee371a6e7c0f2
|
||||
# No modifications — just pinning the digest to prevent supply chain attacks.
|
||||
# All extensions and configs are applied via init scripts at runtime.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Redis 7 — rebuilt from official source, pinned by digest
|
||||
# To update: docker pull redis:7-alpine && docker inspect --format='{{index .RepoDigests 0}}' redis:7-alpine
|
||||
FROM redis:7-alpine@sha256:02f2cc4882f8bf87c79a220ac958f58c700bdec0dfb9b9ea61b62fb0e8f1bfcf
|
||||
+75
-63
@@ -1,50 +1,55 @@
|
||||
services:
|
||||
langfuse-web:
|
||||
hanzo-web:
|
||||
build:
|
||||
dockerfile: ./web/Dockerfile
|
||||
context: .
|
||||
args:
|
||||
- NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=${NEXT_PUBLIC_LANGFUSE_CLOUD_REGION}
|
||||
depends_on: &langfuse-depends-on
|
||||
- NEXT_PUBLIC_HANZO_CLOUD_REGION=${NEXT_PUBLIC_HANZO_CLOUD_REGION}
|
||||
depends_on: &hanzo-depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment: &langfuse-web-env
|
||||
environment: &hanzo-web-env
|
||||
# Bind to all interfaces so health checks via localhost work in containers
|
||||
HOSTNAME: "0.0.0.0"
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/postgres}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-mysecret}
|
||||
SALT: ${SALT:-mysalt}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # generate via `openssl rand -hex 32`
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: ${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||
LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-}
|
||||
LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-}
|
||||
LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-}
|
||||
LANGFUSE_INIT_PROJECT_NAME: ${LANGFUSE_INIT_PROJECT_NAME:-}
|
||||
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:-}
|
||||
LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:-}
|
||||
LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-}
|
||||
LANGFUSE_INIT_USER_NAME: ${LANGFUSE_INIT_USER_NAME:-}
|
||||
LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-}
|
||||
CLICKHOUSE_MIGRATION_URL: ${CLICKHOUSE_MIGRATION_URL:-clickhouse://clickhouse:9000}
|
||||
CLICKHOUSE_URL: ${CLICKHOUSE_URL:-http://clickhouse:8123}
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
|
||||
CLICKHOUSE_CLUSTER_ENABLED: ${CLICKHOUSE_CLUSTER_ENABLED:-false}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: ${LANGFUSE_S3_EVENT_UPLOAD_BUCKET:-langfuse}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION: ${LANGFUSE_S3_EVENT_UPLOAD_REGION:-us-east-1}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: ${LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT:-http://minio:9000}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_PREFIX: ${LANGFUSE_S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
DATASTORE_MIGRATION_URL: ${DATASTORE_MIGRATION_URL:-datastore://hanzo:hanzo@datastore:9000}
|
||||
DATASTORE_URL: ${DATASTORE_URL:-http://datastore:8123}
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
DATASTORE_CLUSTER_ENABLED: ${DATASTORE_CLUSTER_ENABLED:-false}
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-us-east-1}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret}
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret}
|
||||
@@ -54,54 +59,61 @@ services:
|
||||
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/public/health"]
|
||||
interval: 30s
|
||||
# Use node http module — curl/wget may be absent or broken in node:24-alpine
|
||||
test: ["CMD", "node", "-e", "const h=require('http');h.get('http://localhost:3000/api/public/health',{timeout:5000},r=>{r.resume();process.exit(r.statusCode===200?0:1)}).on('error',()=>process.exit(1))"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
retries: 18
|
||||
start_period: 60s
|
||||
|
||||
langfuse-worker:
|
||||
hanzo-worker:
|
||||
build:
|
||||
dockerfile: ./worker/Dockerfile
|
||||
context: .
|
||||
args:
|
||||
- NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=${NEXT_PUBLIC_LANGFUSE_CLOUD_REGION}
|
||||
depends_on: *langfuse-depends-on
|
||||
- NEXT_PUBLIC_HANZO_CLOUD_REGION=${NEXT_PUBLIC_HANZO_CLOUD_REGION}
|
||||
depends_on: *hanzo-depends-on
|
||||
ports:
|
||||
- "3030:3030"
|
||||
environment:
|
||||
<<: *langfuse-web-env
|
||||
<<: *hanzo-web-env
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3030/api/health"]
|
||||
interval: 30s
|
||||
# Use node http module — curl/wget may be absent or broken in node:24-alpine
|
||||
test: ["CMD", "node", "-e", "const h=require('http');h.get('http://localhost:3030/api/health',{timeout:5000},r=>{r.resume();process.exit(r.statusCode===200?0:1)}).on('error',()=>process.exit(1))"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
retries: 18
|
||||
start_period: 60s
|
||||
|
||||
clickhouse:
|
||||
image: docker.io/clickhouse/clickhouse-server
|
||||
user: "101:101"
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:26
|
||||
environment:
|
||||
CLICKHOUSE_DB: default
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
volumes:
|
||||
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||
- hanzo_datastore_data:/var/lib/hanzo-datastore
|
||||
- hanzo_datastore_logs:/var/log/hanzo-datastore-server
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
depends_on:
|
||||
- postgres
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
# Verify BOTH HTTP (8123) and native protocol (9000) are ready.
|
||||
# The native protocol lags behind HTTP; migrations use port 9000.
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8123/ping && datastore client --user ${DATASTORE_USER:-hanzo} --password ${DATASTORE_PASSWORD:-hanzo} --port 9000 --query 'SELECT 1' > /dev/null 2>&1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
|
||||
minio:
|
||||
image: cgr.dev/chainguard/minio
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
entrypoint: sh
|
||||
# create the 'langfuse' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret}
|
||||
@@ -109,16 +121,16 @@ services:
|
||||
- "9090:9000"
|
||||
- "9091:9001"
|
||||
volumes:
|
||||
- langfuse_minio_data:/data
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
@@ -132,7 +144,7 @@ services:
|
||||
retries: 10
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -148,14 +160,14 @@ services:
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
langfuse_postgres_data:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_data:
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_logs:
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
langfuse_minio_data:
|
||||
hanzo_s3_data:
|
||||
driver: local
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
services:
|
||||
clickhouse:
|
||||
image: docker.io/clickhouse/clickhouse-server:24.3
|
||||
user: "101:101"
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
environment:
|
||||
CLICKHOUSE_DB: default
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
volumes:
|
||||
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||
- hanzo_datastore_data:/var/lib/hanzo-datastore
|
||||
- hanzo_datastore_logs:/var/log/hanzo-datastore-server
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
@@ -21,24 +20,24 @@ services:
|
||||
ports:
|
||||
- "10000:10000"
|
||||
volumes:
|
||||
- langfuse_azurite_data:/data
|
||||
- hanzo_azurite_data:/data
|
||||
|
||||
minio:
|
||||
image: cgr.dev/chainguard/minio
|
||||
container_name: ${MINIO_CONTAINER_NAME:-langfuse-minio}
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
container_name: ${S3_CONTAINER_NAME:-hanzo-s3}
|
||||
entrypoint: sh
|
||||
# create the 'langfuse' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret}
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${MINIO_API_PORT:-9090}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${MINIO_CONSOLE_PORT:-9091}:9001
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_API_PORT:-9090}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_CONSOLE_PORT:-9091}:9001
|
||||
volumes:
|
||||
- langfuse_minio_data:/data
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -47,7 +46,7 @@ services:
|
||||
- default
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7.2.4
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
@@ -56,7 +55,7 @@ services:
|
||||
- 6379:6379
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -73,17 +72,17 @@ services:
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
langfuse_postgres_data:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_data:
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_logs:
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
langfuse_azurite_data:
|
||||
hanzo_azurite_data:
|
||||
driver: local
|
||||
langfuse_minio_data:
|
||||
name: ${MINIO_VOLUME_NAME:-langfuse_minio_data}
|
||||
hanzo_s3_data:
|
||||
name: ${S3_VOLUME_NAME:-hanzo_s3_data}
|
||||
driver: local
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
services:
|
||||
clickhouse:
|
||||
image: docker.io/clickhouse/clickhouse-server:24.3
|
||||
user: "101:101"
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
environment:
|
||||
CLICKHOUSE_DB: default
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
volumes:
|
||||
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||
- hanzo_datastore_data:/var/lib/hanzo-datastore
|
||||
- hanzo_datastore_logs:/var/log/hanzo-datastore-server
|
||||
ports:
|
||||
- 127.0.0.1:8123:8123
|
||||
- 127.0.0.1:9000:9000
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
minio:
|
||||
image: cgr.dev/chainguard/minio
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
entrypoint: sh
|
||||
# create the 'langfuse' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret}
|
||||
@@ -27,16 +26,16 @@ services:
|
||||
- 127.0.0.1:9090:9000
|
||||
- 127.0.0.1:9091:9001
|
||||
volumes:
|
||||
- langfuse_minio_data:/data
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -53,7 +52,7 @@ services:
|
||||
ports:
|
||||
- 127.0.0.1:5432:5432
|
||||
volumes:
|
||||
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
# Redis Cluster. Requires a Unix host to work for network_mode: host. I.e. tests will fail on windows and mac with this setup.
|
||||
redis-node-0:
|
||||
@@ -126,13 +125,13 @@ services:
|
||||
REDIS_CLUSTER_CREATOR: yes
|
||||
|
||||
volumes:
|
||||
langfuse_postgres_data:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_data:
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_logs:
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
langfuse_minio_data:
|
||||
hanzo_s3_data:
|
||||
driver: local
|
||||
redis-cluster_data-0:
|
||||
driver: local
|
||||
|
||||
+46
-36
@@ -1,41 +1,46 @@
|
||||
services:
|
||||
clickhouse:
|
||||
# Upgrade from 24.3 to check behaviour on new events table.
|
||||
# Unit tests still verify 24.3 behaviour using -azure and -redis-cluster configs.
|
||||
image: docker.io/clickhouse/clickhouse-server:25.8
|
||||
user: "101:101"
|
||||
container_name: ${CLICKHOUSE_CONTAINER_NAME:-langfuse-clickhouse}
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:26
|
||||
container_name: ${DATASTORE_CONTAINER_NAME:-hanzo-datastore}
|
||||
environment:
|
||||
CLICKHOUSE_DB: default
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse}
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo}
|
||||
volumes:
|
||||
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||
- hanzo_datastore_data:/var/lib/hanzo-datastore
|
||||
- hanzo_datastore_logs:/var/log/hanzo-datastore-server
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${CLICKHOUSE_HTTP_PORT:-8123}:8123
|
||||
- ${HOST_IP:-127.0.0.1}:${CLICKHOUSE_NATIVE_PORT:-9000}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${DATASTORE_HTTP_PORT:-8123}:8123
|
||||
- ${HOST_IP:-127.0.0.1}:${DATASTORE_NATIVE_PORT:-9000}:9000
|
||||
healthcheck:
|
||||
# Verify BOTH HTTP (8123) and native protocol (9000) are ready.
|
||||
# The native protocol lags behind HTTP; migrations use port 9000.
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8123/ping && datastore client --user ${DATASTORE_USER:-hanzo} --password ${DATASTORE_PASSWORD:-hanzo} --port 9000 --query 'SELECT 1' > /dev/null 2>&1"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 10s
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- default
|
||||
|
||||
minio:
|
||||
image: cgr.dev/chainguard/minio
|
||||
container_name: ${MINIO_CONTAINER_NAME:-langfuse-minio}
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
container_name: ${S3_CONTAINER_NAME:-hanzo-s3}
|
||||
entrypoint: sh
|
||||
# create the 'langfuse' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret}
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${MINIO_API_PORT:-9090}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${MINIO_CONSOLE_PORT:-9091}:9001
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_API_PORT:-9090}:9000
|
||||
- ${HOST_IP:-127.0.0.1}:${S3_CONSOLE_PORT:-9091}:9001
|
||||
volumes:
|
||||
- langfuse_minio_data:/data
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -44,20 +49,25 @@ services:
|
||||
- default
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7.2.4
|
||||
container_name: ${REDIS_CONTAINER_NAME:-langfuse-redis}
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
container_name: ${REDIS_CONTAINER_NAME:-hanzo-redis}
|
||||
restart: always
|
||||
command: >
|
||||
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||
--maxmemory-policy noeviction
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${REDIS_HOST_PORT:-6379}:6379
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 3s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
networks:
|
||||
- default
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
container_name: ${POSTGRES_CONTAINER_NAME:-langfuse-postgres}
|
||||
image: postgres:18-alpine
|
||||
container_name: ${POSTGRES_CONTAINER_NAME:-hanzo-postgres}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -74,25 +84,25 @@ services:
|
||||
ports:
|
||||
- ${HOST_IP:-127.0.0.1}:${POSTGRES_HOST_PORT:-5432}:5432
|
||||
volumes:
|
||||
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- default
|
||||
|
||||
volumes:
|
||||
langfuse_postgres_data:
|
||||
name: ${POSTGRES_VOLUME_NAME:-langfuse_postgres_data}
|
||||
hanzo_postgres_data:
|
||||
name: ${POSTGRES_VOLUME_NAME:-hanzo_postgres_data}
|
||||
driver: local
|
||||
langfuse_clickhouse_data:
|
||||
name: ${CLICKHOUSE_DATA_VOLUME_NAME:-langfuse_clickhouse_data}
|
||||
hanzo_datastore_data:
|
||||
name: ${DATASTORE_DATA_VOLUME_NAME:-hanzo_datastore_data}
|
||||
driver: local
|
||||
langfuse_clickhouse_logs:
|
||||
name: ${CLICKHOUSE_LOGS_VOLUME_NAME:-langfuse_clickhouse_logs}
|
||||
hanzo_datastore_logs:
|
||||
name: ${DATASTORE_LOGS_VOLUME_NAME:-hanzo_datastore_logs}
|
||||
driver: local
|
||||
langfuse_minio_data:
|
||||
name: ${MINIO_VOLUME_NAME:-langfuse_minio_data}
|
||||
hanzo_s3_data:
|
||||
name: ${S3_VOLUME_NAME:-hanzo_s3_data}
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: ${DOCKER_NETWORK_NAME:-langfuse-network}
|
||||
name: ${DOCKER_NETWORK_NAME:-hanzo-network}
|
||||
driver: bridge
|
||||
|
||||
+81
-77
@@ -1,61 +1,61 @@
|
||||
# Make sure to update the credential placeholders with your own secrets.
|
||||
# We mark them with # CHANGEME in the file below.
|
||||
# In addition, we recommend to restrict inbound traffic on the host to langfuse-web (port 3000) and minio (port 9090) only.
|
||||
# In addition, we recommend to restrict inbound traffic on the host to hanzo-web (port 3000) and s3 (port 9090) only.
|
||||
# All other components are bound to localhost (127.0.0.1) to only accept connections from the local machine.
|
||||
# External connections from other machines will not be able to reach these services directly.
|
||||
services:
|
||||
langfuse-worker:
|
||||
image: docker.io/langfuse/langfuse-worker:3
|
||||
hanzo-worker:
|
||||
image: docker.io/hanzo/hanzo-worker:3
|
||||
restart: always
|
||||
depends_on: &langfuse-depends-on
|
||||
depends_on: &hanzo-depends-on
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
s3:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
datastore:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- 127.0.0.1:3030:3030
|
||||
environment: &langfuse-worker-env
|
||||
environment: &hanzo-worker-env
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/postgres} # CHANGEME
|
||||
SALT: ${SALT:-mysalt} # CHANGEME
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # CHANGEME: generate via `openssl rand -hex 32`
|
||||
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: ${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||
CLICKHOUSE_MIGRATION_URL: ${CLICKHOUSE_MIGRATION_URL:-clickhouse://clickhouse:9000}
|
||||
CLICKHOUSE_URL: ${CLICKHOUSE_URL:-http://clickhouse:8123}
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
|
||||
CLICKHOUSE_CLUSTER_ENABLED: ${CLICKHOUSE_CLUSTER_ENABLED:-false}
|
||||
LANGFUSE_USE_AZURE_BLOB: ${LANGFUSE_USE_AZURE_BLOB:-false}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: ${LANGFUSE_S3_EVENT_UPLOAD_BUCKET:-langfuse}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_REGION: ${LANGFUSE_S3_EVENT_UPLOAD_REGION:-auto}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: ${LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT:-http://minio:9000}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
LANGFUSE_S3_EVENT_UPLOAD_PREFIX: ${LANGFUSE_S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: ${LANGFUSE_S3_MEDIA_UPLOAD_BUCKET:-langfuse}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_REGION: ${LANGFUSE_S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT:-http://localhost:9090}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: ${LANGFUSE_S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENABLED: ${LANGFUSE_S3_BATCH_EXPORT_ENABLED:-false}
|
||||
LANGFUSE_S3_BATCH_EXPORT_BUCKET: ${LANGFUSE_S3_BATCH_EXPORT_BUCKET:-langfuse}
|
||||
LANGFUSE_S3_BATCH_EXPORT_PREFIX: ${LANGFUSE_S3_BATCH_EXPORT_PREFIX:-exports/}
|
||||
LANGFUSE_S3_BATCH_EXPORT_REGION: ${LANGFUSE_S3_BATCH_EXPORT_REGION:-auto}
|
||||
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_ENDPOINT:-http://minio:9000}
|
||||
LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT:-http://localhost:9090}
|
||||
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID: ${LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID:-minio}
|
||||
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY: ${LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE: ${LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE:-true}
|
||||
LANGFUSE_INGESTION_QUEUE_DELAY_MS: ${LANGFUSE_INGESTION_QUEUE_DELAY_MS:-}
|
||||
LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS: ${LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS:-}
|
||||
HANZO_ENABLE_EXPERIMENTAL_FEATURES: ${HANZO_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||
DATASTORE_MIGRATION_URL: ${DATASTORE_MIGRATION_URL:-datastore://datastore:9000}
|
||||
DATASTORE_URL: ${DATASTORE_URL:-http://datastore:8123}
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo} # CHANGEME
|
||||
DATASTORE_CLUSTER_ENABLED: ${DATASTORE_CLUSTER_ENABLED:-false}
|
||||
HANZO_USE_AZURE_BLOB: ${HANZO_USE_AZURE_BLOB:-false}
|
||||
S3_EVENT_UPLOAD_BUCKET: ${S3_EVENT_UPLOAD_BUCKET:-hanzo}
|
||||
S3_EVENT_UPLOAD_REGION: ${S3_EVENT_UPLOAD_REGION:-auto}
|
||||
S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
S3_EVENT_UPLOAD_ENDPOINT: ${S3_EVENT_UPLOAD_ENDPOINT:-http://s3:9000}
|
||||
S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_EVENT_UPLOAD_PREFIX: ${S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||
S3_MEDIA_UPLOAD_BUCKET: ${S3_MEDIA_UPLOAD_BUCKET:-hanzo}
|
||||
S3_MEDIA_UPLOAD_REGION: ${S3_MEDIA_UPLOAD_REGION:-auto}
|
||||
S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||
S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
S3_MEDIA_UPLOAD_ENDPOINT: ${S3_MEDIA_UPLOAD_ENDPOINT:-http://localhost:9090}
|
||||
S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||
S3_MEDIA_UPLOAD_PREFIX: ${S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||
S3_BATCH_EXPORT_ENABLED: ${S3_BATCH_EXPORT_ENABLED:-false}
|
||||
S3_BATCH_EXPORT_BUCKET: ${S3_BATCH_EXPORT_BUCKET:-hanzo}
|
||||
S3_BATCH_EXPORT_PREFIX: ${S3_BATCH_EXPORT_PREFIX:-exports/}
|
||||
S3_BATCH_EXPORT_REGION: ${S3_BATCH_EXPORT_REGION:-auto}
|
||||
S3_BATCH_EXPORT_ENDPOINT: ${S3_BATCH_EXPORT_ENDPOINT:-http://s3:9000}
|
||||
S3_BATCH_EXPORT_EXTERNAL_ENDPOINT: ${S3_BATCH_EXPORT_EXTERNAL_ENDPOINT:-http://localhost:9090}
|
||||
S3_BATCH_EXPORT_ACCESS_KEY_ID: ${S3_BATCH_EXPORT_ACCESS_KEY_ID:-minio}
|
||||
S3_BATCH_EXPORT_SECRET_ACCESS_KEY: ${S3_BATCH_EXPORT_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||
S3_BATCH_EXPORT_FORCE_PATH_STYLE: ${S3_BATCH_EXPORT_FORCE_PATH_STYLE:-true}
|
||||
HANZO_INGESTION_QUEUE_DELAY_MS: ${HANZO_INGESTION_QUEUE_DELAY_MS:-}
|
||||
HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS: ${HANZO_INGESTION_DATASTORE_WRITE_INTERVAL_MS:-}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_AUTH: ${REDIS_AUTH:-myredissecret} # CHANGEME
|
||||
@@ -66,52 +66,56 @@ services:
|
||||
EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-}
|
||||
SMTP_CONNECTION_URL: ${SMTP_CONNECTION_URL:-}
|
||||
|
||||
langfuse-web:
|
||||
image: docker.io/langfuse/langfuse:3
|
||||
hanzo-web:
|
||||
image: docker.io/hanzo/hanzo:3
|
||||
restart: always
|
||||
depends_on: *langfuse-depends-on
|
||||
depends_on: *hanzo-depends-on
|
||||
ports:
|
||||
- 3000:3000
|
||||
environment:
|
||||
<<: *langfuse-worker-env
|
||||
<<: *hanzo-worker-env
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-mysecret} # CHANGEME
|
||||
LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-}
|
||||
LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-}
|
||||
LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-}
|
||||
LANGFUSE_INIT_PROJECT_NAME: ${LANGFUSE_INIT_PROJECT_NAME:-}
|
||||
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:-}
|
||||
LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:-}
|
||||
LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-}
|
||||
LANGFUSE_INIT_USER_NAME: ${LANGFUSE_INIT_USER_NAME:-}
|
||||
LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-}
|
||||
INIT_ORG_ID: ${INIT_ORG_ID:-}
|
||||
INIT_ORG_NAME: ${INIT_ORG_NAME:-}
|
||||
INIT_ORG_IDS: ${INIT_ORG_IDS:-}
|
||||
INIT_ORG_NAMES: ${INIT_ORG_NAMES:-}
|
||||
INIT_PROJECT_ID: ${INIT_PROJECT_ID:-}
|
||||
INIT_PROJECT_ORG_ID: ${INIT_PROJECT_ORG_ID:-}
|
||||
INIT_PROJECT_NAME: ${INIT_PROJECT_NAME:-}
|
||||
INIT_PROJECT_PUBLIC_KEY: ${INIT_PROJECT_PUBLIC_KEY:-}
|
||||
INIT_PROJECT_SECRET_KEY: ${INIT_PROJECT_SECRET_KEY:-}
|
||||
INIT_USER_EMAIL: ${INIT_USER_EMAIL:-}
|
||||
INIT_USER_NAME: ${INIT_USER_NAME:-}
|
||||
INIT_USER_PASSWORD: ${INIT_USER_PASSWORD:-}
|
||||
|
||||
clickhouse:
|
||||
image: docker.io/clickhouse/clickhouse-server
|
||||
datastore:
|
||||
image: ghcr.io/hanzoai/datastore:latest
|
||||
restart: always
|
||||
user: "101:101"
|
||||
environment:
|
||||
CLICKHOUSE_DB: default
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
|
||||
DATASTORE_DB: default
|
||||
DATASTORE_USER: ${DATASTORE_USER:-hanzo}
|
||||
DATASTORE_PASSWORD: ${DATASTORE_PASSWORD:-hanzo} # CHANGEME
|
||||
volumes:
|
||||
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||
- hanzo_datastore_data:/var/lib/hanzo-datastore
|
||||
- hanzo_datastore_logs:/var/log/hanzo-datastore-server
|
||||
ports:
|
||||
- 127.0.0.1:8123:8123
|
||||
- 127.0.0.1:9000:9000
|
||||
healthcheck:
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||
# Verify BOTH HTTP (8123) and native protocol (9000) are ready.
|
||||
# The native protocol lags behind HTTP; migrations use port 9000.
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8123/ping && datastore client --user ${DATASTORE_USER:-hanzo} --password ${DATASTORE_PASSWORD:-hanzo} --port 9000 --query 'SELECT 1' > /dev/null 2>&1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 1s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 10s
|
||||
|
||||
minio:
|
||||
image: cgr.dev/chainguard/minio
|
||||
s3:
|
||||
image: ghcr.io/hanzoai/s3:latest
|
||||
restart: always
|
||||
entrypoint: sh
|
||||
# create the 'langfuse' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||
# create the 'hanzo' bucket before starting the service
|
||||
command: -c 'mkdir -p /data/hanzo && minio server --address ":9000" --console-address ":9001" /data'
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret} # CHANGEME
|
||||
@@ -119,16 +123,16 @@ services:
|
||||
- 9090:9000
|
||||
- 127.0.0.1:9091:9001
|
||||
volumes:
|
||||
- langfuse_minio_data:/data
|
||||
- hanzo_s3_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 1s
|
||||
|
||||
redis:
|
||||
image: docker.io/redis:7
|
||||
image: ghcr.io/hanzoai/kv:latest
|
||||
restart: always
|
||||
# CHANGEME: row below to secure redis password
|
||||
command: >
|
||||
@@ -143,7 +147,7 @@ services:
|
||||
retries: 10
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -159,14 +163,14 @@ services:
|
||||
ports:
|
||||
- 127.0.0.1:5432:5432
|
||||
volumes:
|
||||
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||
- hanzo_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
langfuse_postgres_data:
|
||||
hanzo_postgres_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_data:
|
||||
hanzo_datastore_data:
|
||||
driver: local
|
||||
langfuse_clickhouse_logs:
|
||||
hanzo_datastore_logs:
|
||||
driver: local
|
||||
langfuse_minio_data:
|
||||
hanzo_s3_data:
|
||||
driver: local
|
||||
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
---
|
||||
title: Hanzo Console
|
||||
description: LLM engineering platform for observability, prompt management, evaluations, datasets, cost tracking, and session replay with distributed tracing.
|
||||
---
|
||||
|
||||
# Hanzo Console
|
||||
|
||||
Hanzo Console is the LLM engineering platform at the center of the Hanzo AI stack. It provides full-lifecycle observability for AI applications: distributed tracing, prompt management, evaluation pipelines, dataset curation, cost tracking, session replay, and A/B testing. All Hanzo services emit telemetry to Console, giving operators and developers a single pane of glass over every LLM call, agent step, and tool invocation.
|
||||
|
||||
**Dashboard:** `console.hanzo.ai`
|
||||
**API:** `api.hanzo.ai/v1/console/*`
|
||||
|
||||
## Features
|
||||
|
||||
- **Distributed Tracing** -- OpenTelemetry-compatible trace ingestion with span-level detail for LLM calls, retrievals, tool use, and agent chains
|
||||
- **Prompt Management** -- Version-controlled prompt templates with variable interpolation, rollback, and deployment slots
|
||||
- **Evaluation Pipelines** -- Automated scoring with built-in and custom evaluators (LLM-as-judge, regex, cosine similarity, human review)
|
||||
- **Dataset Management** -- Curate, version, and export datasets for fine-tuning and evaluation from production traces
|
||||
- **Cost Tracking** -- Per-model, per-project, and per-user cost attribution with budget alerts
|
||||
- **Session Replay** -- Reconstruct full user sessions across multiple traces and generations
|
||||
- **A/B Testing** -- Split traffic across prompt variants and compare metrics side-by-side
|
||||
- **Multi-Org Support** -- Organization isolation via Hanzo IAM SSO; switch between orgs in one click
|
||||
- **OpenAI SDK Compatible** -- Drop-in wrapper; change one line to start tracing existing OpenAI or Hanzo SDK calls
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
+------------------------------------------------------------------+
|
||||
| console.hanzo.ai (Next.js 15, :3001) |
|
||||
+------------------------------------------------------------------+
|
||||
| Traces Explorer | Prompts Manager | Evals Pipeline | Datasets |
|
||||
| | |
|
||||
| Console API |
|
||||
| +-------------+-------------+ |
|
||||
| PostgreSQL Datastore Redis --> Worker |
|
||||
| (metadata) (analytics) (queues) (MQ 27+) |
|
||||
+------------------------------------------------------------------+
|
||||
|
||||
Ingestion: Your App --> SDK/HTTP --> api.hanzo.ai/v1/console/* --> Datastore
|
||||
```
|
||||
|
||||
| Component | Image | Port | Purpose |
|
||||
|-----------|-------|------|---------|
|
||||
| **Web** | `hanzoai/console:latest` | 3001 | Next.js 15 dashboard and API |
|
||||
| **Worker** | `ghcr.io/hanzoai/console-worker:latest` | -- | Hanzo MQ processor (27+ queues) |
|
||||
| **Datastore** | In-cluster | 9000 | Analytics storage (traces, scores, costs) |
|
||||
| **PostgreSQL** | In-cluster | 5432 | Metadata (prompts, datasets, projects, users) |
|
||||
| **Redis** | In-cluster | 6379 | Job queues, caching, pub/sub |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Get an API Key
|
||||
|
||||
Sign in at `console.hanzo.ai` with Hanzo IAM SSO. Navigate to **Settings > API Keys** and create a new key. Keys are scoped to a project and prefixed with `hk-`.
|
||||
|
||||
### 2. Send Your First Trace
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.hanzo.ai/v1/console/ingestion \
|
||||
-H "Authorization: Bearer hk-your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"batch": [
|
||||
{
|
||||
"type": "trace-create",
|
||||
"id": "trace-001",
|
||||
"timestamp": "2026-02-22T00:00:00Z",
|
||||
"body": {
|
||||
"name": "my-first-trace",
|
||||
"input": {"query": "What is Hanzo Console?"},
|
||||
"output": {"answer": "An LLM engineering platform."},
|
||||
"metadata": {"env": "production"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "generation-create",
|
||||
"id": "gen-001",
|
||||
"timestamp": "2026-02-22T00:00:01Z",
|
||||
"body": {
|
||||
"traceId": "trace-001",
|
||||
"name": "llm-call",
|
||||
"model": "anthropic-claude-haiku-4.5",
|
||||
"input": [{"role": "user", "content": "What is Hanzo Console?"}],
|
||||
"output": {"role": "assistant", "content": "An LLM engineering platform."},
|
||||
"usage": {"inputTokens": 12, "outputTokens": 8}
|
||||
}
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
### 3. View in Dashboard
|
||||
|
||||
Open `console.hanzo.ai`, select your project, and click **Traces**. Your trace appears with the generation nested inside, showing latency, token usage, and cost.
|
||||
|
||||
## SDK Integration
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
from hanzoai import Hanzo
|
||||
|
||||
client = Hanzo(api_key="hk-your-api-key", trace=True)
|
||||
|
||||
# Every call is traced automatically
|
||||
response = client.chat.completions.create(
|
||||
model="anthropic-claude-haiku-4.5",
|
||||
messages=[{"role": "user", "content": "Explain distributed tracing."}],
|
||||
metadata={"session_id": "sess-abc", "user_id": "user-42"},
|
||||
)
|
||||
```
|
||||
|
||||
#### Decorator-Based Tracing
|
||||
|
||||
```python
|
||||
from hanzoai.console import observe
|
||||
|
||||
@observe()
|
||||
def my_pipeline(query: str) -> str:
|
||||
docs = retrieve(query) # span: retrieval
|
||||
answer = generate(docs) # span: generation
|
||||
return answer
|
||||
|
||||
@observe(name="generation", capture_input=True, capture_output=True)
|
||||
def generate(docs: list) -> str:
|
||||
return client.chat.completions.create(
|
||||
model="zen4-pro",
|
||||
messages=[{"role": "user", "content": str(docs)}],
|
||||
).choices[0].message.content
|
||||
```
|
||||
|
||||
#### Prompt Management
|
||||
|
||||
```python
|
||||
from hanzoai.console import get_prompt
|
||||
|
||||
prompt = get_prompt(name="qa-system", version=3)
|
||||
compiled = prompt.compile(context="Hanzo docs", question="What is Console?")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="anthropic-claude-haiku-4.5",
|
||||
messages=compiled,
|
||||
hanzo_prompt=prompt, # links generation to prompt version
|
||||
)
|
||||
```
|
||||
|
||||
### JavaScript / TypeScript
|
||||
|
||||
```typescript
|
||||
import Hanzo from '@hanzo/ai'
|
||||
|
||||
const client = new Hanzo({ apiKey: 'hk-your-api-key', trace: true })
|
||||
|
||||
const response = await client.chat.completions.create({
|
||||
model: 'anthropic-claude-haiku-4.5',
|
||||
messages: [{ role: 'user', content: 'Explain distributed tracing.' }],
|
||||
metadata: { sessionId: 'sess-abc', userId: 'user-42' },
|
||||
})
|
||||
```
|
||||
|
||||
#### Manual Spans
|
||||
|
||||
```typescript
|
||||
import { ConsoleClient } from '@hanzo/ai/console'
|
||||
|
||||
const console = new ConsoleClient({ publicKey: 'hk-your-api-key' })
|
||||
const trace = console.trace({ name: 'rag-pipeline' })
|
||||
|
||||
const retrieval = trace.span({ name: 'retrieval', input: { query } })
|
||||
const docs = await vectorSearch(query)
|
||||
retrieval.end({ output: docs })
|
||||
|
||||
const generation = trace.generation({
|
||||
name: 'llm-call',
|
||||
model: 'zen4-pro',
|
||||
input: messages,
|
||||
})
|
||||
const result = await llmCall(messages)
|
||||
generation.end({ output: result, usage: { inputTokens: 120, outputTokens: 45 } })
|
||||
```
|
||||
|
||||
### OpenAI Drop-In
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
from hanzoai.console import wrap_openai
|
||||
|
||||
openai_client = wrap_openai(OpenAI(
|
||||
api_key="your-hanzo-key",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
))
|
||||
|
||||
# All calls are now traced to Hanzo Console
|
||||
response = openai_client.chat.completions.create(
|
||||
model="openai-gpt-5-nano",
|
||||
messages=[{"role": "user", "content": "Hello!"}],
|
||||
)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
All endpoints are under `api.hanzo.ai/v1/console/`.
|
||||
|
||||
### Ingestion
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `POST` | `/ingestion` | Batch ingest traces, spans, generations, scores, events |
|
||||
|
||||
Batch event types: `trace-create`, `span-create`, `span-update`, `generation-create`, `generation-update`, `score-create`, `event-create`.
|
||||
|
||||
### Traces
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/traces` | List traces with filtering and pagination |
|
||||
| `GET` | `/traces/:id` | Get trace with all nested spans |
|
||||
|
||||
### Prompts
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/prompts` | List all prompts |
|
||||
| `GET` | `/prompts/:name` | Get prompt by name (latest or specific version) |
|
||||
| `POST` | `/prompts` | Create or update a prompt |
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.hanzo.ai/v1/console/prompts \
|
||||
-H "Authorization: Bearer hk-your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "qa-system",
|
||||
"prompt": "Answer based on context.\n\nContext: {{context}}\nQuestion: {{question}}",
|
||||
"config": {"model": "anthropic-claude-haiku-4.5", "temperature": 0.2},
|
||||
"labels": ["production"]
|
||||
}'
|
||||
```
|
||||
|
||||
### Scores
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `POST` | `/scores` | Attach a score to a trace or generation |
|
||||
| `GET` | `/scores` | List scores with filtering |
|
||||
|
||||
### Datasets
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/datasets` | List datasets |
|
||||
| `POST` | `/datasets` | Create a dataset |
|
||||
| `POST` | `/datasets/:id/items` | Add items to a dataset |
|
||||
| `POST` | `/datasets/:id/runs` | Execute an evaluation run |
|
||||
|
||||
### Sessions and Metrics
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/sessions` | List sessions |
|
||||
| `GET` | `/sessions/:id` | Get session with all traces |
|
||||
| `GET` | `/metrics/daily` | Daily aggregated metrics (cost, latency, volume) |
|
||||
| `GET` | `/metrics/usage` | Token usage breakdown by model |
|
||||
|
||||
### Evaluators
|
||||
|
||||
| Evaluator | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `llm-as-judge` | LLM | Configurable LLM scores outputs on custom criteria |
|
||||
| `cosine-similarity` | Numeric | Embedding similarity between output and reference |
|
||||
| `contains` | Boolean | Checks output contains expected substrings |
|
||||
| `regex-match` | Boolean | Matches output against regex patterns |
|
||||
| `json-validity` | Boolean | Validates JSON structure |
|
||||
| `custom` | Function | User-defined scoring via webhook |
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `DATABASE_URL` | PostgreSQL connection string |
|
||||
| `DATASTORE_URL` | Datastore connection string |
|
||||
| `REDIS_URL` | Redis connection string |
|
||||
| `NEXTAUTH_URL` | Console public URL (`https://console.hanzo.ai`) |
|
||||
| `NEXTAUTH_SECRET` | NextAuth session encryption key |
|
||||
| `IAM_CLIENT_ID` | IAM app client ID (`hanzo-console-client-id`) |
|
||||
| `IAM_CLIENT_SECRET` | IAM app client secret |
|
||||
| `IAM_SERVER_URL` | IAM OIDC issuer URL (default: `https://hanzo.id`) |
|
||||
| `SALT` | API key hashing salt |
|
||||
|
||||
Optional: `S3_EVENT_UPLOAD_ENDPOINT`, `S3_EVENT_UPLOAD_BUCKET` (`hanzo-events`), `S3_MEDIA_UPLOAD_BUCKET` (`hanzo-media`), `INIT_ORG_IDS`, `INIT_USER_EMAIL`, `INIT_PROJECT_ORG_ID`, `AGENTS_API_URL`.
|
||||
|
||||
### Datastore Migrations
|
||||
|
||||
34 migrations managed by `golang-migrate`. Database must be named `console` (not `hanzo`).
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/datastore 9000:9000 -n hanzo
|
||||
migrate -path ./migrations -database "datastore://localhost:9000/console" up
|
||||
```
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Console runs as two deployments on hanzo-k8s: **console** (2 replicas, `hanzoai/console:latest`, port 3001, health at `/api/public/health`) and **console-worker** (1 replica, `ghcr.io/hanzoai/console-worker:latest`, `imagePullSecrets: ghcr-secret`).
|
||||
|
||||
Worker processes 27+ Hanzo MQ queues: `trace-upsert`, `generation-upsert`, `score-upsert`, `event-upsert`, `dataset-run`, `prompt-cache-invalidation`, `cost-calculation`, `session-aggregation`, `export`, and more.
|
||||
|
||||
DNS: `console.hanzo.ai` and `api.hanzo.ai` both resolve to `24.199.76.156` (hanzo-k8s LB, Cloudflare proxied). The gateway routes `/console/*` to the console service.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Hanzo Console",
|
||||
"description": "LLM engineering platform for observability, prompt management, evaluations, datasets, cost tracking, and session replay with distributed tracing."
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
START NOTE
|
||||
Langfuse is an open core project. Langfuse's core
|
||||
is permissively licensed (MIT license).
|
||||
Certain parts of the periphery of Langfuse are commercially
|
||||
licensed and governed by this Enterprise License.
|
||||
For the avoidance of doubt, this license does not apply
|
||||
to the core of Langfuse as it is defined in its license in
|
||||
the directory "/LICENSE" (as opposed to this file "ee/LICENSE")
|
||||
which can be used and run without infringing the below license
|
||||
and its licensed materials.
|
||||
END NOTE
|
||||
|
||||
START OF LICENSE
|
||||
Langfuse Enterprise license (the “Enterprise License” or "EE license")
|
||||
|
||||
Copyright (c) 2023-2025 Langfuse GmbH
|
||||
|
||||
With regard to the Langfuse Enterprise Software:
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the applicable Langfuse Terms of Service, available
|
||||
at https://langfuse.com/terms (the “Enterprise Terms”), or other
|
||||
agreement governing the use of the Software, as agreed by you and Langfuse,
|
||||
and otherwise have a valid Langfuse Enterprise License.
|
||||
|
||||
Subject to the foregoing sentence, you are free to
|
||||
modify this Software and publish patches to the Software. You agree that Langfuse
|
||||
and/or its licensors (as applicable) retain all right, title and interest in and
|
||||
to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Langfuse Enterprise License. Notwithstanding the foregoing, you may copy and modify
|
||||
the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that Langfuse GmbH and/or its licensors (as applicable) retain
|
||||
all right, title and interest in and to all such modifications. You are not
|
||||
granted any other rights beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the Langfuse Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
|
||||
END OF LICENSE
|
||||
@@ -1,5 +0,0 @@
|
||||
# Enterprise Edition
|
||||
|
||||
This folder includes features that are only available in the Enterprise Edition of Langfuse and on Langfuse Cloud.
|
||||
|
||||
See [LICENSE](../LICENSE) and [docs](https://langfuse.com/docs/open-source) for more details.
|
||||
@@ -1,3 +0,0 @@
|
||||
import baseConfig from "@repo/eslint-config";
|
||||
|
||||
export default [...baseConfig];
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"name": "@langfuse/ee",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "./dist/src/index.js",
|
||||
"types": "./dist/src/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/src/index.js",
|
||||
"require": "./dist/src/index.js"
|
||||
},
|
||||
"./sso": {
|
||||
"import": "./dist/src/sso/index.js",
|
||||
"require": "./dist/src/sso/index.js"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": "24"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build:check": "tsc",
|
||||
"typecheck": "dotenv -e ../../.env -- tsgo --noEmit --skipLibCheck --incremental --tsBuildInfoFile .tsbuildinfo",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "eslint . --cache --cache-location dist/.eslintcache --max-warnings 0",
|
||||
"lint:fix": "eslint . --cache --cache-location dist/.eslintcache --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@langfuse/shared": "workspace:*",
|
||||
"@opentelemetry/api": ">=1.0.0 <1.10.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"next": "15.5.10",
|
||||
"next-auth": "^4.24.13",
|
||||
"zod": "^3.25.62"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/eslint-config": "workspace:*",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"@types/node": "^24.3.0",
|
||||
"@typescript-eslint/parser": "^8.50.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260122.3",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"prettier": "^3.6.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsc-watch": "^6.2.0",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { env } from "../env";
|
||||
|
||||
export const isEeAvailable: boolean =
|
||||
env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION !== undefined ||
|
||||
env.LANGFUSE_EE_LICENSE_KEY !== undefined;
|
||||
@@ -1,9 +0,0 @@
|
||||
import { z } from "zod/v4";
|
||||
import { removeEmptyEnvVariables } from "@langfuse/shared";
|
||||
|
||||
const EnvSchema = z.object({
|
||||
NEXT_PUBLIC_LANGFUSE_CLOUD_REGION: z.string().optional(),
|
||||
LANGFUSE_EE_LICENSE_KEY: z.string().optional(),
|
||||
});
|
||||
|
||||
export const env = EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "@repo/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "NodeNext",
|
||||
"module": "NodeNext",
|
||||
"lib": ["es2023"],
|
||||
"outDir": "./dist",
|
||||
"types": ["node"],
|
||||
"target": "es2024",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
name: langfuse
|
||||
name: hanzo
|
||||
error-discrimination:
|
||||
strategy: status-code
|
||||
auth: bearer
|
||||
|
||||
@@ -9,7 +9,7 @@ groups:
|
||||
# url: npm.buildwithfern.com
|
||||
# package-name: "@finto-fern/react-client"
|
||||
# config:
|
||||
# namespaceExport: Langfuse
|
||||
# namespaceExport: Hanzo
|
||||
# allowCustomFetcher: true
|
||||
- name: fernapi/fern-openapi
|
||||
version: 0.1.7
|
||||
@@ -17,5 +17,5 @@ groups:
|
||||
location: local-file-system
|
||||
path: ../../../web/public/generated/api-client
|
||||
config:
|
||||
namespaceExport: Langfuse
|
||||
namespaceExport: Hanzo
|
||||
allowCustomFetcher: true
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: langfuse-organizations
|
||||
name: hanzo-organizations
|
||||
docs: |
|
||||
## General Notes
|
||||
|
||||
This admin API is only available on self-hosted instances, not on Langfuse Cloud.
|
||||
This admin API is only available on self-hosted instances, not on Hanzo Cloud.
|
||||
An administrator must set the `ADMIN_API_KEY` environment variable to use this API.
|
||||
|
||||
## Authentication
|
||||
@@ -12,13 +12,13 @@ docs: |
|
||||
|
||||
## Exports
|
||||
|
||||
- OpenAPI spec: https://cloud.langfuse.com/generated/organizations-api/openapi.yml
|
||||
- Postman collection: https://cloud.langfuse.com/generated/organizations-postman/collection.json
|
||||
- OpenAPI spec: https://cloud.hanzo.com/generated/organizations-api/openapi.yml
|
||||
- Postman collection: https://cloud.hanzo.com/generated/organizations-postman/collection.json
|
||||
|
||||
## Looking for the Langfuse API?
|
||||
## Looking for the Hanzo API?
|
||||
|
||||
Are you looking for the full Langfuse API?
|
||||
Check out our [API reference](https://api.reference.langfuse.com/#overview).
|
||||
Are you looking for the full Hanzo API?
|
||||
Check out our [API reference](https://api.reference.hanzo.com/#overview).
|
||||
|
||||
error-discrimination:
|
||||
strategy: status-code
|
||||
|
||||
@@ -8,7 +8,7 @@ groups:
|
||||
location: local-file-system
|
||||
path: ../../../web/public/generated/organizations-api
|
||||
config:
|
||||
namespaceExport: Langfuse
|
||||
namespaceExport: Hanzo
|
||||
allowCustomFetcher: true
|
||||
- name: fernapi/fern-postman
|
||||
version: 0.0.45
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
name: langfuse
|
||||
name: hanzo
|
||||
docs: |
|
||||
## Authentication
|
||||
|
||||
Authenticate with the API using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication), get API keys in the project settings:
|
||||
|
||||
- username: Langfuse Public Key
|
||||
- password: Langfuse Secret Key
|
||||
- username: Hanzo Public Key
|
||||
- password: Hanzo Secret Key
|
||||
|
||||
## Exports
|
||||
|
||||
- OpenAPI spec: https://cloud.langfuse.com/generated/api/openapi.yml
|
||||
- Postman collection: https://cloud.langfuse.com/generated/postman/collection.json
|
||||
- OpenAPI spec: https://cloud.hanzo.ai/generated/api/openapi.yml
|
||||
- Postman collection: https://cloud.hanzo.ai/generated/postman/collection.json
|
||||
|
||||
error-discrimination:
|
||||
strategy: status-code
|
||||
@@ -24,6 +24,6 @@ errors:
|
||||
- commons.MethodNotAllowedError
|
||||
- commons.NotFoundError
|
||||
headers:
|
||||
X-Langfuse-Sdk-Name: optional<string>
|
||||
X-Langfuse-Sdk-Version: optional<string>
|
||||
X-Langfuse-Public-Key: optional<string>
|
||||
X-Hanzo-Sdk-Name: optional<string>
|
||||
X-Hanzo-Sdk-Version: optional<string>
|
||||
X-Hanzo-Public-Key: optional<string>
|
||||
|
||||
@@ -42,7 +42,7 @@ service:
|
||||
path-parameters:
|
||||
commentId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of a comment
|
||||
docs: The unique hanzo identifier of a comment
|
||||
response: commons.Comment
|
||||
types:
|
||||
CreateCommentRequest:
|
||||
@@ -66,7 +66,7 @@ types:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
docs: The id of the created object in Langfuse
|
||||
docs: The id of the created object in HanzoCloud
|
||||
GetCommentsResponse:
|
||||
properties:
|
||||
data: list<commons.Comment>
|
||||
|
||||
@@ -41,13 +41,13 @@ types:
|
||||
docs: Public traces are accessible via url without login
|
||||
environment:
|
||||
type: string
|
||||
docs: The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
|
||||
docs: The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'hanzo'.
|
||||
TraceWithDetails: # GET /traces
|
||||
extends: Trace
|
||||
properties:
|
||||
htmlPath:
|
||||
type: string
|
||||
docs: Path of trace in Langfuse UI
|
||||
docs: Path of trace in Hanzo Cloud UI
|
||||
latency:
|
||||
type: optional<nullable<double>>
|
||||
docs: Latency of trace in seconds
|
||||
@@ -65,7 +65,7 @@ types:
|
||||
properties:
|
||||
htmlPath:
|
||||
type: string
|
||||
docs: Path of trace in Langfuse UI
|
||||
docs: Path of trace in Hanzo Cloud UI
|
||||
latency:
|
||||
type: optional<nullable<double>>
|
||||
docs: Latency of trace in seconds
|
||||
@@ -156,7 +156,7 @@ types:
|
||||
docs: The cost details of the observation. Key is the name of the cost metric, value is the cost in USD. The total key is the sum of all (non-total) cost metrics or the total value ingested.
|
||||
environment:
|
||||
type: string
|
||||
docs: The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
|
||||
docs: The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'hanzo'.
|
||||
|
||||
ObservationsView:
|
||||
extends: Observation
|
||||
@@ -278,7 +278,7 @@ types:
|
||||
docs: The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue.
|
||||
environment:
|
||||
type: string
|
||||
docs: The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
|
||||
docs: The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'hanzo'.
|
||||
NumericScoreV1:
|
||||
extends: BaseScoreV1
|
||||
properties:
|
||||
@@ -354,7 +354,7 @@ types:
|
||||
docs: The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue.
|
||||
environment:
|
||||
type: string
|
||||
docs: The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'.
|
||||
docs: The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'hanzo'.
|
||||
NumericScore:
|
||||
extends: BaseScore
|
||||
properties:
|
||||
@@ -554,7 +554,7 @@ types:
|
||||
tokenizerConfig:
|
||||
docs: Optional. Configuration for the selected tokenizer. Needs to be JSON. See docs for more details.
|
||||
type: unknown
|
||||
isLangfuseManaged:
|
||||
isHanzoManaged:
|
||||
type: boolean
|
||||
createdAt:
|
||||
docs: Timestamp when the model was created
|
||||
@@ -762,7 +762,7 @@ types:
|
||||
|
||||
# Utilities
|
||||
ModelUsageUnit:
|
||||
docs: Unit of usage in Langfuse
|
||||
docs: Unit of usage in HanzoCloud
|
||||
enum:
|
||||
- CHARACTERS
|
||||
- TOKENS
|
||||
|
||||
@@ -16,7 +16,7 @@ types:
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
docs: Langfuse server version
|
||||
docs: Hanzo Cloud server version
|
||||
status: string
|
||||
examples:
|
||||
- value:
|
||||
|
||||
@@ -9,21 +9,21 @@ service:
|
||||
batch:
|
||||
availability:
|
||||
status: deprecated
|
||||
message: "Use the OpenTelemetry endpoint at /api/public/otel/v1/traces instead. Learn more: https://langfuse.com/integrations/native/opentelemetry"
|
||||
message: "Use the OpenTelemetry endpoint at /api/public/otel/v1/traces instead. Learn more: https://hanzo.com/integrations/native/opentelemetry"
|
||||
docs: |
|
||||
**Legacy endpoint for batch ingestion for Langfuse Observability.**
|
||||
**Legacy endpoint for batch ingestion for Hanzo Observability.**
|
||||
|
||||
-> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://langfuse.com/integrations/native/opentelemetry
|
||||
-> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://hanzo.com/integrations/native/opentelemetry
|
||||
|
||||
Within each batch, there can be multiple events.
|
||||
Each event has a type, an id, a timestamp, metadata and a body.
|
||||
Internally, we refer to this as the "event envelope" as it tells us something about the event but not the trace.
|
||||
We use the event id within this envelope to deduplicate messages to avoid processing the same event twice, i.e. the event id should be unique per request.
|
||||
The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Langfuse App.
|
||||
The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Hanzo Cloud App.
|
||||
I.e. if you want to update a trace, you'd use the same body id, but separate event IDs.
|
||||
|
||||
Notes:
|
||||
- Introduction to data model: https://langfuse.com/docs/observability/data-model
|
||||
- Introduction to data model: https://hanzo.com/docs/observability/data-model
|
||||
- Batch sizes are limited to 3.5 MB in total. You need to adjust the number of events per batch accordingly.
|
||||
- The API does not return a 4xx status code for input errors. Instead, it responds with a 207 status code, which includes a list of the encountered errors.
|
||||
method: POST
|
||||
@@ -37,7 +37,7 @@ service:
|
||||
docs: "Batch of tracing events to be ingested. Discriminated by attribute `type`."
|
||||
metadata:
|
||||
type: optional<unknown>
|
||||
docs: Optional. Metadata field used by the Langfuse SDKs for debugging.
|
||||
docs: Optional. Metadata field used by the Hanzo Cloud SDKs for debugging.
|
||||
response:
|
||||
type: IngestionResponse
|
||||
status-code: 207
|
||||
@@ -134,7 +134,7 @@ types:
|
||||
|
||||
sdk-log:
|
||||
type: SDKLogEvent
|
||||
docs: Langfuse SDKs only, used for debugging purposes.
|
||||
docs: Hanzo Cloud SDKs only, used for debugging purposes.
|
||||
|
||||
# both are legacy
|
||||
observation-create:
|
||||
@@ -352,7 +352,7 @@ types:
|
||||
docs: "Datetime (ISO 8601) of event creation in client. Should be as close to actual event creation in client as possible, this timestamp will be used for ordering of events in future release. Resolution: milliseconds (required), microseconds (optimal)."
|
||||
metadata:
|
||||
type: optional<unknown>
|
||||
docs: Optional. Metadata field used by the Langfuse SDKs for debugging.
|
||||
docs: Optional. Metadata field used by the Hanzo Cloud SDKs for debugging.
|
||||
|
||||
TraceEvent:
|
||||
extends: BaseEvent
|
||||
|
||||
@@ -13,7 +13,7 @@ service:
|
||||
path-parameters:
|
||||
mediaId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of a media record
|
||||
docs: The unique hanzo identifier of a media record
|
||||
response: GetMediaResponse
|
||||
|
||||
patch:
|
||||
@@ -23,7 +23,7 @@ service:
|
||||
path-parameters:
|
||||
mediaId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of a media record
|
||||
docs: The unique hanzo identifier of a media record
|
||||
request: PatchMediaBody
|
||||
|
||||
getUploadUrl:
|
||||
@@ -38,7 +38,7 @@ types:
|
||||
properties:
|
||||
mediaId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of a media record
|
||||
docs: The unique hanzo identifier of a media record
|
||||
contentType:
|
||||
type: string
|
||||
docs: The MIME type of the media record
|
||||
@@ -96,7 +96,7 @@ types:
|
||||
docs: The presigned upload URL. If the asset is already uploaded, this will be null
|
||||
mediaId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of a media record
|
||||
docs: The unique hanzo identifier of a media record
|
||||
|
||||
MediaContentType:
|
||||
enum:
|
||||
|
||||
@@ -8,7 +8,7 @@ service:
|
||||
endpoints:
|
||||
metrics:
|
||||
docs: |
|
||||
Get metrics from the Langfuse project using a query object. V2 endpoint with optimized performance.
|
||||
Get metrics from the Hanzo project using a query object. V2 endpoint with optimized performance.
|
||||
|
||||
## V2 Differences
|
||||
- Supports `observations`, `scores-numeric`, and `scores-categorical` views only (traces view not supported)
|
||||
@@ -16,7 +16,7 @@ service:
|
||||
- Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view
|
||||
- High cardinality dimensions are not supported and will return a 400 error (see below)
|
||||
|
||||
For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api).
|
||||
For more details, see the [Metrics API documentation](https://hanzo.com/docs/metrics/features/metrics-api).
|
||||
|
||||
## Available Views
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ service:
|
||||
endpoints:
|
||||
metrics:
|
||||
docs: |
|
||||
Get metrics from the Langfuse project using a query object.
|
||||
Get metrics from the Hanzo project using a query object.
|
||||
|
||||
Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
|
||||
|
||||
For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api).
|
||||
For more details, see the [Metrics API documentation](https://hanzo.com/docs/metrics/features/metrics-api).
|
||||
method: GET
|
||||
path: /metrics
|
||||
request:
|
||||
|
||||
@@ -35,7 +35,7 @@ service:
|
||||
response: commons.Model
|
||||
delete:
|
||||
method: DELETE
|
||||
docs: Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though.
|
||||
docs: Delete a model. Cannot delete models managed by HanzoCloud. You can create your own definition with the same modelName to override the definition though.
|
||||
path: /models/{id}
|
||||
path-parameters:
|
||||
id: string
|
||||
|
||||
@@ -13,7 +13,7 @@ service:
|
||||
path-parameters:
|
||||
observationId:
|
||||
type: string
|
||||
docs: The unique langfuse identifier of an observation, can be an event, span or generation
|
||||
docs: The unique hanzo identifier of an observation, can be an event, span or generation
|
||||
response: commons.ObservationsView
|
||||
getMany:
|
||||
docs: |
|
||||
|
||||
@@ -7,7 +7,7 @@ service:
|
||||
docs: |
|
||||
**OpenTelemetry Traces Ingestion Endpoint**
|
||||
|
||||
This endpoint implements the OTLP/HTTP specification for trace ingestion, providing native OpenTelemetry integration for Langfuse Observability.
|
||||
This endpoint implements the OTLP/HTTP specification for trace ingestion, providing native OpenTelemetry integration for Hanzo Observability.
|
||||
|
||||
**Supported Formats:**
|
||||
- Binary Protobuf: `Content-Type: application/x-protobuf`
|
||||
@@ -19,8 +19,8 @@ service:
|
||||
- Implements `ExportTraceServiceRequest` message format
|
||||
|
||||
**Documentation:**
|
||||
- Integration guide: https://langfuse.com/integrations/native/opentelemetry
|
||||
- Data model: https://langfuse.com/docs/observability/data-model
|
||||
- Integration guide: https://hanzo.com/integrations/native/opentelemetry
|
||||
- Data model: https://hanzo.com/docs/observability/data-model
|
||||
method: POST
|
||||
path: /otel/v1/traces
|
||||
request:
|
||||
@@ -47,7 +47,7 @@ service:
|
||||
stringValue: "1.0.0"
|
||||
scopeSpans:
|
||||
- scope:
|
||||
name: "langfuse-sdk"
|
||||
name: "hanzo-sdk"
|
||||
version: "2.60.3"
|
||||
spans:
|
||||
- traceId: "0123456789abcdef0123456789abcdef"
|
||||
@@ -57,7 +57,7 @@ service:
|
||||
startTimeUnixNano: "1747872000000000000"
|
||||
endTimeUnixNano: "1747872001000000000"
|
||||
attributes:
|
||||
- key: "langfuse.observation.type"
|
||||
- key: "hanzo.observation.type"
|
||||
value:
|
||||
stringValue: "generation"
|
||||
status: {}
|
||||
@@ -131,7 +131,7 @@ types:
|
||||
docs: End time in nanoseconds since Unix epoch
|
||||
attributes:
|
||||
type: optional<list<OtelAttribute>>
|
||||
docs: Span attributes including Langfuse-specific attributes (langfuse.observation.*)
|
||||
docs: Span attributes including Hanzo-specific attributes (hanzo.observation.*)
|
||||
status:
|
||||
type: optional<unknown>
|
||||
docs: Span status object
|
||||
@@ -141,7 +141,7 @@ types:
|
||||
properties:
|
||||
key:
|
||||
type: optional<string>
|
||||
docs: Attribute key (e.g., "service.name", "langfuse.observation.type")
|
||||
docs: Attribute key (e.g., "service.name", "hanzo.observation.type")
|
||||
value:
|
||||
type: optional<OtelAttributeValue>
|
||||
docs: Attribute value
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user