@copilotkit/aimock 1.44.0 → 1.45.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +42 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.cts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +216 -17
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +214 -18
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/openrouter-video.cjs +30 -2
  181. package/dist/openrouter-video.cjs.map +1 -1
  182. package/dist/openrouter-video.d.cts.map +1 -1
  183. package/dist/openrouter-video.d.ts.map +1 -1
  184. package/dist/openrouter-video.js +30 -2
  185. package/dist/openrouter-video.js.map +1 -1
  186. package/dist/record-sanitize.cjs +231 -0
  187. package/dist/record-sanitize.cjs.map +1 -0
  188. package/dist/record-sanitize.js +224 -0
  189. package/dist/record-sanitize.js.map +1 -0
  190. package/dist/recorder.cjs +106 -5
  191. package/dist/recorder.cjs.map +1 -1
  192. package/dist/recorder.d.cts +2 -1
  193. package/dist/recorder.d.cts.map +1 -1
  194. package/dist/recorder.d.ts +2 -1
  195. package/dist/recorder.d.ts.map +1 -1
  196. package/dist/recorder.js +107 -7
  197. package/dist/recorder.js.map +1 -1
  198. package/dist/responses.cjs +667 -171
  199. package/dist/responses.cjs.map +1 -1
  200. package/dist/responses.d.cts +5 -13
  201. package/dist/responses.d.cts.map +1 -1
  202. package/dist/responses.d.ts +5 -13
  203. package/dist/responses.d.ts.map +1 -1
  204. package/dist/responses.js +665 -174
  205. package/dist/responses.js.map +1 -1
  206. package/dist/router.cjs +24 -2
  207. package/dist/router.cjs.map +1 -1
  208. package/dist/router.d.cts.map +1 -1
  209. package/dist/router.d.ts.map +1 -1
  210. package/dist/router.js +25 -4
  211. package/dist/router.js.map +1 -1
  212. package/dist/server.cjs +572 -76
  213. package/dist/server.cjs.map +1 -1
  214. package/dist/server.d.cts.map +1 -1
  215. package/dist/server.d.ts.map +1 -1
  216. package/dist/server.js +574 -78
  217. package/dist/server.js.map +1 -1
  218. package/dist/stream-collapse.cjs +236 -34
  219. package/dist/stream-collapse.cjs.map +1 -1
  220. package/dist/stream-collapse.d.cts +39 -4
  221. package/dist/stream-collapse.d.cts.map +1 -1
  222. package/dist/stream-collapse.d.ts +39 -4
  223. package/dist/stream-collapse.d.ts.map +1 -1
  224. package/dist/stream-collapse.js +235 -35
  225. package/dist/stream-collapse.js.map +1 -1
  226. package/dist/types.cjs.map +1 -1
  227. package/dist/types.d.cts +315 -4
  228. package/dist/types.d.cts.map +1 -1
  229. package/dist/types.d.ts +315 -4
  230. package/dist/types.d.ts.map +1 -1
  231. package/dist/types.js.map +1 -1
  232. package/dist/validate-cli.cjs +36 -4
  233. package/dist/validate-cli.cjs.map +1 -1
  234. package/dist/validate-cli.js +37 -5
  235. package/dist/validate-cli.js.map +1 -1
  236. package/dist/vector-types.d.ts.map +1 -1
  237. package/dist/version.cjs +45 -0
  238. package/dist/version.cjs.map +1 -0
  239. package/dist/version.js +44 -0
  240. package/dist/version.js.map +1 -0
  241. package/dist/vitest.cjs +66 -10
  242. package/dist/vitest.cjs.map +1 -1
  243. package/dist/vitest.d.cts +35 -4
  244. package/dist/vitest.d.cts.map +1 -1
  245. package/dist/vitest.d.ts +35 -4
  246. package/dist/vitest.d.ts.map +1 -1
  247. package/dist/vitest.js +67 -11
  248. package/dist/vitest.js.map +1 -1
  249. package/dist/watcher.cjs +6 -2
  250. package/dist/watcher.cjs.map +1 -1
  251. package/dist/watcher.js +6 -2
  252. package/dist/watcher.js.map +1 -1
  253. package/dist/ws-gemini-live.cjs +210 -101
  254. package/dist/ws-gemini-live.cjs.map +1 -1
  255. package/dist/ws-gemini-live.d.cts +9 -3
  256. package/dist/ws-gemini-live.d.cts.map +1 -1
  257. package/dist/ws-gemini-live.d.ts +9 -3
  258. package/dist/ws-gemini-live.d.ts.map +1 -1
  259. package/dist/ws-gemini-live.js +211 -102
  260. package/dist/ws-gemini-live.js.map +1 -1
  261. package/dist/ws-realtime.cjs +175 -62
  262. package/dist/ws-realtime.cjs.map +1 -1
  263. package/dist/ws-realtime.d.cts +8 -3
  264. package/dist/ws-realtime.d.cts.map +1 -1
  265. package/dist/ws-realtime.d.ts +8 -3
  266. package/dist/ws-realtime.d.ts.map +1 -1
  267. package/dist/ws-realtime.js +176 -63
  268. package/dist/ws-realtime.js.map +1 -1
  269. package/dist/ws-responses.cjs +109 -16
  270. package/dist/ws-responses.cjs.map +1 -1
  271. package/dist/ws-responses.d.cts +8 -12
  272. package/dist/ws-responses.d.cts.map +1 -1
  273. package/dist/ws-responses.d.ts +8 -12
  274. package/dist/ws-responses.d.ts.map +1 -1
  275. package/dist/ws-responses.js +111 -18
  276. package/dist/ws-responses.js.map +1 -1
  277. package/package.json +10 -2
  278. package/skills/write-fixtures/SKILL.md +179 -21
@@ -9,7 +9,7 @@
9
9
  "source": {
10
10
  "source": "npm",
11
11
  "package": "@copilotkit/aimock",
12
- "version": "^1.44.0"
12
+ "version": "^1.45.1"
13
13
  },
14
14
  "description": "Fixture authoring skill for @copilotkit/aimock — LLM, multimedia (image/TTS/transcription/video), MCP, A2A, AG-UI, vector, embeddings, structured output, sequential responses, streaming physics, record/replay, agent loop patterns, and debugging"
15
15
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aimock",
3
- "version": "1.44.0",
3
+ "version": "1.45.1",
4
4
  "description": "Fixture authoring guidance for @copilotkit/aimock — LLM, multimedia, MCP, A2A, AG-UI, vector, and service mocking",
