coaiajs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +56 -0
- package/KINSHIP.md +63 -0
- package/README.md +148 -0
- package/articles/academic/creative-orientation-vs-problem-solving.md +177 -0
- package/articles/academic/jsonl-knowledge-graphs-agent-memory.md +142 -0
- package/articles/academic/langfuse-observability-llm-pipelines.md +144 -0
- package/articles/academic/medicine-wheel-software-architecture.md +163 -0
- package/articles/academic/mmot-autonomous-agents.md +156 -0
- package/articles/academic/model-context-protocol-interagent.md +161 -0
- package/articles/academic/pde-prompt-decomposition.md +186 -0
- package/articles/academic/structural-tension-in-ai-agents.md +134 -0
- package/articles/reviews/mcp-protocol-design-review.md +170 -0
- package/articles/reviews/observability-ai-systems-review.md +176 -0
- package/articles/reviews/prompt-engineering-decomposition-review.md +184 -0
- package/articles/surveys/agent-orchestration-survey.md +186 -0
- package/articles/surveys/knowledge-graph-storage-survey.md +204 -0
- package/articles/surveys/structural-tension-methodology-survey.md +154 -0
- package/articles/technical/aws-sdk-v3-polly.md +270 -0
- package/articles/technical/commander-cli-framework.md +262 -0
- package/articles/technical/dotenv-config-patterns.md +360 -0
- package/articles/technical/ioredis-vs-redis.md +142 -0
- package/articles/technical/langfuse-js-sdk-vs-rest.md +191 -0
- package/articles/technical/mcp-sdk-typescript.md +291 -0
- package/articles/technical/octokit-github-api.md +293 -0
- package/articles/technical/openai-sdk-modern.md +231 -0
- package/articles/technical/yaml-parsing-node.md +266 -0
- package/articles/technical/zod-runtime-validation.md +212 -0
- package/dist/mcp/config.d.ts +14 -0
- package/dist/mcp/config.js +185 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +324 -0
- package/dist/mcp/tools/coaiapy-tools.d.ts +8 -0
- package/dist/mcp/tools/coaiapy-tools.js +326 -0
- package/dist/mcp/tools/index.d.ts +3 -0
- package/dist/mcp/tools/index.js +3 -0
- package/dist/src/audio.d.ts +12 -0
- package/dist/src/audio.js +57 -0
- package/dist/src/cli-helpers.d.ts +9 -0
- package/dist/src/cli-helpers.js +78 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.js +1086 -0
- package/dist/src/config.d.ts +15 -0
- package/dist/src/config.js +145 -0
- package/dist/src/environment.d.ts +44 -0
- package/dist/src/environment.js +146 -0
- package/dist/src/github.d.ts +47 -0
- package/dist/src/github.js +79 -0
- package/dist/src/langfuse/client.d.ts +30 -0
- package/dist/src/langfuse/client.js +75 -0
- package/dist/src/langfuse/comments.d.ts +16 -0
- package/dist/src/langfuse/comments.js +36 -0
- package/dist/src/langfuse/datasets.d.ts +19 -0
- package/dist/src/langfuse/datasets.js +140 -0
- package/dist/src/langfuse/index.d.ts +13 -0
- package/dist/src/langfuse/index.js +10 -0
- package/dist/src/langfuse/media.d.ts +11 -0
- package/dist/src/langfuse/media.js +167 -0
- package/dist/src/langfuse/observations.d.ts +18 -0
- package/dist/src/langfuse/observations.js +113 -0
- package/dist/src/langfuse/prompts.d.ts +14 -0
- package/dist/src/langfuse/prompts.js +127 -0
- package/dist/src/langfuse/scores.d.ts +54 -0
- package/dist/src/langfuse/scores.js +366 -0
- package/dist/src/langfuse/traces.d.ts +29 -0
- package/dist/src/langfuse/traces.js +225 -0
- package/dist/src/llm.d.ts +23 -0
- package/dist/src/llm.js +76 -0
- package/dist/src/narrative/graph-manager.d.ts +106 -0
- package/dist/src/narrative/graph-manager.js +915 -0
- package/dist/src/narrative/index.d.ts +9 -0
- package/dist/src/narrative/index.js +7 -0
- package/dist/src/narrative/markdown-export.d.ts +21 -0
- package/dist/src/narrative/markdown-export.js +383 -0
- package/dist/src/narrative/tool-definitions.d.ts +21 -0
- package/dist/src/narrative/tool-definitions.js +588 -0
- package/dist/src/narrative/tool-handlers.d.ts +11 -0
- package/dist/src/narrative/tool-handlers.js +462 -0
- package/dist/src/narrative/types.d.ts +2 -0
- package/dist/src/narrative/types.js +2 -0
- package/dist/src/narrative/validation.d.ts +29 -0
- package/dist/src/narrative/validation.js +144 -0
- package/dist/src/pde/index.d.ts +8 -0
- package/dist/src/pde/index.js +8 -0
- package/dist/src/pde/mcp-handlers.d.ts +7 -0
- package/dist/src/pde/mcp-handlers.js +300 -0
- package/dist/src/pde/mcp-tools.d.ts +15 -0
- package/dist/src/pde/mcp-tools.js +191 -0
- package/dist/src/pde/session-manager.d.ts +32 -0
- package/dist/src/pde/session-manager.js +205 -0
- package/dist/src/pde/stc-mapper.d.ts +26 -0
- package/dist/src/pde/stc-mapper.js +234 -0
- package/dist/src/pipeline/index.d.ts +2 -0
- package/dist/src/pipeline/index.js +3 -0
- package/dist/src/pipeline/template-engine.d.ts +20 -0
- package/dist/src/pipeline/template-engine.js +361 -0
- package/dist/src/planning/index.d.ts +7 -0
- package/dist/src/planning/index.js +7 -0
- package/dist/src/planning/mcp-handlers.d.ts +7 -0
- package/dist/src/planning/mcp-handlers.js +310 -0
- package/dist/src/planning/mcp-tools.d.ts +15 -0
- package/dist/src/planning/mcp-tools.js +145 -0
- package/dist/src/planning/plan-parser.d.ts +35 -0
- package/dist/src/planning/plan-parser.js +506 -0
- package/dist/src/redis.d.ts +21 -0
- package/dist/src/redis.js +78 -0
- package/dist/src/types.d.ts +244 -0
- package/dist/src/types.js +8 -0
- package/mcp/config.ts +196 -0
- package/mcp/server.ts +402 -0
- package/mcp/tools/coaiapy-tools.ts +364 -0
- package/mcp/tools/index.ts +4 -0
- package/package.json +52 -0
- package/rispecs/00-coaiajs-platform.spec.md +102 -0
- package/rispecs/01-core-config.spec.md +89 -0
- package/rispecs/02-redis-module.spec.md +62 -0
- package/rispecs/03-langfuse-module.spec.md +101 -0
- package/rispecs/04-narrative-engine.spec.md +185 -0
- package/rispecs/05-pde-engine.spec.md +112 -0
- package/rispecs/06-planning-engine.spec.md +128 -0
- package/rispecs/07-pipeline-templates.spec.md +97 -0
- package/rispecs/08-cli-interface.spec.md +134 -0
- package/rispecs/09-mcp-server.spec.md +140 -0
- package/rispecs/10-audio-module.spec.md +63 -0
- package/rispecs/KINSHIP.md +56 -0
- package/rispecs/README.md +100 -0
- package/src/audio.ts +76 -0
- package/src/cli-helpers.ts +86 -0
- package/src/cli.ts +1223 -0
- package/src/config.ts +172 -0
- package/src/environment.ts +171 -0
- package/src/github.ts +143 -0
- package/src/langfuse/client.ts +105 -0
- package/src/langfuse/comments.ts +52 -0
- package/src/langfuse/datasets.ts +178 -0
- package/src/langfuse/index.ts +33 -0
- package/src/langfuse/media.ts +193 -0
- package/src/langfuse/observations.ts +131 -0
- package/src/langfuse/prompts.ts +157 -0
- package/src/langfuse/scores.ts +456 -0
- package/src/langfuse/traces.ts +276 -0
- package/src/llm.ts +106 -0
- package/src/narrative/graph-manager.ts +1358 -0
- package/src/narrative/index.ts +32 -0
- package/src/narrative/markdown-export.ts +535 -0
- package/src/narrative/tool-definitions.ts +635 -0
- package/src/narrative/tool-handlers.ts +528 -0
- package/src/narrative/types.ts +9 -0
- package/src/narrative/validation.ts +179 -0
- package/src/pde/index.ts +8 -0
- package/src/pde/mcp-handlers.ts +359 -0
- package/src/pde/mcp-tools.ts +201 -0
- package/src/pde/session-manager.ts +248 -0
- package/src/pde/stc-mapper.ts +298 -0
- package/src/pipeline/index.ts +7 -0
- package/src/pipeline/template-engine.ts +398 -0
- package/src/planning/index.ts +13 -0
- package/src/planning/mcp-handlers.ts +369 -0
- package/src/planning/mcp-tools.ts +155 -0
- package/src/planning/plan-parser.ts +587 -0
- package/src/redis.ts +97 -0
- package/src/types.ts +280 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Config Management in Node.js: Technical Assessment for CoAiA.js
|
|
2
|
+
|
|
3
|
+
> Package selection brief — Configuration cascade replacing coaiapy's multi-file config (env vars > .env > coaia.json > defaults)
|
|
4
|
+
|
|
5
|
+
## Summary & Recommendation
|
|
6
|
+
|
|
7
|
+
**Use `dotenv` v16.x + `cosmiconfig` v9.x + `zod` for validation.** This triple replaces coaiapy's hand-rolled config cascade with a standard, validated pattern:
|
|
8
|
+
- `dotenv` loads `.env` files (matching coaiapy's `.coaia-env`)
|
|
9
|
+
- `cosmiconfig` discovers `coaia.json`, `coaia.yaml`, `.coaiarc`, or `coaia.config.js` (matching coaiapy's multi-format loading)
|
|
10
|
+
- `zod` validates the merged config at startup (what coaiapy lacks entirely)
|
|
11
|
+
|
|
12
|
+
**Pin:**
|
|
13
|
+
```json
|
|
14
|
+
"dotenv": "^16.4.0",
|
|
15
|
+
"cosmiconfig": "^9.0.0",
|
|
16
|
+
"zod": "^4.0.0"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What We're Replacing
|
|
20
|
+
|
|
21
|
+
Coaiapy has a complex config cascade across multiple modules:
|
|
22
|
+
|
|
23
|
+
### environment.py (EnvironmentManager)
|
|
24
|
+
```python
|
|
25
|
+
@dataclass
|
|
26
|
+
class EnvironmentConfig:
|
|
27
|
+
project_env_file: str = ".coaia-env"
|
|
28
|
+
global_env_file: str = "~/.coaia/global.env"
|
|
29
|
+
supported_formats: List[str] = ["json", "env"]
|
|
30
|
+
|
|
31
|
+
class EnvironmentManager:
|
|
32
|
+
def _read_env_file(self, file_path: Path) -> Dict[str, Any]:
|
|
33
|
+
if content.startswith('{'):
|
|
34
|
+
return json.loads(content)
|
|
35
|
+
# Parse KEY=value format
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### coaiamodule.py (read_config)
|
|
39
|
+
```python
|
|
40
|
+
def read_config():
|
|
41
|
+
# Priority: env vars > .env > coaia.json > defaults
|
|
42
|
+
# Searches: cwd, parent dirs, ~/.coaia/
|
|
43
|
+
# Supports: JSON, .env, shell env vars
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### coaia-narrative CLI (minimist + dotenv)
|
|
47
|
+
```typescript
|
|
48
|
+
// Priority order:
|
|
49
|
+
// 1. Command-line flags (--memory-path, -M)
|
|
50
|
+
// 2. Custom env file (--env)
|
|
51
|
+
// 3. .env in cwd
|
|
52
|
+
// 4. _env.sh (fallback)
|
|
53
|
+
// 5. Environment variables
|
|
54
|
+
// 6. Defaults
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The Python approach has no validation — missing keys fail at runtime deep in execution. The TypeScript approach in coaia-narrative works but is ad-hoc per module.
|
|
58
|
+
|
|
59
|
+
## Options Compared
|
|
60
|
+
|
|
61
|
+
| Feature | dotenv + cosmiconfig + zod | dotenv only | convict | nconf | node-config |
|
|
62
|
+
|---------|--------------------------|-------------|---------|-------|-------------|
|
|
63
|
+
| .env loading | ✅ dotenv | ✅ | ⚠️ Manual | ✅ | ❌ |
|
|
64
|
+
| Multi-format (JSON/YAML/JS) | ✅ cosmiconfig | ❌ | ✅ JSON | ✅ | ✅ |
|
|
65
|
+
| Parent dir search | ✅ cosmiconfig | ❌ | ❌ | ❌ | ❌ |
|
|
66
|
+
| Schema validation | ✅ zod | ❌ | ✅ convict | ❌ | ❌ |
|
|
67
|
+
| Type inference | ✅ zod infer | ❌ | ⚠️ Manual | ❌ | ❌ |
|
|
68
|
+
| Variable expansion | ✅ dotenv-expand | ✅ dotenv-expand | ❌ | ❌ | ❌ |
|
|
69
|
+
| Env override | ✅ process.env priority | ✅ | ✅ | ✅ | ✅ |
|
|
70
|
+
| Weekly downloads | ~93M + ~30M + ~100M | ~93M | ~900K | ~900K | ~1.5M |
|
|
71
|
+
| Bundle overhead | Minimal | Tiny | Medium | Medium | Medium |
|
|
72
|
+
| TypeScript | All have types | ✅ | ⚠️ | ⚠️ | ⚠️ |
|
|
73
|
+
|
|
74
|
+
## API Overview
|
|
75
|
+
|
|
76
|
+
### Config Schema (Zod)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// src/config/schema.ts
|
|
80
|
+
import { z } from 'zod';
|
|
81
|
+
|
|
82
|
+
export const CoaiaConfigSchema = z.object({
|
|
83
|
+
// Redis
|
|
84
|
+
redisUrl: z.string().url().default('redis://localhost:6379'),
|
|
85
|
+
|
|
86
|
+
// Langfuse
|
|
87
|
+
langfusePublicKey: z.string().optional(),
|
|
88
|
+
langfuseSecretKey: z.string().optional(),
|
|
89
|
+
langfuseBaseUrl: z.string().url().default('https://cloud.langfuse.com'),
|
|
90
|
+
|
|
91
|
+
// OpenAI
|
|
92
|
+
openaiApiKey: z.string().optional(),
|
|
93
|
+
openaiBaseUrl: z.string().url().optional(),
|
|
94
|
+
openaiModel: z.string().default('gpt-5.4'),
|
|
95
|
+
|
|
96
|
+
// AWS Polly
|
|
97
|
+
awsRegion: z.string().default('us-east-1'),
|
|
98
|
+
pollyKey: z.string().optional(),
|
|
99
|
+
pollySecret: z.string().optional(),
|
|
100
|
+
|
|
101
|
+
// GitHub
|
|
102
|
+
githubToken: z.string().optional(),
|
|
103
|
+
|
|
104
|
+
// Paths
|
|
105
|
+
memoryPath: z.string().default('.coaia/memory.jsonl'),
|
|
106
|
+
plansDir: z.string().default('.coaia/plans'),
|
|
107
|
+
outputDir: z.string().default('.coaia/output'),
|
|
108
|
+
templateDir: z.string().default('.coaia/templates'),
|
|
109
|
+
|
|
110
|
+
// Behavior
|
|
111
|
+
jsonOutput: z.boolean().default(false),
|
|
112
|
+
noColor: z.boolean().default(false),
|
|
113
|
+
verbose: z.boolean().default(false),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export type CoaiaConfig = z.infer<typeof CoaiaConfigSchema>;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Config Loader (cosmiconfig + dotenv)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// src/config/loader.ts
|
|
123
|
+
import { cosmiconfig } from 'cosmiconfig';
|
|
124
|
+
import dotenv from 'dotenv';
|
|
125
|
+
import { CoaiaConfigSchema, type CoaiaConfig } from './schema.js';
|
|
126
|
+
import { existsSync } from 'fs';
|
|
127
|
+
import { resolve } from 'path';
|
|
128
|
+
|
|
129
|
+
// cosmiconfig explorer — searches for config files
|
|
130
|
+
const explorer = cosmiconfig('coaia', {
|
|
131
|
+
searchPlaces: [
|
|
132
|
+
'coaia.config.js',
|
|
133
|
+
'coaia.config.ts',
|
|
134
|
+
'coaia.json',
|
|
135
|
+
'coaia.yaml',
|
|
136
|
+
'coaia.yml',
|
|
137
|
+
'.coaiarc',
|
|
138
|
+
'.coaiarc.json',
|
|
139
|
+
'.coaiarc.yaml',
|
|
140
|
+
'package.json', // "coaia" key in package.json
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
let _config: CoaiaConfig | null = null;
|
|
145
|
+
|
|
146
|
+
export async function loadConfig(overrides?: Partial<CoaiaConfig>): Promise<CoaiaConfig> {
|
|
147
|
+
if (_config && !overrides) return _config;
|
|
148
|
+
|
|
149
|
+
// Step 1: Load .env files (matches coaiapy's .coaia-env pattern)
|
|
150
|
+
const envFiles = [
|
|
151
|
+
'.env',
|
|
152
|
+
'.coaia-env',
|
|
153
|
+
resolve(process.env.HOME ?? '', '.coaia', 'global.env'),
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const envFile of envFiles) {
|
|
157
|
+
if (existsSync(envFile)) {
|
|
158
|
+
dotenv.config({ path: envFile });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Step 2: Load config file via cosmiconfig (searches parent dirs)
|
|
163
|
+
const result = await explorer.search();
|
|
164
|
+
const fileConfig = result?.config ?? {};
|
|
165
|
+
|
|
166
|
+
// Step 3: Merge sources (priority: CLI overrides > env vars > config file > defaults)
|
|
167
|
+
const merged = {
|
|
168
|
+
...fileConfig,
|
|
169
|
+
// Env var overrides (matching coaiapy's env var names)
|
|
170
|
+
...(process.env.REDIS_URL && { redisUrl: process.env.REDIS_URL }),
|
|
171
|
+
...(process.env.UPSTASH_REDIS_URL && { redisUrl: process.env.UPSTASH_REDIS_URL }),
|
|
172
|
+
...(process.env.LANGFUSE_PUBLIC_KEY && { langfusePublicKey: process.env.LANGFUSE_PUBLIC_KEY }),
|
|
173
|
+
...(process.env.LANGFUSE_SECRET_KEY && { langfuseSecretKey: process.env.LANGFUSE_SECRET_KEY }),
|
|
174
|
+
...(process.env.LANGFUSE_BASE_URL && { langfuseBaseUrl: process.env.LANGFUSE_BASE_URL }),
|
|
175
|
+
...(process.env.OPENAI_API_KEY && { openaiApiKey: process.env.OPENAI_API_KEY }),
|
|
176
|
+
...(process.env.OPENAI_BASE_URL && { openaiBaseUrl: process.env.OPENAI_BASE_URL }),
|
|
177
|
+
...(process.env.AWS_REGION && { awsRegion: process.env.AWS_REGION }),
|
|
178
|
+
...(process.env.GH_TOKEN && { githubToken: process.env.GH_TOKEN }),
|
|
179
|
+
...(process.env.GITHUB_TOKEN && { githubToken: process.env.GITHUB_TOKEN }),
|
|
180
|
+
...(process.env.COAIA_MEMORY_PATH && { memoryPath: process.env.COAIA_MEMORY_PATH }),
|
|
181
|
+
...(process.env.COAIA_PLANS_DIR && { plansDir: process.env.COAIA_PLANS_DIR }),
|
|
182
|
+
...(process.env.COAIA_OUTPUT_DIR && { outputDir: process.env.COAIA_OUTPUT_DIR }),
|
|
183
|
+
// CLI overrides (highest priority)
|
|
184
|
+
...overrides,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Step 4: Validate with Zod
|
|
188
|
+
_config = CoaiaConfigSchema.parse(merged);
|
|
189
|
+
return _config;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Synchronous getter after initial load
|
|
193
|
+
export function getConfig(): CoaiaConfig {
|
|
194
|
+
if (!_config) throw new Error('Config not loaded. Call loadConfig() first.');
|
|
195
|
+
return _config;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### CLI Integration with Commander
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// src/cli.ts — CLI flags feed into config overrides
|
|
203
|
+
import { Command } from 'commander';
|
|
204
|
+
import { loadConfig } from './config/loader.js';
|
|
205
|
+
|
|
206
|
+
const program = new Command()
|
|
207
|
+
.option('-M, --memory-path <path>', 'Memory file path')
|
|
208
|
+
.option('--env <file>', 'Custom env file path')
|
|
209
|
+
.option('--json', 'Output as JSON')
|
|
210
|
+
.option('--no-color', 'Disable colored output')
|
|
211
|
+
.option('--verbose', 'Verbose logging');
|
|
212
|
+
|
|
213
|
+
program.hook('preAction', async (thisCommand) => {
|
|
214
|
+
const opts = thisCommand.opts();
|
|
215
|
+
|
|
216
|
+
// Load custom env file if specified
|
|
217
|
+
if (opts.env) {
|
|
218
|
+
dotenv.config({ path: opts.env });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Initialize config with CLI overrides
|
|
222
|
+
await loadConfig({
|
|
223
|
+
...(opts.memoryPath && { memoryPath: opts.memoryPath }),
|
|
224
|
+
...(opts.json && { jsonOutput: true }),
|
|
225
|
+
...(opts.color === false && { noColor: true }),
|
|
226
|
+
...(opts.verbose && { verbose: true }),
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Variable Expansion (dotenv-expand)
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// For .env files that reference other variables
|
|
235
|
+
// .env:
|
|
236
|
+
// BASE_DIR=/opt/coaia
|
|
237
|
+
// MEMORY_PATH=${BASE_DIR}/memory.jsonl
|
|
238
|
+
// PLANS_DIR=${BASE_DIR}/plans
|
|
239
|
+
|
|
240
|
+
import dotenv from 'dotenv';
|
|
241
|
+
import { expand } from 'dotenv-expand';
|
|
242
|
+
|
|
243
|
+
const env = dotenv.config({ path: '.env' });
|
|
244
|
+
expand(env); // Resolves ${BASE_DIR} references
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Config File Examples
|
|
248
|
+
|
|
249
|
+
```yaml
|
|
250
|
+
# coaia.yaml — project-level config
|
|
251
|
+
redis:
|
|
252
|
+
url: redis://localhost:6379
|
|
253
|
+
|
|
254
|
+
langfuse:
|
|
255
|
+
publicKey: pk-lf-xxx
|
|
256
|
+
secretKey: sk-lf-xxx
|
|
257
|
+
baseUrl: https://cloud.langfuse.com
|
|
258
|
+
|
|
259
|
+
openai:
|
|
260
|
+
apiKey: sk-xxx
|
|
261
|
+
model: gpt-5.4
|
|
262
|
+
|
|
263
|
+
paths:
|
|
264
|
+
memory: .coaia/memory.jsonl
|
|
265
|
+
plans: .coaia/plans
|
|
266
|
+
templates: .coaia/templates
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
// coaia.json — alternative JSON format
|
|
271
|
+
{
|
|
272
|
+
"redisUrl": "redis://localhost:6379",
|
|
273
|
+
"langfusePublicKey": "pk-lf-xxx",
|
|
274
|
+
"openaiModel": "gpt-5.4",
|
|
275
|
+
"memoryPath": ".coaia/memory.jsonl"
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```ini
|
|
280
|
+
# .coaia-env — environment variable format (coaiapy compatible)
|
|
281
|
+
REDIS_URL=redis://localhost:6379
|
|
282
|
+
LANGFUSE_PUBLIC_KEY=pk-lf-xxx
|
|
283
|
+
LANGFUSE_SECRET_KEY=sk-lf-xxx
|
|
284
|
+
OPENAI_API_KEY=sk-xxx
|
|
285
|
+
GH_TOKEN=ghp_xxx
|
|
286
|
+
AWS_REGION=us-east-1
|
|
287
|
+
COAIA_MEMORY_PATH=.coaia/memory.jsonl
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Validation Error Messages
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// On startup with invalid config:
|
|
294
|
+
try {
|
|
295
|
+
await loadConfig();
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (error instanceof z.ZodError) {
|
|
298
|
+
console.error('Configuration errors:');
|
|
299
|
+
error.issues.forEach(issue => {
|
|
300
|
+
console.error(` ${issue.path.join('.')}: ${issue.message}`);
|
|
301
|
+
});
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Output:
|
|
308
|
+
// Configuration errors:
|
|
309
|
+
// redisUrl: Invalid url
|
|
310
|
+
// langfuseBaseUrl: Invalid url
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Integration Plan
|
|
314
|
+
|
|
315
|
+
1. **Schema:** `src/config/schema.ts` — Zod schema for all config values
|
|
316
|
+
2. **Loader:** `src/config/loader.ts` — dotenv + cosmiconfig + Zod validation
|
|
317
|
+
3. **Export:** `src/config/index.ts` — `loadConfig()` and `getConfig()`
|
|
318
|
+
4. **CLI hook:** Commander `preAction` hook loads config with CLI overrides
|
|
319
|
+
5. **Testing:** Config loader is mockable via overrides parameter
|
|
320
|
+
6. **Migration:** Support both `coaia.json` and `.coaia-env` formats (backward compat)
|
|
321
|
+
|
|
322
|
+
### Config Priority (matches coaiapy's cascade)
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
1. CLI flags (--memory-path, --json) ← Highest
|
|
326
|
+
2. Environment variables (REDIS_URL, GH_TOKEN)
|
|
327
|
+
3. .env / .coaia-env (project root)
|
|
328
|
+
4. ~/.coaia/global.env (global user config)
|
|
329
|
+
5. coaia.json / coaia.yaml (cosmiconfig search)
|
|
330
|
+
6. Zod defaults (schema defaults) ← Lowest
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Version & Ecosystem
|
|
334
|
+
|
|
335
|
+
| Package | Version | Weekly Downloads | Purpose |
|
|
336
|
+
|---------|---------|-----------------|---------|
|
|
337
|
+
| dotenv | 16.4.x | ~93M | .env file loading |
|
|
338
|
+
| dotenv-expand | 12.0.x | ~30M | Variable expansion in .env |
|
|
339
|
+
| cosmiconfig | 9.0.x | ~30M | Multi-format config discovery |
|
|
340
|
+
| zod | 4.3.x | ~100M+ | Schema validation + type inference |
|
|
341
|
+
|
|
342
|
+
All packages: MIT licensed, zero or minimal dependencies, TypeScript supported.
|
|
343
|
+
|
|
344
|
+
## Why Not Convict?
|
|
345
|
+
|
|
346
|
+
Convict (from Mozilla) offers built-in schema validation, but:
|
|
347
|
+
1. ~900K downloads vs dotenv's ~93M — smaller ecosystem
|
|
348
|
+
2. Doesn't support YAML config files natively
|
|
349
|
+
3. Doesn't search parent directories (cosmiconfig does)
|
|
350
|
+
4. We already have Zod for validation (no need for convict's schema DSL)
|
|
351
|
+
5. Convict's API is less TypeScript-friendly than Zod's type inference
|
|
352
|
+
|
|
353
|
+
## References
|
|
354
|
+
|
|
355
|
+
- dotenv npm: https://www.npmjs.com/package/dotenv
|
|
356
|
+
- cosmiconfig npm: https://www.npmjs.com/package/cosmiconfig
|
|
357
|
+
- cosmiconfig GitHub: https://github.com/cosmiconfig/cosmiconfig
|
|
358
|
+
- dotenv security: https://www.johal.in/secrets-dotenv-secure-config-management-in-production-2026/
|
|
359
|
+
- Config comparison: https://npm-compare.com/config,convict,dotenv,nconf
|
|
360
|
+
- dotenv usage: https://oneuptime.com/blog/post/2026-01-25-dotenv-configuration-nodejs/view
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# ioredis vs node-redis: Technical Assessment for CoAiA.js
|
|
2
|
+
|
|
3
|
+
> Package selection brief — Redis client for structural tension chart storage, session management, and MCP memory persistence
|
|
4
|
+
|
|
5
|
+
## Summary & Recommendation
|
|
6
|
+
|
|
7
|
+
**Use `ioredis` v5.4.x** for coaiajs. Despite Redis Inc. pushing `node-redis` as the official client, ioredis delivers superior ergonomics for our use case: URL-based connection strings (Upstash REST compatibility), built-in cluster support for future scaling, and a smoother pipelining API. The ~14M weekly downloads and battle-tested stability outweigh the marginal concurrency edge of node-redis that we don't need.
|
|
8
|
+
|
|
9
|
+
**Pin:** `"ioredis": "^5.4.0"`
|
|
10
|
+
|
|
11
|
+
## What We're Replacing
|
|
12
|
+
|
|
13
|
+
Coaiapy uses `redis<=4.3.6` (Python redis-py) with a lazy-loading pattern:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# coaiapy/coaiamodule.py — lazy import for Pythonista compatibility
|
|
17
|
+
def _get_redis():
|
|
18
|
+
"""Lazy import of redis module"""
|
|
19
|
+
import redis
|
|
20
|
+
return redis
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The Python client connects via URL string and performs simple GET/SET with TTL for session data, chart state, and webhook coordination. coaia-narrative's MCP server (Redis-backed medicine wheel) also uses Redis for ceremony state.
|
|
24
|
+
|
|
25
|
+
## Options Compared
|
|
26
|
+
|
|
27
|
+
| Feature | ioredis v5.4 | node-redis v4.7 |
|
|
28
|
+
|---------|-------------|-----------------|
|
|
29
|
+
| Weekly npm downloads | ~14–15M | ~8–9M |
|
|
30
|
+
| GitHub stars | ~15,000 | ~17,000 |
|
|
31
|
+
| Connection from URL | `new Redis(url)` — native | `createClient({ url })` — native |
|
|
32
|
+
| Upstash REST compat | Via `@upstash/redis` wrapper or direct URL | Via `@upstash/redis` wrapper |
|
|
33
|
+
| GET/SET with TTL | `redis.set(key, val, 'EX', ttl)` | `client.set(key, val, { EX: ttl })` |
|
|
34
|
+
| Pipelining | `redis.pipeline().set().get().exec()` | `client.multi().set().get().exec()` |
|
|
35
|
+
| Cluster support | Built-in, first-class | Available but newer |
|
|
36
|
+
| Auto-reconnect | Built-in with backoff | Built-in with strategy |
|
|
37
|
+
| TypeScript | `@types/ioredis` bundled | Native types |
|
|
38
|
+
| Concurrent 100-SET ops/sec | ~2,500 | ~3,800 |
|
|
39
|
+
| Sequential GET ops/sec | ~8,700 | ~7,900 |
|
|
40
|
+
| Lua scripting | First-class `defineCommand()` | Supported |
|
|
41
|
+
| Streams API | Rich ergonomic API | Supported |
|
|
42
|
+
|
|
43
|
+
## API Overview
|
|
44
|
+
|
|
45
|
+
### Connection Pattern for coaiajs
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import Redis from 'ioredis';
|
|
49
|
+
import { loadConfig } from '../config.js';
|
|
50
|
+
|
|
51
|
+
// Connection from URL (matches coaiapy pattern)
|
|
52
|
+
const config = loadConfig();
|
|
53
|
+
const redis = new Redis(config.redisUrl ?? 'redis://localhost:6379');
|
|
54
|
+
|
|
55
|
+
// With Upstash (TLS URL)
|
|
56
|
+
const upstashRedis = new Redis(process.env.UPSTASH_REDIS_URL!, {
|
|
57
|
+
tls: { rejectUnauthorized: false },
|
|
58
|
+
lazyConnect: true, // matches coaiapy's lazy pattern
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Core Operations We Need
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Session storage with TTL
|
|
66
|
+
async function saveSession(sessionId: string, data: object, ttlSeconds = 3600): Promise<void> {
|
|
67
|
+
await redis.set(`session:${sessionId}`, JSON.stringify(data), 'EX', ttlSeconds);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function loadSession(sessionId: string): Promise<object | null> {
|
|
71
|
+
const raw = await redis.get(`session:${sessionId}`);
|
|
72
|
+
return raw ? JSON.parse(raw) : null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Chart state persistence (coaia-narrative pattern)
|
|
76
|
+
async function saveChart(chartId: string, chart: object): Promise<void> {
|
|
77
|
+
await redis.hset(`chart:${chartId}`, {
|
|
78
|
+
data: JSON.stringify(chart),
|
|
79
|
+
updatedAt: new Date().toISOString(),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Pipeline for batch operations
|
|
84
|
+
async function loadMultipleCharts(ids: string[]): Promise<Map<string, object>> {
|
|
85
|
+
const pipeline = redis.pipeline();
|
|
86
|
+
ids.forEach(id => pipeline.hgetall(`chart:${id}`));
|
|
87
|
+
const results = await pipeline.exec();
|
|
88
|
+
// ... process results
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Lazy Connection Pattern (matching coaiapy)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
let _redis: Redis | null = null;
|
|
96
|
+
|
|
97
|
+
export function getRedis(): Redis {
|
|
98
|
+
if (!_redis) {
|
|
99
|
+
const url = process.env.REDIS_URL ?? process.env.UPSTASH_REDIS_URL ?? 'redis://localhost:6379';
|
|
100
|
+
_redis = new Redis(url, { lazyConnect: true });
|
|
101
|
+
}
|
|
102
|
+
return _redis;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Integration Plan
|
|
107
|
+
|
|
108
|
+
1. **Core module:** `src/redis.ts` — connection singleton, lazy init, URL-from-config
|
|
109
|
+
2. **Session storage:** `src/session.ts` — GET/SET with TTL for webhook session management
|
|
110
|
+
3. **Chart persistence:** `src/narrative/redis-store.ts` — HSET/HGETALL for structural tension charts
|
|
111
|
+
4. **MCP memory:** `mcp/tools/memory.ts` — Redis-backed tool state for MCP servers
|
|
112
|
+
5. **Graceful shutdown:** `redis.quit()` in process exit handlers
|
|
113
|
+
|
|
114
|
+
## Version & Ecosystem
|
|
115
|
+
|
|
116
|
+
| Metric | Value |
|
|
117
|
+
|--------|-------|
|
|
118
|
+
| Current version | 5.4.2 (March 2026) |
|
|
119
|
+
| Weekly downloads | ~14.5M |
|
|
120
|
+
| TypeScript | Built-in types since v5 |
|
|
121
|
+
| Node.js compat | ≥14 (we target ≥20) |
|
|
122
|
+
| Maintenance | Active, regular releases |
|
|
123
|
+
| License | MIT |
|
|
124
|
+
| Bundle size | ~85KB minified |
|
|
125
|
+
|
|
126
|
+
## Why Not node-redis?
|
|
127
|
+
|
|
128
|
+
1. **Connection API ergonomics**: ioredis accepts URL in constructor directly; node-redis requires `createClient()` factory
|
|
129
|
+
2. **Cluster future-proofing**: ioredis has years of battle-tested cluster support
|
|
130
|
+
3. **Pipelining**: ioredis pipeline API is cleaner for our batch chart operations
|
|
131
|
+
4. **Lazy connect**: `lazyConnect: true` maps directly to coaiapy's lazy import pattern
|
|
132
|
+
5. **Ecosystem**: Used by Bull, BullMQ, and most Redis-dependent MCP servers we integrate with
|
|
133
|
+
|
|
134
|
+
The 3,800 vs 2,500 ops/sec concurrent difference in node-redis's favor is irrelevant — coaiajs is an agent framework, not a high-throughput data pipeline.
|
|
135
|
+
|
|
136
|
+
## References
|
|
137
|
+
|
|
138
|
+
- npm: https://www.npmjs.com/package/ioredis
|
|
139
|
+
- GitHub: https://github.com/redis/ioredis
|
|
140
|
+
- Benchmark: https://glama.ai/blog/2026-01-26-redis-vs-ioredis-vs-valkey-glide
|
|
141
|
+
- npm trends: https://npmtrends.com/ioredis-vs-redis
|
|
142
|
+
- Redis migration guide: https://redis.io/docs/latest/develop/clients/nodejs/migration/
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Langfuse JS SDK vs REST API: Technical Assessment for CoAiA.js
|
|
2
|
+
|
|
3
|
+
> Package selection brief — LLM observability, tracing, and prompt management for CoAiA agent sessions
|
|
4
|
+
|
|
5
|
+
## Summary & Recommendation
|
|
6
|
+
|
|
7
|
+
**Use `langfuse` v4.x SDK** (`@langfuse/core` + `@langfuse/tracing`). The v4 rewrite (August 2025) brings OpenTelemetry-native tracing, modular packages, and direct integration with OpenAI — eliminating coaiapy's manual HTTP request overhead. The SDK handles batching, retries, and serialization that our REST wrapper currently does manually in `cofuse.py`.
|
|
8
|
+
|
|
9
|
+
**Pin:** `"langfuse": "^4.0.0"` (pulls `@langfuse/core`, `@langfuse/tracing`)
|
|
10
|
+
|
|
11
|
+
## What We're Replacing
|
|
12
|
+
|
|
13
|
+
Coaiapy uses raw HTTP requests to the Langfuse REST API via Python `requests`:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# coaiapy/cofuse.py — manual HTTP approach
|
|
17
|
+
import requests
|
|
18
|
+
from requests.auth import HTTPBasicAuth
|
|
19
|
+
|
|
20
|
+
def create_session_and_save():
|
|
21
|
+
# Manual JSON construction, auth header assembly, error handling
|
|
22
|
+
response = requests.post(f"{base_url}/api/public/traces",
|
|
23
|
+
json=payload,
|
|
24
|
+
auth=HTTPBasicAuth(public_key, secret_key))
|
|
25
|
+
|
|
26
|
+
def add_trace_node_and_save():
|
|
27
|
+
# More manual HTTP calls...
|
|
28
|
+
|
|
29
|
+
def list_traces():
|
|
30
|
+
response = requests.get(f"{base_url}/api/public/traces", ...)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This pattern requires ~200 lines of boilerplate for authentication, serialization, error handling, and retry logic that the SDK provides out of the box.
|
|
34
|
+
|
|
35
|
+
## Options Compared
|
|
36
|
+
|
|
37
|
+
| Feature | Langfuse JS SDK v4 | REST API (manual) |
|
|
38
|
+
|---------|-------------------|-------------------|
|
|
39
|
+
| Setup complexity | `new Langfuse({ publicKey, secretKey })` | Manual auth headers, URL construction |
|
|
40
|
+
| Trace creation | `langfuse.trace({ name, metadata })` | `POST /api/public/traces` + JSON body |
|
|
41
|
+
| Span nesting | `trace.span({ name })` → `span.generation()` | Manual parent-child ID tracking |
|
|
42
|
+
| OpenAI integration | `@langfuse/openai` drop-in wrapper | Manual extraction of token counts |
|
|
43
|
+
| Batch flush | Automatic with configurable intervals | Manual batching implementation |
|
|
44
|
+
| Retry logic | Built-in exponential backoff | Manual retry loops |
|
|
45
|
+
| OpenTelemetry | Native OTEL span processor | Not available |
|
|
46
|
+
| Type safety | Full TypeScript types | Manual interface definitions |
|
|
47
|
+
| Prompt management | `langfuse.getPrompt()` | `GET /api/public/prompts` |
|
|
48
|
+
| Scoring | `trace.score({ name, value })` | `POST /api/public/scores` + JSON body |
|
|
49
|
+
| MCP server integration | Native via hosted MCP | Manual tool definitions |
|
|
50
|
+
| Maintenance burden | ~5 lines setup | ~200+ lines of wrapper code |
|
|
51
|
+
|
|
52
|
+
## API Overview
|
|
53
|
+
|
|
54
|
+
### SDK Initialization
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Langfuse } from 'langfuse';
|
|
58
|
+
import { loadConfig } from '../config.js';
|
|
59
|
+
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
const langfuse = new Langfuse({
|
|
62
|
+
publicKey: config.langfusePublicKey,
|
|
63
|
+
secretKey: config.langfuseSecretKey,
|
|
64
|
+
baseUrl: config.langfuseBaseUrl ?? 'https://cloud.langfuse.com',
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Trace Creation (replacing cofuse.py create_session_and_save)
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// coaiapy equivalent: create_session_and_save()
|
|
72
|
+
async function createAgentSession(sessionId: string, metadata: Record<string, unknown>) {
|
|
73
|
+
const trace = langfuse.trace({
|
|
74
|
+
id: sessionId,
|
|
75
|
+
name: `coaia-session-${sessionId}`,
|
|
76
|
+
metadata,
|
|
77
|
+
tags: ['coaiajs', 'agent-session'],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Nested spans for pipeline steps
|
|
81
|
+
const span = trace.span({ name: 'pipeline-execution' });
|
|
82
|
+
|
|
83
|
+
// Generation tracking (replaces add_trace_node_and_save)
|
|
84
|
+
const generation = span.generation({
|
|
85
|
+
name: 'llm-call',
|
|
86
|
+
model: 'gpt-5.4',
|
|
87
|
+
input: messages,
|
|
88
|
+
output: response,
|
|
89
|
+
usage: { promptTokens: 150, completionTokens: 300 },
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
generation.end();
|
|
93
|
+
span.end();
|
|
94
|
+
|
|
95
|
+
return trace;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### OpenAI Integration (automatic tracing)
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { observeOpenAI } from '@langfuse/openai';
|
|
103
|
+
import OpenAI from 'openai';
|
|
104
|
+
|
|
105
|
+
// Wraps OpenAI client for automatic trace capture
|
|
106
|
+
const openai = observeOpenAI(new OpenAI(), {
|
|
107
|
+
langfuse,
|
|
108
|
+
generationName: 'coaia-generation',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Every call is automatically traced
|
|
112
|
+
const response = await openai.chat.completions.create({
|
|
113
|
+
model: 'gpt-5.4',
|
|
114
|
+
messages: [{ role: 'user', content: 'Analyze this chart...' }],
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Prompt Management
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// Fetch versioned prompts from Langfuse
|
|
122
|
+
const prompt = await langfuse.getPrompt('pde-decompose-system');
|
|
123
|
+
const compiled = prompt.compile({ context: 'structural tension chart' });
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Scoring (replacing cofuse.py create_score, apply_score_to_trace)
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
async function scoreTrace(traceId: string, scores: Record<string, number>) {
|
|
130
|
+
for (const [name, value] of Object.entries(scores)) {
|
|
131
|
+
langfuse.score({
|
|
132
|
+
traceId,
|
|
133
|
+
name,
|
|
134
|
+
value,
|
|
135
|
+
comment: `MMOT evaluation: ${name}`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
await langfuse.flushAsync();
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Integration Plan
|
|
143
|
+
|
|
144
|
+
1. **Core module:** `src/langfuse/client.ts` — singleton Langfuse instance from config
|
|
145
|
+
2. **Session tracing:** `src/langfuse/session.ts` — trace lifecycle for agent sessions (replaces cofuse.py)
|
|
146
|
+
3. **OpenAI wrapper:** `src/langfuse/openai.ts` — `observeOpenAI` integration for automatic tracing
|
|
147
|
+
4. **Scoring:** `src/langfuse/scoring.ts` — MMOT evaluation scoring
|
|
148
|
+
5. **Prompt management:** `src/langfuse/prompts.ts` — versioned prompt fetching
|
|
149
|
+
6. **Pipeline integration:** `src/pipeline/traced-step.ts` — auto-trace pipeline template execution
|
|
150
|
+
|
|
151
|
+
### When to Fall Back to REST
|
|
152
|
+
|
|
153
|
+
Keep a thin REST utility for edge cases:
|
|
154
|
+
- Langfuse endpoints not yet covered by SDK v4
|
|
155
|
+
- Direct database queries for custom dashboards
|
|
156
|
+
- Webhook payload verification
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Escape hatch for REST-only endpoints
|
|
160
|
+
async function langfuseRest(path: string, method = 'GET', body?: object) {
|
|
161
|
+
const config = loadConfig();
|
|
162
|
+
const auth = Buffer.from(`${config.langfusePublicKey}:${config.langfuseSecretKey}`).toString('base64');
|
|
163
|
+
return fetch(`${config.langfuseBaseUrl}/api/public${path}`, {
|
|
164
|
+
method,
|
|
165
|
+
headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json' },
|
|
166
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Version & Ecosystem
|
|
172
|
+
|
|
173
|
+
| Metric | Value |
|
|
174
|
+
|--------|-------|
|
|
175
|
+
| Current version | v4.x (rewritten Aug 2025) |
|
|
176
|
+
| Packages | `langfuse`, `@langfuse/core`, `@langfuse/tracing`, `@langfuse/openai` |
|
|
177
|
+
| Tracing standard | OpenTelemetry native |
|
|
178
|
+
| Node.js compat | ≥20 |
|
|
179
|
+
| TypeScript | Full native types |
|
|
180
|
+
| Bundle | Modular tree-shakeable |
|
|
181
|
+
| Integrations | OpenAI, LangChain, Vercel AI SDK |
|
|
182
|
+
| MCP | Hosted MCP server for prompt management |
|
|
183
|
+
| License | MIT |
|
|
184
|
+
|
|
185
|
+
## References
|
|
186
|
+
|
|
187
|
+
- npm: https://www.npmjs.com/package/langfuse
|
|
188
|
+
- GitHub: https://github.com/langfuse/langfuse-js
|
|
189
|
+
- Docs: https://langfuse.com/docs/sdk/typescript
|
|
190
|
+
- Changelog: https://langfuse.com/changelog
|
|
191
|
+
- DeepWiki architecture: https://deepwiki.com/langfuse/langfuse-js
|