llm-mock-server 1.0.6 → 1.0.7

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 (250) hide show
  1. package/dist/cli/cli.d.ts +3 -0
  2. package/dist/cli/cli.d.ts.map +1 -0
  3. package/dist/cli/cli.js +103 -0
  4. package/dist/cli/cli.js.map +1 -0
  5. package/dist/cli/validators.d.ts +7 -0
  6. package/dist/cli/validators.d.ts.map +1 -0
  7. package/dist/cli/validators.js +53 -0
  8. package/dist/cli/validators.js.map +1 -0
  9. package/dist/formats/anthropic/index.d.ts +1 -1
  10. package/dist/formats/anthropic/index.d.ts.map +1 -1
  11. package/dist/formats/anthropic/index.js +1 -1
  12. package/dist/formats/anthropic/index.js.map +1 -1
  13. package/dist/formats/anthropic/parse.d.ts +2 -2
  14. package/dist/formats/anthropic/parse.d.ts.map +1 -1
  15. package/dist/formats/anthropic/parse.js +4 -2
  16. package/dist/formats/anthropic/parse.js.map +1 -1
  17. package/dist/formats/anthropic/schema.d.ts +1 -1
  18. package/dist/formats/anthropic/schema.d.ts.map +1 -1
  19. package/dist/formats/anthropic/schema.js +9 -4
  20. package/dist/formats/anthropic/schema.js.map +1 -1
  21. package/dist/formats/anthropic/serialize.d.ts +2 -2
  22. package/dist/formats/anthropic/serialize.d.ts.map +1 -1
  23. package/dist/formats/anthropic/serialize.js +76 -19
  24. package/dist/formats/anthropic/serialize.js.map +1 -1
  25. package/dist/formats/openai/chat-completions/index.d.ts +3 -0
  26. package/dist/formats/openai/chat-completions/index.d.ts.map +1 -0
  27. package/dist/formats/openai/chat-completions/index.js +13 -0
  28. package/dist/formats/openai/chat-completions/index.js.map +1 -0
  29. package/dist/formats/openai/chat-completions/parse.d.ts +4 -0
  30. package/dist/formats/openai/chat-completions/parse.d.ts.map +1 -0
  31. package/dist/formats/openai/chat-completions/parse.js +33 -0
  32. package/dist/formats/openai/chat-completions/parse.js.map +1 -0
  33. package/dist/formats/openai/chat-completions/schema.d.ts +93 -0
  34. package/dist/formats/openai/chat-completions/schema.d.ts.map +1 -0
  35. package/dist/formats/openai/chat-completions/schema.js +74 -0
  36. package/dist/formats/openai/chat-completions/schema.js.map +1 -0
  37. package/dist/formats/openai/chat-completions/serialize.d.ts +10 -0
  38. package/dist/formats/openai/chat-completions/serialize.d.ts.map +1 -0
  39. package/dist/formats/openai/chat-completions/serialize.js +99 -0
  40. package/dist/formats/openai/chat-completions/serialize.js.map +1 -0
  41. package/dist/formats/openai/responses/index.d.ts +3 -0
  42. package/dist/formats/openai/responses/index.d.ts.map +1 -0
  43. package/dist/formats/openai/responses/index.js +13 -0
  44. package/dist/formats/openai/responses/index.js.map +1 -0
  45. package/dist/formats/openai/responses/parse.d.ts +4 -0
  46. package/dist/formats/openai/responses/parse.d.ts.map +1 -0
  47. package/dist/formats/openai/responses/parse.js +51 -0
  48. package/dist/formats/openai/responses/parse.js.map +1 -0
  49. package/dist/formats/openai/responses/schema.d.ts +103 -0
  50. package/dist/formats/openai/responses/schema.d.ts.map +1 -0
  51. package/dist/formats/openai/responses/schema.js +71 -0
  52. package/dist/formats/openai/responses/schema.js.map +1 -0
  53. package/dist/formats/openai/responses/serialize.d.ts +10 -0
  54. package/dist/formats/openai/responses/serialize.d.ts.map +1 -0
  55. package/dist/formats/openai/responses/serialize.js +273 -0
  56. package/dist/formats/openai/responses/serialize.js.map +1 -0
  57. package/dist/formats/request-helpers.d.ts +1 -1
  58. package/dist/formats/request-helpers.d.ts.map +1 -1
  59. package/dist/formats/request-helpers.js.map +1 -1
  60. package/dist/formats/serialize-helpers.d.ts +1 -1
  61. package/dist/formats/serialize-helpers.d.ts.map +1 -1
  62. package/dist/formats/serialize-helpers.js +6 -3
  63. package/dist/formats/serialize-helpers.js.map +1 -1
  64. package/dist/formats/types.d.ts +2 -1
  65. package/dist/formats/types.d.ts.map +1 -1
  66. package/dist/history.d.ts +6 -2
  67. package/dist/history.d.ts.map +1 -1
  68. package/dist/history.js +2 -0
  69. package/dist/history.js.map +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/loader.d.ts +1 -1
  73. package/dist/loader.d.ts.map +1 -1
  74. package/dist/loader.js +26 -9
  75. package/dist/loader.js.map +1 -1
  76. package/dist/logger.d.ts.map +1 -1
  77. package/dist/logger.js +12 -4
  78. package/dist/logger.js.map +1 -1
  79. package/dist/mock-server.d.ts +44 -48
  80. package/dist/mock-server.d.ts.map +1 -1
  81. package/dist/mock-server.js +37 -85
  82. package/dist/mock-server.js.map +1 -1
  83. package/dist/route-handler.d.ts +1 -1
  84. package/dist/route-handler.d.ts.map +1 -1
  85. package/dist/route-handler.js +19 -7
  86. package/dist/route-handler.js.map +1 -1
  87. package/dist/rule-builder.d.ts +21 -0
  88. package/dist/rule-builder.d.ts.map +1 -0
  89. package/dist/rule-builder.js +58 -0
  90. package/dist/rule-builder.js.map +1 -0
  91. package/dist/rule-engine.d.ts +3 -1
  92. package/dist/rule-engine.d.ts.map +1 -1
  93. package/dist/rule-engine.js +7 -2
  94. package/dist/rule-engine.js.map +1 -1
  95. package/dist/sse-writer.d.ts +1 -1
  96. package/dist/sse-writer.d.ts.map +1 -1
  97. package/dist/types/reply.d.ts +51 -8
  98. package/dist/types/reply.d.ts.map +1 -1
  99. package/dist/types/request.d.ts +21 -6
  100. package/dist/types/request.d.ts.map +1 -1
  101. package/dist/types/rule.d.ts +65 -7
  102. package/dist/types/rule.d.ts.map +1 -1
  103. package/dist/types.d.ts +3 -3
  104. package/dist/types.d.ts.map +1 -1
  105. package/package.json +15 -9
  106. package/.claude/skills/desloppify/SKILL.md +0 -308
  107. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000801.json +0 -242
  108. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000905.json +0 -248
  109. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000917.json +0 -248
  110. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000950.json +0 -311
  111. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/claude_launch_prompt.md +0 -17
  112. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.json +0 -255
  113. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.template.json +0 -22
  114. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/reviewer_instructions.md +0 -20
  115. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/session.json +0 -20
  116. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/canonical_import_20260315_050000.json +0 -286
  117. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/canonical_import_20260315_050028.json +0 -303
  118. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/claude_launch_prompt.md +0 -17
  119. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/review_result.json +0 -297
  120. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/review_result.template.json +0 -22
  121. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/reviewer_instructions.md +0 -20
  122. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/session.json +0 -20
  123. package/.desloppify/query.json +0 -1312
  124. package/.desloppify/review_packet_blind.json +0 -1249
  125. package/.desloppify/review_packets/holistic_packet_20260315_000339.json +0 -1471
  126. package/.desloppify/review_packets/holistic_packet_20260315_045546.json +0 -1480
  127. package/.desloppify/review_packets/holistic_packet_20260315_185401.json +0 -1407
  128. package/.desloppify/review_packets/holistic_packet_20260315_185613.json +0 -1407
  129. package/.desloppify/state-typescript.json +0 -8438
  130. package/.desloppify/state-typescript.json.bak +0 -8432
  131. package/.desloppify/subagents/runs/20260315_185401/logs/batch-1.log +0 -384
  132. package/.desloppify/subagents/runs/20260315_185401/logs/batch-10.log +0 -484
  133. package/.desloppify/subagents/runs/20260315_185401/logs/batch-2.log +0 -408
  134. package/.desloppify/subagents/runs/20260315_185401/logs/batch-3.log +0 -416
  135. package/.desloppify/subagents/runs/20260315_185401/logs/batch-4.log +0 -360
  136. package/.desloppify/subagents/runs/20260315_185401/logs/batch-5.log +0 -360
  137. package/.desloppify/subagents/runs/20260315_185401/logs/batch-6.log +0 -364
  138. package/.desloppify/subagents/runs/20260315_185401/logs/batch-7.log +0 -428
  139. package/.desloppify/subagents/runs/20260315_185401/logs/batch-8.log +0 -388
  140. package/.desloppify/subagents/runs/20260315_185401/logs/batch-9.log +0 -500
  141. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-1.md +0 -83
  142. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-10.md +0 -108
  143. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-2.md +0 -89
  144. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-3.md +0 -91
  145. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-4.md +0 -77
  146. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-5.md +0 -77
  147. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-6.md +0 -78
  148. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-7.md +0 -94
  149. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-8.md +0 -84
  150. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-9.md +0 -112
  151. package/.desloppify/subagents/runs/20260315_185401/results/batch-1.raw.txt +0 -0
  152. package/.desloppify/subagents/runs/20260315_185401/results/batch-10.raw.txt +0 -0
  153. package/.desloppify/subagents/runs/20260315_185401/results/batch-2.raw.txt +0 -0
  154. package/.desloppify/subagents/runs/20260315_185401/results/batch-3.raw.txt +0 -0
  155. package/.desloppify/subagents/runs/20260315_185401/results/batch-4.raw.txt +0 -0
  156. package/.desloppify/subagents/runs/20260315_185401/results/batch-5.raw.txt +0 -0
  157. package/.desloppify/subagents/runs/20260315_185401/results/batch-6.raw.txt +0 -0
  158. package/.desloppify/subagents/runs/20260315_185401/results/batch-7.raw.txt +0 -0
  159. package/.desloppify/subagents/runs/20260315_185401/results/batch-8.raw.txt +0 -0
  160. package/.desloppify/subagents/runs/20260315_185401/results/batch-9.raw.txt +0 -0
  161. package/.desloppify/subagents/runs/20260315_185401/run.log +0 -36
  162. package/.desloppify/subagents/runs/20260315_185401/run_summary.json +0 -156
  163. package/.desloppify/subagents/runs/20260315_185613/holistic_findings_merged.json +0 -741
  164. package/.desloppify/subagents/runs/20260315_185613/logs/batch-1.log +0 -579
  165. package/.desloppify/subagents/runs/20260315_185613/logs/batch-10.log +0 -1537
  166. package/.desloppify/subagents/runs/20260315_185613/logs/batch-2.log +0 -829
  167. package/.desloppify/subagents/runs/20260315_185613/logs/batch-3.log +0 -927
  168. package/.desloppify/subagents/runs/20260315_185613/logs/batch-4.log +0 -429
  169. package/.desloppify/subagents/runs/20260315_185613/logs/batch-5.log +0 -276
  170. package/.desloppify/subagents/runs/20260315_185613/logs/batch-6.log +0 -450
  171. package/.desloppify/subagents/runs/20260315_185613/logs/batch-7.log +0 -730
  172. package/.desloppify/subagents/runs/20260315_185613/logs/batch-8.log +0 -698
  173. package/.desloppify/subagents/runs/20260315_185613/logs/batch-9.log +0 -938
  174. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-1.md +0 -83
  175. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-10.md +0 -108
  176. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-2.md +0 -89
  177. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-3.md +0 -91
  178. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-4.md +0 -77
  179. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-5.md +0 -77
  180. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-6.md +0 -78
  181. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-7.md +0 -94
  182. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-8.md +0 -84
  183. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-9.md +0 -112
  184. package/.desloppify/subagents/runs/20260315_185613/results/batch-1.raw.txt +0 -78
  185. package/.desloppify/subagents/runs/20260315_185613/results/batch-10.raw.txt +0 -242
  186. package/.desloppify/subagents/runs/20260315_185613/results/batch-2.raw.txt +0 -102
  187. package/.desloppify/subagents/runs/20260315_185613/results/batch-3.raw.txt +0 -94
  188. package/.desloppify/subagents/runs/20260315_185613/results/batch-4.raw.txt +0 -86
  189. package/.desloppify/subagents/runs/20260315_185613/results/batch-5.raw.txt +0 -1
  190. package/.desloppify/subagents/runs/20260315_185613/results/batch-6.raw.txt +0 -87
  191. package/.desloppify/subagents/runs/20260315_185613/results/batch-7.raw.txt +0 -1
  192. package/.desloppify/subagents/runs/20260315_185613/results/batch-8.raw.txt +0 -107
  193. package/.desloppify/subagents/runs/20260315_185613/results/batch-9.raw.txt +0 -67
  194. package/.desloppify/subagents/runs/20260315_185613/run.log +0 -96
  195. package/.desloppify/subagents/runs/20260315_185613/run_summary.json +0 -156
  196. package/.editorconfig +0 -12
  197. package/.github/dependabot.yml +0 -11
  198. package/.github/workflows/docs.yml +0 -46
  199. package/.github/workflows/test.yml +0 -40
  200. package/.markdownlint.jsonc +0 -11
  201. package/.node-version +0 -1
  202. package/.oxfmtrc.json +0 -9
  203. package/.oxlintrc.json +0 -35
  204. package/docs/ARCHITECTURE.md +0 -125
  205. package/scorecard.png +0 -0
  206. package/src/cli/cli.ts +0 -141
  207. package/src/cli/validators.ts +0 -68
  208. package/src/formats/anthropic/index.ts +0 -14
  209. package/src/formats/anthropic/parse.ts +0 -70
  210. package/src/formats/anthropic/schema.ts +0 -74
  211. package/src/formats/anthropic/serialize.ts +0 -179
  212. package/src/formats/openai/chat-completions/index.ts +0 -14
  213. package/src/formats/openai/chat-completions/parse.ts +0 -47
  214. package/src/formats/openai/chat-completions/schema.ts +0 -92
  215. package/src/formats/openai/chat-completions/serialize.ts +0 -146
  216. package/src/formats/openai/responses/index.ts +0 -14
  217. package/src/formats/openai/responses/parse.ts +0 -73
  218. package/src/formats/openai/responses/schema.ts +0 -86
  219. package/src/formats/openai/responses/serialize.ts +0 -328
  220. package/src/formats/request-helpers.ts +0 -56
  221. package/src/formats/serialize-helpers.ts +0 -43
  222. package/src/formats/types.ts +0 -26
  223. package/src/history.ts +0 -70
  224. package/src/index.ts +0 -46
  225. package/src/loader.ts +0 -246
  226. package/src/logger.ts +0 -70
  227. package/src/mock-server.ts +0 -203
  228. package/src/route-handler.ts +0 -144
  229. package/src/rule-builder.ts +0 -73
  230. package/src/rule-engine.ts +0 -165
  231. package/src/sse-writer.ts +0 -35
  232. package/src/types/reply.ts +0 -92
  233. package/src/types/request.ts +0 -56
  234. package/src/types/rule.ts +0 -125
  235. package/src/types.ts +0 -24
  236. package/test/cli-validators.test.ts +0 -151
  237. package/test/formats/anthropic.test.ts +0 -336
  238. package/test/formats/openai.test.ts +0 -316
  239. package/test/formats/parse-helpers.test.ts +0 -315
  240. package/test/formats/responses.test.ts +0 -380
  241. package/test/helpers/make-req.ts +0 -18
  242. package/test/history.test.ts +0 -361
  243. package/test/loader.test.ts +0 -333
  244. package/test/logger.test.ts +0 -344
  245. package/test/mock-server.test.ts +0 -619
  246. package/test/rule-engine.test.ts +0 -229
  247. package/tsconfig.json +0 -24
  248. package/tsconfig.test.json +0 -11
  249. package/typedoc.json +0 -9
  250. package/vitest.config.ts +0 -18
