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
package/src/types.ts DELETED
@@ -1,24 +0,0 @@
1
- export type {
2
- FormatName,
3
- MockRequest,
4
- Message,
5
- ToolDef,
6
- } from "./types/request.js";
7
- export type {
8
- Reply,
9
- ReplyObject,
10
- ErrorReply,
11
- ToolCall,
12
- Resolver,
13
- ReplyOptions,
14
- SequenceEntry,
15
- } from "./types/reply.js";
16
- export type {
17
- Match,
18
- MatchObject,
19
- PendingRule,
20
- RuleHandle,
21
- RuleSummary,
22
- Handler,
23
- Rule,
24
- } from "./types/rule.js";
@@ -1,151 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- parsePort,
4
- parseHost,
5
- parseChunkSize,
6
- parseLogLevel,
7
- parseLatency,
8
- } from "#/cli/validators.js";
9
-
10
- describe("parsePort", () => {
11
- it("parses a valid port", () => {
12
- expect(parsePort("5555")).toBe(5555);
13
- });
14
-
15
- it("accepts port 1", () => {
16
- expect(parsePort("1")).toBe(1);
17
- });
18
-
19
- it("accepts port 65535", () => {
20
- expect(parsePort("65535")).toBe(65535);
21
- });
22
-
23
- it("throws on port 0", () => {
24
- expect(() => parsePort("0")).toThrow('Invalid port "0"');
25
- });
26
-
27
- it("throws on port above 65535", () => {
28
- expect(() => parsePort("65536")).toThrow('Invalid port "65536"');
29
- });
30
-
31
- it("throws on negative port", () => {
32
- expect(() => parsePort("-1")).toThrow('Invalid port "-1"');
33
- });
34
-
35
- it("throws on non-numeric string", () => {
36
- expect(() => parsePort("abc")).toThrow('Invalid port "abc"');
37
- });
38
-
39
- it("throws on empty string", () => {
40
- expect(() => parsePort("")).toThrow('Invalid port ""');
41
- });
42
-
43
- it("throws on floating point", () => {
44
- expect(() => parsePort("80.5")).toThrow('Invalid port "80.5"');
45
- });
46
-
47
- it("throws on numeric string with trailing chars", () => {
48
- expect(() => parsePort("80abc")).toThrow('Invalid port "80abc"');
49
- });
50
- });
51
-
52
- describe("parseLogLevel", () => {
53
- it.each(["none", "error", "warning", "info", "debug", "all"] as const)(
54
- "accepts %s",
55
- (level) => {
56
- expect(parseLogLevel(level)).toBe(level);
57
- },
58
- );
59
-
60
- it("throws on invalid level", () => {
61
- expect(() => parseLogLevel("verbose")).toThrow(
62
- 'Invalid log level "verbose"',
63
- );
64
- });
65
-
66
- it("throws on empty string", () => {
67
- expect(() => parseLogLevel("")).toThrow('Invalid log level ""');
68
- });
69
- });
70
-
71
- describe("parseHost", () => {
72
- it("accepts 127.0.0.1", async () => {
73
- await expect(parseHost("127.0.0.1")).resolves.toBe("127.0.0.1");
74
- });
75
-
76
- it("accepts 0.0.0.0", async () => {
77
- await expect(parseHost("0.0.0.0")).resolves.toBe("0.0.0.0");
78
- });
79
-
80
- it("accepts localhost", async () => {
81
- await expect(parseHost("localhost")).resolves.toBe("localhost");
82
- });
83
-
84
- it("accepts an IPv6 address", async () => {
85
- await expect(parseHost("::1")).resolves.toBe("::1");
86
- });
87
-
88
- it("rejects an empty string", async () => {
89
- await expect(parseHost("")).rejects.toThrow('Invalid host ""');
90
- });
91
-
92
- it("rejects an unresolvable hostname", async () => {
93
- await expect(parseHost("not.a.real.host.invalid")).rejects.toThrow(
94
- "Invalid host",
95
- );
96
- });
97
-
98
- it("rejects a string with spaces", async () => {
99
- await expect(parseHost("local host")).rejects.toThrow(
100
- 'Invalid host "local host"',
101
- );
102
- });
103
- });
104
-
105
- describe("parseLatency", () => {
106
- it("parses a valid latency", () => {
107
- expect(parseLatency("100")).toBe(100);
108
- });
109
-
110
- it("accepts zero", () => {
111
- expect(parseLatency("0")).toBe(0);
112
- });
113
-
114
- it("throws on negative value", () => {
115
- expect(() => parseLatency("-1")).toThrow('Invalid latency "-1"');
116
- });
117
-
118
- it("throws on non-numeric value", () => {
119
- expect(() => parseLatency("abc")).toThrow('Invalid latency "abc"');
120
- });
121
-
122
- it("throws on empty string", () => {
123
- expect(() => parseLatency("")).toThrow('Invalid latency ""');
124
- });
125
-
126
- it("throws on floating point", () => {
127
- expect(() => parseLatency("50.7")).toThrow('Invalid latency "50.7"');
128
- });
129
-
130
- it("throws on numeric string with trailing chars", () => {
131
- expect(() => parseLatency("50abc")).toThrow('Invalid latency "50abc"');
132
- });
133
- });
134
-
135
- describe("parseChunkSize", () => {
136
- it("parses a valid chunk size", () => {
137
- expect(parseChunkSize("20")).toBe(20);
138
- });
139
-
140
- it("accepts zero", () => {
141
- expect(parseChunkSize("0")).toBe(0);
142
- });
143
-
144
- it("throws on negative value", () => {
145
- expect(() => parseChunkSize("-5")).toThrow('Invalid chunk size "-5"');
146
- });
147
-
148
- it("throws on non-numeric value", () => {
149
- expect(() => parseChunkSize("abc")).toThrow('Invalid chunk size "abc"');
150
- });
151
- });
@@ -1,336 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { anthropicFormat } from "../../src/formats/anthropic/index.js";
3
- import type {
4
- AnthropicMessageStart,
5
- AnthropicBlockEvent,
6
- AnthropicDelta,
7
- AnthropicComplete,
8
- AnthropicError,
9
- } from "../../src/formats/anthropic/schema.js";
10
-
11
- function parse<T>(chunk: { data: string }): T {
12
- return JSON.parse(chunk.data) as T;
13
- }
14
-
15
- describe("Anthropic Format", () => {
16
- describe("parseRequest", () => {
17
- it("parses messages with top-level system", () => {
18
- const req = anthropicFormat.parseRequest({
19
- model: "claude-sonnet-4-6",
20
- system: "You are a pirate",
21
- messages: [{ role: "user", content: "Hello" }],
22
- max_tokens: 1024,
23
- stream: true,
24
- });
25
- expect(req.format).toBe("anthropic");
26
- expect(req.model).toBe("claude-sonnet-4-6");
27
- expect(req.systemMessage).toBe("You are a pirate");
28
- expect(req.lastMessage).toBe("Hello");
29
- expect(req.messages).toHaveLength(2);
30
- });
31
-
32
- it("parses system as array of blocks", () => {
33
- const req = anthropicFormat.parseRequest({
34
- model: "claude-sonnet-4-6",
35
- max_tokens: 1024,
36
- system: [{ type: "text", text: "Be helpful" }],
37
- messages: [{ role: "user", content: "hi" }],
38
- });
39
- expect(req.systemMessage).toBe("Be helpful");
40
- });
41
-
42
- it("parses content block arrays in messages", () => {
43
- const req = anthropicFormat.parseRequest({
44
- model: "claude-sonnet-4-6",
45
- max_tokens: 1024,
46
- messages: [
47
- { role: "user", content: [{ type: "text", text: "Hello there" }] },
48
- ],
49
- });
50
- expect(req.lastMessage).toBe("Hello there");
51
- });
52
-
53
- it("parses tools with input_schema", () => {
54
- const req = anthropicFormat.parseRequest({
55
- model: "claude-sonnet-4-6",
56
- max_tokens: 1024,
57
- messages: [{ role: "user", content: "read file" }],
58
- tools: [
59
- {
60
- name: "read_file",
61
- description: "Read",
62
- input_schema: { type: "object" },
63
- },
64
- ],
65
- });
66
- expect(req.tools).toHaveLength(1);
67
- expect(req.tools![0]!.name).toBe("read_file");
68
- });
69
-
70
- it("extracts toolNames from tools array", () => {
71
- const req = anthropicFormat.parseRequest({
72
- model: "claude-sonnet-4-6",
73
- max_tokens: 1024,
74
- messages: [{ role: "user", content: "hi" }],
75
- tools: [
76
- { name: "get_weather", input_schema: {} },
77
- { name: "search", input_schema: {} },
78
- ],
79
- });
80
- expect(req.toolNames).toEqual(["get_weather", "search"]);
81
- });
82
-
83
- it("extracts lastToolCallId from tool_result blocks", () => {
84
- const req = anthropicFormat.parseRequest({
85
- model: "claude-sonnet-4-6",
86
- max_tokens: 1024,
87
- messages: [
88
- { role: "user", content: "hi" },
89
- {
90
- role: "user",
91
- content: [
92
- {
93
- type: "tool_result",
94
- tool_use_id: "toolu_123",
95
- content: "result",
96
- },
97
- ],
98
- },
99
- ],
100
- });
101
- expect(req.lastToolCallId).toBe("toolu_123");
102
- });
103
- });
104
-
105
- describe("serialize (streaming)", () => {
106
- it("produces correct event sequence for text", () => {
107
- const chunks = anthropicFormat.serialize(
108
- { text: "Hello" },
109
- "claude-sonnet-4-6",
110
- );
111
- const events = chunks.map((c) => c.event);
112
- expect(events).toEqual([
113
- "message_start",
114
- "content_block_start",
115
- "content_block_delta",
116
- "content_block_stop",
117
- "message_delta",
118
- "message_stop",
119
- ]);
120
- });
121
-
122
- it("message_start contains correct structure", () => {
123
- const chunks = anthropicFormat.serialize(
124
- { text: "Hello" },
125
- "claude-sonnet-4-6",
126
- );
127
- const msg = parse<AnthropicMessageStart>(chunks[0]!);
128
- expect(msg.message).toMatchObject({
129
- type: "message",
130
- role: "assistant",
131
- model: "claude-sonnet-4-6",
132
- content: [],
133
- stop_reason: null,
134
- });
135
- expect(msg.message.usage.input_tokens).toBeTypeOf("number");
136
- expect(msg.message.usage.output_tokens).toBe(0);
137
- });
138
-
139
- it("text block uses index 0 when no reasoning", () => {
140
- const chunks = anthropicFormat.serialize(
141
- { text: "Hello" },
142
- "claude-sonnet-4-6",
143
- );
144
- const blockStart = chunks.find((c) => c.event === "content_block_start");
145
- const data = parse<AnthropicBlockEvent>(blockStart!);
146
- expect(data.index).toBe(0);
147
- expect(data.content_block?.type).toBe("text");
148
- });
149
-
150
- it("thinking block at index 0 and text block at index 1 when reasoning present", () => {
151
- const chunks = anthropicFormat.serialize(
152
- { text: "42", reasoning: "Let me think" },
153
- "claude-sonnet-4-6",
154
- );
155
- const blockStarts = chunks
156
- .filter((c) => c.event === "content_block_start")
157
- .map((c) => parse<AnthropicBlockEvent>(c));
158
-
159
- expect(blockStarts[0]!.index).toBe(0);
160
- expect(blockStarts[0]!.content_block?.type).toBe("thinking");
161
- expect(blockStarts[1]!.index).toBe(1);
162
- expect(blockStarts[1]!.content_block?.type).toBe("text");
163
- });
164
-
165
- it("thinking delta has correct type and content", () => {
166
- const chunks = anthropicFormat.serialize(
167
- { text: "42", reasoning: "Let me think" },
168
- "claude-sonnet-4-6",
169
- );
170
- const thinkingDelta = chunks.find((c) => {
171
- if (c.event !== "content_block_delta") return false;
172
- return parse<AnthropicBlockEvent>(c).delta?.type === "thinking_delta";
173
- });
174
- expect(thinkingDelta).toBeDefined();
175
- expect(parse<AnthropicBlockEvent>(thinkingDelta!).delta?.thinking).toBe(
176
- "Let me think",
177
- );
178
- });
179
-
180
- it("closes thinking block before text block starts", () => {
181
- const chunks = anthropicFormat.serialize(
182
- { text: "answer", reasoning: "think" },
183
- "claude-sonnet-4-6",
184
- );
185
- const events = chunks.map((c) => ({
186
- event: c.event,
187
- data: parse<AnthropicBlockEvent>(c),
188
- }));
189
- const thinkingStop = events.findIndex(
190
- (e) => e.event === "content_block_stop" && e.data.index === 0,
191
- );
192
- const textStart = events.findIndex(
193
- (e) =>
194
- e.event === "content_block_start" &&
195
- e.data.content_block?.type === "text",
196
- );
197
- expect(thinkingStop).toBeLessThan(textStart);
198
- });
199
-
200
- it("includes tool_use blocks with correct structure", () => {
201
- const chunks = anthropicFormat.serialize(
202
- { tools: [{ name: "read_file", args: { path: "/tmp" } }] },
203
- "claude-sonnet-4-6",
204
- );
205
- const toolStart = chunks.find((c) => {
206
- if (c.event !== "content_block_start") return false;
207
- return parse<AnthropicBlockEvent>(c).content_block?.type === "tool_use";
208
- });
209
- expect(toolStart).toBeDefined();
210
- const block = parse<AnthropicBlockEvent>(toolStart!).content_block!;
211
- expect(block.name).toBe("read_file");
212
- expect(block.id).toBeTypeOf("string");
213
- expect(block.input).toEqual({});
214
- });
215
-
216
- it("sets stop_reason to tool_use when tools present", () => {
217
- const chunks = anthropicFormat.serialize(
218
- { tools: [{ name: "read_file", args: {} }] },
219
- "claude-sonnet-4-6",
220
- );
221
- const delta = chunks.find((c) => c.event === "message_delta");
222
- expect(parse<AnthropicDelta>(delta!).delta).toMatchObject({
223
- stop_reason: "tool_use",
224
- });
225
- });
226
-
227
- it("includes stop_sequence: null in message_delta", () => {
228
- const chunks = anthropicFormat.serialize(
229
- { text: "Hello" },
230
- "claude-sonnet-4-6",
231
- );
232
- const delta = chunks.find((c) => c.event === "message_delta");
233
- expect(parse<AnthropicDelta>(delta!).delta.stop_sequence).toBeNull();
234
- });
235
-
236
- it("message_delta includes output_tokens in usage", () => {
237
- const chunks = anthropicFormat.serialize(
238
- { text: "Hello", usage: { input: 20, output: 15 } },
239
- "claude-sonnet-4-6",
240
- );
241
- const delta = chunks.find((c) => c.event === "message_delta");
242
- expect(parse<AnthropicDelta>(delta!).usage.output_tokens).toBe(15);
243
- });
244
- });
245
-
246
- describe("serializeComplete (non-streaming)", () => {
247
- it("produces correct top-level structure", () => {
248
- const result = anthropicFormat.serializeComplete(
249
- { text: "Hello" },
250
- "claude-sonnet-4-6",
251
- ) as AnthropicComplete;
252
- expect(result.type).toBe("message");
253
- expect(result.role).toBe("assistant");
254
- expect(result.model).toBe("claude-sonnet-4-6");
255
- expect(result.stop_reason).toBe("end_turn");
256
- expect(result.stop_sequence).toBeNull();
257
- });
258
-
259
- it("includes text content block", () => {
260
- const result = anthropicFormat.serializeComplete(
261
- { text: "Hello, world!" },
262
- "claude-sonnet-4-6",
263
- ) as AnthropicComplete;
264
- expect(result.content[0]).toMatchObject({
265
- type: "text",
266
- text: "Hello, world!",
267
- });
268
- });
269
-
270
- it("includes thinking before text when reasoning provided", () => {
271
- const result = anthropicFormat.serializeComplete(
272
- { text: "42", reasoning: "Thinking..." },
273
- "claude-sonnet-4-6",
274
- ) as AnthropicComplete;
275
- expect(result.content[0]!.type).toBe("thinking");
276
- expect(result.content[0]!.thinking).toBe("Thinking...");
277
- expect(result.content[1]!.type).toBe("text");
278
- });
279
-
280
- it("includes tool_use with correct structure", () => {
281
- const result = anthropicFormat.serializeComplete(
282
- { tools: [{ name: "read_file", args: { path: "/tmp" } }] },
283
- "claude-sonnet-4-6",
284
- ) as AnthropicComplete;
285
- const tool = result.content.find((c) => c.type === "tool_use");
286
- if (!tool) throw new Error("expected tool_use content block");
287
- expect(tool.name).toBe("read_file");
288
- expect(tool.input).toEqual({ path: "/tmp" });
289
- expect(tool.id).toBeTypeOf("string");
290
- });
291
-
292
- it("generates unique IDs for multiple tools", () => {
293
- const result = anthropicFormat.serializeComplete(
294
- {
295
- tools: [
296
- { name: "read_file", args: { path: "/a" } },
297
- { name: "write_file", args: { path: "/b" } },
298
- ],
299
- },
300
- "claude-sonnet-4-6",
301
- ) as AnthropicComplete;
302
- const tools = result.content.filter((c) => c.type === "tool_use");
303
- if (tools.length !== 2) throw new Error("expected 2 tool_use blocks");
304
- expect(tools[0].id).not.toBe(tools[1].id);
305
- });
306
-
307
- it("sets stop_reason to tool_use when tools present", () => {
308
- const result = anthropicFormat.serializeComplete(
309
- { tools: [{ name: "read_file", args: {} }] },
310
- "claude-sonnet-4-6",
311
- ) as AnthropicComplete;
312
- expect(result.stop_reason).toBe("tool_use");
313
- });
314
-
315
- it("includes usage tokens", () => {
316
- const result = anthropicFormat.serializeComplete(
317
- { text: "hi", usage: { input: 20, output: 15 } },
318
- "claude-sonnet-4-6",
319
- ) as AnthropicComplete;
320
- expect(result.usage).toEqual({ input_tokens: 20, output_tokens: 15 });
321
- });
322
- });
323
-
324
- describe("serializeError", () => {
325
- it("produces Anthropic error format", () => {
326
- const result = anthropicFormat.serializeError({
327
- status: 400,
328
- message: "Bad request",
329
- type: "invalid_request_error",
330
- }) as AnthropicError;
331
- expect(result.type).toBe("error");
332
- expect(result.error.type).toBe("invalid_request_error");
333
- expect(result.error.message).toBe("Bad request");
334
- });
335
- });
336
- });