@copilotkit/aimock 1.7.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 (368) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/LICENSE +21 -0
  4. package/README.md +82 -0
  5. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  6. package/dist/a2a-handler.cjs +203 -0
  7. package/dist/a2a-handler.cjs.map +1 -0
  8. package/dist/a2a-handler.js +199 -0
  9. package/dist/a2a-handler.js.map +1 -0
  10. package/dist/a2a-mock.cjs +292 -0
  11. package/dist/a2a-mock.cjs.map +1 -0
  12. package/dist/a2a-mock.d.cts +41 -0
  13. package/dist/a2a-mock.d.cts.map +1 -0
  14. package/dist/a2a-mock.d.ts +41 -0
  15. package/dist/a2a-mock.d.ts.map +1 -0
  16. package/dist/a2a-mock.js +290 -0
  17. package/dist/a2a-mock.js.map +1 -0
  18. package/dist/a2a-stub.cjs +4 -0
  19. package/dist/a2a-stub.d.cts +3 -0
  20. package/dist/a2a-stub.d.ts +3 -0
  21. package/dist/a2a-stub.js +3 -0
  22. package/dist/a2a-types.d.cts +68 -0
  23. package/dist/a2a-types.d.cts.map +1 -0
  24. package/dist/a2a-types.d.ts +68 -0
  25. package/dist/a2a-types.d.ts.map +1 -0
  26. package/dist/aimock-cli.cjs +112 -0
  27. package/dist/aimock-cli.cjs.map +1 -0
  28. package/dist/aimock-cli.d.cts +19 -0
  29. package/dist/aimock-cli.d.cts.map +1 -0
  30. package/dist/aimock-cli.d.ts +19 -0
  31. package/dist/aimock-cli.d.ts.map +1 -0
  32. package/dist/aimock-cli.js +110 -0
  33. package/dist/aimock-cli.js.map +1 -0
  34. package/dist/aws-event-stream.cjs +117 -0
  35. package/dist/aws-event-stream.cjs.map +1 -0
  36. package/dist/aws-event-stream.d.cts +38 -0
  37. package/dist/aws-event-stream.d.cts.map +1 -0
  38. package/dist/aws-event-stream.d.ts +38 -0
  39. package/dist/aws-event-stream.d.ts.map +1 -0
  40. package/dist/aws-event-stream.js +114 -0
  41. package/dist/aws-event-stream.js.map +1 -0
  42. package/dist/bedrock-converse.cjs +445 -0
  43. package/dist/bedrock-converse.cjs.map +1 -0
  44. package/dist/bedrock-converse.d.cts +50 -0
  45. package/dist/bedrock-converse.d.cts.map +1 -0
  46. package/dist/bedrock-converse.d.ts +50 -0
  47. package/dist/bedrock-converse.d.ts.map +1 -0
  48. package/dist/bedrock-converse.js +443 -0
  49. package/dist/bedrock-converse.js.map +1 -0
  50. package/dist/bedrock.cjs +557 -0
  51. package/dist/bedrock.cjs.map +1 -0
  52. package/dist/bedrock.d.cts +41 -0
  53. package/dist/bedrock.d.cts.map +1 -0
  54. package/dist/bedrock.d.ts +41 -0
  55. package/dist/bedrock.d.ts.map +1 -0
  56. package/dist/bedrock.js +553 -0
  57. package/dist/bedrock.js.map +1 -0
  58. package/dist/chaos.cjs +114 -0
  59. package/dist/chaos.cjs.map +1 -0
  60. package/dist/chaos.d.cts +27 -0
  61. package/dist/chaos.d.cts.map +1 -0
  62. package/dist/chaos.d.ts +27 -0
  63. package/dist/chaos.d.ts.map +1 -0
  64. package/dist/chaos.js +113 -0
  65. package/dist/chaos.js.map +1 -0
  66. package/dist/cli.cjs +268 -0
  67. package/dist/cli.cjs.map +1 -0
  68. package/dist/cli.d.cts +1 -0
  69. package/dist/cli.d.ts +1 -0
  70. package/dist/cli.js +268 -0
  71. package/dist/cli.js.map +1 -0
  72. package/dist/cohere.cjs +434 -0
  73. package/dist/cohere.cjs.map +1 -0
  74. package/dist/cohere.d.cts +34 -0
  75. package/dist/cohere.d.cts.map +1 -0
  76. package/dist/cohere.d.ts +34 -0
  77. package/dist/cohere.d.ts.map +1 -0
  78. package/dist/cohere.js +433 -0
  79. package/dist/cohere.js.map +1 -0
  80. package/dist/config-loader.cjs +111 -0
  81. package/dist/config-loader.cjs.map +1 -0
  82. package/dist/config-loader.d.cts +100 -0
  83. package/dist/config-loader.d.cts.map +1 -0
  84. package/dist/config-loader.d.ts +100 -0
  85. package/dist/config-loader.d.ts.map +1 -0
  86. package/dist/config-loader.js +107 -0
  87. package/dist/config-loader.js.map +1 -0
  88. package/dist/embeddings.cjs +150 -0
  89. package/dist/embeddings.cjs.map +1 -0
  90. package/dist/embeddings.d.cts +12 -0
  91. package/dist/embeddings.d.cts.map +1 -0
  92. package/dist/embeddings.d.ts +12 -0
  93. package/dist/embeddings.d.ts.map +1 -0
  94. package/dist/embeddings.js +150 -0
  95. package/dist/embeddings.js.map +1 -0
  96. package/dist/fixture-loader.cjs +269 -0
  97. package/dist/fixture-loader.cjs.map +1 -0
  98. package/dist/fixture-loader.d.cts +17 -0
  99. package/dist/fixture-loader.d.cts.map +1 -0
  100. package/dist/fixture-loader.d.ts +17 -0
  101. package/dist/fixture-loader.d.ts.map +1 -0
  102. package/dist/fixture-loader.js +265 -0
  103. package/dist/fixture-loader.js.map +1 -0
  104. package/dist/gemini.cjs +403 -0
  105. package/dist/gemini.cjs.map +1 -0
  106. package/dist/gemini.d.cts +10 -0
  107. package/dist/gemini.d.cts.map +1 -0
  108. package/dist/gemini.d.ts +10 -0
  109. package/dist/gemini.d.ts.map +1 -0
  110. package/dist/gemini.js +403 -0
  111. package/dist/gemini.js.map +1 -0
  112. package/dist/helpers.cjs +276 -0
  113. package/dist/helpers.cjs.map +1 -0
  114. package/dist/helpers.d.cts +39 -0
  115. package/dist/helpers.d.cts.map +1 -0
  116. package/dist/helpers.d.ts +39 -0
  117. package/dist/helpers.d.ts.map +1 -0
  118. package/dist/helpers.js +259 -0
  119. package/dist/helpers.js.map +1 -0
  120. package/dist/index.cjs +113 -0
  121. package/dist/index.d.cts +42 -0
  122. package/dist/index.d.ts +42 -0
  123. package/dist/index.js +39 -0
  124. package/dist/interruption.cjs +40 -0
  125. package/dist/interruption.cjs.map +1 -0
  126. package/dist/interruption.d.cts +15 -0
  127. package/dist/interruption.d.cts.map +1 -0
  128. package/dist/interruption.d.ts +15 -0
  129. package/dist/interruption.d.ts.map +1 -0
  130. package/dist/interruption.js +39 -0
  131. package/dist/interruption.js.map +1 -0
  132. package/dist/journal.cjs +65 -0
  133. package/dist/journal.cjs.map +1 -0
  134. package/dist/journal.d.cts +23 -0
  135. package/dist/journal.d.cts.map +1 -0
  136. package/dist/journal.d.ts +23 -0
  137. package/dist/journal.d.ts.map +1 -0
  138. package/dist/journal.js +65 -0
  139. package/dist/journal.js.map +1 -0
  140. package/dist/jsonrpc.cjs +91 -0
  141. package/dist/jsonrpc.cjs.map +1 -0
  142. package/dist/jsonrpc.d.cts +24 -0
  143. package/dist/jsonrpc.d.cts.map +1 -0
  144. package/dist/jsonrpc.d.ts +24 -0
  145. package/dist/jsonrpc.d.ts.map +1 -0
  146. package/dist/jsonrpc.js +90 -0
  147. package/dist/jsonrpc.js.map +1 -0
  148. package/dist/llmock.cjs +223 -0
  149. package/dist/llmock.cjs.map +1 -0
  150. package/dist/llmock.d.cts +70 -0
  151. package/dist/llmock.d.cts.map +1 -0
  152. package/dist/llmock.d.ts +70 -0
  153. package/dist/llmock.d.ts.map +1 -0
  154. package/dist/llmock.js +223 -0
  155. package/dist/llmock.js.map +1 -0
  156. package/dist/logger.cjs +29 -0
  157. package/dist/logger.cjs.map +1 -0
  158. package/dist/logger.d.cts +14 -0
  159. package/dist/logger.d.cts.map +1 -0
  160. package/dist/logger.d.ts +14 -0
  161. package/dist/logger.d.ts.map +1 -0
  162. package/dist/logger.js +28 -0
  163. package/dist/logger.js.map +1 -0
  164. package/dist/mcp-handler.cjs +189 -0
  165. package/dist/mcp-handler.cjs.map +1 -0
  166. package/dist/mcp-handler.js +188 -0
  167. package/dist/mcp-handler.js.map +1 -0
  168. package/dist/mcp-mock.cjs +169 -0
  169. package/dist/mcp-mock.cjs.map +1 -0
  170. package/dist/mcp-mock.d.cts +40 -0
  171. package/dist/mcp-mock.d.cts.map +1 -0
  172. package/dist/mcp-mock.d.ts +40 -0
  173. package/dist/mcp-mock.d.ts.map +1 -0
  174. package/dist/mcp-mock.js +167 -0
  175. package/dist/mcp-mock.js.map +1 -0
  176. package/dist/mcp-stub.cjs +4 -0
  177. package/dist/mcp-stub.d.cts +3 -0
  178. package/dist/mcp-stub.d.ts +3 -0
  179. package/dist/mcp-stub.js +3 -0
  180. package/dist/mcp-types.d.cts +65 -0
  181. package/dist/mcp-types.d.cts.map +1 -0
  182. package/dist/mcp-types.d.ts +65 -0
  183. package/dist/mcp-types.d.ts.map +1 -0
  184. package/dist/messages.cjs +489 -0
  185. package/dist/messages.cjs.map +1 -0
  186. package/dist/messages.d.cts +10 -0
  187. package/dist/messages.d.cts.map +1 -0
  188. package/dist/messages.d.ts +10 -0
  189. package/dist/messages.d.ts.map +1 -0
  190. package/dist/messages.js +489 -0
  191. package/dist/messages.js.map +1 -0
  192. package/dist/metrics.cjs +160 -0
  193. package/dist/metrics.cjs.map +1 -0
  194. package/dist/metrics.d.cts +24 -0
  195. package/dist/metrics.d.cts.map +1 -0
  196. package/dist/metrics.d.ts +24 -0
  197. package/dist/metrics.d.ts.map +1 -0
  198. package/dist/metrics.js +158 -0
  199. package/dist/metrics.js.map +1 -0
  200. package/dist/moderation.cjs +91 -0
  201. package/dist/moderation.cjs.map +1 -0
  202. package/dist/moderation.d.cts +23 -0
  203. package/dist/moderation.d.cts.map +1 -0
  204. package/dist/moderation.d.ts +23 -0
  205. package/dist/moderation.d.ts.map +1 -0
  206. package/dist/moderation.js +91 -0
  207. package/dist/moderation.js.map +1 -0
  208. package/dist/ndjson-writer.cjs +31 -0
  209. package/dist/ndjson-writer.cjs.map +1 -0
  210. package/dist/ndjson-writer.d.cts +17 -0
  211. package/dist/ndjson-writer.d.cts.map +1 -0
  212. package/dist/ndjson-writer.d.ts +17 -0
  213. package/dist/ndjson-writer.d.ts.map +1 -0
  214. package/dist/ndjson-writer.js +31 -0
  215. package/dist/ndjson-writer.js.map +1 -0
  216. package/dist/ollama.cjs +519 -0
  217. package/dist/ollama.cjs.map +1 -0
  218. package/dist/ollama.d.cts +34 -0
  219. package/dist/ollama.d.cts.map +1 -0
  220. package/dist/ollama.d.ts +34 -0
  221. package/dist/ollama.d.ts.map +1 -0
  222. package/dist/ollama.js +517 -0
  223. package/dist/ollama.js.map +1 -0
  224. package/dist/recorder.cjs +311 -0
  225. package/dist/recorder.cjs.map +1 -0
  226. package/dist/recorder.d.cts +23 -0
  227. package/dist/recorder.d.cts.map +1 -0
  228. package/dist/recorder.d.ts +23 -0
  229. package/dist/recorder.d.ts.map +1 -0
  230. package/dist/recorder.js +305 -0
  231. package/dist/recorder.js.map +1 -0
  232. package/dist/rerank.cjs +71 -0
  233. package/dist/rerank.cjs.map +1 -0
  234. package/dist/rerank.d.cts +22 -0
  235. package/dist/rerank.d.cts.map +1 -0
  236. package/dist/rerank.d.ts +22 -0
  237. package/dist/rerank.d.ts.map +1 -0
  238. package/dist/rerank.js +71 -0
  239. package/dist/rerank.js.map +1 -0
  240. package/dist/responses.cjs +637 -0
  241. package/dist/responses.cjs.map +1 -0
  242. package/dist/responses.d.cts +16 -0
  243. package/dist/responses.d.cts.map +1 -0
  244. package/dist/responses.d.ts +16 -0
  245. package/dist/responses.d.ts.map +1 -0
  246. package/dist/responses.js +634 -0
  247. package/dist/responses.js.map +1 -0
  248. package/dist/router.cjs +68 -0
  249. package/dist/router.cjs.map +1 -0
  250. package/dist/router.d.cts +16 -0
  251. package/dist/router.d.cts.map +1 -0
  252. package/dist/router.d.ts +16 -0
  253. package/dist/router.d.ts.map +1 -0
  254. package/dist/router.js +65 -0
  255. package/dist/router.js.map +1 -0
  256. package/dist/search.cjs +59 -0
  257. package/dist/search.cjs.map +1 -0
  258. package/dist/search.d.cts +23 -0
  259. package/dist/search.d.cts.map +1 -0
  260. package/dist/search.d.ts +23 -0
  261. package/dist/search.d.ts.map +1 -0
  262. package/dist/search.js +59 -0
  263. package/dist/search.js.map +1 -0
  264. package/dist/server.cjs +935 -0
  265. package/dist/server.cjs.map +1 -0
  266. package/dist/server.d.cts +28 -0
  267. package/dist/server.d.cts.map +1 -0
  268. package/dist/server.d.ts +28 -0
  269. package/dist/server.d.ts.map +1 -0
  270. package/dist/server.js +933 -0
  271. package/dist/server.js.map +1 -0
  272. package/dist/sse-writer.cjs +59 -0
  273. package/dist/sse-writer.cjs.map +1 -0
  274. package/dist/sse-writer.d.cts +19 -0
  275. package/dist/sse-writer.d.cts.map +1 -0
  276. package/dist/sse-writer.d.ts +19 -0
  277. package/dist/sse-writer.d.ts.map +1 -0
  278. package/dist/sse-writer.js +55 -0
  279. package/dist/sse-writer.js.map +1 -0
  280. package/dist/stream-collapse.cjs +496 -0
  281. package/dist/stream-collapse.cjs.map +1 -0
  282. package/dist/stream-collapse.d.cts +70 -0
  283. package/dist/stream-collapse.d.cts.map +1 -0
  284. package/dist/stream-collapse.d.ts +70 -0
  285. package/dist/stream-collapse.d.ts.map +1 -0
  286. package/dist/stream-collapse.js +489 -0
  287. package/dist/stream-collapse.js.map +1 -0
  288. package/dist/suite.cjs +46 -0
  289. package/dist/suite.cjs.map +1 -0
  290. package/dist/suite.d.cts +31 -0
  291. package/dist/suite.d.cts.map +1 -0
  292. package/dist/suite.d.ts +31 -0
  293. package/dist/suite.d.ts.map +1 -0
  294. package/dist/suite.js +46 -0
  295. package/dist/suite.js.map +1 -0
  296. package/dist/types.d.cts +243 -0
  297. package/dist/types.d.cts.map +1 -0
  298. package/dist/types.d.ts +243 -0
  299. package/dist/types.d.ts.map +1 -0
  300. package/dist/url.cjs +21 -0
  301. package/dist/url.cjs.map +1 -0
  302. package/dist/url.d.cts +16 -0
  303. package/dist/url.d.cts.map +1 -0
  304. package/dist/url.d.ts +16 -0
  305. package/dist/url.d.ts.map +1 -0
  306. package/dist/url.js +20 -0
  307. package/dist/url.js.map +1 -0
  308. package/dist/vector-handler.cjs +239 -0
  309. package/dist/vector-handler.cjs.map +1 -0
  310. package/dist/vector-handler.js +238 -0
  311. package/dist/vector-handler.js.map +1 -0
  312. package/dist/vector-mock.cjs +229 -0
  313. package/dist/vector-mock.cjs.map +1 -0
  314. package/dist/vector-mock.d.cts +39 -0
  315. package/dist/vector-mock.d.cts.map +1 -0
  316. package/dist/vector-mock.d.ts +39 -0
  317. package/dist/vector-mock.d.ts.map +1 -0
  318. package/dist/vector-mock.js +227 -0
  319. package/dist/vector-mock.js.map +1 -0
  320. package/dist/vector-stub.cjs +4 -0
  321. package/dist/vector-stub.d.cts +3 -0
  322. package/dist/vector-stub.d.ts +3 -0
  323. package/dist/vector-stub.js +3 -0
  324. package/dist/vector-types.d.cts +32 -0
  325. package/dist/vector-types.d.cts.map +1 -0
  326. package/dist/vector-types.d.ts +32 -0
  327. package/dist/vector-types.d.ts.map +1 -0
  328. package/dist/watcher.cjs +59 -0
  329. package/dist/watcher.cjs.map +1 -0
  330. package/dist/watcher.js +58 -0
  331. package/dist/watcher.js.map +1 -0
  332. package/dist/ws-framing.cjs +187 -0
  333. package/dist/ws-framing.cjs.map +1 -0
  334. package/dist/ws-framing.d.cts +26 -0
  335. package/dist/ws-framing.d.cts.map +1 -0
  336. package/dist/ws-framing.d.ts +26 -0
  337. package/dist/ws-framing.d.ts.map +1 -0
  338. package/dist/ws-framing.js +184 -0
  339. package/dist/ws-framing.js.map +1 -0
  340. package/dist/ws-gemini-live.cjs +364 -0
  341. package/dist/ws-gemini-live.cjs.map +1 -0
  342. package/dist/ws-gemini-live.d.cts +18 -0
  343. package/dist/ws-gemini-live.d.cts.map +1 -0
  344. package/dist/ws-gemini-live.d.ts +18 -0
  345. package/dist/ws-gemini-live.d.ts.map +1 -0
  346. package/dist/ws-gemini-live.js +364 -0
  347. package/dist/ws-gemini-live.js.map +1 -0
  348. package/dist/ws-realtime.cjs +435 -0
  349. package/dist/ws-realtime.cjs.map +1 -0
  350. package/dist/ws-realtime.d.cts +17 -0
  351. package/dist/ws-realtime.d.cts.map +1 -0
  352. package/dist/ws-realtime.d.ts +17 -0
  353. package/dist/ws-realtime.d.ts.map +1 -0
  354. package/dist/ws-realtime.js +435 -0
  355. package/dist/ws-realtime.js.map +1 -0
  356. package/dist/ws-responses.cjs +164 -0
  357. package/dist/ws-responses.cjs.map +1 -0
  358. package/dist/ws-responses.d.cts +18 -0
  359. package/dist/ws-responses.d.cts.map +1 -0
  360. package/dist/ws-responses.d.ts +18 -0
  361. package/dist/ws-responses.d.ts.map +1 -0
  362. package/dist/ws-responses.js +164 -0
  363. package/dist/ws-responses.js.map +1 -0
  364. package/fixtures/example-greeting.json +12 -0
  365. package/fixtures/example-multi-turn.json +14 -0
  366. package/fixtures/example-tool-call.json +15 -0
  367. package/package.json +118 -0
  368. package/skills/write-fixtures/SKILL.md +625 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "copilotkit-tools",
