@inspectr/mcplab 1.30.0 → 1.31.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/README.md +2 -2
- package/dist/app/assets/index-Co-US91U.js +267 -0
- package/dist/app/assets/index-D5OYchKq.css +2 -0
- package/dist/app/index.html +2 -2
- package/dist/app-server/app-context.d.ts +6 -22
- package/dist/app-server/app-context.d.ts.map +1 -1
- package/dist/app-server/assistant-agent.d.ts +10 -0
- package/dist/app-server/assistant-agent.d.ts.map +1 -0
- package/dist/app-server/assistant-agent.js +29 -0
- package/dist/app-server/assistant-agent.js.map +1 -0
- package/dist/app-server/assistant-common.d.ts +7 -34
- package/dist/app-server/assistant-common.d.ts.map +1 -1
- package/dist/app-server/assistant-common.js +33 -194
- package/dist/app-server/assistant-common.js.map +1 -1
- package/dist/app-server/assistant-events.d.ts +10 -6
- package/dist/app-server/assistant-events.d.ts.map +1 -1
- package/dist/app-server/assistant-events.js +23 -11
- package/dist/app-server/assistant-events.js.map +1 -1
- package/dist/app-server/assistant-graph-nodes.d.ts +226 -0
- package/dist/app-server/assistant-graph-nodes.d.ts.map +1 -0
- package/dist/app-server/assistant-graph-nodes.js +365 -0
- package/dist/app-server/assistant-graph-nodes.js.map +1 -0
- package/dist/app-server/assistant-graph-state.d.ts +64 -0
- package/dist/app-server/assistant-graph-state.d.ts.map +1 -0
- package/dist/app-server/assistant-graph-state.js +137 -0
- package/dist/app-server/assistant-graph-state.js.map +1 -0
- package/dist/app-server/assistant-mcp-context-tools.d.ts +17 -0
- package/dist/app-server/assistant-mcp-context-tools.d.ts.map +1 -0
- package/dist/app-server/assistant-mcp-context-tools.js +149 -0
- package/dist/app-server/assistant-mcp-context-tools.js.map +1 -0
- package/dist/app-server/assistant-model.d.ts +24 -0
- package/dist/app-server/assistant-model.d.ts.map +1 -0
- package/dist/app-server/assistant-model.js +240 -0
- package/dist/app-server/assistant-model.js.map +1 -0
- package/dist/app-server/assistant-runtime-contract.d.ts +46 -0
- package/dist/app-server/assistant-runtime-contract.d.ts.map +1 -0
- package/dist/app-server/assistant-runtime-contract.js +2 -0
- package/dist/app-server/assistant-runtime-contract.js.map +1 -0
- package/dist/app-server/assistant-runtime-policy.d.ts +22 -0
- package/dist/app-server/assistant-runtime-policy.d.ts.map +1 -0
- package/dist/app-server/assistant-runtime-policy.js +71 -0
- package/dist/app-server/assistant-runtime-policy.js.map +1 -0
- package/dist/app-server/assistant-service.d.ts +23 -0
- package/dist/app-server/assistant-service.d.ts.map +1 -0
- package/dist/app-server/assistant-service.js +185 -0
- package/dist/app-server/assistant-service.js.map +1 -0
- package/dist/app-server/assistant-session-routes.d.ts +25 -0
- package/dist/app-server/assistant-session-routes.d.ts.map +1 -0
- package/dist/app-server/assistant-session-routes.js +210 -0
- package/dist/app-server/assistant-session-routes.js.map +1 -0
- package/dist/app-server/assistant-tracing.d.ts +5 -0
- package/dist/app-server/assistant-tracing.d.ts.map +1 -0
- package/dist/app-server/assistant-tracing.js +30 -0
- package/dist/app-server/assistant-tracing.js.map +1 -0
- package/dist/app-server/browser-provider-learning.js +1 -1
- package/dist/app-server/browser-provider-learning.js.map +1 -1
- package/dist/app-server/inspectr-session-manager.d.ts +28 -34
- package/dist/app-server/inspectr-session-manager.d.ts.map +1 -1
- package/dist/app-server/inspectr-session-manager.js +13 -4
- package/dist/app-server/inspectr-session-manager.js.map +1 -1
- package/dist/app-server/langchain-assistant-runtime.d.ts +11 -0
- package/dist/app-server/langchain-assistant-runtime.d.ts.map +1 -0
- package/dist/app-server/langchain-assistant-runtime.js +852 -0
- package/dist/app-server/langchain-assistant-runtime.js.map +1 -0
- package/dist/app-server/one-shot-json.d.ts +26 -0
- package/dist/app-server/one-shot-json.d.ts.map +1 -0
- package/dist/app-server/one-shot-json.js +168 -0
- package/dist/app-server/one-shot-json.js.map +1 -0
- package/dist/app-server/result-assistant-domain.d.ts +46 -48
- package/dist/app-server/result-assistant-domain.d.ts.map +1 -1
- package/dist/app-server/result-assistant-domain.js +148 -133
- package/dist/app-server/result-assistant-domain.js.map +1 -1
- package/dist/app-server/result-assistant.d.ts +2 -2
- package/dist/app-server/result-assistant.d.ts.map +1 -1
- package/dist/app-server/result-assistant.js +43 -311
- package/dist/app-server/result-assistant.js.map +1 -1
- package/dist/app-server/router.d.ts.map +1 -1
- package/dist/app-server/router.js +14 -16
- package/dist/app-server/router.js.map +1 -1
- package/dist/app-server/runs-routes.js +1 -1
- package/dist/app-server/runs-routes.js.map +1 -1
- package/dist/app-server/scenario-assistant-domain.d.ts +43 -136
- package/dist/app-server/scenario-assistant-domain.d.ts.map +1 -1
- package/dist/app-server/scenario-assistant-domain.js +377 -215
- package/dist/app-server/scenario-assistant-domain.js.map +1 -1
- package/dist/app-server/scenario-assistant.d.ts +3 -3
- package/dist/app-server/scenario-assistant.d.ts.map +1 -1
- package/dist/app-server/scenario-assistant.js +52 -406
- package/dist/app-server/scenario-assistant.js.map +1 -1
- package/dist/app-server/settings-store.d.ts.map +1 -1
- package/dist/app-server/settings-store.js +2 -5
- package/dist/app-server/settings-store.js.map +1 -1
- package/dist/app-server/tool-analysis-domain.d.ts +1 -1
- package/dist/app-server/tool-analysis-domain.d.ts.map +1 -1
- package/dist/app-server/tool-analysis-domain.js +5 -4
- package/dist/app-server/tool-analysis-domain.js.map +1 -1
- package/dist/app-server/types.d.ts +1 -1
- package/dist/app-server/types.d.ts.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/package.json +10 -4
- package/dist/app/assets/index-8I9ZyPIK.js +0 -243
- package/dist/app/assets/index-jX7LoIQP.css +0 -2
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { formatAssistantToolName } from '@inspectr/mcplab-core';
|
|
2
|
+
const MAX_DISPLAY_DESCRIPTION_CHARS = 300;
|
|
3
|
+
/** What someone approving a call needs from an MCP tool definition: its title, purpose and risk. */
|
|
4
|
+
export function assistantToolDisplay(tool) {
|
|
5
|
+
const annotations = tool.annotations;
|
|
6
|
+
const hints = {
|
|
7
|
+
...(annotations?.readOnlyHint !== undefined ? { readOnly: annotations.readOnlyHint } : {}),
|
|
8
|
+
...(annotations?.destructiveHint !== undefined
|
|
9
|
+
? { destructive: annotations.destructiveHint }
|
|
10
|
+
: {}),
|
|
11
|
+
...(annotations?.idempotentHint !== undefined
|
|
12
|
+
? { idempotent: annotations.idempotentHint }
|
|
13
|
+
: {}),
|
|
14
|
+
...(annotations?.openWorldHint !== undefined ? { openWorld: annotations.openWorldHint } : {})
|
|
15
|
+
};
|
|
16
|
+
const title = tool.title ?? annotations?.title;
|
|
17
|
+
// The first paragraph is the summary; the rest is usually guidance for the model.
|
|
18
|
+
const summary = tool.description
|
|
19
|
+
?.trim()
|
|
20
|
+
.split(/\n\s*\n/)[0]
|
|
21
|
+
?.trim();
|
|
22
|
+
const description = summary && summary.length > MAX_DISPLAY_DESCRIPTION_CHARS
|
|
23
|
+
? `${summary.slice(0, MAX_DISPLAY_DESCRIPTION_CHARS - 1).trimEnd()}…`
|
|
24
|
+
: summary;
|
|
25
|
+
return {
|
|
26
|
+
...(title ? { title } : {}),
|
|
27
|
+
...(description ? { description } : {}),
|
|
28
|
+
...(Object.keys(hints).length ? { hints } : {})
|
|
29
|
+
};
|
|
30
|
+
}
|
|
3
31
|
export { formatAssistantToolName };
|
|
4
32
|
export function truncateJson(value, maxChars) {
|
|
5
33
|
try {
|
|
@@ -12,114 +40,6 @@ export function truncateJson(value, maxChars) {
|
|
|
12
40
|
return String(value);
|
|
13
41
|
}
|
|
14
42
|
}
|
|
15
|
-
function* extractBalancedJsonCandidates(text) {
|
|
16
|
-
const starts = [];
|
|
17
|
-
for (let i = 0; i < text.length; i += 1) {
|
|
18
|
-
const ch = text[i];
|
|
19
|
-
if (ch === '{')
|
|
20
|
-
starts.push({ idx: i, open: '{', close: '}' });
|
|
21
|
-
if (ch === '[')
|
|
22
|
-
starts.push({ idx: i, open: '[', close: ']' });
|
|
23
|
-
}
|
|
24
|
-
let enclosingCandidateEnd = -1;
|
|
25
|
-
for (const start of starts) {
|
|
26
|
-
if (start.idx <= enclosingCandidateEnd)
|
|
27
|
-
continue;
|
|
28
|
-
let depth = 0;
|
|
29
|
-
let inString = false;
|
|
30
|
-
let escaped = false;
|
|
31
|
-
for (let i = start.idx; i < text.length; i += 1) {
|
|
32
|
-
const ch = text[i];
|
|
33
|
-
if (inString) {
|
|
34
|
-
if (escaped) {
|
|
35
|
-
escaped = false;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (ch === '\\') {
|
|
39
|
-
escaped = true;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (ch === '"')
|
|
43
|
-
inString = false;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (ch === '"') {
|
|
47
|
-
inString = true;
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (ch === start.open)
|
|
51
|
-
depth += 1;
|
|
52
|
-
if (ch === start.close) {
|
|
53
|
-
depth -= 1;
|
|
54
|
-
if (depth === 0) {
|
|
55
|
-
const candidate = text.slice(start.idx, i + 1);
|
|
56
|
-
try {
|
|
57
|
-
JSON.parse(candidate);
|
|
58
|
-
// Keep complete wrappers, not their nested profile or diagnostic arrays.
|
|
59
|
-
enclosingCandidateEnd = i;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// An invalid prose fragment may still contain a complete JSON payload.
|
|
63
|
-
}
|
|
64
|
-
yield candidate;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
export function extractJsonValuesFromAssistantText(text) {
|
|
72
|
-
const values = [];
|
|
73
|
-
for (const candidate of extractBalancedJsonCandidates(text)) {
|
|
74
|
-
try {
|
|
75
|
-
values.push(JSON.parse(candidate));
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
// Ignore CSS selectors and explanatory prose containing brackets.
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return values;
|
|
82
|
-
}
|
|
83
|
-
export function parseJsonFromAssistantText(text, validate) {
|
|
84
|
-
const cleaned = text.trim();
|
|
85
|
-
let validationError;
|
|
86
|
-
let validationErrorLength = -1;
|
|
87
|
-
const parseCandidate = (candidate) => {
|
|
88
|
-
const value = JSON.parse(candidate);
|
|
89
|
-
if (!validate)
|
|
90
|
-
return value;
|
|
91
|
-
try {
|
|
92
|
-
return validate(value);
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
// Keep diagnostics from the most complete candidate, not a nested fragment.
|
|
96
|
-
if (candidate.length > validationErrorLength) {
|
|
97
|
-
validationError = error;
|
|
98
|
-
validationErrorLength = candidate.length;
|
|
99
|
-
}
|
|
100
|
-
throw error;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
try {
|
|
104
|
-
return parseCandidate(cleaned);
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
const fenced = Array.from(cleaned.matchAll(/```(?:json)?\s*([\s\S]+?)```/gi), (match) => match[1].trim());
|
|
108
|
-
for (const candidates of [fenced, extractBalancedJsonCandidates(cleaned)]) {
|
|
109
|
-
for (const candidate of candidates) {
|
|
110
|
-
try {
|
|
111
|
-
return parseCandidate(candidate);
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
// CSS selectors and explanatory prose can contain brackets before the JSON.
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (validationError)
|
|
119
|
-
throw validationError;
|
|
120
|
-
throw new Error('Assistant returned invalid JSON');
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
43
|
export function normalizeAssistantToolName(name) {
|
|
124
44
|
return name.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 60) || `tool_${Date.now()}`;
|
|
125
45
|
}
|
|
@@ -145,6 +65,9 @@ export function cleanupSessionsByTtl(sessions, ttlMs, now = Date.now(), onExpire
|
|
|
145
65
|
export function touchSession(session) {
|
|
146
66
|
session.lastTouchedAt = Date.now();
|
|
147
67
|
}
|
|
68
|
+
/** Every assistant tool call, MCP or local context, gets the same limit. */
|
|
69
|
+
export const ASSISTANT_TOOL_TIMEOUT_MS = 30_000;
|
|
70
|
+
export const ASSISTANT_TOOL_TIMEOUT_MESSAGE = `Tool call timed out after ${ASSISTANT_TOOL_TIMEOUT_MS}ms`;
|
|
148
71
|
export async function withTimeout(promiseFactory, timeoutMs, message = `Operation timed out after ${timeoutMs}ms`, signal) {
|
|
149
72
|
throwIfAborted(signal);
|
|
150
73
|
let timeoutHandle;
|
|
@@ -167,95 +90,11 @@ export async function withTimeout(promiseFactory, timeoutMs, message = `Operatio
|
|
|
167
90
|
signal.removeEventListener('abort', abortListener);
|
|
168
91
|
}
|
|
169
92
|
}
|
|
170
|
-
export function newAssistantEntityId(prefix) {
|
|
171
|
-
return `${prefix}-${randomUUID()}`;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Inject synthetic tool_result messages for any dangling tool_use blocks
|
|
175
|
-
* at the end of llmMessages. This prevents the Anthropic API from rejecting
|
|
176
|
-
* the request when a user sends a new message without approving/denying
|
|
177
|
-
* a pending tool call.
|
|
178
|
-
*/
|
|
179
|
-
export function flushDanglingToolCalls(llmMessages) {
|
|
180
|
-
if (llmMessages.length === 0)
|
|
181
|
-
return;
|
|
182
|
-
const last = llmMessages[llmMessages.length - 1];
|
|
183
|
-
if (last.role === 'assistant' && last.tool_calls && last.tool_calls.length > 0) {
|
|
184
|
-
for (const call of last.tool_calls) {
|
|
185
|
-
llmMessages.push({
|
|
186
|
-
role: 'tool',
|
|
187
|
-
content: JSON.stringify({
|
|
188
|
-
skipped: true,
|
|
189
|
-
reason: 'User continued without approving or denying this tool call.'
|
|
190
|
-
}),
|
|
191
|
-
tool_call_id: call.id ?? 'unknown',
|
|
192
|
-
name: call.name
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
93
|
export function throwIfAborted(signal) {
|
|
198
94
|
if (!signal?.aborted)
|
|
199
95
|
return;
|
|
200
96
|
throw createAbortError();
|
|
201
97
|
}
|
|
202
|
-
export async function chatWithJsonRetry(params) {
|
|
203
|
-
const invalidJsonRetryPrompt = params.invalidJsonRetryPrompt ??
|
|
204
|
-
'Your previous response did not match the required assistant envelope. Reply ONLY with one JSON object using exactly one of these types: "assistant_message" with fields {"type":"assistant_message","text":"..."}, or "tool_call_request" with fields {"type":"tool_call_request","text":"...","toolCall":{"name":"PUBLIC_TOOL_NAME","arguments":{}}}. Do not use any other type, such as "message", "assistant", or an event type.';
|
|
205
|
-
const toToolCallRequest = (response) => {
|
|
206
|
-
if (!response.tool_calls || response.tool_calls.length === 0)
|
|
207
|
-
return null;
|
|
208
|
-
const first = response.tool_calls[0];
|
|
209
|
-
const text = response.content?.trim() || params.toolCallFallbackText(first.name);
|
|
210
|
-
const allCalls = response.tool_calls.map((tc) => ({
|
|
211
|
-
name: tc.name,
|
|
212
|
-
arguments: tc.arguments ?? {}
|
|
213
|
-
}));
|
|
214
|
-
return {
|
|
215
|
-
type: 'tool_call_request',
|
|
216
|
-
text,
|
|
217
|
-
toolCall: {
|
|
218
|
-
name: first.name,
|
|
219
|
-
arguments: first.arguments ?? {}
|
|
220
|
-
},
|
|
221
|
-
toolCalls: allCalls
|
|
222
|
-
};
|
|
223
|
-
};
|
|
224
|
-
let response = await chatWithAgent({
|
|
225
|
-
agent: params.agent,
|
|
226
|
-
messages: params.messages,
|
|
227
|
-
tools: params.tools,
|
|
228
|
-
system: params.system,
|
|
229
|
-
signal: params.signal
|
|
230
|
-
});
|
|
231
|
-
throwIfAborted(params.signal);
|
|
232
|
-
const nativeFirstPass = toToolCallRequest(response);
|
|
233
|
-
if (nativeFirstPass)
|
|
234
|
-
return nativeFirstPass;
|
|
235
|
-
const rawText = response.content?.trim() ?? '';
|
|
236
|
-
try {
|
|
237
|
-
return params.parse(rawText);
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
const retryMessages = [
|
|
241
|
-
...params.messages,
|
|
242
|
-
{ role: 'assistant', content: rawText },
|
|
243
|
-
{ role: 'user', content: invalidJsonRetryPrompt }
|
|
244
|
-
];
|
|
245
|
-
response = await chatWithAgent({
|
|
246
|
-
agent: params.agent,
|
|
247
|
-
messages: retryMessages,
|
|
248
|
-
tools: params.tools,
|
|
249
|
-
system: params.system,
|
|
250
|
-
signal: params.signal
|
|
251
|
-
});
|
|
252
|
-
throwIfAborted(params.signal);
|
|
253
|
-
const nativeRetryPass = toToolCallRequest(response);
|
|
254
|
-
if (nativeRetryPass)
|
|
255
|
-
return nativeRetryPass;
|
|
256
|
-
return params.parse(response.content?.trim() ?? '');
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
98
|
function createAbortError() {
|
|
260
99
|
const error = new Error('Request aborted');
|
|
261
100
|
error.name = 'AbortError';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-common.js","sourceRoot":"","sources":["../../src/app-server/assistant-common.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"assistant-common.js","sourceRoot":"","sources":["../../src/app-server/assistant-common.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAGxB,MAAM,uBAAuB,CAAC;AAG/B,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAE1C,oGAAoG;AACpG,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,MAAM,KAAK,GAAuB;QAChC,GAAG,CAAC,WAAW,EAAE,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,GAAG,CAAC,WAAW,EAAE,eAAe,KAAK,SAAS;YAC5C,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,eAAe,EAAE;YAC9C,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,WAAW,EAAE,cAAc,KAAK,SAAS;YAC3C,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,cAAc,EAAE;YAC5C,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,WAAW,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9F,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,WAAW,EAAE,KAAK,CAAC;IAC/C,kFAAkF;IAClF,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW;QAC9B,EAAE,IAAI,EAAE;SACP,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACpB,EAAE,IAAI,EAAE,CAAC;IACX,MAAM,WAAW,GACf,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,6BAA6B;QACvD,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,6BAA6B,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG;QACrE,CAAC,CAAC,OAAO,CAAC;IACd,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,QAAgB;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,UAAkB,EAClB,QAAgB,EAChB,IAAiB;IAEjB,MAAM,IAAI,GAAG,GAAG,0BAA0B,CAAC,UAAU,CAAC,KAAK,0BAA0B,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClG,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,GAAG,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC;QAChC,MAAM,IAAI,CAAC,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAwB,EACxB,KAAa,EACb,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,EAChB,QAA+B;IAE/B,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC;QACrC,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,GAAG,KAAK,EAAE,CAAC;YACxC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC;YACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAsC,OAAU;IAC1E,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACrC,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAChD,MAAM,CAAC,MAAM,8BAA8B,GAAG,6BAA6B,yBAAyB,IAAI,CAAC;AAEzG,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,cAAgC,EAChC,SAAiB,EACjB,OAAO,GAAG,6BAA6B,SAAS,IAAI,EACpD,MAAoB;IAEpB,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,IAAI,aAAwD,CAAC;IAC7D,IAAI,aAAuC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/C,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,MAAM,YAAY,GAChB,MAAM;QACN,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YAC/B,aAAa,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YACjD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CACvB,YAAY,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,OAAO,CAAC,CACvF,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,aAAa;YAAE,YAAY,CAAC,aAAa,CAAC,CAAC;QAC/C,IAAI,MAAM,IAAI,aAAa;YAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO;IAC7B,MAAM,gBAAgB,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC;IAC1B,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { AssistantRuntimeEvent } from '@inspectr/mcplab-core';
|
|
2
3
|
import { type SseEvent } from './jobs.js';
|
|
3
|
-
export type AssistantSseEventType = '
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export type AssistantSseEventType = AssistantRuntimeEvent['type'];
|
|
5
|
+
/** Streamed text and reasoning deltas are small and frequent; they carry no session snapshot. */
|
|
6
|
+
export declare function isAssistantDeltaEvent(type: AssistantSseEventType): boolean;
|
|
7
|
+
export type AssistantSseEvent = AssistantRuntimeEvent & SseEvent;
|
|
7
8
|
export interface AssistantSseSessionState {
|
|
8
|
-
events: AssistantSseEvent[];
|
|
9
9
|
clients: Set<ServerResponse>;
|
|
10
10
|
}
|
|
11
11
|
export declare function createAssistantSseEvent(type: AssistantSseEventType, payload: Record<string, unknown>): AssistantSseEvent;
|
|
12
12
|
export declare function broadcastAssistantSseEvent(session: AssistantSseSessionState, event: AssistantSseEvent): void;
|
|
13
|
-
export declare function serveAssistantSseStream(req: IncomingMessage, res: ServerResponse, session: AssistantSseSessionState): void;
|
|
13
|
+
export declare function serveAssistantSseStream(req: IncomingMessage, res: ServerResponse, session: AssistantSseSessionState, snapshot: Record<string, unknown>): void;
|
|
14
14
|
export declare function endAssistantSseClients(session: AssistantSseSessionState): void;
|
|
15
|
+
export declare function createAssistantRequestAbortController(res: ServerResponse): {
|
|
16
|
+
signal: AbortSignal;
|
|
17
|
+
dispose: () => ServerResponse<IncomingMessage>;
|
|
18
|
+
};
|
|
15
19
|
//# sourceMappingURL=assistant-events.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-events.d.ts","sourceRoot":"","sources":["../../src/app-server/assistant-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"assistant-events.d.ts","sourceRoot":"","sources":["../../src/app-server/assistant-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAElE,iGAAiG;AACjG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAE1E;AACD,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,QAAQ,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CAC9B;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,iBAAiB,CAMnB;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,iBAAiB,GACvB,IAAI,CAIN;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAgBN;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAK9E;AAED,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,cAAc;IAS9D,MAAM;IAAqB,OAAO;EAC5C"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { sendSseEvent } from './jobs.js';
|
|
2
|
+
/** Streamed text and reasoning deltas are small and frequent; they carry no session snapshot. */
|
|
3
|
+
export function isAssistantDeltaEvent(type) {
|
|
4
|
+
return type === 'assistant_message_delta' || type === 'assistant_reasoning_delta';
|
|
5
|
+
}
|
|
2
6
|
export function createAssistantSseEvent(type, payload) {
|
|
3
7
|
return {
|
|
4
8
|
type,
|
|
@@ -6,29 +10,24 @@ export function createAssistantSseEvent(type, payload) {
|
|
|
6
10
|
payload
|
|
7
11
|
};
|
|
8
12
|
}
|
|
9
|
-
const MAX_REPLAYED_EVENTS = 100;
|
|
10
13
|
export function broadcastAssistantSseEvent(session, event) {
|
|
11
|
-
session.events.push(event);
|
|
12
|
-
if (session.events.length > MAX_REPLAYED_EVENTS)
|
|
13
|
-
session.events.shift();
|
|
14
14
|
for (const client of session.clients) {
|
|
15
15
|
sendSseEvent(client, event);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
export function serveAssistantSseStream(req, res, session) {
|
|
18
|
+
export function serveAssistantSseStream(req, res, session, snapshot) {
|
|
19
19
|
res.statusCode = 200;
|
|
20
20
|
res.setHeader('content-type', 'text/event-stream');
|
|
21
|
-
res.setHeader('cache-control', 'no-cache');
|
|
21
|
+
res.setHeader('cache-control', 'no-cache, no-transform');
|
|
22
|
+
res.setHeader('x-accel-buffering', 'no');
|
|
22
23
|
res.setHeader('connection', 'keep-alive');
|
|
23
24
|
if ('flushHeaders' in res && typeof res.flushHeaders === 'function') {
|
|
24
25
|
res.flushHeaders();
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
sendSseEvent(res, event);
|
|
28
|
-
}
|
|
27
|
+
sendSseEvent(res, createAssistantSseEvent('session_snapshot', snapshot));
|
|
29
28
|
session.clients.add(res);
|
|
30
|
-
if (typeof
|
|
31
|
-
|
|
29
|
+
if (typeof res.on === 'function') {
|
|
30
|
+
res.on('close', () => {
|
|
32
31
|
session.clients.delete(res);
|
|
33
32
|
});
|
|
34
33
|
}
|
|
@@ -39,4 +38,17 @@ export function endAssistantSseClients(session) {
|
|
|
39
38
|
}
|
|
40
39
|
session.clients.clear();
|
|
41
40
|
}
|
|
41
|
+
export function createAssistantRequestAbortController(res) {
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const onClose = () => {
|
|
44
|
+
if (!res.writableEnded)
|
|
45
|
+
controller.abort();
|
|
46
|
+
};
|
|
47
|
+
// A response can close before the handler starts, for example when a client
|
|
48
|
+
// disconnects while the request body is still being received.
|
|
49
|
+
if (res.destroyed && !res.writableEnded)
|
|
50
|
+
controller.abort();
|
|
51
|
+
res.on?.('close', onClose);
|
|
52
|
+
return { signal: controller.signal, dispose: () => res.off?.('close', onClose) };
|
|
53
|
+
}
|
|
42
54
|
//# sourceMappingURL=assistant-events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-events.js","sourceRoot":"","sources":["../../src/app-server/assistant-events.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assistant-events.js","sourceRoot":"","sources":["../../src/app-server/assistant-events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAiB,MAAM,WAAW,CAAC;AAIxD,iGAAiG;AACjG,MAAM,UAAU,qBAAqB,CAAC,IAA2B;IAC/D,OAAO,IAAI,KAAK,yBAAyB,IAAI,IAAI,KAAK,2BAA2B,CAAC;AACpF,CAAC;AAOD,MAAM,UAAU,uBAAuB,CACrC,IAA2B,EAC3B,OAAgC;IAEhC,OAAO;QACL,IAAI;QACJ,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,OAAiC,EACjC,KAAwB;IAExB,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,GAAoB,EACpB,GAAmB,EACnB,OAAiC,EACjC,QAAiC;IAEjC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;IACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,wBAAwB,CAAC,CAAC;IACzD,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAC1C,IAAI,cAAc,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QACpE,GAAG,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IACD,YAAY,CAAC,GAAG,EAAE,uBAAuB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,UAAU,EAAE,CAAC;QACjC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAiC;IACtE,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;IACD,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,qCAAqC,CAAC,GAAmB;IACvE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,GAAG,CAAC,aAAa;YAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC,CAAC;IACF,4EAA4E;IAC5E,8DAA8D;IAC9D,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,aAAa;QAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAC5D,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;AACnF,CAAC"}
|