llm-mock-server 1.0.6 → 1.0.8

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 (251) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/cli.d.ts +3 -0
  3. package/dist/cli/cli.d.ts.map +1 -0
  4. package/dist/cli/cli.js +103 -0
  5. package/dist/cli/cli.js.map +1 -0
  6. package/dist/cli/validators.d.ts +7 -0
  7. package/dist/cli/validators.d.ts.map +1 -0
  8. package/dist/cli/validators.js +53 -0
  9. package/dist/cli/validators.js.map +1 -0
  10. package/dist/formats/anthropic/index.d.ts +1 -1
  11. package/dist/formats/anthropic/index.d.ts.map +1 -1
  12. package/dist/formats/anthropic/index.js +1 -1
  13. package/dist/formats/anthropic/index.js.map +1 -1
  14. package/dist/formats/anthropic/parse.d.ts +2 -2
  15. package/dist/formats/anthropic/parse.d.ts.map +1 -1
  16. package/dist/formats/anthropic/parse.js +4 -2
  17. package/dist/formats/anthropic/parse.js.map +1 -1
  18. package/dist/formats/anthropic/schema.d.ts +1 -1
  19. package/dist/formats/anthropic/schema.d.ts.map +1 -1
  20. package/dist/formats/anthropic/schema.js +9 -4
  21. package/dist/formats/anthropic/schema.js.map +1 -1
  22. package/dist/formats/anthropic/serialize.d.ts +2 -2
  23. package/dist/formats/anthropic/serialize.d.ts.map +1 -1
  24. package/dist/formats/anthropic/serialize.js +76 -19
  25. package/dist/formats/anthropic/serialize.js.map +1 -1
  26. package/dist/formats/openai/chat-completions/index.d.ts +3 -0
  27. package/dist/formats/openai/chat-completions/index.d.ts.map +1 -0
  28. package/dist/formats/openai/chat-completions/index.js +13 -0
  29. package/dist/formats/openai/chat-completions/index.js.map +1 -0
  30. package/dist/formats/openai/chat-completions/parse.d.ts +4 -0
  31. package/dist/formats/openai/chat-completions/parse.d.ts.map +1 -0
  32. package/dist/formats/openai/chat-completions/parse.js +33 -0
  33. package/dist/formats/openai/chat-completions/parse.js.map +1 -0
  34. package/dist/formats/openai/chat-completions/schema.d.ts +93 -0
  35. package/dist/formats/openai/chat-completions/schema.d.ts.map +1 -0
  36. package/dist/formats/openai/chat-completions/schema.js +74 -0
  37. package/dist/formats/openai/chat-completions/schema.js.map +1 -0
  38. package/dist/formats/openai/chat-completions/serialize.d.ts +10 -0
  39. package/dist/formats/openai/chat-completions/serialize.d.ts.map +1 -0
  40. package/dist/formats/openai/chat-completions/serialize.js +99 -0
  41. package/dist/formats/openai/chat-completions/serialize.js.map +1 -0
  42. package/dist/formats/openai/responses/index.d.ts +3 -0
  43. package/dist/formats/openai/responses/index.d.ts.map +1 -0
  44. package/dist/formats/openai/responses/index.js +13 -0
  45. package/dist/formats/openai/responses/index.js.map +1 -0
  46. package/dist/formats/openai/responses/parse.d.ts +4 -0
  47. package/dist/formats/openai/responses/parse.d.ts.map +1 -0
  48. package/dist/formats/openai/responses/parse.js +51 -0
  49. package/dist/formats/openai/responses/parse.js.map +1 -0
  50. package/dist/formats/openai/responses/schema.d.ts +103 -0
  51. package/dist/formats/openai/responses/schema.d.ts.map +1 -0
  52. package/dist/formats/openai/responses/schema.js +71 -0
  53. package/dist/formats/openai/responses/schema.js.map +1 -0
  54. package/dist/formats/openai/responses/serialize.d.ts +10 -0
  55. package/dist/formats/openai/responses/serialize.d.ts.map +1 -0
  56. package/dist/formats/openai/responses/serialize.js +273 -0
  57. package/dist/formats/openai/responses/serialize.js.map +1 -0
  58. package/dist/formats/request-helpers.d.ts +1 -1
  59. package/dist/formats/request-helpers.d.ts.map +1 -1
  60. package/dist/formats/request-helpers.js.map +1 -1
  61. package/dist/formats/serialize-helpers.d.ts +1 -1
  62. package/dist/formats/serialize-helpers.d.ts.map +1 -1
  63. package/dist/formats/serialize-helpers.js +6 -3
  64. package/dist/formats/serialize-helpers.js.map +1 -1
  65. package/dist/formats/types.d.ts +2 -1
  66. package/dist/formats/types.d.ts.map +1 -1
  67. package/dist/history.d.ts +6 -2
  68. package/dist/history.d.ts.map +1 -1
  69. package/dist/history.js +2 -0
  70. package/dist/history.js.map +1 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/loader.d.ts +1 -1
  74. package/dist/loader.d.ts.map +1 -1
  75. package/dist/loader.js +26 -9
  76. package/dist/loader.js.map +1 -1
  77. package/dist/logger.d.ts.map +1 -1
  78. package/dist/logger.js +12 -4
  79. package/dist/logger.js.map +1 -1
  80. package/dist/mock-server.d.ts +44 -48
  81. package/dist/mock-server.d.ts.map +1 -1
  82. package/dist/mock-server.js +37 -85
  83. package/dist/mock-server.js.map +1 -1
  84. package/dist/route-handler.d.ts +1 -1
  85. package/dist/route-handler.d.ts.map +1 -1
  86. package/dist/route-handler.js +19 -7
  87. package/dist/route-handler.js.map +1 -1
  88. package/dist/rule-builder.d.ts +21 -0
  89. package/dist/rule-builder.d.ts.map +1 -0
  90. package/dist/rule-builder.js +58 -0
  91. package/dist/rule-builder.js.map +1 -0
  92. package/dist/rule-engine.d.ts +3 -1
  93. package/dist/rule-engine.d.ts.map +1 -1
  94. package/dist/rule-engine.js +7 -2
  95. package/dist/rule-engine.js.map +1 -1
  96. package/dist/sse-writer.d.ts +1 -1
  97. package/dist/sse-writer.d.ts.map +1 -1
  98. package/dist/types/reply.d.ts +51 -8
  99. package/dist/types/reply.d.ts.map +1 -1
  100. package/dist/types/request.d.ts +21 -6
  101. package/dist/types/request.d.ts.map +1 -1
  102. package/dist/types/rule.d.ts +65 -7
  103. package/dist/types/rule.d.ts.map +1 -1
  104. package/dist/types.d.ts +3 -3
  105. package/dist/types.d.ts.map +1 -1
  106. package/package.json +15 -9
  107. package/.claude/skills/desloppify/SKILL.md +0 -308
  108. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000801.json +0 -242
  109. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000905.json +0 -248
  110. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000917.json +0 -248
  111. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000950.json +0 -311
  112. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/claude_launch_prompt.md +0 -17
  113. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.json +0 -255
  114. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.template.json +0 -22
  115. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/reviewer_instructions.md +0 -20
  116. package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/session.json +0 -20
  117. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/canonical_import_20260315_050000.json +0 -286
  118. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/canonical_import_20260315_050028.json +0 -303
  119. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/claude_launch_prompt.md +0 -17
  120. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/review_result.json +0 -297
  121. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/review_result.template.json +0 -22
  122. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/reviewer_instructions.md +0 -20
  123. package/.desloppify/external_review_sessions/ext_20260315_045546_0587ea3b/session.json +0 -20
  124. package/.desloppify/query.json +0 -1312
  125. package/.desloppify/review_packet_blind.json +0 -1249
  126. package/.desloppify/review_packets/holistic_packet_20260315_000339.json +0 -1471
  127. package/.desloppify/review_packets/holistic_packet_20260315_045546.json +0 -1480
  128. package/.desloppify/review_packets/holistic_packet_20260315_185401.json +0 -1407
  129. package/.desloppify/review_packets/holistic_packet_20260315_185613.json +0 -1407
  130. package/.desloppify/state-typescript.json +0 -8438
  131. package/.desloppify/state-typescript.json.bak +0 -8432
  132. package/.desloppify/subagents/runs/20260315_185401/logs/batch-1.log +0 -384
  133. package/.desloppify/subagents/runs/20260315_185401/logs/batch-10.log +0 -484
  134. package/.desloppify/subagents/runs/20260315_185401/logs/batch-2.log +0 -408
  135. package/.desloppify/subagents/runs/20260315_185401/logs/batch-3.log +0 -416
  136. package/.desloppify/subagents/runs/20260315_185401/logs/batch-4.log +0 -360
  137. package/.desloppify/subagents/runs/20260315_185401/logs/batch-5.log +0 -360
  138. package/.desloppify/subagents/runs/20260315_185401/logs/batch-6.log +0 -364
  139. package/.desloppify/subagents/runs/20260315_185401/logs/batch-7.log +0 -428
  140. package/.desloppify/subagents/runs/20260315_185401/logs/batch-8.log +0 -388
  141. package/.desloppify/subagents/runs/20260315_185401/logs/batch-9.log +0 -500
  142. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-1.md +0 -83
  143. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-10.md +0 -108
  144. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-2.md +0 -89
  145. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-3.md +0 -91
  146. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-4.md +0 -77
  147. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-5.md +0 -77
  148. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-6.md +0 -78
  149. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-7.md +0 -94
  150. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-8.md +0 -84
  151. package/.desloppify/subagents/runs/20260315_185401/prompts/batch-9.md +0 -112
  152. package/.desloppify/subagents/runs/20260315_185401/results/batch-1.raw.txt +0 -0
  153. package/.desloppify/subagents/runs/20260315_185401/results/batch-10.raw.txt +0 -0
  154. package/.desloppify/subagents/runs/20260315_185401/results/batch-2.raw.txt +0 -0
  155. package/.desloppify/subagents/runs/20260315_185401/results/batch-3.raw.txt +0 -0
  156. package/.desloppify/subagents/runs/20260315_185401/results/batch-4.raw.txt +0 -0
  157. package/.desloppify/subagents/runs/20260315_185401/results/batch-5.raw.txt +0 -0
  158. package/.desloppify/subagents/runs/20260315_185401/results/batch-6.raw.txt +0 -0
  159. package/.desloppify/subagents/runs/20260315_185401/results/batch-7.raw.txt +0 -0
  160. package/.desloppify/subagents/runs/20260315_185401/results/batch-8.raw.txt +0 -0
  161. package/.desloppify/subagents/runs/20260315_185401/results/batch-9.raw.txt +0 -0
  162. package/.desloppify/subagents/runs/20260315_185401/run.log +0 -36
  163. package/.desloppify/subagents/runs/20260315_185401/run_summary.json +0 -156
  164. package/.desloppify/subagents/runs/20260315_185613/holistic_findings_merged.json +0 -741
  165. package/.desloppify/subagents/runs/20260315_185613/logs/batch-1.log +0 -579
  166. package/.desloppify/subagents/runs/20260315_185613/logs/batch-10.log +0 -1537
  167. package/.desloppify/subagents/runs/20260315_185613/logs/batch-2.log +0 -829
  168. package/.desloppify/subagents/runs/20260315_185613/logs/batch-3.log +0 -927
  169. package/.desloppify/subagents/runs/20260315_185613/logs/batch-4.log +0 -429
  170. package/.desloppify/subagents/runs/20260315_185613/logs/batch-5.log +0 -276
  171. package/.desloppify/subagents/runs/20260315_185613/logs/batch-6.log +0 -450
  172. package/.desloppify/subagents/runs/20260315_185613/logs/batch-7.log +0 -730
  173. package/.desloppify/subagents/runs/20260315_185613/logs/batch-8.log +0 -698
  174. package/.desloppify/subagents/runs/20260315_185613/logs/batch-9.log +0 -938
  175. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-1.md +0 -83
  176. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-10.md +0 -108
  177. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-2.md +0 -89
  178. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-3.md +0 -91
  179. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-4.md +0 -77
  180. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-5.md +0 -77
  181. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-6.md +0 -78
  182. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-7.md +0 -94
  183. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-8.md +0 -84
  184. package/.desloppify/subagents/runs/20260315_185613/prompts/batch-9.md +0 -112
  185. package/.desloppify/subagents/runs/20260315_185613/results/batch-1.raw.txt +0 -78
  186. package/.desloppify/subagents/runs/20260315_185613/results/batch-10.raw.txt +0 -242
  187. package/.desloppify/subagents/runs/20260315_185613/results/batch-2.raw.txt +0 -102
  188. package/.desloppify/subagents/runs/20260315_185613/results/batch-3.raw.txt +0 -94
  189. package/.desloppify/subagents/runs/20260315_185613/results/batch-4.raw.txt +0 -86
  190. package/.desloppify/subagents/runs/20260315_185613/results/batch-5.raw.txt +0 -1
  191. package/.desloppify/subagents/runs/20260315_185613/results/batch-6.raw.txt +0 -87
  192. package/.desloppify/subagents/runs/20260315_185613/results/batch-7.raw.txt +0 -1
  193. package/.desloppify/subagents/runs/20260315_185613/results/batch-8.raw.txt +0 -107
  194. package/.desloppify/subagents/runs/20260315_185613/results/batch-9.raw.txt +0 -67
  195. package/.desloppify/subagents/runs/20260315_185613/run.log +0 -96
  196. package/.desloppify/subagents/runs/20260315_185613/run_summary.json +0 -156
  197. package/.editorconfig +0 -12
  198. package/.github/dependabot.yml +0 -11
  199. package/.github/workflows/docs.yml +0 -46
  200. package/.github/workflows/test.yml +0 -40
  201. package/.markdownlint.jsonc +0 -11
  202. package/.node-version +0 -1
  203. package/.oxfmtrc.json +0 -9
  204. package/.oxlintrc.json +0 -35
  205. package/docs/ARCHITECTURE.md +0 -125
  206. package/scorecard.png +0 -0
  207. package/src/cli/cli.ts +0 -141
  208. package/src/cli/validators.ts +0 -68
  209. package/src/formats/anthropic/index.ts +0 -14
  210. package/src/formats/anthropic/parse.ts +0 -70
  211. package/src/formats/anthropic/schema.ts +0 -74
  212. package/src/formats/anthropic/serialize.ts +0 -179
  213. package/src/formats/openai/chat-completions/index.ts +0 -14
  214. package/src/formats/openai/chat-completions/parse.ts +0 -47
  215. package/src/formats/openai/chat-completions/schema.ts +0 -92
  216. package/src/formats/openai/chat-completions/serialize.ts +0 -146
  217. package/src/formats/openai/responses/index.ts +0 -14
  218. package/src/formats/openai/responses/parse.ts +0 -73
  219. package/src/formats/openai/responses/schema.ts +0 -86
  220. package/src/formats/openai/responses/serialize.ts +0 -328
  221. package/src/formats/request-helpers.ts +0 -56
  222. package/src/formats/serialize-helpers.ts +0 -43
  223. package/src/formats/types.ts +0 -26
  224. package/src/history.ts +0 -70
  225. package/src/index.ts +0 -46
  226. package/src/loader.ts +0 -246
  227. package/src/logger.ts +0 -70
  228. package/src/mock-server.ts +0 -203
  229. package/src/route-handler.ts +0 -144
  230. package/src/rule-builder.ts +0 -73
  231. package/src/rule-engine.ts +0 -165
  232. package/src/sse-writer.ts +0 -35
  233. package/src/types/reply.ts +0 -92
  234. package/src/types/request.ts +0 -56
  235. package/src/types/rule.ts +0 -125
  236. package/src/types.ts +0 -24
  237. package/test/cli-validators.test.ts +0 -151
  238. package/test/formats/anthropic.test.ts +0 -336
  239. package/test/formats/openai.test.ts +0 -316
  240. package/test/formats/parse-helpers.test.ts +0 -315
  241. package/test/formats/responses.test.ts +0 -380
  242. package/test/helpers/make-req.ts +0 -18
  243. package/test/history.test.ts +0 -361
  244. package/test/loader.test.ts +0 -333
  245. package/test/logger.test.ts +0 -344
  246. package/test/mock-server.test.ts +0 -619
  247. package/test/rule-engine.test.ts +0 -229
  248. package/tsconfig.json +0 -24
  249. package/tsconfig.test.json +0 -11
  250. package/typedoc.json +0 -9
  251. 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
- }