@@ -1,380 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { responsesFormat } from "../../src/formats/openai/responses/index.js";
3
- import type {
4
- ResponsesEvent,
5
- ResponsesComplete,
6
- ResponsesError,
7
- } from "../../src/formats/openai/responses/schema.js";
8
-
9
- function parse<T>(chunk: { data: string }): T {
10
- return JSON.parse(chunk.data) as T;
11
- }
12
-
13
- describe("Responses Format", () => {
14
- describe("parseRequest", () => {
15
- it("parses string input", () => {
16
- const req = responsesFormat.parseRequest({
17
- model: "codex-mini",
18
- input: "Hello world",
19
- });
20
- expect(req.format).toBe("responses");
21
- expect(req.model).toBe("codex-mini");
22
- expect(req.lastMessage).toBe("Hello world");
23
- });
24
-
25
- it("parses array input with items", () => {
26
- const req = responsesFormat.parseRequest({
27
- model: "codex-mini",
28
- input: [
29
- { role: "user", content: "Hello" },
30
- { role: "assistant", content: "Hi" },
31
- { role: "user", content: "How are you?" },
32
- ],
33
- });
34
- expect(req.lastMessage).toBe("How are you?");
35
- expect(req.messages).toHaveLength(3);
36
- });
37
-
38
- it("parses instructions as system message", () => {
39
- const req = responsesFormat.parseRequest({
40
- model: "codex-mini",
41
- input: "Hello",
42
- instructions: "You are a helpful assistant",
43
- });
44
- expect(req.systemMessage).toBe("You are a helpful assistant");
45
- });
46
-
47
- it("parses content block arrays", () => {
48
- const req = responsesFormat.parseRequest({
49
- model: "codex-mini",
50
- input: [
51
- {
52
- role: "user",
53
- content: [{ type: "input_text", text: "Hello there" }],
54
- },
55
- ],
56
- });
57
- expect(req.lastMessage).toBe("Hello there");
58
- });
59
-
60
- it("parses tools", () => {
61
- const req = responsesFormat.parseRequest({
62
- model: "codex-mini",
63
- input: "read file",
64
- tools: [
65
- {
66
- type: "function",
67
- name: "read_file",
68
- description: "Read",
69
- parameters: {},
70
- },
71
- ],
72
- });
73
- expect(req.tools).toHaveLength(1);
74
- expect(req.toolNames).toEqual(["read_file"]);
75
- });
76
-
77
- it("extracts lastToolCallId from function_call_output items", () => {
78
- const req = responsesFormat.parseRequest({
79
- model: "codex-mini",
80
- input: [
81
- { role: "user", content: "hi" },
82
- {
83
- type: "function_call_output",
84
- call_id: "call_abc",
85
- output: "result",
86
- },
87
- ],
88
- });
89
- expect(req.lastToolCallId).toBe("call_abc");
90
- });
91
-
92
- it("handles content blocks with non-text types (image, etc.)", () => {
93
- const req = responsesFormat.parseRequest({
94
- model: "codex-mini",
95
- input: [
96
- {
97
- role: "user",
98
- content: [
99
- { type: "image_url", url: "https://example.com/img.png" },
100
- { type: "input_text", text: "describe this" },
101
- ],
102
- },
103
- ],
104
- });
105
- expect(req.lastMessage).toBe("describe this");
106
- });
107
-
108
- it("accepts requests with only instructions (no input)", () => {
109
- const req = responsesFormat.parseRequest({
110
- model: "codex-mini",
111
- instructions: "You are helpful",
112
- });
113
- expect(req.systemMessage).toBe("You are helpful");
114
- expect(req.lastMessage).toBe("");
115
- });
116
-
117
- it("parses function tools without description", () => {
118
- const req = responsesFormat.parseRequest({
119
- model: "codex-mini",
120
- input: "hi",
121
- tools: [{ type: "function", name: "run_code" }],
122
- });
123
- expect(req.tools![0]!.name).toBe("run_code");
124
- expect(req.tools![0]!.description).toBeUndefined();
125
- });
126
-
127
- it("filters out non-function tools", () => {
128
- const req = responsesFormat.parseRequest({
129
- model: "codex-mini",
130
- input: "hi",
131
- tools: [{ type: "function", name: "run_code" }, { type: "web_search" }],
132
- });
133
- expect(req.tools).toHaveLength(1);
134
- expect(req.tools![0]!.name).toBe("run_code");
135
- });
136
- });
137
-
138
- describe("serialize (streaming)", () => {
139
- it("starts with response.created and response.in_progress", () => {
140
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
141
- expect(parse<ResponsesEvent>(chunks[0]!).type).toBe("response.created");
142
- expect(parse<ResponsesEvent>(chunks[1]!).type).toBe(
143
- "response.in_progress",
144
- );
145
- });
146
-
147
- it("ends with response.completed", () => {
148
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
149
- expect(parse<ResponsesEvent>(chunks.at(-1)!).type).toBe(
150
- "response.completed",
151
- );
152
- });
153
-
154
- it("assigns incrementing sequence_number to every event", () => {
155
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
156
- const seqNumbers = chunks.map(
157
- (c) => parse<ResponsesEvent>(c).sequence_number!,
158
- );
159
- for (let i = 1; i < seqNumbers.length; i++) {
160
- expect(seqNumbers[i]).toBe(seqNumbers[i - 1]! + 1);
161
- }
162
- expect(seqNumbers[0]).toBe(0);
163
- });
164
-
165
- it("uses same created_at across created, in_progress, and completed envelopes", () => {
166
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
167
- const created = parse<ResponsesEvent>(chunks[0]!).response?.created_at;
168
- const inProgress = parse<ResponsesEvent>(chunks[1]!).response?.created_at;
169
- const completed = parse<ResponsesEvent>(chunks.at(-1)!).response
170
- ?.created_at;
171
- expect(created).toBe(inProgress);
172
- expect(created).toBe(completed);
173
- });
174
-
175
- it("produces text delta events with item_id", () => {
176
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
177
- const delta = chunks.find(
178
- (c) => parse<ResponsesEvent>(c).type === "response.output_text.delta",
179
- );
180
- expect(delta).toBeDefined();
181
- const data = parse<ResponsesEvent>(delta!);
182
- expect(data.delta).toBe("Hello");
183
- expect(data.item_id).toBeTypeOf("string");
184
- });
185
-
186
- it("output items have status: in_progress when added, completed when done", () => {
187
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
188
- const added = chunks.find((c) => {
189
- const d = parse<ResponsesEvent>(c);
190
- return (
191
- d.type === "response.output_item.added" && d.item?.type === "message"
192
- );
193
- });
194
- expect(parse<ResponsesEvent>(added!).item?.status).toBe("in_progress");
195
-
196
- const done = chunks.find((c) => {
197
- const d = parse<ResponsesEvent>(c);
198
- return (
199
- d.type === "response.output_item.done" && d.item?.type === "message"
200
- );
201
- });
202
- expect(parse<ResponsesEvent>(done!).item?.status).toBe("completed");
203
- });
204
-
205
- it("includes annotations on output_text parts", () => {
206
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
207
- const partAdded = chunks.find(
208
- (c) => parse<ResponsesEvent>(c).type === "response.content_part.added",
209
- );
210
- expect(parse<ResponsesEvent>(partAdded!).part?.annotations).toEqual([]);
211
- });
212
-
213
- it("includes content_part.done event with full text", () => {
214
- const chunks = responsesFormat.serialize({ text: "Hello" }, "codex-mini");
215
- const partDone = chunks.find(
216
- (c) => parse<ResponsesEvent>(c).type === "response.content_part.done",
217
- );
218
- expect(partDone).toBeDefined();
219
- expect(parse<ResponsesEvent>(partDone!).part?.text).toBe("Hello");
220
- });
221
-
222
- it("emits reasoning events before message events", () => {
223
- const chunks = responsesFormat.serialize(
224
- { text: "42", reasoning: "Let me think..." },
225
- "codex-mini",
226
- );
227
- const types = chunks.map((c) => parse<ResponsesEvent>(c).type);
228
-
229
- expect(types).toContain("response.reasoning_summary_part.added");
230
- expect(types).toContain("response.reasoning_summary_text.delta");
231
- expect(types).toContain("response.reasoning_summary_text.done");
232
- expect(types).toContain("response.reasoning_summary_part.done");
233
-
234
- const reasoningDone = types.indexOf(
235
- "response.reasoning_summary_text.done",
236
- );
237
- const textDelta = types.indexOf("response.output_text.delta");
238
- expect(reasoningDone).toBeLessThan(textDelta);
239
- });
240
-
241
- it("includes reasoning output item in completed response", () => {
242
- const chunks = responsesFormat.serialize(
243
- { text: "42", reasoning: "Let me think" },
244
- "codex-mini",
245
- );
246
- const completed = parse<ResponsesEvent>(chunks.at(-1)!);
247
- expect(completed.response?.output[0]!.type).toBe("reasoning");
248
- expect(completed.response?.output[1]!.type).toBe("message");
249
- });
250
-
251
- it("accumulates text in completed output", () => {
252
- const chunks = responsesFormat.serialize(
253
- { text: "hello world" },
254
- "codex-mini",
255
- );
256
- const completed = parse<ResponsesEvent>(chunks.at(-1)!);
257
- expect(completed.response?.output[0]!.content?.[0]?.text).toBe(
258
- "hello world",
259
- );
260
- });
261
-
262
- it("produces function_call events for tool calls", () => {
263
- const chunks = responsesFormat.serialize(
264
- { tools: [{ name: "read_file", args: { path: "/tmp" } }] },
265
- "codex-mini",
266
- );
267
- const fnAdded = chunks.find((c) => {
268
- const d = parse<ResponsesEvent>(c);
269
- return (
270
- d.type === "response.output_item.added" &&
271
- d.item?.type === "function_call"
272
- );
273
- });
274
- expect(fnAdded).toBeDefined();
275
- const item = parse<ResponsesEvent>(fnAdded!).item!;
276
- expect(item.name).toBe("read_file");
277
- expect(item.status).toBe("in_progress");
278
- });
279
-
280
- it("no named events (responses uses data-only SSE)", () => {
281
- const chunks = responsesFormat.serialize({ text: "hi" }, "codex-mini");
282
- for (const chunk of chunks) {
283
- expect(chunk.event).toBeUndefined();
284
- }
285
- });
286
-
287
- it("works without reasoning events", () => {
288
- const chunks = responsesFormat.serialize({ text: "hello" }, "codex-mini");
289
- const completed = parse<ResponsesEvent>(chunks.at(-1)!);
290
- expect(completed.response?.output).toHaveLength(1);
291
- expect(completed.response?.output[0]!.type).toBe("message");
292
- });
293
- });
294
-
295
- describe("serializeComplete (non-streaming)", () => {
296
- it("produces correct top-level structure", () => {
297
- const result = responsesFormat.serializeComplete(
298
- { text: "Hello" },
299
- "codex-mini",
300
- ) as ResponsesComplete;
301
- expect(result.object).toBe("response");
302
- expect(result.status).toBe("completed");
303
- expect(result.model).toBe("codex-mini");
304
- expect(result.created_at).toBeTypeOf("number");
305
- });
306
-
307
- it("includes message output item with status and annotations", () => {
308
- const result = responsesFormat.serializeComplete(
309
- { text: "Hello, world!" },
310
- "codex-mini",
311
- ) as ResponsesComplete;
312
- const msg = result.output[0]!;
313
- expect(msg.type).toBe("message");
314
- expect(msg.status).toBe("completed");
315
- expect(msg.role).toBe("assistant");
316
- expect(msg.content?.[0]?.type).toBe("output_text");
317
- expect(msg.content?.[0]?.text).toBe("Hello, world!");
318
- expect(msg.content?.[0]?.annotations).toEqual([]);
319
- });
320
-
321
- it("includes reasoning before message in output", () => {
322
- const result = responsesFormat.serializeComplete(
323
- { text: "42", reasoning: "Thinking..." },
324
- "codex-mini",
325
- ) as ResponsesComplete;
326
- expect(result.output[0]!.type).toBe("reasoning");
327
- expect(result.output[1]!.type).toBe("message");
328
- });
329
-
330
- it("includes function_call in output for tool calls", () => {
331
- const result = responsesFormat.serializeComplete(
332
- { tools: [{ name: "read_file", args: { path: "/tmp" } }] },
333
- "codex-mini",
334
- ) as ResponsesComplete;
335
- const fnCall = result.output.find((o) => o.type === "function_call");
336
- if (!fnCall) throw new Error("expected function_call output");
337
- expect(fnCall.name).toBe("read_file");
338
- expect(fnCall.status).toBe("completed");
339
- expect(fnCall.call_id).toBeTypeOf("string");
340
- });
341
-
342
- it("generates unique IDs for multiple tools", () => {
343
- const result = responsesFormat.serializeComplete(
344
- {
345
- tools: [
346
- { name: "read_file", args: { path: "/a" } },
347
- { name: "write_file", args: { path: "/b" } },
348
- ],
349
- },
350
- "codex-mini",
351
- ) as ResponsesComplete;
352
- const calls = result.output.filter((o) => o.type === "function_call");
353
- if (calls.length !== 2)
354
- throw new Error("expected 2 function_call outputs");
355
- expect(calls[0].call_id).not.toBe(calls[1].call_id);
356
- });
357
-
358
- it("includes usage tokens", () => {
359
- const result = responsesFormat.serializeComplete(
360
- { text: "hi", usage: { input: 20, output: 15 } },
361
- "codex-mini",
362
- ) as ResponsesComplete;
363
- expect(result.usage).toEqual({
364
- input_tokens: 20,
365
- output_tokens: 15,
366
- total_tokens: 35,
367
- });
368
- });
369
- });
370
-
371
- describe("serializeError", () => {
372
- it("produces Responses error format", () => {
373
- const result = responsesFormat.serializeError({
374
- status: 500,
375
- message: "Internal error",
376
- }) as ResponsesError;
377
- expect(result.error.message).toBe("Internal error");
378
- });
379
- });
380
- });
@@ -1,18 +0,0 @@
1
- import type { MockRequest } from "../../src/types.js";
2
-
3
- export function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
4
- return {
5
- format: "openai",
6
- model: "gpt-5.4",
7
- streaming: true,
8
- messages: [{ role: "user", content: "hello" }],
9
- lastMessage: "hello",
10
- systemMessage: "",
11
- toolNames: [],
12
- lastToolCallId: undefined,
13
- raw: {},
14
- headers: {},
15
- path: "/v1/chat/completions",
16
- ...overrides,
17
- };
18
- }