coaiajs 0.1.2 → 0.2.1
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/settings.local.json +16 -0
- package/README.md +2 -0
- package/articles/academic/NOTES.md +1 -0
- package/articles/academic/README.md +1 -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/server.js +5 -3
- package/dist/mcp/tools/coaiapy-tools.js +1 -0
- package/dist/src/cli.js +41 -5
- package/dist/src/langfuse/index.d.ts +2 -2
- package/dist/src/langfuse/index.js +2 -2
- package/dist/src/langfuse/observations.d.ts +8 -1
- package/dist/src/langfuse/observations.js +29 -7
- package/dist/src/langfuse/traces.d.ts +20 -1
- package/dist/src/langfuse/traces.js +61 -2
- package/dist/src/redis.d.ts +1 -1
- package/dist/src/redis.js +2 -2
- package/mcp/config.ts +225 -0
- package/mcp/prompts.ts +131 -0
- package/mcp/resources.ts +84 -0
- package/mcp/server.ts +518 -0
- package/mcp/tools/coaiapy-tools.ts +366 -0
- package/mcp/tools/index.ts +4 -0
- package/package.json +4 -69
- package/src/audio.ts +76 -0
- package/src/cli-helpers.ts +86 -0
- package/src/cli.ts +1260 -0
- package/src/config.ts +207 -0
- package/src/environment.ts +171 -0
- package/src/github.ts +143 -0
- package/src/index.ts +82 -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 +37 -0
- package/src/langfuse/media.ts +193 -0
- package/src/langfuse/observations.ts +155 -0
- package/src/langfuse/prompts.ts +157 -0
- package/src/langfuse/scores.ts +456 -0
- package/src/langfuse/traces.ts +353 -0
- package/src/llm.ts +106 -0
- package/src/narrative/graph-manager.ts +1358 -0
- package/src/narrative/index.ts +188 -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 +34 -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 +32 -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 +111 -0
- package/src/types.ts +281 -0
- package/test/config.test.mjs +93 -0
- package/tsconfig.json +26 -0
- package/dist/mcp/config.d.ts.map +0 -1
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/prompts.d.ts.map +0 -1
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/resources.d.ts.map +0 -1
- package/dist/mcp/resources.js.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/tools/coaiapy-tools.d.ts.map +0 -1
- package/dist/mcp/tools/coaiapy-tools.js.map +0 -1
- package/dist/mcp/tools/index.d.ts.map +0 -1
- package/dist/mcp/tools/index.js.map +0 -1
- package/dist/src/audio.d.ts.map +0 -1
- package/dist/src/audio.js.map +0 -1
- package/dist/src/cli-helpers.d.ts.map +0 -1
- package/dist/src/cli-helpers.js.map +0 -1
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts.map +0 -1
- package/dist/src/config.js.map +0 -1
- package/dist/src/environment.d.ts.map +0 -1
- package/dist/src/environment.js.map +0 -1
- package/dist/src/github.d.ts.map +0 -1
- package/dist/src/github.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/langfuse/client.d.ts.map +0 -1
- package/dist/src/langfuse/client.js.map +0 -1
- package/dist/src/langfuse/comments.d.ts.map +0 -1
- package/dist/src/langfuse/comments.js.map +0 -1
- package/dist/src/langfuse/datasets.d.ts.map +0 -1
- package/dist/src/langfuse/datasets.js.map +0 -1
- package/dist/src/langfuse/index.d.ts.map +0 -1
- package/dist/src/langfuse/index.js.map +0 -1
- package/dist/src/langfuse/media.d.ts.map +0 -1
- package/dist/src/langfuse/media.js.map +0 -1
- package/dist/src/langfuse/observations.d.ts.map +0 -1
- package/dist/src/langfuse/observations.js.map +0 -1
- package/dist/src/langfuse/prompts.d.ts.map +0 -1
- package/dist/src/langfuse/prompts.js.map +0 -1
- package/dist/src/langfuse/scores.d.ts.map +0 -1
- package/dist/src/langfuse/scores.js.map +0 -1
- package/dist/src/langfuse/traces.d.ts.map +0 -1
- package/dist/src/langfuse/traces.js.map +0 -1
- package/dist/src/llm.d.ts.map +0 -1
- package/dist/src/llm.js.map +0 -1
- package/dist/src/narrative/graph-manager.d.ts.map +0 -1
- package/dist/src/narrative/graph-manager.js.map +0 -1
- package/dist/src/narrative/index.d.ts.map +0 -1
- package/dist/src/narrative/index.js.map +0 -1
- package/dist/src/narrative/markdown-export.d.ts.map +0 -1
- package/dist/src/narrative/markdown-export.js.map +0 -1
- package/dist/src/narrative/tool-definitions.d.ts.map +0 -1
- package/dist/src/narrative/tool-definitions.js.map +0 -1
- package/dist/src/narrative/tool-handlers.d.ts.map +0 -1
- package/dist/src/narrative/tool-handlers.js.map +0 -1
- package/dist/src/narrative/types.d.ts.map +0 -1
- package/dist/src/narrative/types.js.map +0 -1
- package/dist/src/narrative/validation.d.ts.map +0 -1
- package/dist/src/narrative/validation.js.map +0 -1
- package/dist/src/pde/index.d.ts.map +0 -1
- package/dist/src/pde/index.js.map +0 -1
- package/dist/src/pde/mcp-handlers.d.ts.map +0 -1
- package/dist/src/pde/mcp-handlers.js.map +0 -1
- package/dist/src/pde/mcp-tools.d.ts.map +0 -1
- package/dist/src/pde/mcp-tools.js.map +0 -1
- package/dist/src/pde/session-manager.d.ts.map +0 -1
- package/dist/src/pde/session-manager.js.map +0 -1
- package/dist/src/pde/stc-mapper.d.ts.map +0 -1
- package/dist/src/pde/stc-mapper.js.map +0 -1
- package/dist/src/pipeline/index.d.ts.map +0 -1
- package/dist/src/pipeline/index.js.map +0 -1
- package/dist/src/pipeline/template-engine.d.ts.map +0 -1
- package/dist/src/pipeline/template-engine.js.map +0 -1
- package/dist/src/planning/index.d.ts.map +0 -1
- package/dist/src/planning/index.js.map +0 -1
- package/dist/src/planning/mcp-handlers.d.ts.map +0 -1
- package/dist/src/planning/mcp-handlers.js.map +0 -1
- package/dist/src/planning/mcp-tools.d.ts.map +0 -1
- package/dist/src/planning/mcp-tools.js.map +0 -1
- package/dist/src/planning/plan-parser.d.ts.map +0 -1
- package/dist/src/planning/plan-parser.js.map +0 -1
- package/dist/src/redis.d.ts.map +0 -1
- package/dist/src/redis.js.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js.map +0 -1
|
@@ -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
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# @modelcontextprotocol/sdk: Technical Assessment for CoAiA.js
|
|
2
|
+
|
|
3
|
+
> Package selection brief — MCP server and client framework for exposing CoAiA tools, resources, and prompts to LLM agents
|
|
4
|
+
|
|
5
|
+
## Summary & Recommendation
|
|
6
|
+
|
|
7
|
+
**Use `@modelcontextprotocol/sdk` v1.x** (currently 1.27.x). This is the official Tier-1 TypeScript SDK for the Model Context Protocol. It's already used by coaia-pde, coaia-planning, and coaia-narrative. For coaiajs, we consolidate all three MCP servers into a single unified server with Zod-validated tools. Stick with v1 until v2 reaches stable (expected Q2 2026).
|
|
8
|
+
|
|
9
|
+
**Pin:** `"@modelcontextprotocol/sdk": "^1.25.0"` + `"zod": "^4.0.0"` (peer dependency)
|
|
10
|
+
|
|
11
|
+
## What We're Replacing
|
|
12
|
+
|
|
13
|
+
Three separate MCP servers each with their own Server instance:
|
|
14
|
+
|
|
15
|
+
### coaia-pde (Server + raw JSON schemas)
|
|
16
|
+
```typescript
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
19
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
|
|
21
|
+
const server = new Server(
|
|
22
|
+
{ name: 'coaia-pde', version: '1.0.0' },
|
|
23
|
+
{ capabilities: { tools: {} } }
|
|
24
|
+
);
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
26
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
27
|
+
const { name, arguments: args } = request.params;
|
|
28
|
+
switch(name) { case 'import_pde_decomposition': /* ... */ }
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### coaia-planning (Server + minimist config)
|
|
33
|
+
```typescript
|
|
34
|
+
const args = minimist(process.argv.slice(2));
|
|
35
|
+
const PLANS_DIR = args['plans-dir'] || process.env.COAIA_PLANS_DIR;
|
|
36
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
37
|
+
switch (name) {
|
|
38
|
+
case 'parse_plan_structural': /* ... */
|
|
39
|
+
case 'plan_to_stc': /* ... */
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### coaia-narrative (Server + custom validation.ts)
|
|
45
|
+
```typescript
|
|
46
|
+
// Uses custom validation.ts for argument checking before processing
|
|
47
|
+
const { valid, error } = validate(args, EntityArraySchema);
|
|
48
|
+
if (!valid) return errorResponse(error);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
All three use the **low-level** `Server` class with raw `setRequestHandler` and manual JSON schema definitions. The SDK's higher-level `McpServer` class with Zod eliminates this boilerplate.
|
|
52
|
+
|
|
53
|
+
## Options Compared
|
|
54
|
+
|
|
55
|
+
| Feature | McpServer (high-level) | Server (low-level) | Custom HTTP |
|
|
56
|
+
|---------|----------------------|-------------------|-------------|
|
|
57
|
+
| Tool definition | `server.tool(name, schema, handler)` | Manual `setRequestHandler` + switch | Manual routing |
|
|
58
|
+
| Schema validation | Zod automatic | Manual JSON Schema | Manual |
|
|
59
|
+
| Type inference | Full from Zod schemas | Manual casting | None |
|
|
60
|
+
| Resource support | `server.resource()` | Manual handler | Manual |
|
|
61
|
+
| Prompt templates | `server.prompt()` | Manual handler | N/A |
|
|
62
|
+
| Transport | Stdio, HTTP, SSE built-in | Stdio, HTTP, SSE built-in | Custom |
|
|
63
|
+
| Code per tool | ~10 lines | ~25 lines | ~50 lines |
|
|
64
|
+
| Used by our projects | New for coaiajs | coaia-pde, coaia-planning, coaia-narrative | N/A |
|
|
65
|
+
|
|
66
|
+
## API Overview
|
|
67
|
+
|
|
68
|
+
### Unified MCP Server (High-Level API)
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// mcp/server.ts — single unified MCP server for coaiajs
|
|
72
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
73
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
74
|
+
import { z } from 'zod';
|
|
75
|
+
|
|
76
|
+
const server = new McpServer({
|
|
77
|
+
name: 'coaiajs',
|
|
78
|
+
version: '1.0.0',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// --- NARRATIVE TOOLS ---
|
|
82
|
+
|
|
83
|
+
server.tool(
|
|
84
|
+
'create_structural_tension_chart',
|
|
85
|
+
'Create a new structural tension chart with desired outcome and current reality',
|
|
86
|
+
{
|
|
87
|
+
desiredOutcome: z.string().min(1).describe('What you want to CREATE'),
|
|
88
|
+
currentReality: z.string().min(1).describe('Factual assessment — never "ready to begin"'),
|
|
89
|
+
dueDate: z.string().datetime().optional().describe('ISO 8601 target date'),
|
|
90
|
+
actionSteps: z.array(z.string()).optional().describe('Initial action steps'),
|
|
91
|
+
},
|
|
92
|
+
async ({ desiredOutcome, currentReality, dueDate, actionSteps }) => {
|
|
93
|
+
const chart = await createChart({ desiredOutcome, currentReality, dueDate, actionSteps });
|
|
94
|
+
return { content: [{ type: 'text', text: JSON.stringify(chart) }] };
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
server.tool(
|
|
99
|
+
'mark_action_complete',
|
|
100
|
+
'Mark an action step as completed',
|
|
101
|
+
{
|
|
102
|
+
actionStepName: z.string().min(1).describe('Name of the completed action step'),
|
|
103
|
+
},
|
|
104
|
+
async ({ actionStepName }) => {
|
|
105
|
+
const result = await markComplete(actionStepName);
|
|
106
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// --- PDE TOOLS ---
|
|
111
|
+
|
|
112
|
+
server.tool(
|
|
113
|
+
'pde_decompose',
|
|
114
|
+
'Decompose a complex prompt into structured facets',
|
|
115
|
+
{
|
|
116
|
+
prompt: z.string().min(1).describe('The complex prompt to decompose'),
|
|
117
|
+
extractImplicit: z.boolean().default(true).describe('Extract implicit intents'),
|
|
118
|
+
mapDependencies: z.boolean().default(true).describe('Map inter-facet dependencies'),
|
|
119
|
+
},
|
|
120
|
+
async ({ prompt, extractImplicit, mapDependencies }) => {
|
|
121
|
+
const result = await decompose(prompt, { extractImplicit, mapDependencies });
|
|
122
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// --- PLANNING TOOLS ---
|
|
127
|
+
|
|
128
|
+
server.tool(
|
|
129
|
+
'parse_plan_structural',
|
|
130
|
+
'Parse a plan into structural tension format',
|
|
131
|
+
{
|
|
132
|
+
planPath: z.string().optional().describe('Path to plan file'),
|
|
133
|
+
planContent: z.string().optional().describe('Raw plan content'),
|
|
134
|
+
},
|
|
135
|
+
async ({ planPath, planContent }) => {
|
|
136
|
+
const parsed = planPath ? await parsePlan(planPath) : parsePlanContent(planContent!);
|
|
137
|
+
return { content: [{ type: 'text', text: JSON.stringify(parsed) }] };
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Resources (Read-Only Data)
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Expose chart data as MCP resources
|
|
146
|
+
server.resource(
|
|
147
|
+
'charts',
|
|
148
|
+
'chart://list',
|
|
149
|
+
async (uri) => {
|
|
150
|
+
const charts = await listActiveCharts();
|
|
151
|
+
return {
|
|
152
|
+
contents: [{
|
|
153
|
+
uri: uri.href,
|
|
154
|
+
mimeType: 'application/json',
|
|
155
|
+
text: JSON.stringify(charts),
|
|
156
|
+
}],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Dynamic resource with URI template
|
|
162
|
+
server.resource(
|
|
163
|
+
'chart-detail',
|
|
164
|
+
'chart://{chartId}',
|
|
165
|
+
async (uri, { chartId }) => {
|
|
166
|
+
const chart = await getChart(chartId);
|
|
167
|
+
return {
|
|
168
|
+
contents: [{
|
|
169
|
+
uri: uri.href,
|
|
170
|
+
mimeType: 'application/json',
|
|
171
|
+
text: JSON.stringify(chart),
|
|
172
|
+
}],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Prompt Templates
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
server.prompt(
|
|
182
|
+
'mmot-evaluation',
|
|
183
|
+
'MMOT self-evaluation prompt for structural tension chart',
|
|
184
|
+
{
|
|
185
|
+
chartId: z.string().describe('Chart ID to evaluate'),
|
|
186
|
+
direction: z.enum(['South', 'East', 'West', 'North']).optional(),
|
|
187
|
+
},
|
|
188
|
+
async ({ chartId, direction }) => {
|
|
189
|
+
const chart = await getChart(chartId);
|
|
190
|
+
return {
|
|
191
|
+
messages: [{
|
|
192
|
+
role: 'user',
|
|
193
|
+
content: {
|
|
194
|
+
type: 'text',
|
|
195
|
+
text: `Evaluate chart "${chart.desiredOutcome}" from ${direction ?? 'all'} direction(s)...`,
|
|
196
|
+
},
|
|
197
|
+
}],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Transport & Startup
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Stdio transport (default for CLI agent integration)
|
|
207
|
+
async function main() {
|
|
208
|
+
const transport = new StdioServerTransport();
|
|
209
|
+
await server.connect(transport);
|
|
210
|
+
console.error('coaiajs MCP server running on stdio');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
main().catch(console.error);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Low-Level API (when needed)
|
|
217
|
+
|
|
218
|
+
For advanced scenarios (custom transports, middleware, session state), the low-level `Server` class remains available:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
222
|
+
|
|
223
|
+
const lowLevelServer = new Server(
|
|
224
|
+
{ name: 'coaiajs-advanced', version: '1.0.0' },
|
|
225
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Custom request handler with full control
|
|
229
|
+
lowLevelServer.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
230
|
+
// Pre-processing middleware, custom logging, etc.
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Integration Plan
|
|
235
|
+
|
|
236
|
+
1. **Unified server:** `mcp/server.ts` — single McpServer combining all tools
|
|
237
|
+
2. **Tool modules:** `mcp/tools/` directory
|
|
238
|
+
- `narrative.ts` — chart CRUD, action steps, MMOT
|
|
239
|
+
- `pde.ts` — prompt decomposition tools
|
|
240
|
+
- `planning.ts` — plan parsing, STC conversion
|
|
241
|
+
- `pipeline.ts` — pipeline template execution
|
|
242
|
+
- `langfuse.ts` — trace/score management
|
|
243
|
+
3. **Resources:** `mcp/resources/` — chart data, session data, template listings
|
|
244
|
+
4. **Prompts:** `mcp/prompts/` — MMOT evaluation, PDE system prompts
|
|
245
|
+
5. **Bin entry:** `"coaiajs-mcp": "./dist/mcp/server.js"` in package.json
|
|
246
|
+
6. **Migration:** Gradually absorb coaia-pde, coaia-planning, coaia-narrative tools
|
|
247
|
+
|
|
248
|
+
### Tool Registration Pattern
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
// mcp/tools/index.ts — register all tool modules
|
|
252
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
253
|
+
|
|
254
|
+
export function registerAllTools(server: McpServer) {
|
|
255
|
+
registerNarrativeTools(server);
|
|
256
|
+
registerPdeTools(server);
|
|
257
|
+
registerPlanningTools(server);
|
|
258
|
+
registerPipelineTools(server);
|
|
259
|
+
registerLangfuseTools(server);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Version & Ecosystem
|
|
264
|
+
|
|
265
|
+
| Metric | Value |
|
|
266
|
+
|--------|-------|
|
|
267
|
+
| Current version | 1.27.1 (Feb 2026) |
|
|
268
|
+
| V2 status | Pre-alpha on main branch, stable Q1-Q2 2026 |
|
|
269
|
+
| Peer dependency | zod ≥3.25 |
|
|
270
|
+
| Transports | stdio, Streamable HTTP, SSE |
|
|
271
|
+
| Node.js compat | ≥18 (we target ≥20) |
|
|
272
|
+
| TypeScript | Native, first-class |
|
|
273
|
+
| Protocol spec | modelcontextprotocol.io |
|
|
274
|
+
| Weekly downloads | Growing rapidly (protocol adoption) |
|
|
275
|
+
| License | MIT |
|
|
276
|
+
|
|
277
|
+
## V1 → V2 Migration Notes
|
|
278
|
+
|
|
279
|
+
V2 (pre-alpha) brings breaking changes. Our plan:
|
|
280
|
+
- Build on V1 now (`^1.25.0`)
|
|
281
|
+
- V1 will receive security updates for 6+ months post-V2 release
|
|
282
|
+
- When V2 stabilizes, migrate — the high-level McpServer API is expected to remain similar
|
|
283
|
+
|
|
284
|
+
## References
|
|
285
|
+
|
|
286
|
+
- npm: https://www.npmjs.com/package/@modelcontextprotocol/sdk
|
|
287
|
+
- GitHub: https://github.com/modelcontextprotocol/typescript-sdk
|
|
288
|
+
- Protocol docs: https://modelcontextprotocol.io/docs/sdk
|
|
289
|
+
- API reference: https://markaicode.com/mcp-typescript-sdk-api-reference/
|
|
290
|
+
- V2 docs: https://ts.sdk.modelcontextprotocol.io/v2/
|
|
291
|
+
- Tutorial: https://dev.to/1xapi/how-to-build-mcp-servers-in-nodejs-for-ai-agents-2026-guide-fdi
|