3
+ "owner": {
4
+ "name": "CopilotKit"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "llmock",
9
+ "source": {
10
+ "source": "npm",
11
+ "package": "@copilotkit/aimock",
12
+ "version": "^1.7.0"
13
+ },
14
+ "description": "Fixture authoring skill for @copilotkit/aimock — match fields, response types, embeddings, structured output, sequential responses, streaming physics, agent loop patterns, gotchas, and debugging"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "llmock",
3
+ "version": "1.7.0",
4
+ "description": "Fixture authoring guidance for @copilotkit/aimock",
5
+ "author": {
6
+ "name": "CopilotKit"
7
+ },
8
+ "homepage": "https://github.com/CopilotKit/llmock",
9
+ "repository": "https://github.com/CopilotKit/llmock",
10
+ "license": "MIT",
11
+ "skills": "./skills"
12
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CopilotKit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # aimock [![Unit Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml) [![Drift Tests](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml/badge.svg)](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml) [![npm version](https://img.shields.io/npm/v/@copilotkit/aimock)](https://www.npmjs.com/package/@copilotkit/aimock)
2
+
3
+ Mock infrastructure for AI application testing — LLM APIs, MCP tools, A2A agents, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm install @copilotkit/aimock
9
+ ```
10
+
11
+ ```typescript
12
+ import { LLMock } from "@copilotkit/aimock";
13
+
14
+ const mock = new LLMock({ port: 0 });
15
+ mock.onMessage("hello", { content: "Hi there!" });
16
+ await mock.start();
17
+
18
+ process.env.OPENAI_BASE_URL = `${mock.url}/v1`;
19
+
20
+ // ... run your tests ...
21
+
22
+ await mock.stop();
23
+ ```
24
+
25
+ ## The aimock Suite
26
+
27
+ aimock mocks everything your AI app talks to:
28
+
29
+ | Tool | What it mocks | Docs |
30
+ | -------------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
31
+ | **LLMock** | OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere | [Providers](https://aimock.copilotkit.dev/docs.html) |
32
+ | **MCPMock** | MCP tools, resources, prompts with session management | [MCP](https://aimock.copilotkit.dev/mcp-mock.html) |
33
+ | **A2AMock** | Agent-to-agent protocol with SSE streaming | [A2A](https://aimock.copilotkit.dev/a2a-mock.html) |
34
+ | **VectorMock** | Pinecone, Qdrant, ChromaDB compatible endpoints | [Vector](https://aimock.copilotkit.dev/vector-mock.html) |
35
+ | **Services** | Tavily search, Cohere rerank, OpenAI moderation | [Services](https://aimock.copilotkit.dev/services.html) |
36
+
37
+ Run them all on one port with `npx aimock --config aimock.json`, or use the programmatic API to compose exactly what you need.
38
+
39
+ ## Features
40
+
41
+ - **[Record & Replay](https://aimock.copilotkit.dev/record-replay.html)** — Proxy real APIs, save as fixtures, replay deterministically forever
42
+ - **[11 LLM Providers](https://aimock.copilotkit.dev/docs.html)** — OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere — full streaming support
43
+ - **[MCP / A2A / Vector](https://aimock.copilotkit.dev/mcp-mock.html)** — Mock every protocol your AI agents use
44
+ - **[Chaos Testing](https://aimock.copilotkit.dev/chaos-testing.html)** — 500 errors, malformed JSON, mid-stream disconnects at any probability
45
+ - **[Drift Detection](https://aimock.copilotkit.dev/drift-detection.html)** — Daily CI validation against real APIs
46
+ - **[Streaming Physics](https://aimock.copilotkit.dev/streaming-physics.html)** — Configurable `ttft`, `tps`, and `jitter`
47
+ - **[WebSocket APIs](https://aimock.copilotkit.dev/websocket.html)** — OpenAI Realtime, Responses WS, Gemini Live
48
+ - **[Prometheus Metrics](https://aimock.copilotkit.dev/metrics.html)** — Request counts, latencies, fixture match rates
49
+ - **[Docker + Helm](https://aimock.copilotkit.dev/docker.html)** — Container image and Helm chart for CI/CD
50
+ - **Zero dependencies** — Everything from Node.js builtins
51
+
52
+ ## CLI
53
+
54
+ ```bash
55
+ # LLM mocking only
56
+ npx aimock -p 4010 -f ./fixtures
57
+
58
+ # Full suite from config
59
+ npx aimock --config aimock.json
60
+
61
+ # Record mode: proxy to real APIs, save fixtures
62
+ npx aimock --record --provider-openai https://api.openai.com
63
+
64
+ # Docker
65
+ docker run -d -p 4010:4010 -v ./fixtures:/fixtures ghcr.io/copilotkit/aimock -f /fixtures
66
+ ```
67
+
68
+ ## Switching from other tools?
69
+
70
+ Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw.html) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock.html) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm.html) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks.html) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy.html)
71
+
72
+ ## Documentation
73
+
74
+ **[https://aimock.copilotkit.dev](https://aimock.copilotkit.dev)**
75
+
76
+ ## Real-World Usage
77
+
78
+ [AG-UI](https://github.com/ag-ui-protocol/ag-ui) uses aimock for its [end-to-end test suite](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e), verifying AI agent behavior across LLM providers with [fixture-driven responses](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e/fixtures/openai).
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,29 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+
29
+ exports.__toESM = __toESM;
@@ -0,0 +1,203 @@
1
+ const require_helpers = require('./helpers.cjs');
2
+
3
+ //#region src/a2a-handler.ts
4
+ function extractText(params) {
5
+ const p = params;
6
+ if (!p?.message) return "";
7
+ const parts = p.message.parts;
8
+ if (!Array.isArray(parts)) return "";
9
+ return parts.filter((part) => typeof part.text === "string").map((part) => part.text).join(" ");
10
+ }
11
+ function matchPattern(text, pattern) {
12
+ if (typeof pattern === "string") return text.includes(pattern);
13
+ return pattern.test(text);
14
+ }
15
+ const TERMINAL_STATES = new Set([
16
+ "TASK_STATE_COMPLETED",
17
+ "TASK_STATE_FAILED",
18
+ "TASK_STATE_CANCELED"
19
+ ]);
20
+ function buildAgentCard(agents, baseUrl) {
21
+ const def = agents.values().next().value?.def;
22
+ return {
23
+ name: def?.name ?? "a2a-mock",
24
+ description: def?.description ?? "A2A mock agent",
25
+ version: def?.version ?? "1.0.0",
26
+ supportedInterfaces: [{
27
+ url: baseUrl,
28
+ protocolBinding: "JSONRPC",
29
+ protocolVersion: "1.0"
30
+ }],
31
+ skills: def?.skills ?? [],
32
+ capabilities: def?.capabilities ?? { streaming: true }
33
+ };
34
+ }
35
+ function createA2AMethods(agents, tasks) {
36
+ function findMatch(text) {
37
+ for (const agent of agents.values()) for (const entry of agent.patterns) if (matchPattern(text, entry.pattern)) return entry;
38
+ return null;
39
+ }
40
+ function createTask(_agentName, artifacts, userParts, state = "TASK_STATE_COMPLETED") {
41
+ const taskId = require_helpers.generateId("task");
42
+ const task = {
43
+ id: taskId,
44
+ contextId: require_helpers.generateId("ctx"),
45
+ status: {
46
+ state,
47
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48
+ },
49
+ artifacts,
50
+ history: [{
51
+ messageId: require_helpers.generateId("msg"),
52
+ role: "ROLE_USER",
53
+ parts: userParts
54
+ }]
55
+ };
56
+ tasks.set(taskId, task);
57
+ return task;
58
+ }
59
+ return {
60
+ SendMessage: async (params, id) => {
61
+ const text = extractText(params);
62
+ const entry = findMatch(text);
63
+ if (!entry) return {
64
+ jsonrpc: "2.0",
65
+ id,
66
+ error: {
67
+ code: -32e3,
68
+ message: "No matching pattern for message"
69
+ }
70
+ };
71
+ const userParts = (params?.message)?.parts ?? [{ text }];
72
+ if (entry.kind === "message") return {
73
+ jsonrpc: "2.0",
74
+ id,
75
+ result: { message: {
76
+ messageId: require_helpers.generateId("msg"),
77
+ role: "ROLE_AGENT",
78
+ parts: entry.parts
79
+ } }
80
+ };
81
+ if (entry.kind === "task") {
82
+ const task = createTask(entry.agentName, entry.artifacts, userParts);
83
+ return {
84
+ jsonrpc: "2.0",
85
+ id,
86
+ result: { task: {
87
+ id: task.id,
88
+ contextId: task.contextId,
89
+ status: task.status,
90
+ artifacts: task.artifacts
91
+ } }
92
+ };
93
+ }
94
+ if (entry.kind === "streamingTask") {
95
+ const artifacts = [];
96
+ for (const evt of entry.events) if (evt.type === "artifact") artifacts.push({
97
+ parts: evt.parts,
98
+ name: evt.name
99
+ });
100
+ const task = createTask(entry.agentName, artifacts, userParts);
101
+ return {
102
+ jsonrpc: "2.0",
103
+ id,
104
+ result: { task: {
105
+ id: task.id,
106
+ contextId: task.contextId,
107
+ status: task.status,
108
+ artifacts: task.artifacts
109
+ } }
110
+ };
111
+ }
112
+ return {
113
+ jsonrpc: "2.0",
114
+ id,
115
+ error: {
116
+ code: -32e3,
117
+ message: "No matching pattern for message"
118
+ }
119
+ };
120
+ },
121
+ SendStreamingMessage: async (params, id) => {
122
+ if (!findMatch(extractText(params))) return {
123
+ jsonrpc: "2.0",
124
+ id,
125
+ error: {
126
+ code: -32e3,
127
+ message: "No matching pattern for message"
128
+ }
129
+ };
130
+ return null;
131
+ },
132
+ GetTask: async (params, id) => {
133
+ const taskId = params?.id;
134
+ if (!taskId || !tasks.has(taskId)) return {
135
+ jsonrpc: "2.0",
136
+ id,
137
+ error: {
138
+ code: -32001,
139
+ message: "Task not found"
140
+ }
141
+ };
142
+ return {
143
+ jsonrpc: "2.0",
144
+ id,
145
+ result: { task: tasks.get(taskId) }
146
+ };
147
+ },
148
+ ListTasks: async (params, id) => {
149
+ const p = params;
150
+ const contextId = p?.contextId;
151
+ const status = p?.status;
152
+ let results = Array.from(tasks.values());
153
+ if (contextId) results = results.filter((t) => t.contextId === contextId);
154
+ if (status) results = results.filter((t) => t.status.state === status);
155
+ return {
156
+ jsonrpc: "2.0",
157
+ id,
158
+ result: { tasks: results }
159
+ };
160
+ },
161
+ CancelTask: async (params, id) => {
162
+ const taskId = params?.id;
163
+ if (!taskId || !tasks.has(taskId)) return {
164
+ jsonrpc: "2.0",
165
+ id,
166
+ error: {
167
+ code: -32001,
168
+ message: "Task not found"
169
+ }
170
+ };
171
+ const task = tasks.get(taskId);
172
+ if (TERMINAL_STATES.has(task.status.state)) return {
173
+ jsonrpc: "2.0",
174
+ id,
175
+ error: {
176
+ code: -32002,
177
+ message: "Task already in terminal state"
178
+ }
179
+ };
180
+ task.status = {
181
+ state: "TASK_STATE_CANCELED",
182
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
183
+ };
184
+ return {
185
+ jsonrpc: "2.0",
186
+ id,
187
+ result: { task }
188
+ };
189
+ }
190
+ };
191
+ }
192
+ function findStreamingMatch(text, agents) {
193
+ for (const agent of agents.values()) for (const entry of agent.patterns) if (entry.kind === "streamingTask" && matchPattern(text, entry.pattern)) return entry;
194
+ return null;
195
+ }
196
+
197
+ //#endregion
198
+ exports.TERMINAL_STATES = TERMINAL_STATES;
199
+ exports.buildAgentCard = buildAgentCard;
200
+ exports.createA2AMethods = createA2AMethods;
201
+ exports.extractText = extractText;
202
+ exports.findStreamingMatch = findStreamingMatch;
203
+ //# sourceMappingURL=a2a-handler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a2a-handler.cjs","names":["generateId"],"sources":["../src/a2a-handler.ts"],"sourcesContent":["import type { JsonRpcResponse, MethodHandler } from \"./jsonrpc.js\";\nimport type {\n A2AAgentDefinition,\n A2AArtifact,\n A2APart,\n A2AStreamEvent,\n A2ATask,\n A2ATaskState,\n} from \"./a2a-types.js\";\nimport { generateId } from \"./helpers.js\";\n\n// ---- Pattern types ----\n\nexport interface MessagePatternEntry {\n kind: \"message\";\n pattern: string | RegExp;\n agentName: string;\n parts: A2APart[];\n}\n\nexport interface TaskPatternEntry {\n kind: \"task\";\n pattern: string | RegExp;\n agentName: string;\n artifacts: A2AArtifact[];\n}\n\nexport interface StreamingTaskPatternEntry {\n kind: \"streamingTask\";\n pattern: string | RegExp;\n agentName: string;\n events: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport type PatternEntry = MessagePatternEntry | TaskPatternEntry | StreamingTaskPatternEntry;\n\n// ---- Helpers ----\n\nfunction extractText(params: unknown): string {\n const p = params as Record<string, unknown> | undefined;\n if (!p?.message) return \"\";\n const msg = p.message as Record<string, unknown>;\n const parts = msg.parts as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(parts)) return \"\";\n return parts\n .filter((part) => typeof part.text === \"string\")\n .map((part) => part.text as string)\n .join(\" \");\n}\n\nfunction matchPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.includes(pattern);\n }\n return pattern.test(text);\n}\n\nexport const TERMINAL_STATES: Set<string> = new Set([\n \"TASK_STATE_COMPLETED\",\n \"TASK_STATE_FAILED\",\n \"TASK_STATE_CANCELED\",\n]);\n\n// ---- Agent card builder ----\n\nexport function buildAgentCard(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n baseUrl: string,\n): Record<string, unknown> {\n // Use the first registered agent as the primary card, or a default\n const first = agents.values().next().value;\n const def = first?.def;\n\n return {\n name: def?.name ?? \"a2a-mock\",\n description: def?.description ?? \"A2A mock agent\",\n version: def?.version ?? \"1.0.0\",\n supportedInterfaces: [\n {\n url: baseUrl,\n protocolBinding: \"JSONRPC\",\n protocolVersion: \"1.0\",\n },\n ],\n skills: def?.skills ?? [],\n capabilities: def?.capabilities ?? { streaming: true },\n };\n}\n\n// ---- Method handlers ----\n\nexport function createA2AMethods(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n tasks: Map<string, A2ATask>,\n): Record<string, MethodHandler> {\n function findMatch(text: string): PatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n }\n\n function createTask(\n _agentName: string,\n artifacts: A2AArtifact[],\n userParts: A2APart[],\n state: A2ATaskState = \"TASK_STATE_COMPLETED\",\n ): A2ATask {\n const taskId = generateId(\"task\");\n const contextId = generateId(\"ctx\");\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: { state, timestamp: new Date().toISOString() },\n artifacts,\n history: [\n {\n messageId: generateId(\"msg\"),\n role: \"ROLE_USER\",\n parts: userParts,\n },\n ],\n };\n tasks.set(taskId, task);\n return task;\n }\n\n const methods: Record<string, MethodHandler> = {\n SendMessage: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const text = extractText(params);\n const entry = findMatch(text);\n\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n\n const p = params as Record<string, unknown> | undefined;\n const msg = p?.message as Record<string, unknown> | undefined;\n const userParts: A2APart[] = (msg?.parts as A2APart[]) ?? [{ text }];\n\n if (entry.kind === \"message\") {\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n message: {\n messageId: generateId(\"msg\"),\n role: \"ROLE_AGENT\",\n parts: entry.parts,\n },\n },\n };\n }\n\n if (entry.kind === \"task\") {\n const task = createTask(entry.agentName, entry.artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n // streamingTask patterns matched via SendMessage just return task\n if (entry.kind === \"streamingTask\") {\n const artifacts: A2AArtifact[] = [];\n for (const evt of entry.events) {\n if (evt.type === \"artifact\") {\n artifacts.push({ parts: evt.parts, name: evt.name });\n }\n }\n const task = createTask(entry.agentName, artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n },\n\n // SendStreamingMessage is handled specially in A2AMock (SSE response),\n // but we register a placeholder so the dispatcher doesn't return \"method not found\".\n SendStreamingMessage: async (\n params: unknown,\n id: string | number,\n ): Promise<JsonRpcResponse | null> => {\n // This is intercepted before reaching the dispatcher in a2a-mock.ts\n // If it reaches here, return an error\n const text = extractText(params);\n const entry = findMatch(text);\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n return null;\n },\n\n GetTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task: tasks.get(taskId) },\n };\n },\n\n ListTasks: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const contextId = p?.contextId as string | undefined;\n const status = p?.status as string | undefined;\n\n let results = Array.from(tasks.values());\n\n if (contextId) {\n results = results.filter((t) => t.contextId === contextId);\n }\n if (status) {\n results = results.filter((t) => t.status.state === status);\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { tasks: results },\n };\n },\n\n CancelTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n const task = tasks.get(taskId)!;\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32002, message: \"Task already in terminal state\" },\n };\n }\n\n task.status = {\n state: \"TASK_STATE_CANCELED\",\n timestamp: new Date().toISOString(),\n };\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task },\n };\n },\n };\n\n return methods;\n}\n\n// ---- Streaming helpers ----\n\nexport function findStreamingMatch(\n text: string,\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n): StreamingTaskPatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (entry.kind === \"streamingTask\" && matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n}\n\nexport { extractText };\n"],"mappings":"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"}
@@ -0,0 +1,199 @@
1
+ import { generateId } from "./helpers.js";
2
+
3
+ //#region src/a2a-handler.ts
4
+ function extractText(params) {
5
+ const p = params;
6
+ if (!p?.message) return "";
7
+ const parts = p.message.parts;
8
+ if (!Array.isArray(parts)) return "";
9
+ return parts.filter((part) => typeof part.text === "string").map((part) => part.text).join(" ");
10
+ }
11
+ function matchPattern(text, pattern) {
12
+ if (typeof pattern === "string") return text.includes(pattern);
13
+ return pattern.test(text);
14
+ }
15
+ const TERMINAL_STATES = new Set([
16
+ "TASK_STATE_COMPLETED",
17
+ "TASK_STATE_FAILED",
18
+ "TASK_STATE_CANCELED"
19
+ ]);
20
+ function buildAgentCard(agents, baseUrl) {
21
+ const def = agents.values().next().value?.def;
22
+ return {
23
+ name: def?.name ?? "a2a-mock",
24
+ description: def?.description ?? "A2A mock agent",
25
+ version: def?.version ?? "1.0.0",
26
+ supportedInterfaces: [{
27
+ url: baseUrl,
28
+ protocolBinding: "JSONRPC",
29
+ protocolVersion: "1.0"
30
+ }],
31
+ skills: def?.skills ?? [],
32
+ capabilities: def?.capabilities ?? { streaming: true }
33
+ };
34
+ }
35
+ function createA2AMethods(agents, tasks) {
36
+ function findMatch(text) {
37
+ for (const agent of agents.values()) for (const entry of agent.patterns) if (matchPattern(text, entry.pattern)) return entry;
38
+ return null;
39
+ }
40
+ function createTask(_agentName, artifacts, userParts, state = "TASK_STATE_COMPLETED") {
41
+ const taskId = generateId("task");
42
+ const task = {
43
+ id: taskId,
44
+ contextId: generateId("ctx"),
45
+ status: {
46
+ state,
47
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48
+ },
49
+ artifacts,
50
+ history: [{
51
+ messageId: generateId("msg"),
52
+ role: "ROLE_USER",
53
+ parts: userParts
54
+ }]
55
+ };
56
+ tasks.set(taskId, task);
57
+ return task;
58
+ }
59
+ return {
60
+ SendMessage: async (params, id) => {
61
+ const text = extractText(params);
62
+ const entry = findMatch(text);
63
+ if (!entry) return {
64
+ jsonrpc: "2.0",
65
+ id,
66
+ error: {
67
+ code: -32e3,
68
+ message: "No matching pattern for message"
69
+ }
70
+ };
71
+ const userParts = (params?.message)?.parts ?? [{ text }];
72
+ if (entry.kind === "message") return {
73
+ jsonrpc: "2.0",
74
+ id,
75
+ result: { message: {
76
+ messageId: generateId("msg"),
77
+ role: "ROLE_AGENT",
78
+ parts: entry.parts
79
+ } }
80
+ };
81
+ if (entry.kind === "task") {
82
+ const task = createTask(entry.agentName, entry.artifacts, userParts);
83
+ return {
84
+ jsonrpc: "2.0",
85
+ id,
86
+ result: { task: {
87
+ id: task.id,
88
+ contextId: task.contextId,
89
+ status: task.status,
90
+ artifacts: task.artifacts
91
+ } }
92
+ };
93
+ }
94
+ if (entry.kind === "streamingTask") {
95
+ const artifacts = [];
96
+ for (const evt of entry.events) if (evt.type === "artifact") artifacts.push({
97
+ parts: evt.parts,
98
+ name: evt.name
99
+ });
100
+ const task = createTask(entry.agentName, artifacts, userParts);
101
+ return {
102
+ jsonrpc: "2.0",
103
+ id,
104
+ result: { task: {
105
+ id: task.id,
106
+ contextId: task.contextId,
107
+ status: task.status,
108
+ artifacts: task.artifacts
109
+ } }
110
+ };
111
+ }
112
+ return {
113
+ jsonrpc: "2.0",
114
+ id,
115
+ error: {
116
+ code: -32e3,
117
+ message: "No matching pattern for message"
118
+ }
119
+ };
120
+ },
121
+ SendStreamingMessage: async (params, id) => {
122
+ if (!findMatch(extractText(params))) return {
123
+ jsonrpc: "2.0",
124
+ id,
125
+ error: {
126
+ code: -32e3,
127
+ message: "No matching pattern for message"
128
+ }
129
+ };
130
+ return null;
131
+ },
132
+ GetTask: async (params, id) => {
133
+ const taskId = params?.id;
134
+ if (!taskId || !tasks.has(taskId)) return {
135
+ jsonrpc: "2.0",
136
+ id,
137
+ error: {
138
+ code: -32001,
139
+ message: "Task not found"
140
+ }
141
+ };
142
+ return {
143
+ jsonrpc: "2.0",
144
+ id,
145
+ result: { task: tasks.get(taskId) }
146
+ };
147
+ },
148
+ ListTasks: async (params, id) => {
149
+ const p = params;
150
+ const contextId = p?.contextId;
151
+ const status = p?.status;
152
+ let results = Array.from(tasks.values());
153
+ if (contextId) results = results.filter((t) => t.contextId === contextId);
154
+ if (status) results = results.filter((t) => t.status.state === status);
155
+ return {
156
+ jsonrpc: "2.0",
157
+ id,
158
+ result: { tasks: results }
159
+ };
160
+ },
161
+ CancelTask: async (params, id) => {
162
+ const taskId = params?.id;
163
+ if (!taskId || !tasks.has(taskId)) return {
164
+ jsonrpc: "2.0",
165
+ id,
166
+ error: {
167
+ code: -32001,
168
+ message: "Task not found"
169
+ }
170
+ };
171
+ const task = tasks.get(taskId);
172
+ if (TERMINAL_STATES.has(task.status.state)) return {
173
+ jsonrpc: "2.0",
174
+ id,
175
+ error: {
176
+ code: -32002,
177
+ message: "Task already in terminal state"
178
+ }
179
+ };
180
+ task.status = {
181
+ state: "TASK_STATE_CANCELED",
182
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
183
+ };
184
+ return {
185
+ jsonrpc: "2.0",
186
+ id,
187
+ result: { task }
188
+ };
189
+ }
190
+ };
191
+ }
192
+ function findStreamingMatch(text, agents) {
193
+ for (const agent of agents.values()) for (const entry of agent.patterns) if (entry.kind === "streamingTask" && matchPattern(text, entry.pattern)) return entry;
194
+ return null;
195
+ }
196
+
197
+ //#endregion
198
+ export { TERMINAL_STATES, buildAgentCard, createA2AMethods, extractText, findStreamingMatch };
199
+ //# sourceMappingURL=a2a-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a2a-handler.js","names":[],"sources":["../src/a2a-handler.ts"],"sourcesContent":["import type { JsonRpcResponse, MethodHandler } from \"./jsonrpc.js\";\nimport type {\n A2AAgentDefinition,\n A2AArtifact,\n A2APart,\n A2AStreamEvent,\n A2ATask,\n A2ATaskState,\n} from \"./a2a-types.js\";\nimport { generateId } from \"./helpers.js\";\n\n// ---- Pattern types ----\n\nexport interface MessagePatternEntry {\n kind: \"message\";\n pattern: string | RegExp;\n agentName: string;\n parts: A2APart[];\n}\n\nexport interface TaskPatternEntry {\n kind: \"task\";\n pattern: string | RegExp;\n agentName: string;\n artifacts: A2AArtifact[];\n}\n\nexport interface StreamingTaskPatternEntry {\n kind: \"streamingTask\";\n pattern: string | RegExp;\n agentName: string;\n events: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport type PatternEntry = MessagePatternEntry | TaskPatternEntry | StreamingTaskPatternEntry;\n\n// ---- Helpers ----\n\nfunction extractText(params: unknown): string {\n const p = params as Record<string, unknown> | undefined;\n if (!p?.message) return \"\";\n const msg = p.message as Record<string, unknown>;\n const parts = msg.parts as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(parts)) return \"\";\n return parts\n .filter((part) => typeof part.text === \"string\")\n .map((part) => part.text as string)\n .join(\" \");\n}\n\nfunction matchPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.includes(pattern);\n }\n return pattern.test(text);\n}\n\nexport const TERMINAL_STATES: Set<string> = new Set([\n \"TASK_STATE_COMPLETED\",\n \"TASK_STATE_FAILED\",\n \"TASK_STATE_CANCELED\",\n]);\n\n// ---- Agent card builder ----\n\nexport function buildAgentCard(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n baseUrl: string,\n): Record<string, unknown> {\n // Use the first registered agent as the primary card, or a default\n const first = agents.values().next().value;\n const def = first?.def;\n\n return {\n name: def?.name ?? \"a2a-mock\",\n description: def?.description ?? \"A2A mock agent\",\n version: def?.version ?? \"1.0.0\",\n supportedInterfaces: [\n {\n url: baseUrl,\n protocolBinding: \"JSONRPC\",\n protocolVersion: \"1.0\",\n },\n ],\n skills: def?.skills ?? [],\n capabilities: def?.capabilities ?? { streaming: true },\n };\n}\n\n// ---- Method handlers ----\n\nexport function createA2AMethods(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n tasks: Map<string, A2ATask>,\n): Record<string, MethodHandler> {\n function findMatch(text: string): PatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n }\n\n function createTask(\n _agentName: string,\n artifacts: A2AArtifact[],\n userParts: A2APart[],\n state: A2ATaskState = \"TASK_STATE_COMPLETED\",\n ): A2ATask {\n const taskId = generateId(\"task\");\n const contextId = generateId(\"ctx\");\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: { state, timestamp: new Date().toISOString() },\n artifacts,\n history: [\n {\n messageId: generateId(\"msg\"),\n role: \"ROLE_USER\",\n parts: userParts,\n },\n ],\n };\n tasks.set(taskId, task);\n return task;\n }\n\n const methods: Record<string, MethodHandler> = {\n SendMessage: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const text = extractText(params);\n const entry = findMatch(text);\n\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n\n const p = params as Record<string, unknown> | undefined;\n const msg = p?.message as Record<string, unknown> | undefined;\n const userParts: A2APart[] = (msg?.parts as A2APart[]) ?? [{ text }];\n\n if (entry.kind === \"message\") {\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n message: {\n messageId: generateId(\"msg\"),\n role: \"ROLE_AGENT\",\n parts: entry.parts,\n },\n },\n };\n }\n\n if (entry.kind === \"task\") {\n const task = createTask(entry.agentName, entry.artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n // streamingTask patterns matched via SendMessage just return task\n if (entry.kind === \"streamingTask\") {\n const artifacts: A2AArtifact[] = [];\n for (const evt of entry.events) {\n if (evt.type === \"artifact\") {\n artifacts.push({ parts: evt.parts, name: evt.name });\n }\n }\n const task = createTask(entry.agentName, artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n },\n\n // SendStreamingMessage is handled specially in A2AMock (SSE response),\n // but we register a placeholder so the dispatcher doesn't return \"method not found\".\n SendStreamingMessage: async (\n params: unknown,\n id: string | number,\n ): Promise<JsonRpcResponse | null> => {\n // This is intercepted before reaching the dispatcher in a2a-mock.ts\n // If it reaches here, return an error\n const text = extractText(params);\n const entry = findMatch(text);\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n return null;\n },\n\n GetTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task: tasks.get(taskId) },\n };\n },\n\n ListTasks: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const contextId = p?.contextId as string | undefined;\n const status = p?.status as string | undefined;\n\n let results = Array.from(tasks.values());\n\n if (contextId) {\n results = results.filter((t) => t.contextId === contextId);\n }\n if (status) {\n results = results.filter((t) => t.status.state === status);\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { tasks: results },\n };\n },\n\n CancelTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n const task = tasks.get(taskId)!;\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32002, message: \"Task already in terminal state\" },\n };\n }\n\n task.status = {\n state: \"TASK_STATE_CANCELED\",\n timestamp: new Date().toISOString(),\n };\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task },\n };\n },\n };\n\n return methods;\n}\n\n// ---- Streaming helpers ----\n\nexport function findStreamingMatch(\n text: string,\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n): StreamingTaskPatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (entry.kind === \"streamingTask\" && matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n}\n\nexport { extractText };\n"],"mappings":"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"}