@copilotkit/aimock 1.16.3 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +30 -0
  4. package/README.md +10 -10
  5. package/dist/a2a-mock.d.cts +2 -2
  6. package/dist/a2a-mock.d.cts.map +1 -1
  7. package/dist/a2a-mock.d.ts +2 -2
  8. package/dist/a2a-mock.d.ts.map +1 -1
  9. package/dist/a2a-mock.js +2 -2
  10. package/dist/a2a-mock.js.map +1 -1
  11. package/dist/agui-handler.cjs +120 -5
  12. package/dist/agui-handler.cjs.map +1 -1
  13. package/dist/agui-handler.d.cts +41 -5
  14. package/dist/agui-handler.d.cts.map +1 -1
  15. package/dist/agui-handler.d.ts +41 -5
  16. package/dist/agui-handler.d.ts.map +1 -1
  17. package/dist/agui-handler.js +114 -6
  18. package/dist/agui-handler.js.map +1 -1
  19. package/dist/agui-mock.cjs +18 -7
  20. package/dist/agui-mock.cjs.map +1 -1
  21. package/dist/agui-mock.d.cts +2 -2
  22. package/dist/agui-mock.d.cts.map +1 -1
  23. package/dist/agui-mock.d.ts +2 -2
  24. package/dist/agui-mock.d.ts.map +1 -1
  25. package/dist/agui-mock.js +20 -9
  26. package/dist/agui-mock.js.map +1 -1
  27. package/dist/agui-recorder.cjs +43 -22
  28. package/dist/agui-recorder.cjs.map +1 -1
  29. package/dist/agui-recorder.d.cts +4 -3
  30. package/dist/agui-recorder.d.cts.map +1 -1
  31. package/dist/agui-recorder.d.ts +4 -3
  32. package/dist/agui-recorder.d.ts.map +1 -1
  33. package/dist/agui-recorder.js +45 -24
  34. package/dist/agui-recorder.js.map +1 -1
  35. package/dist/agui-stub.cjs +28 -0
  36. package/dist/agui-stub.d.cts +5 -0
  37. package/dist/agui-stub.d.ts +5 -0
  38. package/dist/agui-stub.js +5 -0
  39. package/dist/agui-types.d.cts +33 -6
  40. package/dist/agui-types.d.cts.map +1 -1
  41. package/dist/agui-types.d.ts +33 -6
  42. package/dist/agui-types.d.ts.map +1 -1
  43. package/dist/aimock-cli.cjs +1 -1
  44. package/dist/aimock-cli.js +1 -1
  45. package/dist/aws-event-stream.d.cts +2 -2
  46. package/dist/aws-event-stream.d.cts.map +1 -1
  47. package/dist/aws-event-stream.d.ts +2 -2
  48. package/dist/aws-event-stream.d.ts.map +1 -1
  49. package/dist/bedrock-converse.d.cts +3 -3
  50. package/dist/bedrock-converse.d.cts.map +1 -1
  51. package/dist/bedrock-converse.d.ts +3 -3
  52. package/dist/bedrock-converse.d.ts.map +1 -1
  53. package/dist/bedrock.d.cts +3 -3
  54. package/dist/bedrock.d.cts.map +1 -1
  55. package/dist/bedrock.d.ts +3 -3
  56. package/dist/bedrock.d.ts.map +1 -1
  57. package/dist/chaos.d.cts +3 -3
  58. package/dist/chaos.d.cts.map +1 -1
  59. package/dist/chaos.d.ts +3 -3
  60. package/dist/chaos.d.ts.map +1 -1
  61. package/dist/cli.cjs +6 -5
  62. package/dist/cli.cjs.map +1 -1
  63. package/dist/cli.js +6 -5
  64. package/dist/cli.js.map +1 -1
  65. package/dist/cohere.d.cts +2 -2
  66. package/dist/cohere.d.cts.map +1 -1
  67. package/dist/cohere.d.ts +2 -2
  68. package/dist/cohere.d.ts.map +1 -1
  69. package/dist/config-loader.cjs +3 -3
  70. package/dist/config-loader.d.cts +1 -1
  71. package/dist/config-loader.d.cts.map +1 -1
  72. package/dist/config-loader.d.ts +1 -1
  73. package/dist/config-loader.js +2 -2
  74. package/dist/convert-vidaimock.cjs +1 -1
  75. package/dist/convert-vidaimock.js +1 -1
  76. package/dist/convert.cjs +1 -1
  77. package/dist/convert.js +1 -1
  78. package/dist/elevenlabs-audio.cjs +209 -0
  79. package/dist/elevenlabs-audio.cjs.map +1 -0
  80. package/dist/elevenlabs-audio.d.cts +11 -0
  81. package/dist/elevenlabs-audio.d.cts.map +1 -0
  82. package/dist/elevenlabs-audio.d.ts +11 -0
  83. package/dist/elevenlabs-audio.d.ts.map +1 -0
  84. package/dist/elevenlabs-audio.js +209 -0
  85. package/dist/elevenlabs-audio.js.map +1 -0
  86. package/dist/embeddings.d.cts +2 -2
  87. package/dist/embeddings.d.cts.map +1 -1
  88. package/dist/embeddings.d.ts +2 -2
  89. package/dist/embeddings.d.ts.map +1 -1
  90. package/dist/fal-audio.cjs +477 -0
  91. package/dist/fal-audio.cjs.map +1 -0
  92. package/dist/fal-audio.d.cts +10 -0
  93. package/dist/fal-audio.d.cts.map +1 -0
  94. package/dist/fal-audio.d.ts +10 -0
  95. package/dist/fal-audio.d.ts.map +1 -0
  96. package/dist/fal-audio.js +474 -0
  97. package/dist/fal-audio.js.map +1 -0
  98. package/dist/fixture-loader.cjs +14 -1
  99. package/dist/fixture-loader.cjs.map +1 -1
  100. package/dist/fixture-loader.js +14 -1
  101. package/dist/fixture-loader.js.map +1 -1
  102. package/dist/fixtures-remote.cjs +1 -1
  103. package/dist/fixtures-remote.js +1 -1
  104. package/dist/gemini-interactions.cjs +617 -0
  105. package/dist/gemini-interactions.cjs.map +1 -0
  106. package/dist/gemini-interactions.d.cts +46 -0
  107. package/dist/gemini-interactions.d.cts.map +1 -0
  108. package/dist/gemini-interactions.d.ts +46 -0
  109. package/dist/gemini-interactions.d.ts.map +1 -0
  110. package/dist/gemini-interactions.js +616 -0
  111. package/dist/gemini-interactions.js.map +1 -0
  112. package/dist/gemini.cjs +76 -0
  113. package/dist/gemini.cjs.map +1 -1
  114. package/dist/gemini.d.cts +2 -2
  115. package/dist/gemini.d.cts.map +1 -1
  116. package/dist/gemini.d.ts +2 -2
  117. package/dist/gemini.d.ts.map +1 -1
  118. package/dist/gemini.js +77 -1
  119. package/dist/gemini.js.map +1 -1
  120. package/dist/helpers.cjs +24 -1
  121. package/dist/helpers.cjs.map +1 -1
  122. package/dist/helpers.d.cts +13 -3
  123. package/dist/helpers.d.cts.map +1 -1
  124. package/dist/helpers.d.ts +13 -3
  125. package/dist/helpers.d.ts.map +1 -1
  126. package/dist/helpers.js +23 -2
  127. package/dist/helpers.js.map +1 -1
  128. package/dist/images.d.cts +2 -2
  129. package/dist/images.d.cts.map +1 -1
  130. package/dist/images.d.ts +2 -2
  131. package/dist/images.d.ts.map +1 -1
  132. package/dist/index.cjs +21 -4
  133. package/dist/index.d.cts +10 -7
  134. package/dist/index.d.ts +10 -7
  135. package/dist/index.js +10 -7
  136. package/dist/jest.cjs +1 -1
  137. package/dist/jest.js +1 -1
  138. package/dist/jsonrpc.d.cts +3 -3
  139. package/dist/jsonrpc.d.cts.map +1 -1
  140. package/dist/jsonrpc.d.ts +3 -3
  141. package/dist/jsonrpc.d.ts.map +1 -1
  142. package/dist/llmock.cjs +38 -2
  143. package/dist/llmock.cjs.map +1 -1
  144. package/dist/llmock.d.cts +4 -0
  145. package/dist/llmock.d.cts.map +1 -1
  146. package/dist/llmock.d.ts +4 -0
  147. package/dist/llmock.d.ts.map +1 -1
  148. package/dist/llmock.js +38 -2
  149. package/dist/llmock.js.map +1 -1
  150. package/dist/logger.cjs +5 -4
  151. package/dist/logger.cjs.map +1 -1
  152. package/dist/logger.d.cts +1 -1
  153. package/dist/logger.d.cts.map +1 -1
  154. package/dist/logger.d.ts +1 -1
  155. package/dist/logger.d.ts.map +1 -1
  156. package/dist/logger.js +5 -4
  157. package/dist/logger.js.map +1 -1
  158. package/dist/mcp-mock.d.cts +2 -2
  159. package/dist/mcp-mock.d.cts.map +1 -1
  160. package/dist/mcp-mock.d.ts +2 -2
  161. package/dist/mcp-mock.d.ts.map +1 -1
  162. package/dist/mcp-mock.js +2 -2
  163. package/dist/mcp-mock.js.map +1 -1
  164. package/dist/messages.d.cts +2 -2
  165. package/dist/messages.d.cts.map +1 -1
  166. package/dist/messages.d.ts +2 -2
  167. package/dist/messages.d.ts.map +1 -1
  168. package/dist/moderation.d.cts +3 -3
  169. package/dist/moderation.d.cts.map +1 -1
  170. package/dist/moderation.d.ts +3 -3
  171. package/dist/moderation.d.ts.map +1 -1
  172. package/dist/ndjson-writer.d.cts +2 -2
  173. package/dist/ndjson-writer.d.cts.map +1 -1
  174. package/dist/ndjson-writer.d.ts +2 -2
  175. package/dist/ndjson-writer.d.ts.map +1 -1
  176. package/dist/ollama.d.cts +3 -3
  177. package/dist/ollama.d.cts.map +1 -1
  178. package/dist/ollama.d.ts +3 -3
  179. package/dist/ollama.d.ts.map +1 -1
  180. package/dist/recorder.cjs +64 -21
  181. package/dist/recorder.cjs.map +1 -1
  182. package/dist/recorder.d.cts +2 -2
  183. package/dist/recorder.d.cts.map +1 -1
  184. package/dist/recorder.d.ts +2 -2
  185. package/dist/recorder.d.ts.map +1 -1
  186. package/dist/recorder.js +66 -23
  187. package/dist/recorder.js.map +1 -1
  188. package/dist/rerank.d.cts +3 -3
  189. package/dist/rerank.d.cts.map +1 -1
  190. package/dist/rerank.d.ts +3 -3
  191. package/dist/rerank.d.ts.map +1 -1
  192. package/dist/responses.d.cts +2 -2
  193. package/dist/responses.d.cts.map +1 -1
  194. package/dist/responses.d.ts +2 -2
  195. package/dist/responses.d.ts.map +1 -1
  196. package/dist/router.cjs +3 -3
  197. package/dist/router.cjs.map +1 -1
  198. package/dist/router.js +3 -3
  199. package/dist/router.js.map +1 -1
  200. package/dist/search.d.cts +3 -3
  201. package/dist/search.d.cts.map +1 -1
  202. package/dist/search.d.ts +3 -3
  203. package/dist/search.d.ts.map +1 -1
  204. package/dist/server.cjs +170 -1
  205. package/dist/server.cjs.map +1 -1
  206. package/dist/server.d.cts +2 -2
  207. package/dist/server.d.cts.map +1 -1
  208. package/dist/server.d.ts +2 -2
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +173 -4
  211. package/dist/server.js.map +1 -1
  212. package/dist/speech.cjs +18 -9
  213. package/dist/speech.cjs.map +1 -1
  214. package/dist/speech.d.cts +2 -2
  215. package/dist/speech.d.cts.map +1 -1
  216. package/dist/speech.d.ts +2 -2
  217. package/dist/speech.d.ts.map +1 -1
  218. package/dist/speech.js +18 -9
  219. package/dist/speech.js.map +1 -1
  220. package/dist/sse-writer.d.cts +3 -3
  221. package/dist/sse-writer.d.cts.map +1 -1
  222. package/dist/sse-writer.d.ts +3 -3
  223. package/dist/sse-writer.d.ts.map +1 -1
  224. package/dist/stream-collapse.cjs +80 -9
  225. package/dist/stream-collapse.cjs.map +1 -1
  226. package/dist/stream-collapse.d.cts +11 -1
  227. package/dist/stream-collapse.d.cts.map +1 -1
  228. package/dist/stream-collapse.d.ts +11 -1
  229. package/dist/stream-collapse.d.ts.map +1 -1
  230. package/dist/stream-collapse.js +80 -10
  231. package/dist/stream-collapse.js.map +1 -1
  232. package/dist/suite.cjs +1 -1
  233. package/dist/suite.d.cts +2 -2
  234. package/dist/suite.d.ts +2 -2
  235. package/dist/suite.js +1 -1
  236. package/dist/transcription.d.cts +2 -2
  237. package/dist/transcription.d.cts.map +1 -1
  238. package/dist/transcription.d.ts +2 -2
  239. package/dist/transcription.d.ts.map +1 -1
  240. package/dist/types.d.cts +10 -7
  241. package/dist/types.d.cts.map +1 -1
  242. package/dist/types.d.ts +10 -7
  243. package/dist/types.d.ts.map +1 -1
  244. package/dist/vector-mock.d.cts +2 -2
  245. package/dist/vector-mock.d.cts.map +1 -1
  246. package/dist/vector-mock.d.ts +2 -2
  247. package/dist/vector-mock.d.ts.map +1 -1
  248. package/dist/vector-mock.js +2 -2
  249. package/dist/vector-mock.js.map +1 -1
  250. package/dist/vector-types.d.ts.map +1 -1
  251. package/dist/video.d.cts +3 -3
  252. package/dist/video.d.cts.map +1 -1
  253. package/dist/video.d.ts +3 -3
  254. package/dist/video.d.ts.map +1 -1
  255. package/dist/vitest.cjs +1 -1
  256. package/dist/vitest.js +1 -1
  257. package/dist/ws-framing.d.cts +2 -2
  258. package/dist/ws-framing.d.cts.map +1 -1
  259. package/dist/ws-framing.d.ts +2 -2
  260. package/dist/ws-framing.d.ts.map +1 -1
  261. package/dist/ws-gemini-live.cjs +145 -2
  262. package/dist/ws-gemini-live.cjs.map +1 -1
  263. package/dist/ws-gemini-live.d.cts.map +1 -1
  264. package/dist/ws-gemini-live.d.ts.map +1 -1
  265. package/dist/ws-gemini-live.js +146 -3
  266. package/dist/ws-gemini-live.js.map +1 -1
  267. package/package.json +16 -2
  268. package/skills/write-fixtures/SKILL.md +10 -10