5
5
  "author": {
6
6
  "name": "CopilotKit"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,48 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.45.1] - 2026-10-11
6
+
7
+ ### Changed
8
+
9
+ - OpenRouter Video: `openai/sora-2` now returns OpenRouter's 400 removal error, not a job (#520)
10
+
11
+ ### Fixed
12
+
13
+ - MCP `tools/list`: a tool registered without `inputSchema` now lists `{"type":"object"}` (#529)
14
+ - MCP `tools/list`: a registered `inputSchema` with no `type` now gets `"type": "object"` (#529)
15
+
16
+ ## [1.45.0] - 2026-10-10
17
+
18
+ Every fixture, config and request that 1.44.0 accepted behaves the same by default. New behavior that would change those inputs is opt-in.
19
+
20
+ ### Added
21
+
22
+ - Record live MCP servers into `mcpFakes` files and replay them offline: `--mcp-record <mount>=<url>` and `--mcp-proxy-only <mount>=<url>` (`llmock` bin and Docker image), `llm.record.mcp` with the opt-in `llm.enableMcpRecording: true` for `aimock --config` (without the opt-in, `llm.record.mcp` is ignored with a warning, as 1.44.0 ignored it), and `MCPMock.enableRecording()` / `disableRecording()` (#509).
23
+ - Recordings never contain headers and redact known secrets (`AIMOCK_RECORD_SECRET_VALUES`, `AIMOCK_MCP_UPSTREAM_AUTH`); a file is not written while a secret remains (#509).
24
+ - Recorded MCP fakes replay list order, progress and log notifications, and call timing (scaled by `--replay-speed`). The recorded `mcpFakes` keys (`list`, `recorded`, `timing`, `notifications`, `durationMs`) need 1.45.0 or later (#509).
25
+ - Per-test MCP fake report at `GET /__aimock/mcp/fakes/report` (#509).
26
+ - Vitest and Jest: `fakesFor()` and `fakesReport()` on a new `AimockFakesHandle` returned by `useAimock()`, and opt-in `useAimock({ fakesReport: "warn" | "fail" })` (default `"off"`); Jest option `testIdRoot`. New exports `assertFakesReport`, `AimockFakesReportError` and `AimockTestIdCollisionError` (#509).
27
+ - aimock-pytest 0.7.0: `fakes_for`, `fakes_report` and `assert_fakes_report` (#509), and `AIMockServer` opt-ins `enable_misbehavior` and `responses_tools` (#508, #511).
28
+ - Workflow-target examples: a Mastra Workflow and a LangGraph JS graph call MCP fakes with no LLM (`examples/mcp-workflow-targets`), plus record and report proofs (#509).
29
+ - Model misbehavior faults (invalid tool arguments, schema violations, unknown tools, duplicate IDs, length stops, empty responses, refusals, content filtering, reasoning-only) across provider wires, with seeded rates, `/__aimock/misbehavior` runtime controls, journal evidence and the `aimock_misbehavior_total` metric. Off unless enabled with `enableMisbehavior: true` (programmatic, including `useAimock`), `llmock --misbehavior` / `aimock validate --misbehavior`, or `aimock --misbehavior`, or the config opt-in `llm.enableMisbehavior: true` (an `llm.misbehavior` key alone never enables it, as in 1.44.0). Invalid misbehavior settings throw the new `MisbehaviorConfigError` (#508).
30
+ - Namespaced function calls and custom tool calls on the OpenAI Responses API, over HTTP, SSE and WebSocket, plus `match.toolNamespace` (#511). Like the fixture fields below, `match.toolNamespace` applies only with `responsesTools: "extended"`; in the default mode it is ignored, as in 1.44.0.
31
+ - Responses namespaced and custom tool calls: with `responsesTools: "extended"` (CLI `--responses-tools extended`, also on `aimock validate`; config `llm.responsesTools`), tools inside `namespace` tools, `custom` tools and `additional_tools` / `tool_search_output` tools are visible to `toolName`, `toolNamespace` and predicates, custom tool rounds count for `hasToolResult`, `toolCallId` and `turnIndex`, and fixtures can answer with namespaced calls and `customToolCalls` / `responsesBlocks`. The default `"legacy"` keeps 1.44.0 behavior. New types: `CustomToolCallMessage`, `ResponsesToolsMode` (#511).
32
+ - Record mode keeps Responses namespaces and custom tool calls (`customToolCalls`, `responsesBlocks`, `CollapseResult.customToolCalls`) in streamed recordings when `responsesTools: "extended"` is set (#513).
33
+ - Strict tool arguments: with `strictToolArguments` (CLI `--strict-tool-arguments`, config `llm.strictToolArguments`), malformed tool-call argument strings are sent unchanged on string wires and return an explicit error on object wires. The default keeps 1.44.0 behavior (#501).
34
+ - Vertex and Bedrock modeled-contract comparisons for the misbehavior faults in the daily drift checks (#508).
35
+
36
+ ### Fixed
37
+
38
+ - MCP recording checks its config at start, redacts credentials in errors, fails loudly when the upstream dies mid-body (502 or a terminated stream, logged and journaled), and defaults `aimock --config` with record mounts to `logLevel: "warn"` (#517).
39
+ - Kept 1.44.0 default behavior for strict tool arguments, model misbehavior, Responses namespaced and custom tools, `llm.record.mcp`, fixture identity and the exported stream helpers, and made each new behavior opt-in (#518).
40
+ - Kept the published types compatible with 1.44.0: `AimockHandle`, `Mountable` and `McpFakeAddOrigin` keep their 1.44.0 shape, and every entry point type-checks with `skipLibCheck: false` (#517).
41
+ - Align Cohere streaming length-stop faults with captured provider framing (#508).
42
+ - Retain drift evidence across retries and for oversized records (#510, #512).
43
+ - Classify `claude-haiku-5-5` in the drift model registry (#515).
44
+ - Docs: dark-site font smoothing, consistent homepage comparison headings, the test-suite highlight, and the copy-button fallback (#504, #506, #514).
45
+ - Invalid opt-in values never stop startup: an invalid `responsesTools` warns once and runs `"legacy"`, and a non-boolean `llm.strictToolArguments`, `llm.enableMisbehavior` or `llm.enableMcpRecording` warns once and stays off (#518).
46
+
5
47
  ## [1.44.0] - 2026-10-07
6
48
 
7
49
  ### Added
package/README.md CHANGED
@@ -77,7 +77,10 @@ Run them all on one port with `npx @copilotkit/aimock --config aimock.json`, or
77
77
  - **OpenAI platform APIs** — [Files](https://aimock.copilotkit.dev/files) (byte-exact uploads, purpose validation), [Vector Stores](https://aimock.copilotkit.dev/vector-stores) (CRUD, file attach with deterministic poll progression, file batches, deterministic direct search; hosted `file_search` execution is not supported), [fine-tuning jobs](https://aimock.copilotkit.dev/fine-tuning) (deterministic lifecycle, events, cursor pages) and Batches (`/v1/batches` create/list/retrieve/cancel with deterministic poll progression and real output files)
78
78
  - **[MCP](https://aimock.copilotkit.dev/mcp-mock) / [A2A](https://aimock.copilotkit.dev/a2a-mock) / [AG-UI](https://aimock.copilotkit.dev/agui-mock) / [Vector](https://aimock.copilotkit.dev/vector-mock)** — Mock every protocol your AI agents use
79
79
  - **[MCP Scenario Fakes](https://aimock.copilotkit.dev/mcp-mock#scenario-fakes)** — An `mcpFakes` block in a fixture file scripts each test's MCP tool answers next to its LLM turns: ordered answers, exact or any-argument matching, scripted tool errors, and a closed-world mode that fails on any undeclared tool. Works with any MCP client over Streamable HTTP
80
+ - **[MCP Recording](https://aimock.copilotkit.dev/record-replay#mcp-recording)** — Record a live MCP server into `mcpFakes` files (`--mcp-record /mcp=<url>`, or `llm.record.mcp` with `llm.enableMcpRecording: true` in a config) and replay them offline, with the recorded tool list, progress notifications and timing; known secrets are redacted before anything is written
81
+ - **[MCP Fake Reports](https://aimock.copilotkit.dev/mcp-mock#fakes-report)** — `GET /__aimock/mcp/fakes/report` lists each test's served, unused and failed fakes; with `useAimock({ fakesReport: "fail" })` a swallowed fake error or an unused fake fails the test, and `fakesFor()` gives the MCP URL and headers for the current test. Works for agents, workflows and pipelines alike
80
82
  - **[Chaos Testing](https://aimock.copilotkit.dev/chaos-testing)** — 500 errors, malformed JSON, mid-stream disconnects and 429 rate limits (`--chaos-ratelimit`, with `Retry-After`) at any probability, plus a fixed pre-handling delay (`--chaos-latency <ms>`); read, set and clear the rates at runtime via `GET` / `POST` / `DELETE /__aimock/chaos`, scoped to the caller's `X-Test-Id` so one test cannot destabilise the suite running beside it
83
+ - **[Model Misbehavior](https://aimock.copilotkit.dev/model-misbehavior)** — Test invalid tool arguments, schema violations, unknown tools, duplicate IDs, length stops, empty responses, refusals, content filtering, and reasoning-only responses. Supported wires include OpenAI Chat, Responses, Realtime GA, Anthropic, Bedrock InvokeModel and Converse, Gemini generateContent (including the Vertex wrapper), Gemini Live, Gemini Interactions, Cohere, and Ollama chat. Fault and mode support varies by wire. Azure and OpenRouter use the Chat wire. Seeded rates, per-test limits, and journal evidence apply across supported wires. See the reference for the support matrix, SDK behavior, and modeled contracts whose native occurrence remains unverified.
81
84
  - **Request journal** — `GET /__aimock/journal` returns every recorded request, filterable by `path`, `method`, `status`, `service`, `testId` and `requestId` with `limit` / `offset` paging and an `X-Total-Count` header carrying the pre-pagination total
82
85
  - **HTTP route catalog** — `GET /__aimock/openapi.json` returns OpenAPI 3.1; `GET /__aimock/routes` returns `{ count, routes }`. For programmatic inspection, import `buildOpenApiDocument`, `CATALOG_ROUTES` and `ROUTE_DEFINITIONS` (with `CatalogRoute`/`RouteDefinition` types) from `@copilotkit/aimock`. The catalog describes HTTP operations; streaming responses include media and framing metadata, not a complete-stream JSON body.
83
86
  - **Request IDs** — every response carries `X-Request-Id`, echoing the caller's header or minting one; the journal stores it on each entry and `GET /__aimock/journal?requestId=<id>` returns that request. A minted id is never forwarded upstream in record/proxy mode
@@ -92,10 +95,13 @@ Run them all on one port with `npx @copilotkit/aimock --config aimock.json`, or
92
95
  - **[Vitest & Jest Plugins](https://aimock.copilotkit.dev/test-plugins)** — Zero-config `useAimock()` with auto lifecycle and env patching
93
96
  - **[Response Overrides](https://aimock.copilotkit.dev/fixtures)** — Control `id`, `model`, `usage`, `finishReason` in fixture responses
94
97
  - **[Ordered Blocks](https://aimock.copilotkit.dev/fixtures#ordered-blocks)** — A `blocks` array streams text and tool calls in any order (tool-first or interleaved); blocks-only fixtures are first-class, and the recorder captures order from genuinely tool-first/interleaved streams
98
+ - **[Namespaced and Custom Tool Calls](https://aimock.copilotkit.dev/responses-api#namespaced-and-custom-tool-calls)** — Responses API fixtures can return namespaced function calls and custom tool calls (`custom_tool_call`) over HTTP streaming, non-streaming and WebSocket, and can match on `toolNamespace`. This lets you script OpenAI Codex CLI's namespaced MCP and sub-agent tools and its freeform `apply_patch` tool (with the `responsesTools: "extended"` server option)
95
99
  - **[Streaming Usage Chunks](https://aimock.copilotkit.dev/streaming-physics)** — `stream_options.include_usage` support emits a final chunk with token counts, matching OpenAI's streaming usage protocol
96
100
  - **[Rate Limiting Headers](https://aimock.copilotkit.dev/chaos-testing)** — `x-ratelimit-*` headers on every response and `Retry-After` on 429 errors for testing retry/backoff logic
97
101
  - **Zero dependencies** — Everything from Node.js builtins
98
102
 
103
+ Model misbehavior requires aimock 1.45.0 or later. Older versions silently ignore the fixture's `misbehavior` field and serve its original response. Invalid configurations now fail during fixture loading or programmatic addition. See the [model misbehavior reference](https://aimock.copilotkit.dev/model-misbehavior) for supported parameters and compatibility details.
104
+
99
105
  ## GitHub Action
100
106
 
101
107
  ```yaml
@@ -1 +1 @@
1
- {"version":3,"file":"agui-types.d.cts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"agui-types.d.cts","names":[],"sources":["../src/agui-types.ts"],"sourcesContent":[],"mappings":"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"}
@@ -17,6 +17,11 @@ Options:
17
17
  -c, --config <path> Path to aimock config JSON file (required)
18
18
  -p, --port <number> Port override (default: from config or 0)
19
19
  --host <string> Host override (default: from config or 127.0.0.1)
20
+ --misbehavior Enable model misbehavior (same as llm.enableMisbehavior: true)
21
+ --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments
22
+ instead of serving {} (same as llm.strictToolArguments: true)
23
+ --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or
24
+ extended (overrides llm.responsesTools)
20
25
  -h, --help Show this help message
21
26
 
22
27
  Subcommands:
@@ -66,6 +71,15 @@ function runAimockCli(deps = {}) {
66
71
  short: "p"
67
72
  },
68
73
  host: { type: "string" },
74
+ misbehavior: {
75
+ type: "boolean",
76
+ default: false
77
+ },
78
+ "strict-tool-arguments": {
79
+ type: "boolean",
80
+ default: false
81
+ },
82
+ "responses-tools": { type: "string" },
69
83
  help: {
70
84
  type: "boolean",
71
85
  short: "h",
@@ -92,7 +106,8 @@ function runAimockCli(deps = {}) {
92
106
  const blank = [
93
107
  ["config", values.config],
94
108
  ["port", values.port],
95
- ["host", values.host]
109
+ ["host", values.host],
110
+ ["responses-tools", values["responses-tools"]]
96
111
  ].find(([, value]) => value !== void 0 && value.trim() === "");
97
112
  if (blank !== void 0) {
98
113
  logError(`Error: --${blank[0]} requires a non-empty value.\n\n${HELP}`);
@@ -115,11 +130,22 @@ function runAimockCli(deps = {}) {
115
130
  return;
116
131
  }
117
132
  const host = values.host;
133
+ const responsesToolsFlag = values["responses-tools"];
134
+ if (responsesToolsFlag !== void 0 && responsesToolsFlag !== "legacy" && responsesToolsFlag !== "extended") {
135
+ logError(`Error: invalid --responses-tools "${responsesToolsFlag}" (expected "legacy" or "extended").\n\n${HELP}`);
136
+ exit(1);
137
+ return;
138
+ }
139
+ const responsesTools = responsesToolsFlag;
140
+ const overrides = {
141
+ port,
142
+ host,
143
+ ...values.misbehavior ? { enableMisbehavior: true } : {},
144
+ ...values["strict-tool-arguments"] ? { strictToolArguments: true } : {},
145
+ ...responsesTools !== void 0 ? { responsesTools } : {}
146
+ };
118
147
  async function main() {
119
- const { llmock, url } = await startFromConfigFn(config, {
120
- port,
121
- host
122
- });
148
+ const { llmock, url } = await startFromConfigFn(config, overrides);
123
149
  function shutdown() {
124
150
  log("Shutting down...");
125
151
  process.removeListener("SIGINT", shutdown);
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.cjs","names":["loadConfig","startFromConfig"],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\nimport { runValidateCli } from \"./validate-cli.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n aimock validate [--strict] [--json] [--] <path> [more paths ...]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n --host <string> Host override (default: from config or 127.0.0.1)\n -h, --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n validate Validate fixture files or directories offline\n Run \"aimock validate --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n validateDeps?: {\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n };\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n // Intercept \"validate\" the same way — it takes file paths, not --config.\n if (argv[0] === \"validate\") {\n runValidateCli({\n argv: argv.slice(1),\n log: deps.validateDeps?.log ?? log,\n logError: deps.validateDeps?.logError ?? logError,\n exit: deps.validateDeps?.exit ?? exit,\n });\n return;\n }\n\n // Short-flag rule for the `aimock` bin: a short flag means the same thing at\n // the top level and in every subcommand. `-h` is `--help` everywhere, which\n // is what `convert` (src/convert.ts) and `validate` (src/validate-cli.ts)\n // already did and what a reader typing `aimock -h` expects; the host\n // override is long-form `--host` only, and had no documented short use.\n // Short flags are per-bin: the separate `llmock` bin (src/cli.ts, the\n // Docker ENTRYPOINT) keeps its own documented set, where `-h` is `--host`\n // and `-c` is `--chunk-size`.\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (values.config === undefined) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n // A value-taking option that was GIVEN an empty (or blank) value is a usage\n // error, not an absent option. Testing these for truthiness instead let\n // `--config \"\"` read as \"not given\", and let `--port \"\"` / `--host \"\"` be\n // dropped in silence — `--host \"\"` in particular reached the server as an\n // empty bind address, which listens on every interface rather than on the\n // documented 127.0.0.1 default.\n const blank = (\n [\n [\"config\", values.config],\n [\"port\", values.port],\n [\"host\", values.host],\n ] as const\n ).find(([, value]) => value !== undefined && value.trim() === \"\");\n if (blank !== undefined) {\n logError(`Error: --${blank[0]} requires a non-empty value.\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port === undefined ? undefined : Number(values.port);\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\n// The basenames this module is ever argv[1] under: the `aimock` bin (the\n// package.json \"bin\" name), both build outputs — tsdown.config.ts builds\n// src/aimock-cli.ts in \"esm\" AND \"cjs\" format, which under `\"type\": \"module\"`\n// emits dist/aimock-cli.js and dist/aimock-cli.cjs — and the TypeScript\n// source, run through tsx. Omitting the .cjs made `node dist/aimock-cli.cjs`\n// print nothing and exit 0 despite its shebang and exec bit.\nconst ENTRY_BASENAMES = new Set([\"aimock\", \"aimock-cli.js\", \"aimock-cli.cjs\", \"aimock-cli.ts\"]);\nconst scriptName = process.argv[1] ?? \"\";\nif (ENTRY_BASENAMES.has(basename(scriptName))) {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":"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"}
1
+ {"version":3,"file":"aimock-cli.cjs","names":["loadConfig","startFromConfig"],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig, type StartFromConfigOverrides } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\nimport { runValidateCli } from \"./validate-cli.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n aimock validate [--strict] [--json] [--] <path> [more paths ...]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n --host <string> Host override (default: from config or 127.0.0.1)\n --misbehavior Enable model misbehavior (same as llm.enableMisbehavior: true)\n --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments\n instead of serving {} (same as llm.strictToolArguments: true)\n --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or\n extended (overrides llm.responsesTools)\n -h, --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n validate Validate fixture files or directories offline\n Run \"aimock validate --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n validateDeps?: {\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n };\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n // Intercept \"validate\" the same way — it takes file paths, not --config.\n if (argv[0] === \"validate\") {\n runValidateCli({\n argv: argv.slice(1),\n log: deps.validateDeps?.log ?? log,\n logError: deps.validateDeps?.logError ?? logError,\n exit: deps.validateDeps?.exit ?? exit,\n });\n return;\n }\n\n // Short-flag rule for the `aimock` bin: a short flag means the same thing at\n // the top level and in every subcommand. `-h` is `--help` everywhere, which\n // is what `convert` (src/convert.ts) and `validate` (src/validate-cli.ts)\n // already did and what a reader typing `aimock -h` expects; the host\n // override is long-form `--host` only, and had no documented short use.\n // Short flags are per-bin: the separate `llmock` bin (src/cli.ts, the\n // Docker ENTRYPOINT) keeps its own documented set, where `-h` is `--host`\n // and `-c` is `--chunk-size`.\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\" },\n misbehavior: { type: \"boolean\", default: false },\n \"strict-tool-arguments\": { type: \"boolean\", default: false },\n \"responses-tools\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (values.config === undefined) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n // A value-taking option that was GIVEN an empty (or blank) value is a usage\n // error, not an absent option. Testing these for truthiness instead let\n // `--config \"\"` read as \"not given\", and let `--port \"\"` / `--host \"\"` be\n // dropped in silence — `--host \"\"` in particular reached the server as an\n // empty bind address, which listens on every interface rather than on the\n // documented 127.0.0.1 default.\n const blank = (\n [\n [\"config\", values.config],\n [\"port\", values.port],\n [\"host\", values.host],\n [\"responses-tools\", values[\"responses-tools\"]],\n ] as const\n ).find(([, value]) => value !== undefined && value.trim() === \"\");\n if (blank !== undefined) {\n logError(`Error: --${blank[0]} requires a non-empty value.\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port === undefined ? undefined : Number(values.port);\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n const responsesToolsFlag = values[\"responses-tools\"];\n if (\n responsesToolsFlag !== undefined &&\n responsesToolsFlag !== \"legacy\" &&\n responsesToolsFlag !== \"extended\"\n ) {\n logError(\n `Error: invalid --responses-tools \"${responsesToolsFlag}\" (expected \"legacy\" or \"extended\").\\n\\n${HELP}`,\n );\n exit(1);\n return;\n }\n // The boolean opt-ins override the config only when given, so an absent flag\n // leaves llm.enableMisbehavior / llm.strictToolArguments in charge.\n const responsesTools: StartFromConfigOverrides[\"responsesTools\"] = responsesToolsFlag;\n const overrides: StartFromConfigOverrides = {\n port,\n host,\n ...(values.misbehavior ? { enableMisbehavior: true } : {}),\n ...(values[\"strict-tool-arguments\"] ? { strictToolArguments: true } : {}),\n ...(responsesTools !== undefined ? { responsesTools } : {}),\n };\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, overrides);\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\n// The basenames this module is ever argv[1] under: the `aimock` bin (the\n// package.json \"bin\" name), both build outputs — tsdown.config.ts builds\n// src/aimock-cli.ts in \"esm\" AND \"cjs\" format, which under `\"type\": \"module\"`\n// emits dist/aimock-cli.js and dist/aimock-cli.cjs — and the TypeScript\n// source, run through tsx. Omitting the .cjs made `node dist/aimock-cli.cjs`\n// print nothing and exit 0 despite its shebang and exec bit.\nconst ENTRY_BASENAMES = new Set([\"aimock\", \"aimock-cli.js\", \"aimock-cli.cjs\", \"aimock-cli.ts\"]);\nconst scriptName = process.argv[1] ?? \"\";\nif (ENTRY_BASENAMES.has(basename(scriptName))) {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":";;;;;;;;;;AAOA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;EAqBX,MAAM;AAkBR,SAAgB,aAAa,OAAsB,EAAE,EAAQ;;CAE3D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,MAAM,EAAE;CAC/C,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,QAAQ;CACjD,MAAM,WAAW,KAAK,YAAY,QAAQ,MAAM,KAAK,QAAQ;CAC7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,QAAQ;CACpD,MAAM,eAAe,KAAK,gBAAgBA;CAC1C,MAAM,oBAAoB,KAAK,qBAAqBC;AAGpD,KAAI,KAAK,OAAO,WAAW;AACzB,gCAAc;GACZ,MAAM,KAAK,MAAM,EAAE;GACnB;GACA;GACA;GACA,GAAG,KAAK;GACT,CAAC;AACF;;AAIF,KAAI,KAAK,OAAO,YAAY;AAC1B,sCAAe;GACb,MAAM,KAAK,MAAM,EAAE;GACnB,KAAK,KAAK,cAAc,OAAO;GAC/B,UAAU,KAAK,cAAc,YAAY;GACzC,MAAM,KAAK,cAAc,QAAQ;GAClC,CAAC;AACF;;CAWF,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,mCAAqB;GACtB,MAAM;GACN,SAAS;IACP,QAAQ;KAAE,MAAM;KAAU,OAAO;KAAK;IACtC,MAAM;KAAE,MAAM;KAAU,OAAO;KAAK;IACpC,MAAM,EAAE,MAAM,UAAU;IACxB,aAAa;KAAE,MAAM;KAAW,SAAS;KAAO;IAChD,yBAAyB;KAAE,MAAM;KAAW,SAAS;KAAO;IAC5D,mBAAmB,EAAE,MAAM,UAAU;IACrC,MAAM;KAAE,MAAM;KAAW,OAAO;KAAK,SAAS;KAAO;IACtD;GACD,QAAQ;GACT,CAAC;UACK,KAAK;AAGZ,WAAS,UADG,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACrC,MAAM,OAAO;AACpC,OAAK,EAAE;AACP;;AAGF,KAAI,OAAO,MAAM;AACf,MAAI,KAAK;AACT,OAAK,EAAE;AACP;;AAEF,KAAI,OAAO,WAAW,QAAW;AAC/B,WAAS,qCAAqC,KAAK;AACnD,OAAK,EAAE;AACP;;CAQF,MAAM,QACJ;EACE,CAAC,UAAU,OAAO,OAAO;EACzB,CAAC,QAAQ,OAAO,KAAK;EACrB,CAAC,QAAQ,OAAO,KAAK;EACrB,CAAC,mBAAmB,OAAO,mBAAmB;EAC/C,CACD,MAAM,GAAG,WAAW,UAAU,UAAa,MAAM,MAAM,KAAK,GAAG;AACjE,KAAI,UAAU,QAAW;AACvB,WAAS,YAAY,MAAM,GAAG,kCAAkC,OAAO;AACvE,OAAK,EAAE;AACP;;CAGF,MAAM,oCAAqB,OAAO,OAAO;CACzC,IAAI;AACJ,KAAI;AACF,WAAS,aAAa,WAAW;UAC1B,KAAK;AAEZ,WAAS,8BAA8B,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACA;AAC5D,OAAK,EAAE;AACP;;CAGF,MAAM,OAAO,OAAO,SAAS,SAAY,SAAY,OAAO,OAAO,KAAK;AACxE,KACE,SAAS,WACR,OAAO,MAAM,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,QACrE;AACA,WAAS,wBAAwB,OAAO,KAAK,QAAQ,OAAO;AAC5D,OAAK,EAAE;AACP;;CAEF,MAAM,OAAO,OAAO;CACpB,MAAM,qBAAqB,OAAO;AAClC,KACE,uBAAuB,UACvB,uBAAuB,YACvB,uBAAuB,YACvB;AACA,WACE,qCAAqC,mBAAmB,0CAA0C,OACnG;AACD,OAAK,EAAE;AACP;;CAIF,MAAM,iBAA6D;CACnE,MAAM,YAAsC;EAC1C;EACA;EACA,GAAI,OAAO,cAAc,EAAE,mBAAmB,MAAM,GAAG,EAAE;EACzD,GAAI,OAAO,2BAA2B,EAAE,qBAAqB,MAAM,GAAG,EAAE;EACxE,GAAI,mBAAmB,SAAY,EAAE,gBAAgB,GAAG,EAAE;EAC3D;CAED,eAAe,OAAO;EACpB,MAAM,EAAE,QAAQ,QAAQ,MAAM,kBAAkB,QAAS,UAAU;EAEnE,SAAS,WAAW;AAClB,OAAI,mBAAmB;AACvB,WAAQ,eAAe,UAAU,SAAS;AAC1C,WAAQ,eAAe,WAAW,SAAS;AAC3C,UAAO,MAAM,CAAC,WACN,KAAK,EAAE,GACZ,QAAQ;AACP,aAAS,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC/E,SAAK,EAAE;KAEV;;AAIH,UAAQ,GAAG,UAAU,SAAS;AAC9B,UAAQ,GAAG,WAAW,SAAS;AAE/B,MAAI,8BAA8B,MAAM;AAExC,MAAI,KAAK,QACP,MAAK,QAAQ,EAAE,UAAU,CAAC;;AAI9B,OAAM,CAAC,OAAO,QAAQ;AACpB,WAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;AAC1D,OAAK,EAAE;GACP;;;AAWJ,MAAM,kBAAkB,IAAI,IAAI;CAAC;CAAU;CAAiB;CAAkB;CAAgB,CAAC;AAC/F,MAAM,aAAa,QAAQ,KAAK,MAAM;AACtC,IAAI,gBAAgB,4BAAa,WAAW,CAAC,CAC3C,eAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.d.cts","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":[],"mappings":";;;;UAyBiB,aAAA;EAAA,IAAA,CAAA,EAAA,MAAA,EAAA;EAAa,GAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;UAKN,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;MACK,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;cAEL,CAAA,EAAA,OAHA,UAGA;mBAAR,CAAA,EAAA,OAFa,eAEb;EAAO,OAAA,CAAA,EAAA,CAAA,GAAA,EAAA;IAQP,QAAA,EAAA,GAAY,GAAA,IAAA;;gBARZ,QAAQ;;;;;;;iBAQR,YAAA,QAAmB"}
1
+ {"version":3,"file":"aimock-cli.d.cts","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":[],"mappings":";;;;UA8BiB,aAAA;EAAA,IAAA,CAAA,EAAA,MAAA,EAAA;EAAa,GAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;UAKN,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;MACK,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;cAEL,CAAA,EAAA,OAHA,UAGA;mBAAR,CAAA,EAAA,OAFa,eAEb;EAAO,OAAA,CAAA,EAAA,CAAA,GAAA,EAAA;IAQP,QAAA,EAAA,GAAY,GAAA,IAAA;;gBARZ,QAAQ;;;;;;;iBAQR,YAAA,QAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.d.ts","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":[],"mappings":";;;;UAyBiB,aAAA;EAAA,IAAA,CAAA,EAAA,MAAA,EAAA;EAAa,GAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;UAKN,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;MACK,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;cAEL,CAAA,EAAA,OAHA,UAGA;mBAAR,CAAA,EAAA,OAFa,eAEb;EAAO,OAAA,CAAA,EAAA,CAAA,GAAA,EAAA;IAQP,QAAA,EAAA,GAAY,GAAA,IAAA;;gBARZ,QAAQ;;;;;;;iBAQR,YAAA,QAAmB"}
1
+ {"version":3,"file":"aimock-cli.d.ts","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":[],"mappings":";;;;UA8BiB,aAAA;EAAA,IAAA,CAAA,EAAA,MAAA,EAAA;EAAa,GAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;UAKN,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA;MACK,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;cAEL,CAAA,EAAA,OAHA,UAGA;mBAAR,CAAA,EAAA,OAFa,eAEb;EAAO,OAAA,CAAA,EAAA,CAAA,GAAA,EAAA;IAQP,QAAA,EAAA,GAAY,GAAA,IAAA;;gBARZ,QAAQ;;;;;;;iBAQR,YAAA,QAAmB"}
@@ -15,6 +15,11 @@ Options:
15
15
  -c, --config <path> Path to aimock config JSON file (required)
16
16
  -p, --port <number> Port override (default: from config or 0)
17
17
  --host <string> Host override (default: from config or 127.0.0.1)
18
+ --misbehavior Enable model misbehavior (same as llm.enableMisbehavior: true)
19
+ --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments
20
+ instead of serving {} (same as llm.strictToolArguments: true)
21
+ --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or
22
+ extended (overrides llm.responsesTools)
18
23
  -h, --help Show this help message
19
24
 
20
25
  Subcommands:
@@ -64,6 +69,15 @@ function runAimockCli(deps = {}) {
64
69
  short: "p"
65
70
  },
66
71
  host: { type: "string" },
72
+ misbehavior: {
73
+ type: "boolean",
74
+ default: false
75
+ },
76
+ "strict-tool-arguments": {
77
+ type: "boolean",
78
+ default: false
79
+ },
80
+ "responses-tools": { type: "string" },
67
81
  help: {
68
82
  type: "boolean",
69
83
  short: "h",
@@ -90,7 +104,8 @@ function runAimockCli(deps = {}) {
90
104
  const blank = [
91
105
  ["config", values.config],
92
106
  ["port", values.port],
93
- ["host", values.host]
107
+ ["host", values.host],
108
+ ["responses-tools", values["responses-tools"]]
94
109
  ].find(([, value]) => value !== void 0 && value.trim() === "");
95
110
  if (blank !== void 0) {
96
111
  logError(`Error: --${blank[0]} requires a non-empty value.\n\n${HELP}`);
@@ -113,11 +128,22 @@ function runAimockCli(deps = {}) {
113
128
  return;
114
129
  }
115
130
  const host = values.host;
131
+ const responsesToolsFlag = values["responses-tools"];
132
+ if (responsesToolsFlag !== void 0 && responsesToolsFlag !== "legacy" && responsesToolsFlag !== "extended") {
133
+ logError(`Error: invalid --responses-tools "${responsesToolsFlag}" (expected "legacy" or "extended").\n\n${HELP}`);
134
+ exit(1);
135
+ return;
136
+ }
137
+ const responsesTools = responsesToolsFlag;
138
+ const overrides = {
139
+ port,
140
+ host,
141
+ ...values.misbehavior ? { enableMisbehavior: true } : {},
142
+ ...values["strict-tool-arguments"] ? { strictToolArguments: true } : {},
143
+ ...responsesTools !== void 0 ? { responsesTools } : {}
144
+ };
116
145
  async function main() {
117
- const { llmock, url } = await startFromConfigFn(config, {
118
- port,
119
- host
120
- });
146
+ const { llmock, url } = await startFromConfigFn(config, overrides);
121
147
  function shutdown() {
122
148
  log("Shutting down...");
123
149
  process.removeListener("SIGINT", shutdown);
@@ -1 +1 @@
1
- {"version":3,"file":"aimock-cli.js","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\nimport { runValidateCli } from \"./validate-cli.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n aimock validate [--strict] [--json] [--] <path> [more paths ...]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n --host <string> Host override (default: from config or 127.0.0.1)\n -h, --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n validate Validate fixture files or directories offline\n Run \"aimock validate --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n validateDeps?: {\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n };\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n // Intercept \"validate\" the same way — it takes file paths, not --config.\n if (argv[0] === \"validate\") {\n runValidateCli({\n argv: argv.slice(1),\n log: deps.validateDeps?.log ?? log,\n logError: deps.validateDeps?.logError ?? logError,\n exit: deps.validateDeps?.exit ?? exit,\n });\n return;\n }\n\n // Short-flag rule for the `aimock` bin: a short flag means the same thing at\n // the top level and in every subcommand. `-h` is `--help` everywhere, which\n // is what `convert` (src/convert.ts) and `validate` (src/validate-cli.ts)\n // already did and what a reader typing `aimock -h` expects; the host\n // override is long-form `--host` only, and had no documented short use.\n // Short flags are per-bin: the separate `llmock` bin (src/cli.ts, the\n // Docker ENTRYPOINT) keeps its own documented set, where `-h` is `--host`\n // and `-c` is `--chunk-size`.\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (values.config === undefined) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n // A value-taking option that was GIVEN an empty (or blank) value is a usage\n // error, not an absent option. Testing these for truthiness instead let\n // `--config \"\"` read as \"not given\", and let `--port \"\"` / `--host \"\"` be\n // dropped in silence — `--host \"\"` in particular reached the server as an\n // empty bind address, which listens on every interface rather than on the\n // documented 127.0.0.1 default.\n const blank = (\n [\n [\"config\", values.config],\n [\"port\", values.port],\n [\"host\", values.host],\n ] as const\n ).find(([, value]) => value !== undefined && value.trim() === \"\");\n if (blank !== undefined) {\n logError(`Error: --${blank[0]} requires a non-empty value.\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port === undefined ? undefined : Number(values.port);\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, { port, host });\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\n// The basenames this module is ever argv[1] under: the `aimock` bin (the\n// package.json \"bin\" name), both build outputs — tsdown.config.ts builds\n// src/aimock-cli.ts in \"esm\" AND \"cjs\" format, which under `\"type\": \"module\"`\n// emits dist/aimock-cli.js and dist/aimock-cli.cjs — and the TypeScript\n// source, run through tsx. Omitting the .cjs made `node dist/aimock-cli.cjs`\n// print nothing and exit 0 despite its shebang and exec bit.\nconst ENTRY_BASENAMES = new Set([\"aimock\", \"aimock-cli.js\", \"aimock-cli.cjs\", \"aimock-cli.ts\"]);\nconst scriptName = process.argv[1] ?? \"\";\nif (ENTRY_BASENAMES.has(basename(scriptName))) {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":"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"}
1
+ {"version":3,"file":"aimock-cli.js","names":[],"sources":["../src/aimock-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { resolve, basename } from \"node:path\";\nimport { loadConfig, startFromConfig, type StartFromConfigOverrides } from \"./config-loader.js\";\nimport { runConvertCli, type ConvertCliDeps } from \"./convert.js\";\nimport { runValidateCli } from \"./validate-cli.js\";\n\nconst HELP = `\nUsage: aimock [options]\n aimock convert <format> <input> [output]\n aimock validate [--strict] [--json] [--] <path> [more paths ...]\n\nOptions:\n -c, --config <path> Path to aimock config JSON file (required)\n -p, --port <number> Port override (default: from config or 0)\n --host <string> Host override (default: from config or 127.0.0.1)\n --misbehavior Enable model misbehavior (same as llm.enableMisbehavior: true)\n --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments\n instead of serving {} (same as llm.strictToolArguments: true)\n --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or\n extended (overrides llm.responsesTools)\n -h, --help Show this help message\n\nSubcommands:\n convert Convert third-party mock configs to aimock format\n Run \"aimock convert --help\" for details\n validate Validate fixture files or directories offline\n Run \"aimock validate --help\" for details\n`.trim();\n\nexport interface AimockCliDeps {\n argv?: string[];\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n loadConfigFn?: typeof loadConfig;\n startFromConfigFn?: typeof startFromConfig;\n onReady?: (ctx: { shutdown: () => void }) => void;\n convertDeps?: Partial<ConvertCliDeps>;\n validateDeps?: {\n log?: (msg: string) => void;\n logError?: (msg: string) => void;\n exit?: (code: number) => void;\n };\n}\n\nexport function runAimockCli(deps: AimockCliDeps = {}): void {\n /* v8 ignore next 6 -- defaults used only when called from CLI entry point */\n const argv = deps.argv ?? process.argv.slice(2);\n const log = deps.log ?? console.log.bind(console);\n const logError = deps.logError ?? console.error.bind(console);\n const exit = deps.exit ?? process.exit.bind(process);\n const loadConfigFn = deps.loadConfigFn ?? loadConfig;\n const startFromConfigFn = deps.startFromConfigFn ?? startFromConfig;\n\n // Intercept \"convert\" subcommand before parseArgs (which uses strict mode)\n if (argv[0] === \"convert\") {\n runConvertCli({\n argv: argv.slice(1),\n log,\n logError,\n exit,\n ...deps.convertDeps,\n });\n return;\n }\n\n // Intercept \"validate\" the same way — it takes file paths, not --config.\n if (argv[0] === \"validate\") {\n runValidateCli({\n argv: argv.slice(1),\n log: deps.validateDeps?.log ?? log,\n logError: deps.validateDeps?.logError ?? logError,\n exit: deps.validateDeps?.exit ?? exit,\n });\n return;\n }\n\n // Short-flag rule for the `aimock` bin: a short flag means the same thing at\n // the top level and in every subcommand. `-h` is `--help` everywhere, which\n // is what `convert` (src/convert.ts) and `validate` (src/validate-cli.ts)\n // already did and what a reader typing `aimock -h` expects; the host\n // override is long-form `--host` only, and had no documented short use.\n // Short flags are per-bin: the separate `llmock` bin (src/cli.ts, the\n // Docker ENTRYPOINT) keeps its own documented set, where `-h` is `--host`\n // and `-c` is `--chunk-size`.\n let values;\n try {\n ({ values } = parseArgs({\n args: argv,\n options: {\n config: { type: \"string\", short: \"c\" },\n port: { type: \"string\", short: \"p\" },\n host: { type: \"string\" },\n misbehavior: { type: \"boolean\", default: false },\n \"strict-tool-arguments\": { type: \"boolean\", default: false },\n \"responses-tools\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n }));\n } catch (err) {\n /* v8 ignore next -- parseArgs always throws Error subclasses */\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Error: ${msg}\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n if (values.help) {\n log(HELP);\n exit(0);\n return;\n }\n if (values.config === undefined) {\n logError(\"Error: --config is required.\\n\\n\" + HELP);\n exit(1);\n return;\n }\n // A value-taking option that was GIVEN an empty (or blank) value is a usage\n // error, not an absent option. Testing these for truthiness instead let\n // `--config \"\"` read as \"not given\", and let `--port \"\"` / `--host \"\"` be\n // dropped in silence — `--host \"\"` in particular reached the server as an\n // empty bind address, which listens on every interface rather than on the\n // documented 127.0.0.1 default.\n const blank = (\n [\n [\"config\", values.config],\n [\"port\", values.port],\n [\"host\", values.host],\n [\"responses-tools\", values[\"responses-tools\"]],\n ] as const\n ).find(([, value]) => value !== undefined && value.trim() === \"\");\n if (blank !== undefined) {\n logError(`Error: --${blank[0]} requires a non-empty value.\\n\\n${HELP}`);\n exit(1);\n return;\n }\n\n const configPath = resolve(values.config);\n let config;\n try {\n config = loadConfigFn(configPath);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logError(`Failed to load config from ${configPath}: ${msg}`);\n exit(1);\n return;\n }\n\n const port = values.port === undefined ? undefined : Number(values.port);\n if (\n port !== undefined &&\n (Number.isNaN(port) || !Number.isInteger(port) || port < 0 || port > 65535)\n ) {\n logError(`Error: invalid port \"${values.port}\".\\n\\n${HELP}`);\n exit(1);\n return;\n }\n const host = values.host;\n const responsesToolsFlag = values[\"responses-tools\"];\n if (\n responsesToolsFlag !== undefined &&\n responsesToolsFlag !== \"legacy\" &&\n responsesToolsFlag !== \"extended\"\n ) {\n logError(\n `Error: invalid --responses-tools \"${responsesToolsFlag}\" (expected \"legacy\" or \"extended\").\\n\\n${HELP}`,\n );\n exit(1);\n return;\n }\n // The boolean opt-ins override the config only when given, so an absent flag\n // leaves llm.enableMisbehavior / llm.strictToolArguments in charge.\n const responsesTools: StartFromConfigOverrides[\"responsesTools\"] = responsesToolsFlag;\n const overrides: StartFromConfigOverrides = {\n port,\n host,\n ...(values.misbehavior ? { enableMisbehavior: true } : {}),\n ...(values[\"strict-tool-arguments\"] ? { strictToolArguments: true } : {}),\n ...(responsesTools !== undefined ? { responsesTools } : {}),\n };\n\n async function main() {\n const { llmock, url } = await startFromConfigFn(config!, overrides);\n\n function shutdown() {\n log(\"Shutting down...\");\n process.removeListener(\"SIGINT\", shutdown);\n process.removeListener(\"SIGTERM\", shutdown);\n llmock.stop().then(\n () => exit(0),\n (err) => {\n logError(`Shutdown error: ${err instanceof Error ? err.message : String(err)}`);\n exit(1);\n },\n );\n }\n // Register BEFORE announcing readiness — see the note in src/cli.ts. A supervisor\n // that reacts to the readiness line must never win a race against this listener.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n log(`aimock server listening on ${url}`);\n\n if (deps.onReady) {\n deps.onReady({ shutdown });\n }\n }\n\n main().catch((err) => {\n logError(err instanceof Error ? err.message : String(err));\n exit(1);\n });\n}\n\n// Run when executed as a script (not when imported for testing).\n/* v8 ignore start -- entry-point guard, exercised by integration tests */\n// The basenames this module is ever argv[1] under: the `aimock` bin (the\n// package.json \"bin\" name), both build outputs — tsdown.config.ts builds\n// src/aimock-cli.ts in \"esm\" AND \"cjs\" format, which under `\"type\": \"module\"`\n// emits dist/aimock-cli.js and dist/aimock-cli.cjs — and the TypeScript\n// source, run through tsx. Omitting the .cjs made `node dist/aimock-cli.cjs`\n// print nothing and exit 0 despite its shebang and exec bit.\nconst ENTRY_BASENAMES = new Set([\"aimock\", \"aimock-cli.js\", \"aimock-cli.cjs\", \"aimock-cli.ts\"]);\nconst scriptName = process.argv[1] ?? \"\";\nif (ENTRY_BASENAMES.has(basename(scriptName))) {\n runAimockCli();\n}\n/* v8 ignore stop */\n"],"mappings":"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"}