@copilotkit/aimock 1.26.1 → 1.27.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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +29 -0
- package/dist/agui-handler.cjs +36 -3
- package/dist/agui-handler.cjs.map +1 -1
- package/dist/agui-handler.d.cts +9 -1
- package/dist/agui-handler.d.cts.map +1 -1
- package/dist/agui-handler.d.ts +9 -1
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/agui-handler.js +36 -4
- package/dist/agui-handler.js.map +1 -1
- package/dist/agui-mock.cjs +14 -0
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts +1 -0
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts +1 -0
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +14 -0
- package/dist/agui-mock.js.map +1 -1
- package/dist/agui-recorder.cjs +49 -21
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.d.cts +0 -1
- package/dist/agui-recorder.d.cts.map +1 -1
- package/dist/agui-recorder.d.ts +0 -1
- package/dist/agui-recorder.d.ts.map +1 -1
- package/dist/agui-recorder.js +50 -22
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-stub.cjs +1 -0
- package/dist/agui-stub.d.cts +3 -3
- package/dist/agui-stub.d.ts +3 -3
- package/dist/agui-stub.js +2 -2
- package/dist/agui-types.d.cts +10 -2
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +10 -2
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/config-loader.cjs +25 -11
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +1 -0
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +1 -0
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +25 -11
- package/dist/config-loader.js.map +1 -1
- package/dist/elevenlabs-audio.cjs +2 -2
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.js +2 -2
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/fal-audio.cjs +32 -8
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.js +32 -8
- package/dist/fal-audio.js.map +1 -1
- package/dist/gemini-interactions.cjs +61 -6
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts +18 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts +18 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +61 -6
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/helpers.cjs +7 -7
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +4 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +4 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +7 -7
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/recorder.cjs +3 -3
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +3 -3
- package/dist/recorder.js.map +1 -1
- package/dist/router.cjs +2 -7
- package/dist/router.cjs.map +1 -1
- package/dist/router.js +2 -7
- package/dist/router.js.map +1 -1
- package/dist/transcription.cjs +3 -1
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +3 -1
- package/dist/transcription.js.map +1 -1
- package/dist/ws-gemini-live.cjs +28 -14
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +28 -14
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +64 -41
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +64 -41
- package/dist/ws-realtime.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"source": {
|
|
10
10
|
"source": "npm",
|
|
11
11
|
"package": "@copilotkit/aimock",
|
|
12
|
-
"version": "^1.
|
|
12
|
+
"version": "^1.27.1"
|
|
13
13
|
},
|
|
14
14
|
"description": "Fixture authoring skill for @copilotkit/aimock — LLM, multimedia (image/TTS/transcription/video), MCP, A2A, AG-UI, vector, embeddings, structured output, sequential responses, streaming physics, record/replay, agent loop patterns, and debugging"
|
|
15
15
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.27.1] - 2026-05-22
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Router** — systemMessage array exact-match logic was unsatisfiable for 2+ needles; collapsed to substring matching. Added `elevenlabs-tts` and `translation` to endpoint compatibility filter.
|
|
10
|
+
- **Recorder** — Content-Type empty-string fallback (`??` → `||`), derived `EndpointType` from `FixtureMatch` instead of duplicate union, negative guards on Gemini Interactions outputs detection, scoped `turnIndex`/`hasToolResult` to chat endpoints only.
|
|
11
|
+
- **WS-Realtime** — session.update rollback now captures full snapshot instead of just model/type. Added Beta flat fields for noise reduction, transcription, and turn_detection. Joined all text content parts in `realtimeItemsToMessages`. Added try-catch with debug logging around `sendEvent` for WebSocket close race safety.
|
|
12
|
+
- **WS-Gemini-Live** — replaced deterministic `call_gemini_${name}_${i}` tool call IDs with random `generateToolCallId()` to prevent cross-turn collisions. Pre-computed `resolvedToolCalls` for wire/history ID consistency. Added unrecognized-role warning and ws.send try-catch with debug logging.
|
|
13
|
+
- **Gemini Interactions** — `interactionsUsage` honors Gemini-native field names (`promptTokenCount`/`candidatesTokenCount`/`totalTokenCount`). `truncateAfterChunks` only counts `content.delta` events. Added `webSearches` warning on tool-call branch.
|
|
14
|
+
- **fal-audio + ElevenLabs** — all journal entries now use `flattenHeaders(req.headers)` instead of `{}`. `handleSyncRun` accepts `RawJSONResponse` fixtures from queue-walk recordings.
|
|
15
|
+
- **Helpers** — extended `resolveUsage` with Gemini-native token fields. Preserved error cause in `resolveResponse` factory rethrow. `buildEmbeddingResponse` accepts optional usage. `extractFormField` escapes regex metacharacters.
|
|
16
|
+
- **Drift test infra** — retry logging with body consumption, broadened `redactUrl` to cover `api_key`/`apikey`/`token`/`access_token` patterns, URL threaded into error messages with redaction, `parseDataOnlySSE` [DONE] filter fix, `parseTypedSSE` multi-line data handling with null guards.
|
|
17
|
+
- **Drift collector** — invoke vitest directly via npx to avoid pnpm stdout prefix breaking JSON parse; classify raw stack traces as infrastructure errors instead of crashing.
|
|
18
|
+
- **AG-UI config loader** — removed `/.*/` catch-all regex fallback when `match.message` is absent; fixtures without a message pattern no longer shadow other fixtures.
|
|
19
|
+
- **AG-UI input validation** — runtime check that `input.messages` is an array after JSON parse; returns 400 instead of confusing downstream 404.
|
|
20
|
+
- **AG-UI SSE writer** — `writeAGUIEventStream` uses logger abstraction instead of `console.warn`; handles non-Error throws.
|
|
21
|
+
- **Drift test helpers** — `parseDataOnlySSE` handles multi-line data blocks, aligned with `providers.ts` implementation.
|
|
22
|
+
|
|
23
|
+
## [1.27.0] - 2026-05-20
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **HITL continuation recording/replay support** — `toolCallId` matching for continuation fixtures. New `toolCallId` field on `AGUIFixtureMatch` and `AGUIConfigFixture`. `getLastMessageIfToolResult` helper and `onToolResult` fluent API. Recorder uses tool-result-first priority for continuation fixtures. ([#233](https://github.com/CopilotKit/aimock/pull/233), closes [#232](https://github.com/CopilotKit/aimock/issues/232))
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Walk structured content arrays in `extractLastUserMessage`** — handle multimodal user content (`AGUIMessageContentPart[]`) by joining text parts and skipping non-text. Export `NO_USER_MESSAGE_SENTINEL` constant and `AGUIMessageContentPart` type. ([#231](https://github.com/CopilotKit/aimock/pull/231))
|
|
32
|
+
- **Harden recorder against error responses, double-settle, and broken sentinel persistence** — guard against recording fixtures from non-2xx upstream responses, add `settled` flag to prevent error+end race, skip disk write for predicate fixtures (sentinel was semantically broken on reload), include parse error reason in SSE warning log
|
|
33
|
+
|
|
5
34
|
## [1.26.1] - 2026-05-19
|
|
6
35
|
|
|
7
36
|
### Added
|
package/dist/agui-handler.cjs
CHANGED
|
@@ -4,15 +4,34 @@ let node_crypto = require("node:crypto");
|
|
|
4
4
|
//#region src/agui-handler.ts
|
|
5
5
|
/**
|
|
6
6
|
* Extract the content of the last message with role "user" from the input.
|
|
7
|
+
* Walks structured content arrays (e.g. `[{type:"text", text:"..."}, {type:"document", ...}]`)
|
|
8
|
+
* and joins their text parts. Returns `""` when no user message is present or has no text.
|
|
7
9
|
*/
|
|
8
10
|
function extractLastUserMessage(input) {
|
|
9
11
|
if (!input.messages || input.messages.length === 0) return "";
|
|
10
12
|
for (let i = input.messages.length - 1; i >= 0; i--) {
|
|
11
13
|
const msg = input.messages[i];
|
|
12
|
-
if (msg.role
|
|
14
|
+
if (msg.role !== "user") continue;
|
|
15
|
+
const text = extractTextFromContent(msg.content);
|
|
16
|
+
if (text) return text;
|
|
13
17
|
}
|
|
14
18
|
return "";
|
|
15
19
|
}
|
|
20
|
+
function extractTextFromContent(content) {
|
|
21
|
+
if (typeof content === "string") return content;
|
|
22
|
+
if (!Array.isArray(content)) return "";
|
|
23
|
+
const parts = [];
|
|
24
|
+
for (const part of content) if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text) parts.push(part.text);
|
|
25
|
+
return parts.join(" ").trim();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Return the absolute last message if it has role "tool", otherwise null.
|
|
29
|
+
*/
|
|
30
|
+
function getLastMessageIfToolResult(input) {
|
|
31
|
+
if (!input.messages || input.messages.length === 0) return null;
|
|
32
|
+
const last = input.messages[input.messages.length - 1];
|
|
33
|
+
return last.role === "tool" ? last : null;
|
|
34
|
+
}
|
|
16
35
|
/**
|
|
17
36
|
* Check whether an input matches a fixture's match criteria.
|
|
18
37
|
* All specified criteria must pass (AND logic).
|
|
@@ -27,6 +46,10 @@ function matchesFixture(input, match) {
|
|
|
27
46
|
if (!match.message.test(text)) return false;
|
|
28
47
|
}
|
|
29
48
|
}
|
|
49
|
+
if (match.toolCallId !== void 0) {
|
|
50
|
+
const lastMsg = input.messages?.[input.messages.length - 1];
|
|
51
|
+
if (!lastMsg || lastMsg.role !== "tool" || lastMsg.toolCallId !== match.toolCallId) return false;
|
|
52
|
+
}
|
|
30
53
|
if (match.toolName !== void 0) {
|
|
31
54
|
if (!(input.tools ?? []).some((t) => t.name === match.toolName)) return false;
|
|
32
55
|
}
|
|
@@ -421,8 +444,17 @@ async function writeAGUIEventStream(res, events, opts) {
|
|
|
421
444
|
try {
|
|
422
445
|
res.write(`data: ${JSON.stringify(stamped)}\n\n`);
|
|
423
446
|
} catch (err) {
|
|
424
|
-
if (err instanceof TypeError || err instanceof RangeError)
|
|
425
|
-
|
|
447
|
+
if (err instanceof TypeError || err instanceof RangeError) {
|
|
448
|
+
const msg = err.message;
|
|
449
|
+
if (opts?.logger) opts.logger.warn("AG-UI SSE write failed (serialization):", msg);
|
|
450
|
+
else console.warn("AG-UI SSE write failed (serialization):", msg);
|
|
451
|
+
} else if (err instanceof Error) if (opts?.logger) opts.logger.warn("AG-UI SSE write failed:", err.message);
|
|
452
|
+
else console.warn("AG-UI SSE write failed:", err.message);
|
|
453
|
+
else {
|
|
454
|
+
const msg = String(err);
|
|
455
|
+
if (opts?.logger) opts.logger.warn("AG-UI SSE write failed:", msg);
|
|
456
|
+
else console.warn("AG-UI SSE write failed:", msg);
|
|
457
|
+
}
|
|
426
458
|
break;
|
|
427
459
|
}
|
|
428
460
|
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -450,6 +482,7 @@ exports.buildToolCallChunk = buildToolCallChunk;
|
|
|
450
482
|
exports.buildToolCallResponse = buildToolCallResponse;
|
|
451
483
|
exports.extractLastUserMessage = extractLastUserMessage;
|
|
452
484
|
exports.findFixture = findFixture;
|
|
485
|
+
exports.getLastMessageIfToolResult = getLastMessageIfToolResult;
|
|
453
486
|
exports.matchesFixture = matchesFixture;
|
|
454
487
|
exports.writeAGUIEventStream = writeAGUIEventStream;
|
|
455
488
|
//# sourceMappingURL=agui-handler.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-handler.cjs","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role === \"user\" && typeof msg.content === \"string\") {\n return msg.content;\n }\n }\n return \"\";\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [started, ...inner, ...(hasError ? [] : [makeRunFinished(started)])];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n console.warn(\"AG-UI SSE write failed (serialization):\", (err as Error).message);\n } else if (err instanceof Error) {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agui-handler.cjs","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type { Logger } from \"./logger.js\";\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n * Walks structured content arrays (e.g. `[{type:\"text\", text:\"...\"}, {type:\"document\", ...}]`)\n * and joins their text parts. Returns `\"\"` when no user message is present or has no text.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role !== \"user\") continue;\n const text = extractTextFromContent(msg.content);\n if (text) return text;\n }\n return \"\";\n}\n\nfunction extractTextFromContent(content: AGUIMessage[\"content\"]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const part of content) {\n if (\n part &&\n typeof part === \"object\" &&\n part.type === \"text\" &&\n typeof part.text === \"string\" &&\n part.text\n ) {\n parts.push(part.text);\n }\n }\n return parts.join(\" \").trim();\n}\n\n/**\n * Return the absolute last message if it has role \"tool\", otherwise null.\n */\nexport function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null {\n if (!input.messages || input.messages.length === 0) return null;\n const last = input.messages[input.messages.length - 1];\n return last.role === \"tool\" ? last : null;\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolCallId !== undefined) {\n const lastMsg = input.messages?.[input.messages.length - 1];\n if (!lastMsg || lastMsg.role !== \"tool\" || lastMsg.toolCallId !== match.toolCallId) {\n return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [started, ...inner, ...(hasError ? [] : [makeRunFinished(started)])];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal; logger?: Logger },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n const msg = (err as Error).message;\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed (serialization):\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed (serialization):\", msg);\n }\n } else if (err instanceof Error) {\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", err.message);\n } else {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n } else {\n const msg = String(err);\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed:\", msg);\n }\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":";;;;;;;;;AAqDA,SAAgB,uBAAuB,OAAkC;AACvE,KAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,EAAG,QAAO;AAC3D,MAAK,IAAI,IAAI,MAAM,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;EACnD,MAAM,MAAM,MAAM,SAAS;AAC3B,MAAI,IAAI,SAAS,OAAQ;EACzB,MAAM,OAAO,uBAAuB,IAAI,QAAQ;AAChD,MAAI,KAAM,QAAO;;AAEnB,QAAO;;AAGT,SAAS,uBAAuB,SAAyC;AACvE,KAAI,OAAO,YAAY,SAAU,QAAO;AACxC,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;CACpC,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,QAAQ,QACjB,KACE,QACA,OAAO,SAAS,YAChB,KAAK,SAAS,UACd,OAAO,KAAK,SAAS,YACrB,KAAK,KAEL,OAAM,KAAK,KAAK,KAAK;AAGzB,QAAO,MAAM,KAAK,IAAI,CAAC,MAAM;;;;;AAM/B,SAAgB,2BAA2B,OAA8C;AACvF,KAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,EAAG,QAAO;CAC3D,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,SAAS;AACpD,QAAO,KAAK,SAAS,SAAS,OAAO;;;;;;AAOvC,SAAgB,eAAe,OAA0B,OAAkC;AACzF,KAAI,MAAM,YAAY,QAAW;EAC/B,MAAM,OAAO,uBAAuB,MAAM;AAC1C,MAAI,OAAO,MAAM,YAAY,UAC3B;OAAI,CAAC,KAAK,SAAS,MAAM,QAAQ,CAAE,QAAO;SACrC;AACL,SAAM,QAAQ,YAAY;AAC1B,OAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,CAAE,QAAO;;;AAI1C,KAAI,MAAM,eAAe,QAAW;EAClC,MAAM,UAAU,MAAM,WAAW,MAAM,SAAS,SAAS;AACzD,MAAI,CAAC,WAAW,QAAQ,SAAS,UAAU,QAAQ,eAAe,MAAM,WACtE,QAAO;;AAIX,KAAI,MAAM,aAAa,QAErB;MAAI,EADU,MAAM,SAAS,EAAE,EACpB,MAAM,MAAM,EAAE,SAAS,MAAM,SAAS,CAAE,QAAO;;AAG5D,KAAI,MAAM,aAAa,QACrB;MACE,MAAM,UAAU,QAChB,MAAM,UAAU,UAChB,OAAO,MAAM,UAAU,YACvB,EAAE,MAAM,YAAa,MAAM,OAE3B,QAAO;;AAIX,KAAI,MAAM,cAAc,QACtB;MAAI,CAAC,MAAM,UAAU,MAAM,CAAE,QAAO;;AAGtC,QAAO;;;;;AAMT,SAAgB,YAAY,OAA0B,UAA6C;AACjG,MAAK,MAAM,WAAW,SACpB,KAAI,eAAe,OAAO,QAAQ,MAAM,CACtC,QAAO;AAGX,QAAO;;AAeT,SAAS,eAAe,MAA2C;AACjE,QAAO;EACL,MAAM;EACN,UAAU,MAAM,yCAAwB;EACxC,OAAO,MAAM,sCAAqB;EAClC,GAAI,MAAM,cAAc,EAAE,aAAa,KAAK,aAAa,GAAG,EAAE;EAC/D;;AAGH,SAAS,gBACP,SACA,YACsB;AACtB,QAAO;EACL,MAAM;EACN,UAAU,QAAQ;EAClB,OAAO,QAAQ;EACf,GAAI,YAAY,WAAW,SAAY,EAAE,QAAQ,WAAW,QAAQ,GAAG,EAAE;EACzE,GAAI,YAAY,YAAY,SAAY,EAAE,SAAS,WAAW,SAAS,GAAG,EAAE;EAC7E;;;;;;AAOH,SAAgB,kBAAkB,MAAc,MAAmC;CACjF,MAAM,UAAU,eAAe,KAAK;CACpC,MAAM,yCAAwB;AAC9B,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA,MAAM;GACP;EACD;GACE,MAAM;GACN;GACA,OAAO;GACR;EACD;GACE,MAAM;GACN;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,uBAAuB,MAAc,MAAmC;CACtF,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN,wCAAuB;GACvB,MAAM;GACN,OAAO;GACR;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,sBACd,UACA,MACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;CACpC,MAAM,0CAAyB;CAC/B,MAAM,SAAsB;EAC1B;EACA;GACE,MAAM;GACN;GACA,cAAc;GACf;EACD;GACE,MAAM;GACN;GACA,OAAO;GACR;EACD;GACE,MAAM;GACN;GACD;EACF;AAED,KAAI,MAAM,WAAW,OACnB,QAAO,KAAK;EACV,MAAM;EACN,wCAAuB;EACvB;EACA,SAAS,KAAK;EACd,MAAM;EACP,CAA4B;AAG/B,QAAO,KAAK,gBAAgB,QAAQ,CAAC;AACrC,QAAO;;;;;;AAOT,SAAgB,iBAAiB,UAAmB,MAAmC;CACrF,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,gBAAgB,SAAoB,MAAmC;CACrF,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN,OAAO;GACR;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,sBAAsB,UAAyB,MAAmC;CAChG,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;;AAQH,SAAgB,uBAAuB,MAAc,MAAmC;CACtF,MAAM,UAAU,eAAe,KAAK;CACpC,MAAM,yCAAwB;AAC9B,QAAO;EACL;EACA;GACE,MAAM;GACN;GACD;EACD;GACE,MAAM;GACN;GACA,MAAM;GACP;EACD;GACE,MAAM;GACN;GACA,OAAO;GACR;EACD;GACE,MAAM;GACN;GACD;EACD;GACE,MAAM;GACN;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,sBACd,WACA,cACA,SACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA;GACA;GACA,SAAS;GACV;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,mBACd,SACA,MACA,MACa;AAEb,QAAO,CADS,eAAe,KAAK,EAGlC;EACE,MAAM;EACN;EACA,GAAI,SAAS,SAAY,EAAE,MAAM,GAAG,EAAE;EACvC,CACF;;;;;;;AAQH,SAAgB,kBACd,UACA,MACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;CACpC,MAAM,yCAAwB;AAC9B,QAAO;EACL;EACA;GACE,MAAM;GACN;GACD;EACD;GACE,MAAM;GACN;GACA,MAAM;GACP;EACD;GACE,MAAM;GACN;GACA,OAAO;GACR;EACD;GACE,MAAM;GACN;GACD;EACD;GACE,MAAM;GACN;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;;AAQH,SAAgB,uBACd,gBACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;CACpC,MAAM,QAAqB,EAAE;AAE7B,MAAK,MAAM,UAAU,eACnB,MAAK,MAAM,SAAS,OAClB,KAAI,MAAM,SAAS,iBAAiB,MAAM,SAAS,eACjD,OAAM,KAAK,MAAM;CAKvB,MAAM,WAAW,MAAM,MAAM,MAAM,EAAE,SAAS,YAAY;AAC1D,QAAO;EAAC;EAAS,GAAG;EAAO,GAAI,WAAW,EAAE,GAAG,CAAC,gBAAgB,QAAQ,CAAC;EAAE;;;;;;AAS7E,SAAgB,mBACd,WACA,cACA,OACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA;GACA;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,mBACd,OACA,MAKa;CACb,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,KAAK,YAAY,GAAG,EAAE;GACzE,GAAI,MAAM,iBAAiB,SAAY,EAAE,cAAc,KAAK,cAAc,GAAG,EAAE;GAC/E,GAAI,MAAM,oBAAoB,SAAY,EAAE,iBAAiB,KAAK,iBAAiB,GAAG,EAAE;GACxF;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,cAAc,OAAgB,QAAiB,MAAmC;CAChG,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA,GAAI,WAAW,SAAY,EAAE,QAAQ,GAAG,EAAE;GAC3C;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,iBAAiB,MAAc,OAAgB,MAAmC;CAChG,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,oBACd,OACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,KAAK,WAAW,GAAG,EAAE;GACtE;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;AAOH,SAAgB,6BACd,SACA,UACA,gBACA,MACa;CACb,MAAM,UAAU,eAAe,KAAK;AACpC,QAAO;EACL;EACA;GACE,MAAM;GACN;GACA;GACA;GACD;EACD,gBAAgB,QAAQ;EACzB;;;;;;;AAUH,eAAsB,qBACpB,KACA,QACA,MACe;CACf,MAAM,UAAU,MAAM,WAAW;AAEjC,KAAI,UAAU,KAAK;EACjB,gBAAgB;EAChB,iBAAiB;EACjB,YAAY;EACb,CAAC;AAEF,MAAK,MAAM,SAAS,QAAQ;AAC1B,MAAI,MAAM,QAAQ,QAAS;AAC3B,MAAI,IAAI,QAAQ,UAAW;EAE3B,MAAM,UAAU;GAAE,GAAG;GAAO,WAAW,MAAM,aAAa,KAAK,KAAK;GAAE;AACtE,MAAI;AACF,OAAI,MAAM,SAAS,KAAK,UAAU,QAAQ,CAAC,MAAM;WAC1C,KAAK;AACZ,OAAI,eAAe,aAAa,eAAe,YAAY;IACzD,MAAM,MAAO,IAAc;AAC3B,QAAI,MAAM,OACR,MAAK,OAAO,KAAK,2CAA2C,IAAI;QAEhE,SAAQ,KAAK,2CAA2C,IAAI;cAErD,eAAe,MACxB,KAAI,MAAM,OACR,MAAK,OAAO,KAAK,2BAA2B,IAAI,QAAQ;OAExD,SAAQ,KAAK,2BAA2B,IAAI,QAAQ;QAEjD;IACL,MAAM,MAAM,OAAO,IAAI;AACvB,QAAI,MAAM,OACR,MAAK,OAAO,KAAK,2BAA2B,IAAI;QAEhD,SAAQ,KAAK,2BAA2B,IAAI;;AAGhD;;AAGF,MAAI,UAAU,EACZ,OAAM,IAAI,SAAe,YAAY,WAAW,SAAS,QAAQ,CAAC;;AAItE,KAAI,CAAC,IAAI,cAAe,KAAI,KAAK"}
|
package/dist/agui-handler.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from "./logger.cjs";
|
|
1
2
|
import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput } from "./agui-types.cjs";
|
|
2
3
|
import * as http$1 from "node:http";
|
|
3
4
|
|
|
@@ -5,8 +6,14 @@ import * as http$1 from "node:http";
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Extract the content of the last message with role "user" from the input.
|
|
9
|
+
* Walks structured content arrays (e.g. `[{type:"text", text:"..."}, {type:"document", ...}]`)
|
|
10
|
+
* and joins their text parts. Returns `""` when no user message is present or has no text.
|
|
8
11
|
*/
|
|
9
12
|
declare function extractLastUserMessage(input: AGUIRunAgentInput): string;
|
|
13
|
+
/**
|
|
14
|
+
* Return the absolute last message if it has role "tool", otherwise null.
|
|
15
|
+
*/
|
|
16
|
+
declare function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null;
|
|
10
17
|
/**
|
|
11
18
|
* Check whether an input matches a fixture's match criteria.
|
|
12
19
|
* All specified criteria must pass (AND logic).
|
|
@@ -125,8 +132,9 @@ declare function buildReasoningEncryptedValue(subtype: AGUIReasoningEncryptedVal
|
|
|
125
132
|
declare function writeAGUIEventStream(res: http$1.ServerResponse, events: AGUIEvent[], opts?: {
|
|
126
133
|
delayMs?: number;
|
|
127
134
|
signal?: AbortSignal;
|
|
135
|
+
logger?: Logger;
|
|
128
136
|
}): Promise<void>;
|
|
129
137
|
//# sourceMappingURL=agui-handler.d.ts.map
|
|
130
138
|
//#endregion
|
|
131
|
-
export { AGUIBuildOpts, buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, matchesFixture, writeAGUIEventStream };
|
|
139
|
+
export { AGUIBuildOpts, buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, getLastMessageIfToolResult, matchesFixture, writeAGUIEventStream };
|
|
132
140
|
//# sourceMappingURL=agui-handler.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-handler.d.cts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agui-handler.d.cts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/agui-handler.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from "./logger.js";
|
|
1
2
|
import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput } from "./agui-types.js";
|
|
2
3
|
import * as http$1 from "node:http";
|
|
3
4
|
|
|
@@ -5,8 +6,14 @@ import * as http$1 from "node:http";
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Extract the content of the last message with role "user" from the input.
|
|
9
|
+
* Walks structured content arrays (e.g. `[{type:"text", text:"..."}, {type:"document", ...}]`)
|
|
10
|
+
* and joins their text parts. Returns `""` when no user message is present or has no text.
|
|
8
11
|
*/
|
|
9
12
|
declare function extractLastUserMessage(input: AGUIRunAgentInput): string;
|
|
13
|
+
/**
|
|
14
|
+
* Return the absolute last message if it has role "tool", otherwise null.
|
|
15
|
+
*/
|
|
16
|
+
declare function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null;
|
|
10
17
|
/**
|
|
11
18
|
* Check whether an input matches a fixture's match criteria.
|
|
12
19
|
* All specified criteria must pass (AND logic).
|
|
@@ -125,8 +132,9 @@ declare function buildReasoningEncryptedValue(subtype: AGUIReasoningEncryptedVal
|
|
|
125
132
|
declare function writeAGUIEventStream(res: http$1.ServerResponse, events: AGUIEvent[], opts?: {
|
|
126
133
|
delayMs?: number;
|
|
127
134
|
signal?: AbortSignal;
|
|
135
|
+
logger?: Logger;
|
|
128
136
|
}): Promise<void>;
|
|
129
137
|
//# sourceMappingURL=agui-handler.d.ts.map
|
|
130
138
|
//#endregion
|
|
131
|
-
export { AGUIBuildOpts, buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, matchesFixture, writeAGUIEventStream };
|
|
139
|
+
export { AGUIBuildOpts, buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, getLastMessageIfToolResult, matchesFixture, writeAGUIEventStream };
|
|
132
140
|
//# sourceMappingURL=agui-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/agui-handler.js
CHANGED
|
@@ -3,15 +3,34 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
//#region src/agui-handler.ts
|
|
4
4
|
/**
|
|
5
5
|
* Extract the content of the last message with role "user" from the input.
|
|
6
|
+
* Walks structured content arrays (e.g. `[{type:"text", text:"..."}, {type:"document", ...}]`)
|
|
7
|
+
* and joins their text parts. Returns `""` when no user message is present or has no text.
|
|
6
8
|
*/
|
|
7
9
|
function extractLastUserMessage(input) {
|
|
8
10
|
if (!input.messages || input.messages.length === 0) return "";
|
|
9
11
|
for (let i = input.messages.length - 1; i >= 0; i--) {
|
|
10
12
|
const msg = input.messages[i];
|
|
11
|
-
if (msg.role
|
|
13
|
+
if (msg.role !== "user") continue;
|
|
14
|
+
const text = extractTextFromContent(msg.content);
|
|
15
|
+
if (text) return text;
|
|
12
16
|
}
|
|
13
17
|
return "";
|
|
14
18
|
}
|
|
19
|
+
function extractTextFromContent(content) {
|
|
20
|
+
if (typeof content === "string") return content;
|
|
21
|
+
if (!Array.isArray(content)) return "";
|
|
22
|
+
const parts = [];
|
|
23
|
+
for (const part of content) if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text) parts.push(part.text);
|
|
24
|
+
return parts.join(" ").trim();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Return the absolute last message if it has role "tool", otherwise null.
|
|
28
|
+
*/
|
|
29
|
+
function getLastMessageIfToolResult(input) {
|
|
30
|
+
if (!input.messages || input.messages.length === 0) return null;
|
|
31
|
+
const last = input.messages[input.messages.length - 1];
|
|
32
|
+
return last.role === "tool" ? last : null;
|
|
33
|
+
}
|
|
15
34
|
/**
|
|
16
35
|
* Check whether an input matches a fixture's match criteria.
|
|
17
36
|
* All specified criteria must pass (AND logic).
|
|
@@ -26,6 +45,10 @@ function matchesFixture(input, match) {
|
|
|
26
45
|
if (!match.message.test(text)) return false;
|
|
27
46
|
}
|
|
28
47
|
}
|
|
48
|
+
if (match.toolCallId !== void 0) {
|
|
49
|
+
const lastMsg = input.messages?.[input.messages.length - 1];
|
|
50
|
+
if (!lastMsg || lastMsg.role !== "tool" || lastMsg.toolCallId !== match.toolCallId) return false;
|
|
51
|
+
}
|
|
29
52
|
if (match.toolName !== void 0) {
|
|
30
53
|
if (!(input.tools ?? []).some((t) => t.name === match.toolName)) return false;
|
|
31
54
|
}
|
|
@@ -420,8 +443,17 @@ async function writeAGUIEventStream(res, events, opts) {
|
|
|
420
443
|
try {
|
|
421
444
|
res.write(`data: ${JSON.stringify(stamped)}\n\n`);
|
|
422
445
|
} catch (err) {
|
|
423
|
-
if (err instanceof TypeError || err instanceof RangeError)
|
|
424
|
-
|
|
446
|
+
if (err instanceof TypeError || err instanceof RangeError) {
|
|
447
|
+
const msg = err.message;
|
|
448
|
+
if (opts?.logger) opts.logger.warn("AG-UI SSE write failed (serialization):", msg);
|
|
449
|
+
else console.warn("AG-UI SSE write failed (serialization):", msg);
|
|
450
|
+
} else if (err instanceof Error) if (opts?.logger) opts.logger.warn("AG-UI SSE write failed:", err.message);
|
|
451
|
+
else console.warn("AG-UI SSE write failed:", err.message);
|
|
452
|
+
else {
|
|
453
|
+
const msg = String(err);
|
|
454
|
+
if (opts?.logger) opts.logger.warn("AG-UI SSE write failed:", msg);
|
|
455
|
+
else console.warn("AG-UI SSE write failed:", msg);
|
|
456
|
+
}
|
|
425
457
|
break;
|
|
426
458
|
}
|
|
427
459
|
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -430,5 +462,5 @@ async function writeAGUIEventStream(res, events, opts) {
|
|
|
430
462
|
}
|
|
431
463
|
|
|
432
464
|
//#endregion
|
|
433
|
-
export { buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, matchesFixture, writeAGUIEventStream };
|
|
465
|
+
export { buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, getLastMessageIfToolResult, matchesFixture, writeAGUIEventStream };
|
|
434
466
|
//# sourceMappingURL=agui-handler.js.map
|
package/dist/agui-handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-handler.js","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role === \"user\" && typeof msg.content === \"string\") {\n return msg.content;\n }\n }\n return \"\";\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [started, ...inner, ...(hasError ? [] : [makeRunFinished(started)])];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n console.warn(\"AG-UI SSE write failed (serialization):\", (err as Error).message);\n } else if (err instanceof Error) {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agui-handler.js","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":["// ─── AG-UI Handler ───────────────────────────────────────────────────────────\n//\n// Matching functions, event builders, and SSE writer for AG-UI protocol.\n\nimport * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type { Logger } from \"./logger.js\";\nimport type {\n AGUIRunAgentInput,\n AGUIFixtureMatch,\n AGUIFixture,\n AGUIEvent,\n AGUIMessage,\n AGUIRunStartedEvent,\n AGUIRunFinishedEvent,\n AGUIRunFinishedOutcome,\n AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallChunkEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningMessageChunkEvent,\n AGUIReasoningEndEvent,\n AGUIReasoningEncryptedValueEvent,\n AGUIReasoningEncryptedValueSubtype,\n AGUIActivitySnapshotEvent,\n AGUIActivityDeltaEvent,\n AGUIRawEvent,\n AGUICustomEvent,\n} from \"./agui-types.js\";\n\n// ─── Matching functions ──────────────────────────────────────────────────────\n\n/**\n * Extract the content of the last message with role \"user\" from the input.\n * Walks structured content arrays (e.g. `[{type:\"text\", text:\"...\"}, {type:\"document\", ...}]`)\n * and joins their text parts. Returns `\"\"` when no user message is present or has no text.\n */\nexport function extractLastUserMessage(input: AGUIRunAgentInput): string {\n if (!input.messages || input.messages.length === 0) return \"\";\n for (let i = input.messages.length - 1; i >= 0; i--) {\n const msg = input.messages[i];\n if (msg.role !== \"user\") continue;\n const text = extractTextFromContent(msg.content);\n if (text) return text;\n }\n return \"\";\n}\n\nfunction extractTextFromContent(content: AGUIMessage[\"content\"]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const part of content) {\n if (\n part &&\n typeof part === \"object\" &&\n part.type === \"text\" &&\n typeof part.text === \"string\" &&\n part.text\n ) {\n parts.push(part.text);\n }\n }\n return parts.join(\" \").trim();\n}\n\n/**\n * Return the absolute last message if it has role \"tool\", otherwise null.\n */\nexport function getLastMessageIfToolResult(input: AGUIRunAgentInput): AGUIMessage | null {\n if (!input.messages || input.messages.length === 0) return null;\n const last = input.messages[input.messages.length - 1];\n return last.role === \"tool\" ? last : null;\n}\n\n/**\n * Check whether an input matches a fixture's match criteria.\n * All specified criteria must pass (AND logic).\n */\nexport function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean {\n if (match.message !== undefined) {\n const text = extractLastUserMessage(input);\n if (typeof match.message === \"string\") {\n if (!text.includes(match.message)) return false;\n } else {\n match.message.lastIndex = 0;\n if (!match.message.test(text)) return false;\n }\n }\n\n if (match.toolCallId !== undefined) {\n const lastMsg = input.messages?.[input.messages.length - 1];\n if (!lastMsg || lastMsg.role !== \"tool\" || lastMsg.toolCallId !== match.toolCallId) {\n return false;\n }\n }\n\n if (match.toolName !== undefined) {\n const tools = input.tools ?? [];\n if (!tools.some((t) => t.name === match.toolName)) return false;\n }\n\n if (match.stateKey !== undefined) {\n if (\n input.state === null ||\n input.state === undefined ||\n typeof input.state !== \"object\" ||\n !(match.stateKey in (input.state as Record<string, unknown>))\n ) {\n return false;\n }\n }\n\n if (match.predicate !== undefined) {\n if (!match.predicate(input)) return false;\n }\n\n return true;\n}\n\n/**\n * Find the first fixture whose match criteria pass for the given input.\n */\nexport function findFixture(input: AGUIRunAgentInput, fixtures: AGUIFixture[]): AGUIFixture | null {\n for (const fixture of fixtures) {\n if (matchesFixture(input, fixture.match)) {\n return fixture;\n }\n }\n return null;\n}\n\n// ─── Builder options ─────────────────────────────────────────────────────────\n\nexport interface AGUIBuildOpts {\n threadId?: string;\n runId?: string;\n parentRunId?: string;\n /** For tool call builder: include a result event */\n result?: string;\n}\n\n// ─── Event builders ──────────────────────────────────────────────────────────\n\nfunction makeRunStarted(opts?: AGUIBuildOpts): AGUIRunStartedEvent {\n return {\n type: \"RUN_STARTED\",\n threadId: opts?.threadId ?? randomUUID(),\n runId: opts?.runId ?? randomUUID(),\n ...(opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}),\n };\n}\n\nfunction makeRunFinished(\n started: AGUIRunStartedEvent,\n finishOpts?: { outcome?: AGUIRunFinishedOutcome; result?: unknown },\n): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\n ...(finishOpts?.result !== undefined ? { result: finishOpts.result } : {}),\n ...(finishOpts?.outcome !== undefined ? { outcome: finishOpts.outcome } : {}),\n };\n}\n\n/**\n * Build a complete text message response sequence.\n * [RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, RUN_FINISHED]\n */\nexport function buildTextResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a text chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TEXT_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildTextChunkResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TEXT_MESSAGE_CHUNK\",\n messageId: randomUUID(),\n role: \"assistant\",\n delta: text,\n } as AGUITextMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call response sequence.\n * [RUN_STARTED, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, (TOOL_CALL_RESULT)?, RUN_FINISHED]\n */\nexport function buildToolCallResponse(\n toolName: string,\n args: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const toolCallId = randomUUID();\n const events: AGUIEvent[] = [\n started,\n {\n type: \"TOOL_CALL_START\",\n toolCallId,\n toolCallName: toolName,\n } as AGUIToolCallStartEvent,\n {\n type: \"TOOL_CALL_ARGS\",\n toolCallId,\n delta: args,\n } as AGUIToolCallArgsEvent,\n {\n type: \"TOOL_CALL_END\",\n toolCallId,\n } as AGUIToolCallEndEvent,\n ];\n\n if (opts?.result !== undefined) {\n events.push({\n type: \"TOOL_CALL_RESULT\",\n messageId: randomUUID(),\n toolCallId,\n content: opts.result,\n role: \"tool\",\n } as AGUIToolCallResultEvent);\n }\n\n events.push(makeRunFinished(started));\n return events;\n}\n\n/**\n * Build a state snapshot response.\n * [RUN_STARTED, STATE_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildStateUpdate(snapshot: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_SNAPSHOT\",\n snapshot,\n } as AGUIStateSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a state delta response (JSON Patch).\n * [RUN_STARTED, STATE_DELTA, RUN_FINISHED]\n */\nexport function buildStateDelta(patches: unknown[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"STATE_DELTA\",\n delta: patches,\n } as AGUIStateDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a messages snapshot response.\n * [RUN_STARTED, MESSAGES_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildMessagesSnapshot(messages: AGUIMessage[], opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"MESSAGES_SNAPSHOT\",\n messages,\n } as AGUIMessagesSnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning response sequence.\n * [RUN_STARTED, REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT,\n * REASONING_MESSAGE_END, REASONING_END, RUN_FINISHED]\n */\nexport function buildReasoningResponse(text: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"REASONING_START\",\n messageId,\n } as AGUIReasoningStartEvent,\n {\n type: \"REASONING_MESSAGE_START\",\n messageId,\n role: \"reasoning\",\n } as AGUIReasoningMessageStartEvent,\n {\n type: \"REASONING_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUIReasoningMessageContentEvent,\n {\n type: \"REASONING_MESSAGE_END\",\n messageId,\n } as AGUIReasoningMessageEndEvent,\n {\n type: \"REASONING_END\",\n messageId,\n } as AGUIReasoningEndEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an activity snapshot response.\n * [RUN_STARTED, ACTIVITY_SNAPSHOT, RUN_FINISHED]\n */\nexport function buildActivityResponse(\n messageId: string,\n activityType: string,\n content: Record<string, unknown>,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_SNAPSHOT\",\n messageId,\n activityType,\n content,\n replace: true,\n } as AGUIActivitySnapshotEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build an error response.\n * [RUN_STARTED, RUN_ERROR] (no RUN_FINISHED — the run errored)\n */\nexport function buildErrorResponse(\n message: string,\n code?: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RUN_ERROR\",\n message,\n ...(code !== undefined ? { code } : {}),\n } as AGUIRunErrorEvent,\n ];\n}\n\n/**\n * Build a step-wrapped text response.\n * [RUN_STARTED, STEP_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT,\n * TEXT_MESSAGE_END, STEP_FINISHED, RUN_FINISHED]\n */\nexport function buildStepWithText(\n stepName: string,\n text: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const messageId = randomUUID();\n return [\n started,\n {\n type: \"STEP_STARTED\",\n stepName,\n } as AGUIStepStartedEvent,\n {\n type: \"TEXT_MESSAGE_START\",\n messageId,\n role: \"assistant\",\n } as AGUITextMessageStartEvent,\n {\n type: \"TEXT_MESSAGE_CONTENT\",\n messageId,\n delta: text,\n } as AGUITextMessageContentEvent,\n {\n type: \"TEXT_MESSAGE_END\",\n messageId,\n } as AGUITextMessageEndEvent,\n {\n type: \"STEP_FINISHED\",\n stepName,\n } as AGUIStepFinishedEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Combine multiple builder outputs into a single run.\n * Strips RUN_STARTED/RUN_FINISHED from each input, wraps all inner events\n * in one RUN_STARTED...RUN_FINISHED pair.\n */\nexport function buildCompositeResponse(\n builderOutputs: AGUIEvent[][],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n const inner: AGUIEvent[] = [];\n\n for (const events of builderOutputs) {\n for (const event of events) {\n if (event.type !== \"RUN_STARTED\" && event.type !== \"RUN_FINISHED\") {\n inner.push(event);\n }\n }\n }\n\n const hasError = inner.some((e) => e.type === \"RUN_ERROR\");\n return [started, ...inner, ...(hasError ? [] : [makeRunFinished(started)])];\n}\n\n// ─── Convenience event builders ─────────────────────────────────────────────\n\n/**\n * Build an activity delta response (JSON Patch on an activity).\n * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]\n */\nexport function buildActivityDelta(\n messageId: string,\n activityType: string,\n patch: unknown[],\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"ACTIVITY_DELTA\",\n messageId,\n activityType,\n patch,\n } as AGUIActivityDeltaEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a tool call chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]\n */\nexport function buildToolCallChunk(\n delta: string,\n opts?: AGUIBuildOpts & {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"TOOL_CALL_CHUNK\",\n ...(opts?.toolCallId !== undefined ? { toolCallId: opts.toolCallId } : {}),\n ...(opts?.toolCallName !== undefined ? { toolCallName: opts.toolCallName } : {}),\n ...(opts?.parentMessageId !== undefined ? { parentMessageId: opts.parentMessageId } : {}),\n delta,\n } as AGUIToolCallChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a raw event response.\n * [RUN_STARTED, RAW, RUN_FINISHED]\n */\nexport function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"RAW\",\n event,\n ...(source !== undefined ? { source } : {}),\n } as AGUIRawEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a custom event response.\n * [RUN_STARTED, CUSTOM, RUN_FINISHED]\n */\nexport function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"CUSTOM\",\n name,\n value,\n } as AGUICustomEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning message chunk response (single chunk, no start/end envelope).\n * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]\n */\nexport function buildReasoningChunk(\n delta: string,\n opts?: AGUIBuildOpts & { messageId?: string },\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_MESSAGE_CHUNK\",\n ...(opts?.messageId !== undefined ? { messageId: opts.messageId } : {}),\n delta,\n } as AGUIReasoningMessageChunkEvent,\n makeRunFinished(started),\n ];\n}\n\n/**\n * Build a reasoning encrypted value event response.\n * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]\n */\nexport function buildReasoningEncryptedValue(\n subtype: AGUIReasoningEncryptedValueSubtype,\n entityId: string,\n encryptedValue: string,\n opts?: AGUIBuildOpts,\n): AGUIEvent[] {\n const started = makeRunStarted(opts);\n return [\n started,\n {\n type: \"REASONING_ENCRYPTED_VALUE\",\n subtype,\n entityId,\n encryptedValue,\n } as AGUIReasoningEncryptedValueEvent,\n makeRunFinished(started),\n ];\n}\n\n// ─── SSE writer ──────────────────────────────────────────────────────────────\n\n/**\n * Write AG-UI events as an SSE stream to an HTTP response.\n * Sets appropriate headers, serializes each event as `data: {...}\\n\\n`,\n * and optionally delays between events.\n */\nexport async function writeAGUIEventStream(\n res: http.ServerResponse,\n events: AGUIEvent[],\n opts?: { delayMs?: number; signal?: AbortSignal; logger?: Logger },\n): Promise<void> {\n const delayMs = opts?.delayMs ?? 0;\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n for (const event of events) {\n if (opts?.signal?.aborted) break;\n if (res.socket?.destroyed) break;\n\n const stamped = { ...event, timestamp: event.timestamp ?? Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch (err) {\n if (err instanceof TypeError || err instanceof RangeError) {\n const msg = (err as Error).message;\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed (serialization):\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed (serialization):\", msg);\n }\n } else if (err instanceof Error) {\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", err.message);\n } else {\n console.warn(\"AG-UI SSE write failed:\", err.message);\n }\n } else {\n const msg = String(err);\n if (opts?.logger) {\n opts.logger.warn(\"AG-UI SSE write failed:\", msg);\n } else {\n console.warn(\"AG-UI SSE write failed:\", msg);\n }\n }\n break;\n }\n\n if (delayMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n if (!res.writableEnded) res.end();\n}\n"],"mappings":"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"}
|
package/dist/agui-mock.cjs
CHANGED
|
@@ -76,6 +76,14 @@ var AGUIMock = class {
|
|
|
76
76
|
});
|
|
77
77
|
return this;
|
|
78
78
|
}
|
|
79
|
+
onToolResult(toolCallId, events, delayMs) {
|
|
80
|
+
this.fixtures.push({
|
|
81
|
+
match: { toolCallId },
|
|
82
|
+
events,
|
|
83
|
+
delayMs
|
|
84
|
+
});
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
79
87
|
enableRecording(config) {
|
|
80
88
|
this.recordConfig = config;
|
|
81
89
|
return this;
|
|
@@ -108,6 +116,12 @@ var AGUIMock = class {
|
|
|
108
116
|
this.journalRequest(req, pathname, 400);
|
|
109
117
|
return true;
|
|
110
118
|
}
|
|
119
|
+
if (input.messages !== void 0 && !Array.isArray(input.messages)) {
|
|
120
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
121
|
+
res.end(JSON.stringify({ error: "Invalid input: 'messages' must be an array when provided" }));
|
|
122
|
+
this.journalRequest(req, pathname, 400);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
111
125
|
const fixture = require_agui_handler.findFixture(input, this.fixtures);
|
|
112
126
|
if (fixture) {
|
|
113
127
|
await require_agui_handler.writeAGUIEventStream(res, fixture.events, { delayMs: fixture.delayMs });
|