@@ -1,5 +1,5 @@
1
- import { AGUIEvent, AGUIFixture, AGUIMessage, AGUIRunAgentInput } from "./agui-types.js";
2
- import * as http from "node:http";
1
+ import { AGUIEvent, AGUIFixture, AGUIFixtureMatch, AGUIMessage, AGUIReasoningEncryptedValueSubtype, AGUIRunAgentInput } from "./agui-types.js";
2
+ import * as http$1 from "node:http";
3
3
 
4
4
  //#region src/agui-handler.d.ts
5
5
 
@@ -11,7 +11,7 @@ declare function extractLastUserMessage(input: AGUIRunAgentInput): string;
11
11
  * Check whether an input matches a fixture's match criteria.
12
12
  * All specified criteria must pass (AND logic).
13
13
  */
14
-
14
+ declare function matchesFixture(input: AGUIRunAgentInput, match: AGUIFixtureMatch): boolean;
15
15
  /**
16
16
  * Find the first fixture whose match criteria pass for the given input.
17
17
  */
@@ -81,16 +81,52 @@ declare function buildStepWithText(stepName: string, text: string, opts?: AGUIBu
81
81
  * in one RUN_STARTED...RUN_FINISHED pair.
82
82
  */
83
83
  declare function buildCompositeResponse(builderOutputs: AGUIEvent[][], opts?: AGUIBuildOpts): AGUIEvent[];
84
+ /**
85
+ * Build an activity delta response (JSON Patch on an activity).
86
+ * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]
87
+ */
88
+ declare function buildActivityDelta(messageId: string, activityType: string, patch: unknown[], opts?: AGUIBuildOpts): AGUIEvent[];
89
+ /**
90
+ * Build a tool call chunk response (single chunk, no start/end envelope).
91
+ * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]
92
+ */
93
+ declare function buildToolCallChunk(delta: string, opts?: AGUIBuildOpts & {
94
+ toolCallId?: string;
95
+ toolCallName?: string;
96
+ parentMessageId?: string;
97
+ }): AGUIEvent[];
98
+ /**
99
+ * Build a raw event response.
100
+ * [RUN_STARTED, RAW, RUN_FINISHED]
101
+ */
102
+ declare function buildRawEvent(event: unknown, source?: string, opts?: AGUIBuildOpts): AGUIEvent[];
103
+ /**
104
+ * Build a custom event response.
105
+ * [RUN_STARTED, CUSTOM, RUN_FINISHED]
106
+ */
107
+ declare function buildCustomEvent(name: string, value: unknown, opts?: AGUIBuildOpts): AGUIEvent[];
108
+ /**
109
+ * Build a reasoning message chunk response (single chunk, no start/end envelope).
110
+ * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]
111
+ */
112
+ declare function buildReasoningChunk(delta: string, opts?: AGUIBuildOpts & {
113
+ messageId?: string;
114
+ }): AGUIEvent[];
115
+ /**
116
+ * Build a reasoning encrypted value event response.
117
+ * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]
118
+ */
119
+ declare function buildReasoningEncryptedValue(subtype: AGUIReasoningEncryptedValueSubtype, entityId: string, encryptedValue: string, opts?: AGUIBuildOpts): AGUIEvent[];
84
120
  /**
85
121
  * Write AG-UI events as an SSE stream to an HTTP response.
86
122
  * Sets appropriate headers, serializes each event as `data: {...}\n\n`,
87
123
  * and optionally delays between events.
88
124
  */
89
- declare function writeAGUIEventStream(res: http.ServerResponse, events: AGUIEvent[], opts?: {
125
+ declare function writeAGUIEventStream(res: http$1.ServerResponse, events: AGUIEvent[], opts?: {
90
126
  delayMs?: number;
91
127
  signal?: AbortSignal;
92
128
  }): Promise<void>;
93
129
  //# sourceMappingURL=agui-handler.d.ts.map
94
130
  //#endregion
95
- export { buildActivityResponse, buildCompositeResponse, buildErrorResponse, buildMessagesSnapshot, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallResponse, extractLastUserMessage, findFixture, writeAGUIEventStream };
131
+ export { AGUIBuildOpts, buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, matchesFixture, writeAGUIEventStream };
96
132
  //# sourceMappingURL=agui-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":";;;;;;;AA0CA;AAmDgB,iBAnDA,sBAAA,CAmDW,KAAA,EAnDmB,iBAmDnB,CAAA,EAAA,MAAA;;;;;;AAW3B;AA+BA;;AAAuD,iBA1CvC,WAAA,CA0CuC,KAAA,EA1CpB,iBA0CoB,EAAA,QAAA,EA1CS,WA0CT,EAAA,CAAA,EA1CyB,WA0CzB,GAAA,IAAA;AAAgB,UA/BtD,aAAA,CA+BsD;EAAS,QAAA,CAAA,EAAA,MAAA;EA2BhE,KAAA,CAAA,EAAA,MAAA;EAAsB,WAAA,CAAA,EAAA,MAAA;;QAAsC,CAAA,EAAA,MAAA;;AAkB5E;;;;AAIY,iBAjDI,iBAAA,CAiDJ,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAjD2C,aAiD3C,CAAA,EAjD2D,SAiD3D,EAAA;AAuCZ;;;;AAAoF,iBA7DpE,sBAAA,CA6DoE,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EA7DxB,aA6DwB,CAAA,EA7DR,SA6DQ,EAAA;AAgBpF;;;;AAAoF,iBA3DpE,qBAAA,CA2DoE,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAxD3E,aAwD2E,CAAA,EAvDjF,SAuDiF,EAAA;AAgBpF;;;;AAAsF,iBAhCtE,gBAAA,CAgCsE,QAAA,EAAA,OAAA,EAAA,IAAA,CAAA,EAhC3B,aAgC2B,CAAA,EAhCX,SAgCW,EAAA;;AAiBtF;;;AAA4E,iBAjC5D,eAAA,CAiC4D,OAAA,EAAA,OAAA,EAAA,EAAA,IAAA,CAAA,EAjCjB,aAiCiB,CAAA,EAjCD,SAiCC,EAAA;;AAmC5E;;;AAIS,iBAxDO,qBAAA,CAwDP,QAAA,EAxDuC,WAwDvC,EAAA,EAAA,IAAA,CAAA,EAxD6D,aAwD7D,CAAA,EAxD6E,SAwD7E,EAAA;;;AAoBT;;;AAIG,iBA/Da,sBAAA,CA+Db,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EA/DyD,aA+DzD,CAAA,EA/DyE,SA+DzE,EAAA;;AAiBH;;;AAIG,iBAjDa,qBAAA,CAiDb,SAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,OAAA,EA9CQ,MA8CR,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,IAAA,CAAA,EA7CM,aA6CN,CAAA,EA5CA,SA4CA,EAAA;;AAoCH;;;AAES,iBA/DO,kBAAA,CA+DP,OAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EA5DA,aA4DA,CAAA,EA3DN,SA2DM,EAAA;;;AAuBT;;;AAEU,iBAnEM,iBAAA,CAmEN,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAhED,aAgEC,CAAA,EA/DP,SA+DO,EAAA;;;;;;iBA3BM,sBAAA,iBACE,sBACT,gBACN;;;;;;iBAsBmB,oBAAA,MACf,IAAA,CAAK,wBACF;;WAC4B;IACnC"}
1
+ {"version":3,"file":"agui-handler.d.ts","names":[],"sources":["../src/agui-handler.ts"],"sourcesContent":[],"mappings":"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"}
@@ -21,7 +21,10 @@ function matchesFixture(input, match) {
21
21
  const text = extractLastUserMessage(input);
22
22
  if (typeof match.message === "string") {
23
23
  if (!text.includes(match.message)) return false;
24
- } else if (!match.message.test(text)) return false;
24
+ } else {
25
+ match.message.lastIndex = 0;
26
+ if (!match.message.test(text)) return false;
27
+ }
25
28
  }
26
29
  if (match.toolName !== void 0) {
27
30
  if (!(input.tools ?? []).some((t) => t.name === match.toolName)) return false;
@@ -49,11 +52,13 @@ function makeRunStarted(opts) {
49
52
  ...opts?.parentRunId ? { parentRunId: opts.parentRunId } : {}
50
53
  };
51
54
  }
52
- function makeRunFinished(started) {
55
+ function makeRunFinished(started, finishOpts) {
53
56
  return {
54
57
  type: "RUN_FINISHED",
55
58
  threadId: started.threadId,
56
- runId: started.runId
59
+ runId: started.runId,
60
+ ...finishOpts?.result !== void 0 ? { result: finishOpts.result } : {},
61
+ ...finishOpts?.outcome !== void 0 ? { outcome: finishOpts.outcome } : {}
57
62
  };
58
63
  }
59
64
  /**
@@ -286,9 +291,110 @@ function buildCompositeResponse(builderOutputs, opts) {
286
291
  const started = makeRunStarted(opts);
287
292
  const inner = [];
288
293
  for (const events of builderOutputs) for (const event of events) if (event.type !== "RUN_STARTED" && event.type !== "RUN_FINISHED") inner.push(event);
294
+ const hasError = inner.some((e) => e.type === "RUN_ERROR");
289
295
  return [
290
296
  started,
291
297
  ...inner,
298
+ ...hasError ? [] : [makeRunFinished(started)]
299
+ ];
300
+ }
301
+ /**
302
+ * Build an activity delta response (JSON Patch on an activity).
303
+ * [RUN_STARTED, ACTIVITY_DELTA, RUN_FINISHED]
304
+ */
305
+ function buildActivityDelta(messageId, activityType, patch, opts) {
306
+ const started = makeRunStarted(opts);
307
+ return [
308
+ started,
309
+ {
310
+ type: "ACTIVITY_DELTA",
311
+ messageId,
312
+ activityType,
313
+ patch
314
+ },
315
+ makeRunFinished(started)
316
+ ];
317
+ }
318
+ /**
319
+ * Build a tool call chunk response (single chunk, no start/end envelope).
320
+ * [RUN_STARTED, TOOL_CALL_CHUNK, RUN_FINISHED]
321
+ */
322
+ function buildToolCallChunk(delta, opts) {
323
+ const started = makeRunStarted(opts);
324
+ return [
325
+ started,
326
+ {
327
+ type: "TOOL_CALL_CHUNK",
328
+ ...opts?.toolCallId !== void 0 ? { toolCallId: opts.toolCallId } : {},
329
+ ...opts?.toolCallName !== void 0 ? { toolCallName: opts.toolCallName } : {},
330
+ ...opts?.parentMessageId !== void 0 ? { parentMessageId: opts.parentMessageId } : {},
331
+ delta
332
+ },
333
+ makeRunFinished(started)
334
+ ];
335
+ }
336
+ /**
337
+ * Build a raw event response.
338
+ * [RUN_STARTED, RAW, RUN_FINISHED]
339
+ */
340
+ function buildRawEvent(event, source, opts) {
341
+ const started = makeRunStarted(opts);
342
+ return [
343
+ started,
344
+ {
345
+ type: "RAW",
346
+ event,
347
+ ...source !== void 0 ? { source } : {}
348
+ },
349
+ makeRunFinished(started)
350
+ ];
351
+ }
352
+ /**
353
+ * Build a custom event response.
354
+ * [RUN_STARTED, CUSTOM, RUN_FINISHED]
355
+ */
356
+ function buildCustomEvent(name, value, opts) {
357
+ const started = makeRunStarted(opts);
358
+ return [
359
+ started,
360
+ {
361
+ type: "CUSTOM",
362
+ name,
363
+ value
364
+ },
365
+ makeRunFinished(started)
366
+ ];
367
+ }
368
+ /**
369
+ * Build a reasoning message chunk response (single chunk, no start/end envelope).
370
+ * [RUN_STARTED, REASONING_MESSAGE_CHUNK, RUN_FINISHED]
371
+ */
372
+ function buildReasoningChunk(delta, opts) {
373
+ const started = makeRunStarted(opts);
374
+ return [
375
+ started,
376
+ {
377
+ type: "REASONING_MESSAGE_CHUNK",
378
+ ...opts?.messageId !== void 0 ? { messageId: opts.messageId } : {},
379
+ delta
380
+ },
381
+ makeRunFinished(started)
382
+ ];
383
+ }
384
+ /**
385
+ * Build a reasoning encrypted value event response.
386
+ * [RUN_STARTED, REASONING_ENCRYPTED_VALUE, RUN_FINISHED]
387
+ */
388
+ function buildReasoningEncryptedValue(subtype, entityId, encryptedValue, opts) {
389
+ const started = makeRunStarted(opts);
390
+ return [
391
+ started,
392
+ {
393
+ type: "REASONING_ENCRYPTED_VALUE",
394
+ subtype,
395
+ entityId,
396
+ encryptedValue
397
+ },
292
398
  makeRunFinished(started)
293
399
  ];
294
400
  }
@@ -309,11 +415,13 @@ async function writeAGUIEventStream(res, events, opts) {
309
415
  if (res.socket?.destroyed) break;
310
416
  const stamped = {
311
417
  ...event,
312
- timestamp: Date.now()
418
+ timestamp: event.timestamp ?? Date.now()
313
419
  };
314
420
  try {
315
421
  res.write(`data: ${JSON.stringify(stamped)}\n\n`);
316
- } catch {
422
+ } catch (err) {
423
+ if (err instanceof TypeError || err instanceof RangeError) console.warn("AG-UI SSE write failed (serialization):", err.message);
424
+ else if (err instanceof Error) console.warn("AG-UI SSE write failed:", err.message);
317
425
  break;
318
426
  }
319
427
  if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
@@ -322,5 +430,5 @@ async function writeAGUIEventStream(res, events, opts) {
322
430
  }
323
431
 
324
432
  //#endregion
325
- export { buildActivityResponse, buildCompositeResponse, buildErrorResponse, buildMessagesSnapshot, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallResponse, extractLastUserMessage, findFixture, writeAGUIEventStream };
433
+ export { buildActivityDelta, buildActivityResponse, buildCompositeResponse, buildCustomEvent, buildErrorResponse, buildMessagesSnapshot, buildRawEvent, buildReasoningChunk, buildReasoningEncryptedValue, buildReasoningResponse, buildStateDelta, buildStateUpdate, buildStepWithText, buildTextChunkResponse, buildTextResponse, buildToolCallChunk, buildToolCallResponse, extractLastUserMessage, findFixture, matchesFixture, writeAGUIEventStream };
326
434
  //# sourceMappingURL=agui-handler.js.map
@@ -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 AGUIRunErrorEvent,\n AGUITextMessageStartEvent,\n AGUITextMessageContentEvent,\n AGUITextMessageEndEvent,\n AGUITextMessageChunkEvent,\n AGUIToolCallStartEvent,\n AGUIToolCallArgsEvent,\n AGUIToolCallEndEvent,\n AGUIToolCallResultEvent,\n AGUIStateSnapshotEvent,\n AGUIStateDeltaEvent,\n AGUIMessagesSnapshotEvent,\n AGUIStepStartedEvent,\n AGUIStepFinishedEvent,\n AGUIReasoningStartEvent,\n AGUIReasoningMessageStartEvent,\n AGUIReasoningMessageContentEvent,\n AGUIReasoningMessageEndEvent,\n AGUIReasoningEndEvent,\n AGUIActivitySnapshotEvent,\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 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(started: AGUIRunStartedEvent): AGUIRunFinishedEvent {\n return {\n type: \"RUN_FINISHED\",\n threadId: started.threadId,\n runId: started.runId,\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 return [started, ...inner, makeRunFinished(started)];\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: Date.now() };\n try {\n res.write(`data: ${JSON.stringify(stamped)}\\n\\n`);\n } catch {\n break; // client disconnected or stream error — stop writing\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 {\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,8 +1,8 @@
1
1
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
2
  const require_helpers = require('./helpers.cjs');
3
- const require_logger = require('./logger.cjs');
4
3
  const require_agui_handler = require('./agui-handler.cjs');
5
4
  const require_agui_recorder = require('./agui-recorder.cjs');
5
+ const require_logger = require('./logger.cjs');
6
6
  let node_http = require("node:http");
7
7
  node_http = require_runtime.__toESM(node_http);
8
8
 
@@ -18,7 +18,7 @@ var AGUIMock = class {
18
18
  logger;
19
19
  constructor(options) {
20
20
  this.options = options ?? {};
21
- this.logger = new require_logger.Logger("silent");
21
+ this.logger = new require_logger.Logger(options?.logLevel ?? "warn");
22
22
  }
23
23
  addFixture(fixture) {
24
24
  this.fixtures.push(fixture);
@@ -88,13 +88,23 @@ var AGUIMock = class {
88
88
  async handleRequest(req, res, pathname) {
89
89
  if (req.method !== "POST" || pathname !== "/" && pathname !== "") return false;
90
90
  if (this.registry) this.registry.incrementCounter("aimock_agui_requests_total", { method: "POST" });
91
- const body = await require_helpers.readBody(req);
91
+ let body;
92
+ try {
93
+ body = await require_helpers.readBody(req);
94
+ } catch (err) {
95
+ res.writeHead(400, { "Content-Type": "application/json" });
96
+ const detail = err instanceof Error ? err.message : "body read failed";
97
+ res.end(JSON.stringify({ error: `Failed to read request body: ${detail}` }));
98
+ this.journalRequest(req, pathname, 400);
99
+ return true;
100
+ }
92
101
  let input;
93
102
  try {
94
103
  input = JSON.parse(body);
95
- } catch {
104
+ } catch (err) {
96
105
  res.writeHead(400, { "Content-Type": "application/json" });
97
- res.end(JSON.stringify({ error: "Invalid JSON body" }));
106
+ const detail = err instanceof Error ? err.message : "unknown parse error";
107
+ res.end(JSON.stringify({ error: `Invalid JSON body: ${detail}` }));
98
108
  this.journalRequest(req, pathname, 400);
99
109
  return true;
100
110
  }
@@ -105,8 +115,9 @@ var AGUIMock = class {
105
115
  return true;
106
116
  }
107
117
  if (this.recordConfig) {
108
- if (await require_agui_recorder.proxyAndRecordAGUI(req, res, input, this.fixtures, this.recordConfig, this.logger)) {
109
- this.journalRequest(req, pathname, 200);
118
+ const result = await require_agui_recorder.proxyAndRecordAGUI(req, res, input, this.fixtures, this.recordConfig, this.logger);
119
+ if (result !== false) {
120
+ this.journalRequest(req, pathname, result);
110
121
  return true;
111
122
  }
112
123
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agui-mock.cjs","names":["Logger","buildTextResponse","buildToolCallResponse","buildStateUpdate","buildReasoningResponse","readBody","findFixture","writeAGUIEventStream","proxyAndRecordAGUI","http","flattenHeaders"],"sources":["../src/agui-mock.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type { Mountable } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\nimport type {\n AGUIFixture,\n AGUIMockOptions,\n AGUIRecordConfig,\n AGUIEvent,\n AGUIRunAgentInput,\n} from \"./agui-types.js\";\nimport {\n findFixture,\n buildTextResponse,\n buildToolCallResponse,\n buildStateUpdate,\n buildReasoningResponse,\n writeAGUIEventStream,\n} from \"./agui-handler.js\";\nimport { flattenHeaders, readBody } from \"./helpers.js\";\nimport { proxyAndRecordAGUI } from \"./agui-recorder.js\";\nimport { Logger } from \"./logger.js\";\n\nexport class AGUIMock implements Mountable {\n private fixtures: AGUIFixture[] = [];\n private server: http.Server | null = null;\n private journal: Journal | null = null;\n private registry: MetricsRegistry | null = null;\n private options: AGUIMockOptions;\n private baseUrl = \"\";\n private recordConfig: AGUIRecordConfig | undefined;\n private logger: Logger;\n\n constructor(options?: AGUIMockOptions) {\n this.options = options ?? {};\n this.logger = new Logger(\"silent\");\n }\n\n // ---- Fluent registration API ----\n\n addFixture(fixture: AGUIFixture): this {\n this.fixtures.push(fixture);\n return this;\n }\n\n onMessage(pattern: string | RegExp, text: string, opts?: { delayMs?: number }): this {\n const events = buildTextResponse(text);\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onRun(pattern: string | RegExp, events: AGUIEvent[], delayMs?: number): this {\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs,\n });\n return this;\n }\n\n onToolCall(\n pattern: string | RegExp,\n toolName: string,\n args: string,\n opts?: { result?: string; delayMs?: number },\n ): this {\n const events = buildToolCallResponse(toolName, args, {\n result: opts?.result,\n });\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onStateKey(key: string, snapshot: Record<string, unknown>, delayMs?: number): this {\n const events = buildStateUpdate(snapshot);\n this.fixtures.push({\n match: { stateKey: key },\n events,\n delayMs,\n });\n return this;\n }\n\n onReasoning(pattern: string | RegExp, text: string, opts?: { delayMs?: number }): this {\n const events = buildReasoningResponse(text);\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onPredicate(\n predicate: (input: AGUIRunAgentInput) => boolean,\n events: AGUIEvent[],\n delayMs?: number,\n ): this {\n this.fixtures.push({\n match: { predicate },\n events,\n delayMs,\n });\n return this;\n }\n\n enableRecording(config: AGUIRecordConfig): this {\n this.recordConfig = config;\n return this;\n }\n\n reset(): this {\n this.fixtures = [];\n this.recordConfig = undefined;\n return this;\n }\n\n // ---- Mountable interface ----\n\n async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n if (req.method !== \"POST\" || (pathname !== \"/\" && pathname !== \"\")) {\n return false;\n }\n\n if (this.registry) {\n this.registry.incrementCounter(\"aimock_agui_requests_total\", { method: \"POST\" });\n }\n\n const body = await readBody(req);\n\n let input: AGUIRunAgentInput;\n try {\n input = JSON.parse(body) as AGUIRunAgentInput;\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON body\" }));\n this.journalRequest(req, pathname, 400);\n return true;\n }\n\n const fixture = findFixture(input, this.fixtures);\n\n if (fixture) {\n await writeAGUIEventStream(res, fixture.events, { delayMs: fixture.delayMs });\n this.journalRequest(req, pathname, 200);\n return true;\n }\n\n // No match — if recording is enabled, proxy to upstream\n if (this.recordConfig) {\n const proxied = await proxyAndRecordAGUI(\n req,\n res,\n input,\n this.fixtures,\n this.recordConfig,\n this.logger,\n );\n if (proxied) {\n this.journalRequest(req, pathname, 200);\n return true;\n }\n }\n\n // No match, no recorder — 404\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"No matching AG-UI fixture\" }));\n this.journalRequest(req, pathname, 404);\n return true;\n }\n\n health(): { status: string; fixtures: number } {\n return {\n status: \"ok\",\n fixtures: this.fixtures.length,\n };\n }\n\n setJournal(journal: Journal): void {\n this.journal = journal;\n }\n\n setBaseUrl(url: string): void {\n this.baseUrl = url;\n }\n\n setRegistry(registry: MetricsRegistry): void {\n this.registry = registry;\n }\n\n // ---- Standalone mode ----\n\n async start(): Promise<string> {\n if (this.server) {\n throw new Error(\"AGUIMock server already started\");\n }\n\n const host = this.options.host ?? \"127.0.0.1\";\n const port = this.options.port ?? 0;\n\n return new Promise<string>((resolve, reject) => {\n const srv = http.createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const handled = await this.handleRequest(req, res, url.pathname).catch((err) => {\n this.logger.error(`AGUIMock request error: ${err instanceof Error ? err.message : err}`);\n if (!res.headersSent) {\n res.writeHead(500);\n res.end(\"Internal server error\");\n } else if (!res.writableEnded) {\n res.end();\n }\n return true;\n });\n if (!handled && !res.headersSent) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n }\n });\n\n srv.on(\"error\", reject);\n\n srv.listen(port, host, () => {\n const addr = srv.address();\n if (typeof addr === \"object\" && addr !== null) {\n this.baseUrl = `http://${host}:${addr.port}`;\n }\n this.server = srv;\n resolve(this.baseUrl);\n });\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n throw new Error(\"AGUIMock server not started\");\n }\n const srv = this.server;\n await new Promise<void>((resolve, reject) => {\n srv.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.server = null;\n }\n\n get url(): string {\n if (!this.server) {\n throw new Error(\"AGUIMock server not started\");\n }\n return this.baseUrl;\n }\n\n // ---- Private helpers ----\n\n private journalRequest(req: http.IncomingMessage, pathname: string, status: number): void {\n if (this.journal) {\n this.journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"agui\",\n response: { status, fixture: null },\n });\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agui-mock.cjs","names":["Logger","buildTextResponse","buildToolCallResponse","buildStateUpdate","buildReasoningResponse","readBody","findFixture","writeAGUIEventStream","proxyAndRecordAGUI","http","flattenHeaders"],"sources":["../src/agui-mock.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type { Mountable } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\nimport type {\n AGUIFixture,\n AGUIMockOptions,\n AGUIRecordConfig,\n AGUIEvent,\n AGUIRunAgentInput,\n} from \"./agui-types.js\";\nimport {\n findFixture,\n buildTextResponse,\n buildToolCallResponse,\n buildStateUpdate,\n buildReasoningResponse,\n writeAGUIEventStream,\n} from \"./agui-handler.js\";\nimport { flattenHeaders, readBody } from \"./helpers.js\";\nimport { proxyAndRecordAGUI } from \"./agui-recorder.js\";\nimport { Logger, type LogLevel } from \"./logger.js\";\n\nexport class AGUIMock implements Mountable {\n private fixtures: AGUIFixture[] = [];\n private server: http.Server | null = null;\n private journal: Journal | null = null;\n private registry: MetricsRegistry | null = null;\n private options: AGUIMockOptions;\n private baseUrl = \"\";\n private recordConfig: AGUIRecordConfig | undefined;\n private logger: Logger;\n\n constructor(options?: AGUIMockOptions) {\n this.options = options ?? {};\n this.logger = new Logger((options?.logLevel as LogLevel) ?? \"warn\");\n }\n\n // ---- Fluent registration API ----\n\n addFixture(fixture: AGUIFixture): this {\n this.fixtures.push(fixture);\n return this;\n }\n\n onMessage(pattern: string | RegExp, text: string, opts?: { delayMs?: number }): this {\n const events = buildTextResponse(text);\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onRun(pattern: string | RegExp, events: AGUIEvent[], delayMs?: number): this {\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs,\n });\n return this;\n }\n\n onToolCall(\n pattern: string | RegExp,\n toolName: string,\n args: string,\n opts?: { result?: string; delayMs?: number },\n ): this {\n const events = buildToolCallResponse(toolName, args, {\n result: opts?.result,\n });\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onStateKey(key: string, snapshot: Record<string, unknown>, delayMs?: number): this {\n const events = buildStateUpdate(snapshot);\n this.fixtures.push({\n match: { stateKey: key },\n events,\n delayMs,\n });\n return this;\n }\n\n onReasoning(pattern: string | RegExp, text: string, opts?: { delayMs?: number }): this {\n const events = buildReasoningResponse(text);\n this.fixtures.push({\n match: { message: pattern },\n events,\n delayMs: opts?.delayMs,\n });\n return this;\n }\n\n onPredicate(\n predicate: (input: AGUIRunAgentInput) => boolean,\n events: AGUIEvent[],\n delayMs?: number,\n ): this {\n this.fixtures.push({\n match: { predicate },\n events,\n delayMs,\n });\n return this;\n }\n\n enableRecording(config: AGUIRecordConfig): this {\n this.recordConfig = config;\n return this;\n }\n\n reset(): this {\n this.fixtures = [];\n this.recordConfig = undefined;\n return this;\n }\n\n // ---- Mountable interface ----\n\n async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n if (req.method !== \"POST\" || (pathname !== \"/\" && pathname !== \"\")) {\n return false;\n }\n\n if (this.registry) {\n this.registry.incrementCounter(\"aimock_agui_requests_total\", { method: \"POST\" });\n }\n\n let body: string;\n try {\n body = await readBody(req);\n } catch (err) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n const detail = err instanceof Error ? err.message : \"body read failed\";\n res.end(JSON.stringify({ error: `Failed to read request body: ${detail}` }));\n this.journalRequest(req, pathname, 400);\n return true;\n }\n\n let input: AGUIRunAgentInput;\n try {\n input = JSON.parse(body) as AGUIRunAgentInput;\n } catch (err) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n const detail = err instanceof Error ? err.message : \"unknown parse error\";\n res.end(JSON.stringify({ error: `Invalid JSON body: ${detail}` }));\n this.journalRequest(req, pathname, 400);\n return true;\n }\n\n const fixture = findFixture(input, this.fixtures);\n\n if (fixture) {\n await writeAGUIEventStream(res, fixture.events, { delayMs: fixture.delayMs });\n this.journalRequest(req, pathname, 200);\n return true;\n }\n\n // No match — if recording is enabled, proxy to upstream\n if (this.recordConfig) {\n const result = await proxyAndRecordAGUI(\n req,\n res,\n input,\n this.fixtures,\n this.recordConfig,\n this.logger,\n );\n if (result !== false) {\n this.journalRequest(req, pathname, result);\n return true;\n }\n }\n\n // No match, no recorder — 404\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"No matching AG-UI fixture\" }));\n this.journalRequest(req, pathname, 404);\n return true;\n }\n\n health(): { status: string; fixtures: number } {\n return {\n status: \"ok\",\n fixtures: this.fixtures.length,\n };\n }\n\n setJournal(journal: Journal): void {\n this.journal = journal;\n }\n\n setBaseUrl(url: string): void {\n this.baseUrl = url;\n }\n\n setRegistry(registry: MetricsRegistry): void {\n this.registry = registry;\n }\n\n // ---- Standalone mode ----\n\n async start(): Promise<string> {\n if (this.server) {\n throw new Error(\"AGUIMock server already started\");\n }\n\n const host = this.options.host ?? \"127.0.0.1\";\n const port = this.options.port ?? 0;\n\n return new Promise<string>((resolve, reject) => {\n const srv = http.createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const handled = await this.handleRequest(req, res, url.pathname).catch((err) => {\n this.logger.error(`AGUIMock request error: ${err instanceof Error ? err.message : err}`);\n if (!res.headersSent) {\n res.writeHead(500);\n res.end(\"Internal server error\");\n } else if (!res.writableEnded) {\n res.end();\n }\n return true;\n });\n if (!handled && !res.headersSent) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n }\n });\n\n srv.on(\"error\", reject);\n\n srv.listen(port, host, () => {\n const addr = srv.address();\n if (typeof addr === \"object\" && addr !== null) {\n this.baseUrl = `http://${host}:${addr.port}`;\n }\n this.server = srv;\n resolve(this.baseUrl);\n });\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n throw new Error(\"AGUIMock server not started\");\n }\n const srv = this.server;\n await new Promise<void>((resolve, reject) => {\n srv.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.server = null;\n }\n\n get url(): string {\n if (!this.server) {\n throw new Error(\"AGUIMock server not started\");\n }\n return this.baseUrl;\n }\n\n // ---- Private helpers ----\n\n private journalRequest(req: http.IncomingMessage, pathname: string, status: number): void {\n if (this.journal) {\n this.journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"agui\",\n response: { status, fixture: null },\n });\n }\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { Journal } from "./journal.cjs";
2
2
  import { MetricsRegistry } from "./metrics.cjs";
3
3
  import { Mountable } from "./types.cjs";
4
4
  import { AGUIEvent, AGUIFixture, AGUIMockOptions, AGUIRecordConfig, AGUIRunAgentInput } from "./agui-types.cjs";
5
- import * as http from "node:http";
5
+ import * as http$1 from "node:http";
6
6
 
7
7
  //#region src/agui-mock.d.ts
8
8
  declare class AGUIMock implements Mountable {
@@ -31,7 +31,7 @@ declare class AGUIMock implements Mountable {
31
31
  onPredicate(predicate: (input: AGUIRunAgentInput) => boolean, events: AGUIEvent[], delayMs?: number): this;
32
32
  enableRecording(config: AGUIRecordConfig): this;
33
33
  reset(): this;
34
- handleRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<boolean>;
34
+ handleRequest(req: http$1.IncomingMessage, res: http$1.ServerResponse, pathname: string): Promise<boolean>;
35
35
  health(): {
36
36
  status: string;
37
37
  fixtures: number;
@@ -1 +1 @@
1
- {"version":3,"file":"agui-mock.d.cts","names":[],"sources":["../src/agui-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAuBa,QAAA,YAAoB;;EAApB,QAAA,MAAS;EAAA,QAAA,OAAA;UAUE,QAAA;UAOF,OAAA;UAKQ,OAAA;UAUJ,YAAA;UAAgB,MAAA;aAUpB,CAAA,OAAA,CAAA,EAhCE,eAgCF;YAgBc,CAAA,OAAA,EAzCd,WAyCc,CAAA,EAAA,IAAA;WAUJ,CAAA,OAAA,EAAA,MAAA,GA9CF,MA8CE,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAWT,OAAA,CAAA,EAAA,MAAA;MACX,IAAA;OAWc,CAAA,OAAA,EAAA,MAAA,GA3DA,MA2DA,EAAA,MAAA,EA3DgB,SA2DhB,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;YAcZ,CAAA,OAAA,EAAA,MAAA,GA/DQ,MA+DR,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IACL,MAAK,CAAA,EAAA,MAAA;IAET,OAAA,CAAA,EAAA,MAAA;MA2DiB,IAAA;YAQE,CAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EArHY,MAqHZ,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAMP,CAAA,OAAA,EAAA,MAAA,GAjHe,MAiHf,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAwCD,OAAA,CAAA,EAAA,MAAA;MA7NiB,IAAA;EAAS,WAAA,CAAA,SAAA,EAAA,CAAA,KAAA,EA+EnB,iBA/EmB,EAAA,GAAA,OAAA,EAAA,MAAA,EAgF9B,SAhF8B,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;0BA2FhB;;qBAcjB,IAAA,CAAK,sBACL,IAAA,CAAK,mCAET;;;;;sBA2DiB;;wBAQE;WAMP;UAwCD"}
1
+ {"version":3,"file":"agui-mock.d.cts","names":[],"sources":["../src/agui-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAuBa,QAAA,YAAoB;;EAApB,QAAA,MAAS;EAAA,QAAA,OAAA;UAUE,QAAA;UAOF,OAAA;UAKQ,OAAA;UAUJ,YAAA;UAAgB,MAAA;aAUpB,CAAA,OAAA,CAAA,EAhCE,eAgCF;YAgBc,CAAA,OAAA,EAzCd,WAyCc,CAAA,EAAA,IAAA;WAUJ,CAAA,OAAA,EAAA,MAAA,GA9CF,MA8CE,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAWT,OAAA,CAAA,EAAA,MAAA;MACX,IAAA;OAWc,CAAA,OAAA,EAAA,MAAA,GA3DA,MA2DA,EAAA,MAAA,EA3DgB,SA2DhB,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;YAcZ,CAAA,OAAA,EAAA,MAAA,GA/DQ,MA+DR,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IACL,MAAK,CAAA,EAAA,MAAA;IAET,OAAA,CAAA,EAAA,MAAA;MAqEiB,IAAA;YAQE,CAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EA/HY,MA+HZ,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAMP,CAAA,OAAA,EAAA,MAAA,GA3He,MA2Hf,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAwCD,OAAA,CAAA,EAAA,MAAA;MAvOiB,IAAA;EAAS,WAAA,CAAA,SAAA,EAAA,CAAA,KAAA,EA+EnB,iBA/EmB,EAAA,GAAA,OAAA,EAAA,MAAA,EAgF9B,SAhF8B,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;0BA2FhB;;qBAcjB,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;;;;;sBAqEiB;;wBAQE;WAMP;UAwCD"}
@@ -2,7 +2,7 @@ import { Journal } from "./journal.js";
2
2
  import { MetricsRegistry } from "./metrics.js";
3
3
  import { Mountable } from "./types.js";
4
4
  import { AGUIEvent, AGUIFixture, AGUIMockOptions, AGUIRecordConfig, AGUIRunAgentInput } from "./agui-types.js";
5
- import * as http from "node:http";
5
+ import * as http$1 from "node:http";
6
6
 
7
7
  //#region src/agui-mock.d.ts
8
8
  declare class AGUIMock implements Mountable {
@@ -31,7 +31,7 @@ declare class AGUIMock implements Mountable {
31
31
  onPredicate(predicate: (input: AGUIRunAgentInput) => boolean, events: AGUIEvent[], delayMs?: number): this;
32
32
  enableRecording(config: AGUIRecordConfig): this;
33
33
  reset(): this;
34
- handleRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<boolean>;
34
+ handleRequest(req: http$1.IncomingMessage, res: http$1.ServerResponse, pathname: string): Promise<boolean>;
35
35
  health(): {
36
36
  status: string;
37
37
  fixtures: number;
@@ -1 +1 @@
1
- {"version":3,"file":"agui-mock.d.ts","names":[],"sources":["../src/agui-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAuBa,QAAA,YAAoB;;EAApB,QAAA,MAAS;EAAA,QAAA,OAAA;UAUE,QAAA;UAOF,OAAA;UAKQ,OAAA;UAUJ,YAAA;UAAgB,MAAA;aAUpB,CAAA,OAAA,CAAA,EAhCE,eAgCF;YAgBc,CAAA,OAAA,EAzCd,WAyCc,CAAA,EAAA,IAAA;WAUJ,CAAA,OAAA,EAAA,MAAA,GA9CF,MA8CE,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAWT,OAAA,CAAA,EAAA,MAAA;MACX,IAAA;OAWc,CAAA,OAAA,EAAA,MAAA,GA3DA,MA2DA,EAAA,MAAA,EA3DgB,SA2DhB,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;YAcZ,CAAA,OAAA,EAAA,MAAA,GA/DQ,MA+DR,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IACL,MAAK,CAAA,EAAA,MAAA;IAET,OAAA,CAAA,EAAA,MAAA;MA2DiB,IAAA;YAQE,CAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EArHY,MAqHZ,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAMP,CAAA,OAAA,EAAA,MAAA,GAjHe,MAiHf,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAwCD,OAAA,CAAA,EAAA,MAAA;MA7NiB,IAAA;EAAS,WAAA,CAAA,SAAA,EAAA,CAAA,KAAA,EA+EnB,iBA/EmB,EAAA,GAAA,OAAA,EAAA,MAAA,EAgF9B,SAhF8B,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;0BA2FhB;;qBAcjB,IAAA,CAAK,sBACL,IAAA,CAAK,mCAET;;;;;sBA2DiB;;wBAQE;WAMP;UAwCD"}
1
+ {"version":3,"file":"agui-mock.d.ts","names":[],"sources":["../src/agui-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAuBa,QAAA,YAAoB;;EAApB,QAAA,MAAS;EAAA,QAAA,OAAA;UAUE,QAAA;UAOF,OAAA;UAKQ,OAAA;UAUJ,YAAA;UAAgB,MAAA;aAUpB,CAAA,OAAA,CAAA,EAhCE,eAgCF;YAgBc,CAAA,OAAA,EAzCd,WAyCc,CAAA,EAAA,IAAA;WAUJ,CAAA,OAAA,EAAA,MAAA,GA9CF,MA8CE,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAWT,OAAA,CAAA,EAAA,MAAA;MACX,IAAA;OAWc,CAAA,OAAA,EAAA,MAAA,GA3DA,MA2DA,EAAA,MAAA,EA3DgB,SA2DhB,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;YAcZ,CAAA,OAAA,EAAA,MAAA,GA/DQ,MA+DR,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IACL,MAAK,CAAA,EAAA,MAAA;IAET,OAAA,CAAA,EAAA,MAAA;MAqEiB,IAAA;YAQE,CAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EA/HY,MA+HZ,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAMP,CAAA,OAAA,EAAA,MAAA,GA3He,MA2Hf,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA;IAwCD,OAAA,CAAA,EAAA,MAAA;MAvOiB,IAAA;EAAS,WAAA,CAAA,SAAA,EAAA,CAAA,KAAA,EA+EnB,iBA/EmB,EAAA,GAAA,OAAA,EAAA,MAAA,EAgF9B,SAhF8B,EAAA,EAAA,OAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;0BA2FhB;;qBAcjB,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;;;;;sBAqEiB;;wBAQE;WAMP;UAwCD"}
package/dist/agui-mock.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { flattenHeaders, readBody } from "./helpers.js";
2
- import { Logger } from "./logger.js";
3
2
  import { buildReasoningResponse, buildStateUpdate, buildTextResponse, buildToolCallResponse, findFixture, writeAGUIEventStream } from "./agui-handler.js";
4
3
  import { proxyAndRecordAGUI } from "./agui-recorder.js";
5
- import * as http from "node:http";
4
+ import { Logger } from "./logger.js";
5
+ import * as http$1 from "node:http";
6
6
 
7
7
  //#region src/agui-mock.ts
8
8
  var AGUIMock = class {
@@ -16,7 +16,7 @@ var AGUIMock = class {
16
16
  logger;
17
17
  constructor(options) {
18
18
  this.options = options ?? {};
19
- this.logger = new Logger("silent");
19
+ this.logger = new Logger(options?.logLevel ?? "warn");
20
20
  }
21
21
  addFixture(fixture) {
22
22
  this.fixtures.push(fixture);
@@ -86,13 +86,23 @@ var AGUIMock = class {
86
86
  async handleRequest(req, res, pathname) {
87
87
  if (req.method !== "POST" || pathname !== "/" && pathname !== "") return false;
88
88
  if (this.registry) this.registry.incrementCounter("aimock_agui_requests_total", { method: "POST" });
89
- const body = await readBody(req);
89
+ let body;
90
+ try {
91
+ body = await readBody(req);
92
+ } catch (err) {
93
+ res.writeHead(400, { "Content-Type": "application/json" });
94
+ const detail = err instanceof Error ? err.message : "body read failed";
95
+ res.end(JSON.stringify({ error: `Failed to read request body: ${detail}` }));
96
+ this.journalRequest(req, pathname, 400);
97
+ return true;
98
+ }
90
99
  let input;
91
100
  try {
92
101
  input = JSON.parse(body);
93
- } catch {
102
+ } catch (err) {
94
103
  res.writeHead(400, { "Content-Type": "application/json" });
95
- res.end(JSON.stringify({ error: "Invalid JSON body" }));
104
+ const detail = err instanceof Error ? err.message : "unknown parse error";
105
+ res.end(JSON.stringify({ error: `Invalid JSON body: ${detail}` }));
96
106
  this.journalRequest(req, pathname, 400);
97
107
  return true;
98
108
  }
@@ -103,8 +113,9 @@ var AGUIMock = class {
103
113
  return true;
104
114
  }
105
115
  if (this.recordConfig) {
106
- if (await proxyAndRecordAGUI(req, res, input, this.fixtures, this.recordConfig, this.logger)) {
107
- this.journalRequest(req, pathname, 200);
116
+ const result = await proxyAndRecordAGUI(req, res, input, this.fixtures, this.recordConfig, this.logger);
117
+ if (result !== false) {
118
+ this.journalRequest(req, pathname, result);
108
119
  return true;
109
120
  }
110
121
  }
@@ -133,7 +144,7 @@ var AGUIMock = class {
133
144
  const host = this.options.host ?? "127.0.0.1";
134
145
  const port = this.options.port ?? 0;
135
146
  return new Promise((resolve, reject) => {
136
- const srv = http.createServer(async (req, res) => {
147
+ const srv = http$1.createServer(async (req, res) => {
137
148
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
138
149
  if (!await this.handleRequest(req, res, url.pathname).catch((err) => {
139
150
  this.logger.error(`AGUIMock request error: ${err instanceof Error ? err.message : err}`);