network-ai 5.13.4 → 5.15.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/INTEGRATION_GUIDE.md +6 -3
- package/QUICKSTART.md +9 -4
- package/README.md +72 -15
- package/SKILL.md +1 -1
- package/bin/cli.ts +73 -0
- package/bin/mcp-server.ts +24 -1
- package/dist/adapters/claude-agent-sdk-adapter.d.ts +100 -0
- package/dist/adapters/claude-agent-sdk-adapter.d.ts.map +1 -0
- package/dist/adapters/claude-agent-sdk-adapter.js +204 -0
- package/dist/adapters/claude-agent-sdk-adapter.js.map +1 -0
- package/dist/adapters/gemini-adapter.d.ts +124 -0
- package/dist/adapters/gemini-adapter.d.ts.map +1 -0
- package/dist/adapters/gemini-adapter.js +239 -0
- package/dist/adapters/gemini-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +10 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/openai-responses-adapter.d.ts +119 -0
- package/dist/adapters/openai-responses-adapter.d.ts.map +1 -0
- package/dist/adapters/openai-responses-adapter.js +235 -0
- package/dist/adapters/openai-responses-adapter.js.map +1 -0
- package/dist/bin/cli.js +72 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/mcp-server.js +22 -1
- package/dist/bin/mcp-server.js.map +1 -1
- package/dist/esm/adapters/claude-agent-sdk-adapter.js +204 -0
- package/dist/esm/adapters/claude-agent-sdk-adapter.js.map +1 -0
- package/dist/esm/adapters/gemini-adapter.js +239 -0
- package/dist/esm/adapters/gemini-adapter.js.map +1 -0
- package/dist/esm/adapters/index.js +10 -1
- package/dist/esm/adapters/index.js.map +1 -1
- package/dist/esm/adapters/openai-responses-adapter.js +235 -0
- package/dist/esm/adapters/openai-responses-adapter.js.map +1 -0
- package/dist/esm/index.js +20 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/a2a-server.js +293 -0
- package/dist/esm/lib/a2a-server.js.map +1 -0
- package/dist/esm/lib/claude-hooks.js +307 -0
- package/dist/esm/lib/claude-hooks.js.map +1 -0
- package/dist/esm/lib/context-composer.js +332 -0
- package/dist/esm/lib/context-composer.js.map +1 -0
- package/dist/esm/lib/mcp-elicitation.js +198 -0
- package/dist/esm/lib/mcp-elicitation.js.map +1 -0
- package/dist/esm/lib/mcp-tools-context.js +266 -0
- package/dist/esm/lib/mcp-tools-context.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/a2a-server.d.ts +120 -0
- package/dist/lib/a2a-server.d.ts.map +1 -0
- package/dist/lib/a2a-server.js +293 -0
- package/dist/lib/a2a-server.js.map +1 -0
- package/dist/lib/claude-hooks.d.ts +150 -0
- package/dist/lib/claude-hooks.d.ts.map +1 -0
- package/dist/lib/claude-hooks.js +307 -0
- package/dist/lib/claude-hooks.js.map +1 -0
- package/dist/lib/context-composer.d.ts +187 -0
- package/dist/lib/context-composer.d.ts.map +1 -0
- package/dist/lib/context-composer.js +332 -0
- package/dist/lib/context-composer.js.map +1 -0
- package/dist/lib/mcp-elicitation.d.ts +116 -0
- package/dist/lib/mcp-elicitation.d.ts.map +1 -0
- package/dist/lib/mcp-elicitation.js +198 -0
- package/dist/lib/mcp-elicitation.js.map +1 -0
- package/dist/lib/mcp-tools-context.d.ts +77 -0
- package/dist/lib/mcp-tools-context.d.ts.map +1 -0
- package/dist/lib/mcp-tools-context.js +266 -0
- package/dist/lib/mcp-tools-context.js.map +1 -0
- package/package.json +2 -2
- package/scripts/clawhub-publish.js +14 -1
- package/socket.json +1 -1
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Context Composer — token-budgeted, relevance-ranked context assembly.
|
|
4
|
+
*
|
|
5
|
+
* Agents have large context windows but a much smaller *effective reasoning*
|
|
6
|
+
* window: irrelevant, stale, or noisy context degrades output quality long
|
|
7
|
+
* before the hard token limit ("context rot"). This module assembles the
|
|
8
|
+
* context block for an LLM call from candidate sources (blackboard entries,
|
|
9
|
+
* project context, memory recall) under a **hard token budget**, ranked by:
|
|
10
|
+
*
|
|
11
|
+
* score = w.relevance × relevance + w.recency × recency + w.affinity × affinity
|
|
12
|
+
*
|
|
13
|
+
* - **relevance** — semantic similarity to the task via a pluggable
|
|
14
|
+
* {@link SemanticRanker} (BYOE — e.g. wrap `SemanticMemory`), with a
|
|
15
|
+
* deterministic lexical-overlap fallback when no ranker is supplied;
|
|
16
|
+
* - **recency** — exponential half-life decay on the entry timestamp
|
|
17
|
+
* (the same math `EpisodicMemory` uses);
|
|
18
|
+
* - **affinity** — scope-tag match on the key (same substring semantics as
|
|
19
|
+
* `ContextThrottler`).
|
|
20
|
+
*
|
|
21
|
+
* Pinned sources (task-critical instructions, Layer-3 project context) are
|
|
22
|
+
* always included first. Assembly is position-aware by default: the
|
|
23
|
+
* strongest items are placed at the start *and end* of the block, weakest in
|
|
24
|
+
* the middle — mitigating "lost in the middle" attention decay.
|
|
25
|
+
*
|
|
26
|
+
* The result carries full observability metadata: what was included,
|
|
27
|
+
* what was excluded and why, token usage, and budget utilization.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const composer = new ContextComposer();
|
|
32
|
+
* const sources = ContextComposer.fromSnapshot(blackboard.getScopedSnapshot('analyst'));
|
|
33
|
+
* const pack = await composer.compose(sources, {
|
|
34
|
+
* task: 'Summarize Q3 revenue anomalies',
|
|
35
|
+
* budgetTokens: 2000,
|
|
36
|
+
* scopeTags: ['analytics', 'task'],
|
|
37
|
+
* });
|
|
38
|
+
* llmPrompt = `${instructions}\n\n${pack.text}`;
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @module ContextComposer
|
|
42
|
+
* @version 1.0.0
|
|
43
|
+
*/
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.ContextComposer = void 0;
|
|
46
|
+
exports.estimateTokens = estimateTokens;
|
|
47
|
+
exports.createSemanticMemoryRanker = createSemanticMemoryRanker;
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// TOKEN ESTIMATION
|
|
50
|
+
// ============================================================================
|
|
51
|
+
/**
|
|
52
|
+
* Estimate the token count of a text without a tokenizer dependency.
|
|
53
|
+
*
|
|
54
|
+
* Uses the ~4-characters-per-token heuristic blended with a word count
|
|
55
|
+
* (English prose averages ~0.75 tokens/word; code and JSON run denser).
|
|
56
|
+
* Accurate to roughly ±15% across prose/code/JSON — sufficient for budget
|
|
57
|
+
* enforcement, not for billing.
|
|
58
|
+
*/
|
|
59
|
+
function estimateTokens(text) {
|
|
60
|
+
if (!text)
|
|
61
|
+
return 0;
|
|
62
|
+
const byChars = text.length / 4;
|
|
63
|
+
const words = text.split(/\s+/).filter(Boolean).length;
|
|
64
|
+
const byWords = words * 1.33;
|
|
65
|
+
return Math.max(1, Math.ceil((byChars + byWords) / 2));
|
|
66
|
+
}
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// INTERNAL HELPERS
|
|
69
|
+
// ============================================================================
|
|
70
|
+
/** Tokenize text into a lowercase word set for lexical overlap scoring. */
|
|
71
|
+
function wordSet(text) {
|
|
72
|
+
return new Set(text
|
|
73
|
+
.toLowerCase()
|
|
74
|
+
.split(/[^a-z0-9_]+/)
|
|
75
|
+
.filter((w) => w.length > 2));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Deterministic lexical relevance: fraction of task words present in the
|
|
79
|
+
* item (key + text). Zero-dependency fallback when no semantic ranker is
|
|
80
|
+
* configured.
|
|
81
|
+
*/
|
|
82
|
+
function lexicalRelevance(taskWords, item) {
|
|
83
|
+
if (taskWords.size === 0)
|
|
84
|
+
return 0;
|
|
85
|
+
const itemWords = wordSet(`${item.key} ${item.text}`);
|
|
86
|
+
if (itemWords.size === 0)
|
|
87
|
+
return 0;
|
|
88
|
+
let hits = 0;
|
|
89
|
+
for (const w of taskWords) {
|
|
90
|
+
if (itemWords.has(w))
|
|
91
|
+
hits++;
|
|
92
|
+
}
|
|
93
|
+
return hits / taskWords.size;
|
|
94
|
+
}
|
|
95
|
+
/** Exponential half-life recency decay (1 = now, → 0 with age). */
|
|
96
|
+
function recencyScore(timestamp, halfLifeMs, now) {
|
|
97
|
+
if (!timestamp)
|
|
98
|
+
return 0.5; // unknown age — neutral
|
|
99
|
+
const t = Date.parse(timestamp);
|
|
100
|
+
if (Number.isNaN(t))
|
|
101
|
+
return 0.5;
|
|
102
|
+
const elapsed = Math.max(0, now - t);
|
|
103
|
+
return Math.pow(0.5, elapsed / halfLifeMs);
|
|
104
|
+
}
|
|
105
|
+
/** Scope-tag affinity — ContextThrottler substring semantics on the key. */
|
|
106
|
+
function affinityScore(key, scopeTags) {
|
|
107
|
+
if (!scopeTags || scopeTags.length === 0)
|
|
108
|
+
return 0.5; // no scoping — neutral
|
|
109
|
+
const lowerKey = key.toLowerCase();
|
|
110
|
+
return scopeTags.some((tag) => lowerKey.includes(tag.toLowerCase())) ? 1 : 0;
|
|
111
|
+
}
|
|
112
|
+
/** True when the entry's TTL has already elapsed relative to its timestamp. */
|
|
113
|
+
function isStale(source, now) {
|
|
114
|
+
if (source.ttl === null || source.ttl === undefined)
|
|
115
|
+
return false;
|
|
116
|
+
if (!source.timestamp)
|
|
117
|
+
return false;
|
|
118
|
+
const t = Date.parse(source.timestamp);
|
|
119
|
+
if (Number.isNaN(t))
|
|
120
|
+
return false;
|
|
121
|
+
return now - t > source.ttl * 1000;
|
|
122
|
+
}
|
|
123
|
+
/** Render one item as a labelled context block. */
|
|
124
|
+
function renderBlock(item) {
|
|
125
|
+
const origin = item.sourceAgent ? ` (from ${item.sourceAgent})` : '';
|
|
126
|
+
return `### ${item.key}${origin}\n${item.text}`;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Serpentine layout: ranked items `[1,2,3,4,5]` become `[1,3,5,4,2]` —
|
|
130
|
+
* strongest first, second-strongest last, weakest in the middle.
|
|
131
|
+
*/
|
|
132
|
+
function positionAwareLayout(ranked) {
|
|
133
|
+
const head = [];
|
|
134
|
+
const tail = [];
|
|
135
|
+
ranked.forEach((item, i) => {
|
|
136
|
+
if (i % 2 === 0)
|
|
137
|
+
head.push(item);
|
|
138
|
+
else
|
|
139
|
+
tail.unshift(item);
|
|
140
|
+
});
|
|
141
|
+
return [...head, ...tail];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Adapt a `SemanticMemory` instance (or anything with a compatible
|
|
145
|
+
* `search()`) into a {@link SemanticRanker}. Items the memory does not know
|
|
146
|
+
* about simply fall back to lexical scoring.
|
|
147
|
+
*/
|
|
148
|
+
function createSemanticMemoryRanker(memory) {
|
|
149
|
+
return async (query, items) => {
|
|
150
|
+
const results = await memory.search(query, items.length, 0);
|
|
151
|
+
const scores = new Map();
|
|
152
|
+
for (const r of results) {
|
|
153
|
+
// Cosine similarity may be negative — clamp to 0–1.
|
|
154
|
+
scores.set(r.key, Math.max(0, Math.min(1, r.score)));
|
|
155
|
+
}
|
|
156
|
+
return scores;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// CONTEXT COMPOSER
|
|
161
|
+
// ============================================================================
|
|
162
|
+
/**
|
|
163
|
+
* Assembles token-budgeted, relevance-ranked context packs from candidate
|
|
164
|
+
* sources. See the module docs for the ranking model.
|
|
165
|
+
*/
|
|
166
|
+
class ContextComposer {
|
|
167
|
+
halfLifeMs;
|
|
168
|
+
weights;
|
|
169
|
+
ranker;
|
|
170
|
+
constructor(options = {}) {
|
|
171
|
+
this.halfLifeMs = options.halfLifeMs ?? 1_800_000;
|
|
172
|
+
if (this.halfLifeMs <= 0) {
|
|
173
|
+
throw new Error('ContextComposer: halfLifeMs must be > 0');
|
|
174
|
+
}
|
|
175
|
+
const w = { relevance: 0.5, recency: 0.3, affinity: 0.2, ...(options.weights ?? {}) };
|
|
176
|
+
const sum = w.relevance + w.recency + w.affinity;
|
|
177
|
+
if (sum <= 0) {
|
|
178
|
+
throw new Error('ContextComposer: score weights must sum to a positive number');
|
|
179
|
+
}
|
|
180
|
+
this.weights = {
|
|
181
|
+
relevance: w.relevance / sum,
|
|
182
|
+
recency: w.recency / sum,
|
|
183
|
+
affinity: w.affinity / sum,
|
|
184
|
+
};
|
|
185
|
+
this.ranker = options.ranker;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Convert a blackboard snapshot (`getSnapshot()` / `getScopedSnapshot()`
|
|
189
|
+
* shape) into {@link ContextSource} candidates. Values are rendered as
|
|
190
|
+
* strings (JSON for objects) and truncated to `maxValueChars`.
|
|
191
|
+
*/
|
|
192
|
+
static fromSnapshot(snapshot, options = {}) {
|
|
193
|
+
const maxChars = options.maxValueChars ?? 4000;
|
|
194
|
+
const sources = [];
|
|
195
|
+
for (const [key, raw] of Object.entries(snapshot ?? {})) {
|
|
196
|
+
if (raw === null || raw === undefined)
|
|
197
|
+
continue;
|
|
198
|
+
let text;
|
|
199
|
+
let sourceAgent;
|
|
200
|
+
let timestamp;
|
|
201
|
+
let ttl;
|
|
202
|
+
if (typeof raw === 'object' && ('value' in raw)) {
|
|
203
|
+
const entry = raw;
|
|
204
|
+
const v = entry.value;
|
|
205
|
+
text = typeof v === 'string' ? v : JSON.stringify(v);
|
|
206
|
+
sourceAgent = entry.sourceAgent ?? entry.source_agent;
|
|
207
|
+
timestamp = entry.timestamp;
|
|
208
|
+
ttl = entry.ttl;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
text = typeof raw === 'string' ? raw : JSON.stringify(raw);
|
|
212
|
+
}
|
|
213
|
+
if (text === undefined || text === null)
|
|
214
|
+
continue;
|
|
215
|
+
sources.push({
|
|
216
|
+
key,
|
|
217
|
+
text: text.length > maxChars ? `${text.slice(0, maxChars)}…[truncated]` : text,
|
|
218
|
+
...(sourceAgent !== undefined ? { sourceAgent } : {}),
|
|
219
|
+
...(timestamp !== undefined ? { timestamp } : {}),
|
|
220
|
+
...(ttl !== undefined ? { ttl } : {}),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return sources;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Rank the candidate sources against the task and assemble the largest
|
|
227
|
+
* high-signal context block that fits the token budget.
|
|
228
|
+
*/
|
|
229
|
+
async compose(sources, options) {
|
|
230
|
+
if (!options || typeof options.task !== 'string' || options.task.trim() === '') {
|
|
231
|
+
throw new Error('ContextComposer.compose: options.task must be a non-empty string');
|
|
232
|
+
}
|
|
233
|
+
if (typeof options.budgetTokens !== 'number' || options.budgetTokens <= 0) {
|
|
234
|
+
throw new Error('ContextComposer.compose: options.budgetTokens must be > 0');
|
|
235
|
+
}
|
|
236
|
+
const now = Date.now();
|
|
237
|
+
const halfLifeMs = options.halfLifeMs ?? this.halfLifeMs;
|
|
238
|
+
const minScore = options.minScore ?? 0.05;
|
|
239
|
+
const maxItems = options.maxItems ?? 0;
|
|
240
|
+
const w = (() => {
|
|
241
|
+
if (!options.weights)
|
|
242
|
+
return this.weights;
|
|
243
|
+
const merged = { ...this.weights, ...options.weights };
|
|
244
|
+
const sum = merged.relevance + merged.recency + merged.affinity;
|
|
245
|
+
return sum > 0
|
|
246
|
+
? { relevance: merged.relevance / sum, recency: merged.recency / sum, affinity: merged.affinity / sum }
|
|
247
|
+
: this.weights;
|
|
248
|
+
})();
|
|
249
|
+
const excluded = [];
|
|
250
|
+
const pinned = [];
|
|
251
|
+
const candidates = [];
|
|
252
|
+
for (const source of sources ?? []) {
|
|
253
|
+
if (!source || typeof source.key !== 'string' || source.key === '')
|
|
254
|
+
continue;
|
|
255
|
+
if (!source.text || source.text.trim() === '') {
|
|
256
|
+
excluded.push({ key: source.key ?? '(unknown)', reason: 'empty' });
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (isStale(source, now)) {
|
|
260
|
+
excluded.push({ key: source.key, reason: 'stale' });
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
(source.pinned ? pinned : candidates).push(source);
|
|
264
|
+
}
|
|
265
|
+
// ── Relevance scores (semantic ranker with lexical fallback) ────────────
|
|
266
|
+
const taskWords = wordSet(options.task);
|
|
267
|
+
let semanticScores = new Map();
|
|
268
|
+
const ranker = options.ranker ?? this.ranker;
|
|
269
|
+
if (ranker && candidates.length > 0) {
|
|
270
|
+
try {
|
|
271
|
+
semanticScores = await ranker(options.task, candidates.map((c) => ({ key: c.key, text: c.text })));
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
semanticScores = new Map(); // ranker failure → lexical fallback for all
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// ── Score every candidate ────────────────────────────────────────────────
|
|
278
|
+
const ranked = candidates.map((c) => {
|
|
279
|
+
const relevance = semanticScores.get(c.key) ?? lexicalRelevance(taskWords, c);
|
|
280
|
+
const recency = recencyScore(c.timestamp, halfLifeMs, now);
|
|
281
|
+
const affinity = affinityScore(c.key, options.scopeTags);
|
|
282
|
+
const score = w.relevance * relevance + w.recency * recency + w.affinity * affinity;
|
|
283
|
+
return { ...c, relevance, recency, affinity, score, tokens: estimateTokens(renderBlock(c)) };
|
|
284
|
+
});
|
|
285
|
+
ranked.sort((a, b) => b.score - a.score);
|
|
286
|
+
// ── Budget-enforced selection: pinned first, then by score ──────────────
|
|
287
|
+
const included = [];
|
|
288
|
+
let usedTokens = 0;
|
|
289
|
+
for (const p of pinned) {
|
|
290
|
+
const tokens = estimateTokens(renderBlock(p));
|
|
291
|
+
if (usedTokens + tokens > options.budgetTokens) {
|
|
292
|
+
excluded.push({ key: p.key, reason: 'budget' });
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
usedTokens += tokens;
|
|
296
|
+
included.push({ ...p, relevance: 1, recency: 1, affinity: 1, score: 1, tokens });
|
|
297
|
+
}
|
|
298
|
+
for (const item of ranked) {
|
|
299
|
+
if (item.score < minScore) {
|
|
300
|
+
excluded.push({ key: item.key, reason: 'score', score: item.score });
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (maxItems > 0 && included.length >= maxItems) {
|
|
304
|
+
excluded.push({ key: item.key, reason: 'budget', score: item.score });
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (usedTokens + item.tokens > options.budgetTokens) {
|
|
308
|
+
excluded.push({ key: item.key, reason: 'budget', score: item.score });
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
usedTokens += item.tokens;
|
|
312
|
+
included.push(item);
|
|
313
|
+
}
|
|
314
|
+
// ── Assembly (pinned lead; ranked items in position-aware layout) ────────
|
|
315
|
+
const pinnedBlocks = included.filter((i) => i.pinned);
|
|
316
|
+
const rankedBlocks = included.filter((i) => !i.pinned);
|
|
317
|
+
const layout = (options.positionAware ?? true)
|
|
318
|
+
? positionAwareLayout(rankedBlocks)
|
|
319
|
+
: rankedBlocks;
|
|
320
|
+
const text = [...pinnedBlocks, ...layout].map((i) => renderBlock(i)).join('\n\n');
|
|
321
|
+
return {
|
|
322
|
+
text,
|
|
323
|
+
included,
|
|
324
|
+
excluded,
|
|
325
|
+
budgetTokens: options.budgetTokens,
|
|
326
|
+
usedTokens,
|
|
327
|
+
utilization: Math.min(1, usedTokens / options.budgetTokens),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
exports.ContextComposer = ContextComposer;
|
|
332
|
+
//# sourceMappingURL=context-composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-composer.js","sourceRoot":"","sources":["../../../lib/context-composer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP Elicitation — native in-client approval prompts.
|
|
4
|
+
*
|
|
5
|
+
* Implements the MCP elicitation capability (spec revision 2025-06-18):
|
|
6
|
+
* the server sends an `elicitation/create` JSON-RPC request *to the client*,
|
|
7
|
+
* the client renders it natively (Claude Code, Codex, Gemini CLI, Cursor…),
|
|
8
|
+
* and the user's answer comes back as the response.
|
|
9
|
+
*
|
|
10
|
+
* Network-AI uses this to surface `ApprovalGate` / `ApprovalInbox` decisions
|
|
11
|
+
* directly inside the MCP client instead of a separate HTTP inbox: wrap a
|
|
12
|
+
* request sender with {@link createElicitationApprovalCallback} and pass the
|
|
13
|
+
* resulting callback to `ApprovalGate`.
|
|
14
|
+
*
|
|
15
|
+
* Transport plumbing for stdio servers is provided by
|
|
16
|
+
* {@link StdioElicitationChannel}: it assigns request ids, writes
|
|
17
|
+
* newline-delimited JSON-RPC to the client, and resolves pending promises
|
|
18
|
+
* when responses arrive.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const channel = new StdioElicitationChannel((line) => process.stdout.write(line + '\n'));
|
|
23
|
+
* // in the stdin loop: if (channel.handleMessage(parsed)) return; // consumed a response
|
|
24
|
+
* const approvalCallback = createElicitationApprovalCallback(
|
|
25
|
+
* (params) => channel.request('elicitation/create', params),
|
|
26
|
+
* );
|
|
27
|
+
* const gate = new ApprovalGate(approvalCallback);
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @module McpElicitation
|
|
31
|
+
* @version 1.0.0
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.StdioElicitationChannel = void 0;
|
|
35
|
+
exports.createElicitationApprovalCallback = createElicitationApprovalCallback;
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// APPROVAL CALLBACK FACTORY
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Build an `ApprovalCallback` (as used by `ApprovalGate` / `AgentRuntime`)
|
|
41
|
+
* that resolves approvals by asking the connected MCP client through
|
|
42
|
+
* elicitation. Fail-closed: timeouts, transport errors, declines, and
|
|
43
|
+
* cancellations all resolve to `approved: false`.
|
|
44
|
+
*/
|
|
45
|
+
function createElicitationApprovalCallback(send, options = {}) {
|
|
46
|
+
const approvedBy = options.approvedBy ?? 'mcp-client';
|
|
47
|
+
const timeoutMs = options.timeoutMs ?? 300_000;
|
|
48
|
+
return async (request) => {
|
|
49
|
+
const params = {
|
|
50
|
+
message: `Approval required — agent "${request.agentId}" requests ${request.type} ` +
|
|
51
|
+
`on "${request.target}" (risk: ${request.risk})` +
|
|
52
|
+
(request.justification ? `\nJustification: ${request.justification}` : ''),
|
|
53
|
+
requestedSchema: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
approve: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
title: 'Approve this action?',
|
|
59
|
+
description: `Allow ${request.type} on ${request.target}`,
|
|
60
|
+
},
|
|
61
|
+
reason: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
title: 'Reason (optional)',
|
|
64
|
+
description: 'Why you approved or denied this action',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ['approve'],
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
let timer = null;
|
|
71
|
+
try {
|
|
72
|
+
const result = await Promise.race([
|
|
73
|
+
send(params),
|
|
74
|
+
new Promise((_, reject) => {
|
|
75
|
+
timer = setTimeout(() => reject(new Error(`elicitation timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
76
|
+
}),
|
|
77
|
+
]);
|
|
78
|
+
if (result.action === 'accept' && result.content?.['approve'] === true) {
|
|
79
|
+
const reason = typeof result.content['reason'] === 'string'
|
|
80
|
+
? result.content['reason']
|
|
81
|
+
: undefined;
|
|
82
|
+
return { approved: true, approvedBy, ...(reason ? { reason } : {}) };
|
|
83
|
+
}
|
|
84
|
+
const why = result.action === 'accept'
|
|
85
|
+
? 'user answered no'
|
|
86
|
+
: `user ${result.action === 'decline' ? 'declined' : 'cancelled'} the prompt`;
|
|
87
|
+
return { approved: false, reason: `Denied via MCP elicitation — ${why}` };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
91
|
+
// Fail closed: any transport failure is a denial, never an approval.
|
|
92
|
+
return { approved: false, reason: `Elicitation failed — ${message}` };
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
if (timer)
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Server→client request channel for newline-delimited JSON-RPC transports
|
|
102
|
+
* (stdio). Assigns unique ids to outgoing requests and resolves the pending
|
|
103
|
+
* promise when the matching response arrives.
|
|
104
|
+
*
|
|
105
|
+
* Integration contract for the stdin loop: for every parsed inbound message,
|
|
106
|
+
* call {@link handleMessage} first — if it returns `true` the message was a
|
|
107
|
+
* response to a server-initiated request and must not be dispatched as a
|
|
108
|
+
* client request.
|
|
109
|
+
*/
|
|
110
|
+
class StdioElicitationChannel {
|
|
111
|
+
write;
|
|
112
|
+
pending = new Map();
|
|
113
|
+
nextId = 1_000_000; // high offset avoids collisions with client request ids
|
|
114
|
+
defaultTimeoutMs;
|
|
115
|
+
/**
|
|
116
|
+
* @param write Writes one serialized JSON-RPC line to the client.
|
|
117
|
+
* @param defaultTimeoutMs Per-request timeout (default: 300000 = 5 min).
|
|
118
|
+
*/
|
|
119
|
+
constructor(write, defaultTimeoutMs = 300_000) {
|
|
120
|
+
this.write = write;
|
|
121
|
+
this.defaultTimeoutMs = defaultTimeoutMs;
|
|
122
|
+
}
|
|
123
|
+
/** Number of requests currently awaiting a client response */
|
|
124
|
+
get pendingCount() {
|
|
125
|
+
return this.pending.size;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Send a server→client request and resolve its result.
|
|
129
|
+
* Rejects on timeout, client error response, or malformed result.
|
|
130
|
+
*/
|
|
131
|
+
request(method, params, timeoutMs) {
|
|
132
|
+
const id = this.nextId++;
|
|
133
|
+
const line = JSON.stringify({ jsonrpc: '2.0', id, method, params });
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const effective = timeoutMs ?? this.defaultTimeoutMs;
|
|
136
|
+
const timer = effective > 0
|
|
137
|
+
? setTimeout(() => {
|
|
138
|
+
this.pending.delete(id);
|
|
139
|
+
reject(new Error(`request ${id} (${method}) timed out after ${effective}ms`));
|
|
140
|
+
}, effective)
|
|
141
|
+
: null;
|
|
142
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
143
|
+
try {
|
|
144
|
+
this.write(line);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (timer)
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
this.pending.delete(id);
|
|
150
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Route an inbound message. Returns `true` when the message was a response
|
|
156
|
+
* to a pending server-initiated request (and was consumed); `false` when it
|
|
157
|
+
* is a client request the caller should dispatch normally.
|
|
158
|
+
*/
|
|
159
|
+
handleMessage(message) {
|
|
160
|
+
if (message === null || typeof message !== 'object')
|
|
161
|
+
return false;
|
|
162
|
+
const msg = message;
|
|
163
|
+
// Requests (and notifications) carry a method — not ours to consume.
|
|
164
|
+
if (typeof msg.method === 'string')
|
|
165
|
+
return false;
|
|
166
|
+
if (msg.id === null || msg.id === undefined)
|
|
167
|
+
return false;
|
|
168
|
+
const id = typeof msg.id === 'number' ? msg.id : Number(msg.id);
|
|
169
|
+
const entry = this.pending.get(id);
|
|
170
|
+
if (!entry)
|
|
171
|
+
return false;
|
|
172
|
+
this.pending.delete(id);
|
|
173
|
+
if (entry.timer)
|
|
174
|
+
clearTimeout(entry.timer);
|
|
175
|
+
if (msg.error) {
|
|
176
|
+
entry.reject(new Error(`client error ${msg.error.code}: ${msg.error.message}`));
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
const result = msg.result;
|
|
180
|
+
if (!result || (result.action !== 'accept' && result.action !== 'decline' && result.action !== 'cancel')) {
|
|
181
|
+
entry.reject(new Error('malformed elicitation result from client'));
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
entry.resolve(result);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
/** Reject every pending request (e.g. on shutdown or client disconnect). */
|
|
188
|
+
rejectAll(reason = 'channel closed') {
|
|
189
|
+
for (const [id, entry] of this.pending) {
|
|
190
|
+
if (entry.timer)
|
|
191
|
+
clearTimeout(entry.timer);
|
|
192
|
+
entry.reject(new Error(`request ${id} aborted — ${reason}`));
|
|
193
|
+
}
|
|
194
|
+
this.pending.clear();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.StdioElicitationChannel = StdioElicitationChannel;
|
|
198
|
+
//# sourceMappingURL=mcp-elicitation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-elicitation.js","sourceRoot":"","sources":["../../../lib/mcp-elicitation.ts"],"names":[],"mappings":"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"}
|