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.
Files changed (171) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/README.md +2 -0
  3. package/articles/academic/NOTES.md +1 -0
  4. package/articles/academic/README.md +1 -0
  5. package/articles/academic/creative-orientation-vs-problem-solving.md +177 -0
  6. package/articles/academic/jsonl-knowledge-graphs-agent-memory.md +142 -0
  7. package/articles/academic/langfuse-observability-llm-pipelines.md +144 -0
  8. package/articles/academic/medicine-wheel-software-architecture.md +163 -0
  9. package/articles/academic/mmot-autonomous-agents.md +156 -0
  10. package/articles/academic/model-context-protocol-interagent.md +161 -0
  11. package/articles/academic/pde-prompt-decomposition.md +186 -0
  12. package/articles/academic/structural-tension-in-ai-agents.md +134 -0
  13. package/articles/reviews/mcp-protocol-design-review.md +170 -0
  14. package/articles/reviews/observability-ai-systems-review.md +176 -0
  15. package/articles/reviews/prompt-engineering-decomposition-review.md +184 -0
  16. package/articles/surveys/agent-orchestration-survey.md +186 -0
  17. package/articles/surveys/knowledge-graph-storage-survey.md +204 -0
  18. package/articles/surveys/structural-tension-methodology-survey.md +154 -0
  19. package/articles/technical/aws-sdk-v3-polly.md +270 -0
  20. package/articles/technical/commander-cli-framework.md +262 -0
  21. package/articles/technical/dotenv-config-patterns.md +360 -0
  22. package/articles/technical/ioredis-vs-redis.md +142 -0
  23. package/articles/technical/langfuse-js-sdk-vs-rest.md +191 -0
  24. package/articles/technical/mcp-sdk-typescript.md +291 -0
  25. package/articles/technical/octokit-github-api.md +293 -0
  26. package/articles/technical/openai-sdk-modern.md +231 -0
  27. package/articles/technical/yaml-parsing-node.md +266 -0
  28. package/articles/technical/zod-runtime-validation.md +212 -0
  29. package/dist/mcp/server.js +5 -3
  30. package/dist/mcp/tools/coaiapy-tools.js +1 -0
  31. package/dist/src/cli.js +41 -5
  32. package/dist/src/langfuse/index.d.ts +2 -2
  33. package/dist/src/langfuse/index.js +2 -2
  34. package/dist/src/langfuse/observations.d.ts +8 -1
  35. package/dist/src/langfuse/observations.js +29 -7
  36. package/dist/src/langfuse/traces.d.ts +20 -1
  37. package/dist/src/langfuse/traces.js +61 -2
  38. package/dist/src/redis.d.ts +1 -1
  39. package/dist/src/redis.js +2 -2
  40. package/mcp/config.ts +225 -0
  41. package/mcp/prompts.ts +131 -0
  42. package/mcp/resources.ts +84 -0
  43. package/mcp/server.ts +518 -0
  44. package/mcp/tools/coaiapy-tools.ts +366 -0
  45. package/mcp/tools/index.ts +4 -0
  46. package/package.json +4 -69
  47. package/src/audio.ts +76 -0
  48. package/src/cli-helpers.ts +86 -0
  49. package/src/cli.ts +1260 -0
  50. package/src/config.ts +207 -0
  51. package/src/environment.ts +171 -0
  52. package/src/github.ts +143 -0
  53. package/src/index.ts +82 -0
  54. package/src/langfuse/client.ts +105 -0
  55. package/src/langfuse/comments.ts +52 -0
  56. package/src/langfuse/datasets.ts +178 -0
  57. package/src/langfuse/index.ts +37 -0
  58. package/src/langfuse/media.ts +193 -0
  59. package/src/langfuse/observations.ts +155 -0
  60. package/src/langfuse/prompts.ts +157 -0
  61. package/src/langfuse/scores.ts +456 -0
  62. package/src/langfuse/traces.ts +353 -0
  63. package/src/llm.ts +106 -0
  64. package/src/narrative/graph-manager.ts +1358 -0
  65. package/src/narrative/index.ts +188 -0
  66. package/src/narrative/markdown-export.ts +535 -0
  67. package/src/narrative/tool-definitions.ts +635 -0
  68. package/src/narrative/tool-handlers.ts +528 -0
  69. package/src/narrative/types.ts +9 -0
  70. package/src/narrative/validation.ts +179 -0
  71. package/src/pde/index.ts +34 -0
  72. package/src/pde/mcp-handlers.ts +359 -0
  73. package/src/pde/mcp-tools.ts +201 -0
  74. package/src/pde/session-manager.ts +248 -0
  75. package/src/pde/stc-mapper.ts +298 -0
  76. package/src/pipeline/index.ts +7 -0
  77. package/src/pipeline/template-engine.ts +398 -0
  78. package/src/planning/index.ts +32 -0
  79. package/src/planning/mcp-handlers.ts +369 -0
  80. package/src/planning/mcp-tools.ts +155 -0
  81. package/src/planning/plan-parser.ts +587 -0
  82. package/src/redis.ts +111 -0
  83. package/src/types.ts +281 -0
  84. package/test/config.test.mjs +93 -0
  85. package/tsconfig.json +26 -0
  86. package/dist/mcp/config.d.ts.map +0 -1
  87. package/dist/mcp/config.js.map +0 -1
  88. package/dist/mcp/prompts.d.ts.map +0 -1
  89. package/dist/mcp/prompts.js.map +0 -1
  90. package/dist/mcp/resources.d.ts.map +0 -1
  91. package/dist/mcp/resources.js.map +0 -1
  92. package/dist/mcp/server.d.ts.map +0 -1
  93. package/dist/mcp/server.js.map +0 -1
  94. package/dist/mcp/tools/coaiapy-tools.d.ts.map +0 -1
  95. package/dist/mcp/tools/coaiapy-tools.js.map +0 -1
  96. package/dist/mcp/tools/index.d.ts.map +0 -1
  97. package/dist/mcp/tools/index.js.map +0 -1
  98. package/dist/src/audio.d.ts.map +0 -1
  99. package/dist/src/audio.js.map +0 -1
  100. package/dist/src/cli-helpers.d.ts.map +0 -1
  101. package/dist/src/cli-helpers.js.map +0 -1
  102. package/dist/src/cli.d.ts.map +0 -1
  103. package/dist/src/cli.js.map +0 -1
  104. package/dist/src/config.d.ts.map +0 -1
  105. package/dist/src/config.js.map +0 -1
  106. package/dist/src/environment.d.ts.map +0 -1
  107. package/dist/src/environment.js.map +0 -1
  108. package/dist/src/github.d.ts.map +0 -1
  109. package/dist/src/github.js.map +0 -1
  110. package/dist/src/index.d.ts.map +0 -1
  111. package/dist/src/index.js.map +0 -1
  112. package/dist/src/langfuse/client.d.ts.map +0 -1
  113. package/dist/src/langfuse/client.js.map +0 -1
  114. package/dist/src/langfuse/comments.d.ts.map +0 -1
  115. package/dist/src/langfuse/comments.js.map +0 -1
  116. package/dist/src/langfuse/datasets.d.ts.map +0 -1
  117. package/dist/src/langfuse/datasets.js.map +0 -1
  118. package/dist/src/langfuse/index.d.ts.map +0 -1
  119. package/dist/src/langfuse/index.js.map +0 -1
  120. package/dist/src/langfuse/media.d.ts.map +0 -1
  121. package/dist/src/langfuse/media.js.map +0 -1
  122. package/dist/src/langfuse/observations.d.ts.map +0 -1
  123. package/dist/src/langfuse/observations.js.map +0 -1
  124. package/dist/src/langfuse/prompts.d.ts.map +0 -1
  125. package/dist/src/langfuse/prompts.js.map +0 -1
  126. package/dist/src/langfuse/scores.d.ts.map +0 -1
  127. package/dist/src/langfuse/scores.js.map +0 -1
  128. package/dist/src/langfuse/traces.d.ts.map +0 -1
  129. package/dist/src/langfuse/traces.js.map +0 -1
  130. package/dist/src/llm.d.ts.map +0 -1
  131. package/dist/src/llm.js.map +0 -1
  132. package/dist/src/narrative/graph-manager.d.ts.map +0 -1
  133. package/dist/src/narrative/graph-manager.js.map +0 -1
  134. package/dist/src/narrative/index.d.ts.map +0 -1
  135. package/dist/src/narrative/index.js.map +0 -1
  136. package/dist/src/narrative/markdown-export.d.ts.map +0 -1
  137. package/dist/src/narrative/markdown-export.js.map +0 -1
  138. package/dist/src/narrative/tool-definitions.d.ts.map +0 -1
  139. package/dist/src/narrative/tool-definitions.js.map +0 -1
  140. package/dist/src/narrative/tool-handlers.d.ts.map +0 -1
  141. package/dist/src/narrative/tool-handlers.js.map +0 -1
  142. package/dist/src/narrative/types.d.ts.map +0 -1
  143. package/dist/src/narrative/types.js.map +0 -1
  144. package/dist/src/narrative/validation.d.ts.map +0 -1
  145. package/dist/src/narrative/validation.js.map +0 -1
  146. package/dist/src/pde/index.d.ts.map +0 -1
  147. package/dist/src/pde/index.js.map +0 -1
  148. package/dist/src/pde/mcp-handlers.d.ts.map +0 -1
  149. package/dist/src/pde/mcp-handlers.js.map +0 -1
  150. package/dist/src/pde/mcp-tools.d.ts.map +0 -1
  151. package/dist/src/pde/mcp-tools.js.map +0 -1
  152. package/dist/src/pde/session-manager.d.ts.map +0 -1
  153. package/dist/src/pde/session-manager.js.map +0 -1
  154. package/dist/src/pde/stc-mapper.d.ts.map +0 -1
  155. package/dist/src/pde/stc-mapper.js.map +0 -1
  156. package/dist/src/pipeline/index.d.ts.map +0 -1
  157. package/dist/src/pipeline/index.js.map +0 -1
  158. package/dist/src/pipeline/template-engine.d.ts.map +0 -1
  159. package/dist/src/pipeline/template-engine.js.map +0 -1
  160. package/dist/src/planning/index.d.ts.map +0 -1
  161. package/dist/src/planning/index.js.map +0 -1
  162. package/dist/src/planning/mcp-handlers.d.ts.map +0 -1
  163. package/dist/src/planning/mcp-handlers.js.map +0 -1
  164. package/dist/src/planning/mcp-tools.d.ts.map +0 -1
  165. package/dist/src/planning/mcp-tools.js.map +0 -1
  166. package/dist/src/planning/plan-parser.d.ts.map +0 -1
  167. package/dist/src/planning/plan-parser.js.map +0 -1
  168. package/dist/src/redis.d.ts.map +0 -1
  169. package/dist/src/redis.js.map +0 -1
  170. package/dist/src/types.d.ts.map +0 -1
  171. 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