@sean.holung/minicode 0.3.11 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +5 -3
  2. package/dist/scripts/run-benchmarks.js +7 -1
  3. package/dist/src/benchmark/runner.js +66 -3
  4. package/dist/src/cli/benchmark-run.js +1 -1
  5. package/dist/src/index.js +1 -1
  6. package/dist/src/indexer/code-map.js +16 -1
  7. package/dist/src/serve/agent-bridge.js +1 -1
  8. package/dist/src/session/session-store.js +1 -1
  9. package/dist/src/shared/symbol-resolution.js +24 -3
  10. package/dist/src/tools/find-path.js +1 -1
  11. package/dist/src/tools/find-references.js +1 -1
  12. package/dist/src/tools/get-dependencies.js +1 -1
  13. package/dist/src/tools/post-edit-diagnostics.js +185 -0
  14. package/dist/src/tools/read-symbol.js +2 -2
  15. package/dist/src/tools/registry.js +18 -3
  16. package/dist/src/tools/search-code-map.js +101 -9
  17. package/dist/src/ui/cli-ink.js +1 -1
  18. package/dist/tests/agent.test.js +1 -1
  19. package/dist/tests/context-indicator.test.js +1 -1
  20. package/dist/tests/file-tools.test.js +2 -2
  21. package/dist/tests/focus-tracker.test.js +1 -1
  22. package/dist/tests/guardrails.test.js +1 -1
  23. package/dist/tests/indexer.test.js +59 -28
  24. package/dist/tests/model-client-openai.test.js +1 -1
  25. package/dist/tests/model-selection.test.js +1 -1
  26. package/dist/tests/python-plugin.test.js +3 -3
  27. package/dist/tests/read-symbol.test.js +84 -10
  28. package/dist/tests/reasoning-effort.test.js +1 -1
  29. package/dist/tests/search-code-map.test.js +132 -1
  30. package/dist/tests/serve.integration.test.js +1 -1
  31. package/dist/tests/session-store.test.js +1 -1
  32. package/dist/tests/session.test.js +1 -1
  33. package/dist/tests/symbol-resolution.test.js +57 -0
  34. package/dist/tests/system-prompt.test.js +1 -1
  35. package/dist/tests/tool-registry.test.js +1 -1
  36. package/node_modules/@sean.holung/minicode-sdk/LICENSE +201 -0
  37. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/README.md +43 -22
  38. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/agent.d.ts +10 -1
  39. package/node_modules/@sean.holung/minicode-sdk/dist/src/agent/agent.d.ts.map +1 -0
  40. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/agent.js +18 -9
  41. package/node_modules/@sean.holung/minicode-sdk/dist/src/agent/agent.js.map +1 -0
  42. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/index.d.ts +1 -1
  43. package/node_modules/@sean.holung/minicode-sdk/dist/src/index.d.ts.map +1 -0
  44. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/index.js +1 -1
  45. package/node_modules/@sean.holung/minicode-sdk/dist/src/index.js.map +1 -0
  46. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/mcp/client-registry.js +1 -1
  47. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/mcp/client-registry.js.map +1 -1
  48. package/node_modules/@sean.holung/minicode-sdk/dist/src/model/client.d.ts.map +1 -0
  49. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/model/client.js +71 -4
  50. package/node_modules/@sean.holung/minicode-sdk/dist/src/model/client.js.map +1 -0
  51. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/prompt/system-prompt.d.ts.map +1 -1
  52. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/prompt/system-prompt.js +1 -1
  53. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/prompt/system-prompt.js.map +1 -1
  54. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file-replacers.d.ts +59 -0
  55. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file-replacers.d.ts.map +1 -0
  56. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file-replacers.js +392 -0
  57. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file-replacers.js.map +1 -0
  58. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file.d.ts +19 -0
  59. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file.d.ts.map +1 -0
  60. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/edit-file.js +14 -25
  61. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/edit-file.js.map +1 -0
  62. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/read-file.d.ts.map +1 -1
  63. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/read-file.js +11 -5
  64. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/read-file.js.map +1 -1
  65. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/run-command.d.ts.map +1 -1
  66. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/run-command.js +3 -0
  67. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/run-command.js.map +1 -0
  68. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/search.d.ts.map +1 -1
  69. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/search.js +52 -25
  70. package/node_modules/@sean.holung/minicode-sdk/dist/src/tools/search.js.map +1 -0
  71. package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/package.json +6 -2
  72. package/node_modules/minicode-plugin-python/dist/src/index.d.ts +1 -1
  73. package/node_modules/minicode-plugin-python/dist/src/index.d.ts.map +1 -1
  74. package/node_modules/minicode-plugin-python/dist/tsconfig.tsbuildinfo +1 -1
  75. package/node_modules/minicode-plugin-python/package.json +2 -2
  76. package/package.json +3 -3
  77. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts.map +0 -1
  78. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js.map +0 -1
  79. package/node_modules/@minicode/agent-sdk/dist/src/index.d.ts.map +0 -1
  80. package/node_modules/@minicode/agent-sdk/dist/src/index.js.map +0 -1
  81. package/node_modules/@minicode/agent-sdk/dist/src/model/client.d.ts.map +0 -1
  82. package/node_modules/@minicode/agent-sdk/dist/src/model/client.js.map +0 -1
  83. package/node_modules/@minicode/agent-sdk/dist/src/tools/edit-file.d.ts +0 -13
  84. package/node_modules/@minicode/agent-sdk/dist/src/tools/edit-file.d.ts.map +0 -1
  85. package/node_modules/@minicode/agent-sdk/dist/src/tools/edit-file.js.map +0 -1
  86. package/node_modules/@minicode/agent-sdk/dist/src/tools/run-command.js.map +0 -1
  87. package/node_modules/@minicode/agent-sdk/dist/src/tools/search.js.map +0 -1
  88. package/node_modules/@minicode/agent-sdk/dist/tests/agent.test.d.ts +0 -2
  89. package/node_modules/@minicode/agent-sdk/dist/tests/agent.test.d.ts.map +0 -1
  90. package/node_modules/@minicode/agent-sdk/dist/tests/agent.test.js +0 -569
  91. package/node_modules/@minicode/agent-sdk/dist/tests/agent.test.js.map +0 -1
  92. package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.d.ts +0 -2
  93. package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.d.ts.map +0 -1
  94. package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.js +0 -131
  95. package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.js.map +0 -1
  96. package/node_modules/@minicode/agent-sdk/dist/tests/guardrails.test.d.ts +0 -2
  97. package/node_modules/@minicode/agent-sdk/dist/tests/guardrails.test.d.ts.map +0 -1
  98. package/node_modules/@minicode/agent-sdk/dist/tests/guardrails.test.js +0 -54
  99. package/node_modules/@minicode/agent-sdk/dist/tests/guardrails.test.js.map +0 -1
  100. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.integration.test.d.ts +0 -2
  101. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.integration.test.d.ts.map +0 -1
  102. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.integration.test.js +0 -64
  103. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.integration.test.js.map +0 -1
  104. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.test.d.ts +0 -2
  105. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.test.d.ts.map +0 -1
  106. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.test.js +0 -350
  107. package/node_modules/@minicode/agent-sdk/dist/tests/mcp-client.test.js.map +0 -1
  108. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-anthropic-structured-output.test.d.ts +0 -2
  109. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-anthropic-structured-output.test.d.ts.map +0 -1
  110. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-anthropic-structured-output.test.js +0 -211
  111. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-anthropic-structured-output.test.js.map +0 -1
  112. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-openai.test.d.ts +0 -2
  113. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-openai.test.d.ts.map +0 -1
  114. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-openai.test.js +0 -330
  115. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-openai.test.js.map +0 -1
  116. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-structured-output.test.d.ts +0 -2
  117. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-structured-output.test.d.ts.map +0 -1
  118. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-structured-output.test.js +0 -171
  119. package/node_modules/@minicode/agent-sdk/dist/tests/model-client-structured-output.test.js.map +0 -1
  120. package/node_modules/@minicode/agent-sdk/dist/tests/session.test.d.ts +0 -2
  121. package/node_modules/@minicode/agent-sdk/dist/tests/session.test.d.ts.map +0 -1
  122. package/node_modules/@minicode/agent-sdk/dist/tests/session.test.js +0 -226
  123. package/node_modules/@minicode/agent-sdk/dist/tests/session.test.js.map +0 -1
  124. package/node_modules/@minicode/agent-sdk/dist/tests/structured-output.test.d.ts +0 -2
  125. package/node_modules/@minicode/agent-sdk/dist/tests/structured-output.test.d.ts.map +0 -1
  126. package/node_modules/@minicode/agent-sdk/dist/tests/structured-output.test.js +0 -212
  127. package/node_modules/@minicode/agent-sdk/dist/tests/structured-output.test.js.map +0 -1
  128. package/node_modules/@minicode/agent-sdk/dist/tests/system-prompt.test.d.ts +0 -2
  129. package/node_modules/@minicode/agent-sdk/dist/tests/system-prompt.test.d.ts.map +0 -1
  130. package/node_modules/@minicode/agent-sdk/dist/tests/system-prompt.test.js +0 -76
  131. package/node_modules/@minicode/agent-sdk/dist/tests/system-prompt.test.js.map +0 -1
  132. package/node_modules/@minicode/agent-sdk/dist/tests/test-utils.d.ts +0 -3
  133. package/node_modules/@minicode/agent-sdk/dist/tests/test-utils.d.ts.map +0 -1
  134. package/node_modules/@minicode/agent-sdk/dist/tests/test-utils.js +0 -20
  135. package/node_modules/@minicode/agent-sdk/dist/tests/test-utils.js.map +0 -1
  136. package/node_modules/@minicode/agent-sdk/dist/tests/tool-factory-options.test.d.ts +0 -2
  137. package/node_modules/@minicode/agent-sdk/dist/tests/tool-factory-options.test.d.ts.map +0 -1
  138. package/node_modules/@minicode/agent-sdk/dist/tests/tool-factory-options.test.js +0 -72
  139. package/node_modules/@minicode/agent-sdk/dist/tests/tool-factory-options.test.js.map +0 -1
  140. package/node_modules/@minicode/agent-sdk/dist/tests/tool-registry.test.d.ts +0 -2
  141. package/node_modules/@minicode/agent-sdk/dist/tests/tool-registry.test.d.ts.map +0 -1
  142. package/node_modules/@minicode/agent-sdk/dist/tests/tool-registry.test.js +0 -69
  143. package/node_modules/@minicode/agent-sdk/dist/tests/tool-registry.test.js.map +0 -1
  144. package/node_modules/@minicode/agent-sdk/dist/tsconfig.tsbuildinfo +0 -1
  145. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/structured-output.d.ts +0 -0
  146. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/structured-output.d.ts.map +0 -0
  147. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/structured-output.js +0 -0
  148. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/structured-output.js.map +0 -0
  149. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/types.d.ts +0 -0
  150. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/types.d.ts.map +0 -0
  151. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/types.js +0 -0
  152. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/agent/types.js.map +0 -0
  153. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/focus-tracker.d.ts +0 -0
  154. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/focus-tracker.d.ts.map +0 -0
  155. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/focus-tracker.js +0 -0
  156. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/focus-tracker.js.map +0 -0
  157. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/types.d.ts +0 -0
  158. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/types.d.ts.map +0 -0
  159. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/types.js +0 -0
  160. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/indexer/types.js.map +0 -0
  161. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/mcp/client-registry.d.ts +0 -0
  162. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/mcp/client-registry.d.ts.map +0 -0
  163. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/model/client.d.ts +0 -0
  164. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/prompt/system-prompt.d.ts +0 -0
  165. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/safety/guardrails.d.ts +0 -0
  166. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/safety/guardrails.d.ts.map +0 -0
  167. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/safety/guardrails.js +0 -0
  168. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/safety/guardrails.js.map +0 -0
  169. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/session/session.d.ts +0 -0
  170. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/session/session.d.ts.map +0 -0
  171. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/session/session.js +0 -0
  172. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/session/session.js.map +0 -0
  173. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/helpers.d.ts +0 -0
  174. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/helpers.d.ts.map +0 -0
  175. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/helpers.js +0 -0
  176. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/helpers.js.map +0 -0
  177. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/list-files.d.ts +0 -0
  178. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/list-files.d.ts.map +0 -0
  179. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/list-files.js +0 -0
  180. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/list-files.js.map +0 -0
  181. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/read-file.d.ts +0 -0
  182. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/registry.d.ts +0 -0
  183. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/registry.d.ts.map +0 -0
  184. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/registry.js +0 -0
  185. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/registry.js.map +0 -0
  186. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/run-command.d.ts +0 -0
  187. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/search.d.ts +0 -0
  188. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/write-file.d.ts +0 -0
  189. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/write-file.d.ts.map +0 -0
  190. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/write-file.js +0 -0
  191. /package/node_modules/{@minicode/agent-sdk → @sean.holung/minicode-sdk}/dist/src/tools/write-file.js.map +0 -0
@@ -1,171 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { test } from "node:test";
3
- import { OpenAICompatibleModelClient } from "../src/model/client.js";
4
- import { OutputValidationError } from "../src/agent/types.js";
5
- const InvoiceSchema = {
6
- name: "Invoice",
7
- description: "Extracted invoice fields",
8
- schema: {
9
- type: "object",
10
- properties: {
11
- vendor: { type: "string" },
12
- total: { type: "number" },
13
- },
14
- required: ["vendor", "total"],
15
- additionalProperties: false,
16
- },
17
- };
18
- test("openai-compat client appends synthetic respond-tool when outputSchema is set", async () => {
19
- let capturedBody = "";
20
- const fetchImpl = async (_input, init) => {
21
- capturedBody = String(init?.body ?? "");
22
- return new Response(JSON.stringify({
23
- choices: [
24
- {
25
- finish_reason: "tool_calls",
26
- message: {
27
- content: "",
28
- tool_calls: [
29
- {
30
- id: "call_1",
31
- type: "function",
32
- function: {
33
- name: "Invoice",
34
- arguments: '{"vendor":"Acme","total":1234}',
35
- },
36
- },
37
- ],
38
- },
39
- },
40
- ],
41
- usage: { prompt_tokens: 1, completion_tokens: 1 },
42
- }), { status: 200, headers: { "content-type": "application/json" } });
43
- };
44
- const client = new OpenAICompatibleModelClient({
45
- baseUrl: "http://localhost:1234/v1",
46
- fetchImpl,
47
- });
48
- const response = await client.chat({
49
- model: "test",
50
- system: "sys",
51
- messages: [{ role: "user", content: "hi" }],
52
- tools: [
53
- {
54
- name: "read_file",
55
- description: "read",
56
- input_schema: { type: "object", properties: {} },
57
- },
58
- ],
59
- maxTokens: 64,
60
- outputSchema: InvoiceSchema,
61
- });
62
- // The synthetic tool was appended to the request alongside read_file.
63
- const parsedBody = JSON.parse(capturedBody);
64
- const tools = parsedBody.tools;
65
- assert.equal(tools.length, 2);
66
- const fns = tools.map((t) => t.function.name);
67
- assert.deepEqual(fns, ["read_file", "Invoice"]);
68
- // The synthetic call was extracted into `output` and stripped from
69
- // `toolCalls` so the agent loop won't try to dispatch it.
70
- assert.deepEqual(response.output, { vendor: "Acme", total: 1234 });
71
- assert.equal(response.toolCalls.length, 0);
72
- });
73
- test("openai-compat client throws OutputValidationError on schema mismatch", async () => {
74
- const fetchImpl = async () => new Response(JSON.stringify({
75
- choices: [
76
- {
77
- finish_reason: "tool_calls",
78
- message: {
79
- content: "",
80
- tool_calls: [
81
- {
82
- id: "call_1",
83
- type: "function",
84
- function: {
85
- name: "Invoice",
86
- // total should be a number — provide string instead
87
- arguments: '{"vendor":"Acme","total":"oops"}',
88
- },
89
- },
90
- ],
91
- },
92
- },
93
- ],
94
- usage: { prompt_tokens: 1, completion_tokens: 1 },
95
- }), { status: 200, headers: { "content-type": "application/json" } });
96
- const client = new OpenAICompatibleModelClient({
97
- baseUrl: "http://localhost:1234/v1",
98
- fetchImpl,
99
- });
100
- await assert.rejects(() => client.chat({
101
- model: "test",
102
- system: "sys",
103
- messages: [{ role: "user", content: "hi" }],
104
- tools: [],
105
- maxTokens: 64,
106
- outputSchema: InvoiceSchema,
107
- }), (error) => {
108
- assert.ok(error instanceof OutputValidationError);
109
- assert.match(error.message, /Invoice.*failed schema validation/);
110
- return true;
111
- });
112
- });
113
- test("openai-compat client passes through unchanged when outputSchema is omitted", async () => {
114
- let capturedBody = "";
115
- const fetchImpl = async (_input, init) => {
116
- capturedBody = String(init?.body ?? "");
117
- return new Response(JSON.stringify({
118
- choices: [
119
- {
120
- finish_reason: "stop",
121
- message: { content: "ok", tool_calls: [] },
122
- },
123
- ],
124
- usage: { prompt_tokens: 1, completion_tokens: 1 },
125
- }), { status: 200, headers: { "content-type": "application/json" } });
126
- };
127
- const client = new OpenAICompatibleModelClient({
128
- baseUrl: "http://localhost:1234/v1",
129
- fetchImpl,
130
- });
131
- const response = await client.chat({
132
- model: "test",
133
- system: "sys",
134
- messages: [{ role: "user", content: "hi" }],
135
- tools: [
136
- {
137
- name: "read_file",
138
- description: "r",
139
- input_schema: { type: "object", properties: {} },
140
- },
141
- ],
142
- maxTokens: 64,
143
- });
144
- const parsedBody = JSON.parse(capturedBody);
145
- const tools = parsedBody.tools;
146
- assert.equal(tools.length, 1);
147
- assert.equal(response.output, undefined);
148
- assert.equal(response.text, "ok");
149
- });
150
- test("openai-compat client throws on outputSchema name collision with a real tool", async () => {
151
- const fetchImpl = async () => new Response("{}");
152
- const client = new OpenAICompatibleModelClient({
153
- baseUrl: "http://localhost:1234/v1",
154
- fetchImpl,
155
- });
156
- await assert.rejects(() => client.chat({
157
- model: "test",
158
- system: "sys",
159
- messages: [{ role: "user", content: "hi" }],
160
- tools: [
161
- {
162
- name: "Invoice",
163
- description: "real tool with the same name",
164
- input_schema: { type: "object" },
165
- },
166
- ],
167
- maxTokens: 64,
168
- outputSchema: InvoiceSchema,
169
- }), /collides with a registered tool/);
170
- });
171
- //# sourceMappingURL=model-client-structured-output.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model-client-structured-output.test.js","sourceRoot":"","sources":["../../tests/model-client-structured-output.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=session.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session.test.d.ts","sourceRoot":"","sources":["../../tests/session.test.ts"],"names":[],"mappings":""}
@@ -1,226 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { Session } from "../src/session/session.js";
4
- test("session stores and returns messages", () => {
5
- const session = new Session("test");
6
- session.addMessage({ role: "user", content: "hello" });
7
- session.addMessage({ role: "assistant", content: "world" });
8
- const messages = session.getMessages();
9
- assert.equal(messages.length, 2);
10
- assert.equal(messages[0]?.role, "user");
11
- assert.equal(messages[1]?.role, "assistant");
12
- });
13
- test("session getMessages returns a copy", () => {
14
- const session = new Session("test");
15
- session.addMessage({ role: "user", content: "hello" });
16
- const messages1 = session.getMessages();
17
- const messages2 = session.getMessages();
18
- assert.notEqual(messages1, messages2);
19
- assert.deepEqual(messages1, messages2);
20
- });
21
- test("session generates unique id if not provided", () => {
22
- const session1 = new Session();
23
- const session2 = new Session();
24
- assert.notEqual(session1.id, session2.id);
25
- assert.ok(session1.id.length > 0);
26
- });
27
- test("session uses provided id", () => {
28
- const session = new Session("my-session");
29
- assert.equal(session.id, "my-session");
30
- });
31
- test("session tracks token estimate", () => {
32
- const session = new Session("test");
33
- assert.equal(session.getTokenEstimate(), 0);
34
- session.addMessage({ role: "user", content: "a".repeat(100) });
35
- assert.equal(session.getTokenEstimate(), 25); // 100 / 4
36
- });
37
- test("trim keeps recent messages while reducing token estimate", () => {
38
- const session = new Session("test");
39
- session.addMessage({ role: "user", content: "a".repeat(200) });
40
- session.addMessage({
41
- role: "assistant",
42
- content: "thinking",
43
- toolCalls: [{ id: "1", name: "read_file", input: { path: "x" } }],
44
- });
45
- session.addMessage({
46
- role: "tool",
47
- toolCallId: "1",
48
- toolName: "read_file",
49
- content: "tool-output",
50
- });
51
- session.addMessage({ role: "assistant", content: "done" });
52
- const before = session.getTokenEstimate();
53
- session.trim(30, 2);
54
- const after = session.getTokenEstimate();
55
- const messages = session.getMessages();
56
- assert.ok(after <= before);
57
- assert.equal(messages.length, 3);
58
- assert.equal(messages[0]?.role, "assistant");
59
- assert.equal(messages[1]?.role, "tool");
60
- assert.equal(messages[2]?.role, "assistant");
61
- });
62
- test("trim does nothing when within budget", () => {
63
- const session = new Session("test");
64
- session.addMessage({ role: "user", content: "short" });
65
- session.addMessage({ role: "assistant", content: "reply" });
66
- session.trim(100_000, 10);
67
- assert.equal(session.getMessages().length, 2);
68
- });
69
- test("trim does nothing when keepRecentMessages is negative", () => {
70
- const session = new Session("test");
71
- session.addMessage({ role: "user", content: "a".repeat(1000) });
72
- session.addMessage({ role: "assistant", content: "b".repeat(1000) });
73
- session.trim(1, -1);
74
- assert.equal(session.getMessages().length, 2);
75
- });
76
- test("toJSON returns a serializable snapshot", () => {
77
- const session = new Session("snap-id");
78
- session.addMessage({ role: "user", content: "hello" });
79
- session.addMessage({ role: "assistant", content: "world" });
80
- const snapshot = session.toJSON();
81
- assert.equal(snapshot.id, "snap-id");
82
- assert.equal(typeof snapshot.createdAt, "string");
83
- assert.equal(snapshot.messages.length, 2);
84
- assert.equal(snapshot.messages[0]?.content, "hello");
85
- const parsed = JSON.parse(JSON.stringify(snapshot));
86
- assert.deepEqual(parsed, snapshot);
87
- });
88
- test("fromJSON restores a session from a snapshot", () => {
89
- const original = new Session("restore-id");
90
- original.addMessage({ role: "user", content: "question" });
91
- original.addMessage({
92
- role: "assistant",
93
- content: "answer",
94
- toolCalls: [{ id: "t1", name: "read_file", input: { path: "x.ts" } }],
95
- });
96
- original.addMessage({
97
- role: "tool",
98
- toolCallId: "t1",
99
- toolName: "read_file",
100
- content: "file contents",
101
- });
102
- const snapshot = original.toJSON();
103
- const restored = Session.fromJSON(snapshot);
104
- assert.equal(restored.id, "restore-id");
105
- assert.equal(restored.createdAt.toISOString(), original.createdAt.toISOString());
106
- assert.deepEqual(restored.getMessages(), original.getMessages());
107
- });
108
- test("fromJSON roundtrips through JSON.stringify/parse", () => {
109
- const session = new Session("rt-id");
110
- session.addMessage({ role: "user", content: "test" });
111
- const json = JSON.stringify(session.toJSON());
112
- const restored = Session.fromJSON(JSON.parse(json));
113
- assert.equal(restored.id, "rt-id");
114
- assert.equal(restored.getMessages().length, 1);
115
- assert.equal(restored.getMessages()[0]?.content, "test");
116
- });
117
- // --- LLM-based compaction tests ---
118
- class FakeModelClient {
119
- lastMessages = [];
120
- responseText;
121
- constructor(responseText = "Summary: user asked to fix a bug in app.ts") {
122
- this.responseText = responseText;
123
- }
124
- async chat(params) {
125
- this.lastMessages.push([...params.messages]);
126
- return {
127
- text: this.responseText,
128
- toolCalls: [],
129
- stopReason: "end_turn",
130
- usage: { inputTokens: 100, outputTokens: 50 },
131
- };
132
- }
133
- }
134
- test("compactWithLlm uses LLM summary and preserves recent messages", async () => {
135
- const session = new Session("llm-compact");
136
- session.addMessage({ role: "user", content: "fix the bug in app.ts" });
137
- session.addMessage({ role: "assistant", content: "I will read the file" });
138
- session.addMessage({
139
- role: "assistant",
140
- content: "reading",
141
- toolCalls: [{ id: "t1", name: "read_file", input: { path: "app.ts" } }],
142
- });
143
- session.addMessage({
144
- role: "tool",
145
- toolCallId: "t1",
146
- toolName: "read_file",
147
- content: "const x = 1;\nconst y = 2;",
148
- });
149
- session.addMessage({ role: "assistant", content: "I found the issue" });
150
- session.addMessage({ role: "user", content: "great, fix it" });
151
- const client = new FakeModelClient();
152
- const result = await session.compactWithLlm(2, client, "test-haiku");
153
- assert.ok(result);
154
- assert.equal(result.removedMessages, 4);
155
- const messages = session.getMessages();
156
- // Summary + 2 preserved recent messages
157
- assert.equal(messages.length, 3);
158
- assert.equal(messages[0]?.role, "user");
159
- assert.ok(messages[0]?.content.includes("LLM summarization"));
160
- assert.ok(messages[0]?.content.includes("Summary: user asked to fix a bug"));
161
- // Recent messages preserved
162
- assert.equal(messages[1]?.content, "I found the issue");
163
- assert.equal(messages[2]?.content, "great, fix it");
164
- });
165
- test("compactWithLlm returns null when nothing to compact", async () => {
166
- const session = new Session("llm-empty");
167
- session.addMessage({ role: "user", content: "hello" });
168
- const client = new FakeModelClient();
169
- const result = await session.compactWithLlm(5, client, "test-haiku");
170
- assert.equal(result, null);
171
- assert.equal(client.lastMessages.length, 0); // LLM should not be called
172
- });
173
- test("compactWithLlm falls back to mechanical compaction on error", async () => {
174
- const session = new Session("llm-fallback");
175
- session.addMessage({ role: "user", content: "first message" });
176
- session.addMessage({ role: "assistant", content: "first response" });
177
- session.addMessage({ role: "user", content: "second message" });
178
- session.addMessage({ role: "assistant", content: "second response" });
179
- const failingClient = {
180
- async chat() {
181
- throw new Error("API unavailable");
182
- },
183
- };
184
- const result = await session.compactWithLlm(2, failingClient, "test-haiku");
185
- assert.ok(result);
186
- const messages = session.getMessages();
187
- // Should fall back to mechanical compaction
188
- assert.equal(messages[0]?.role, "user");
189
- assert.ok(messages[0]?.content.includes("Conversation Summary"));
190
- assert.ok(!messages[0]?.content.includes("LLM summarization"));
191
- });
192
- test("CompactionResult.method reflects which strategy actually ran", async () => {
193
- // Mechanical path
194
- const mech = new Session("method-mech");
195
- mech.addMessage({ role: "user", content: "a" });
196
- mech.addMessage({ role: "assistant", content: "b" });
197
- mech.addMessage({ role: "user", content: "c" });
198
- mech.addMessage({ role: "assistant", content: "d" });
199
- const mechResult = mech.compact(2);
200
- assert.ok(mechResult);
201
- assert.equal(mechResult.method, "mechanical");
202
- // LLM success path
203
- const llm = new Session("method-llm");
204
- llm.addMessage({ role: "user", content: "a" });
205
- llm.addMessage({ role: "assistant", content: "b" });
206
- llm.addMessage({ role: "user", content: "c" });
207
- llm.addMessage({ role: "assistant", content: "d" });
208
- const llmResult = await llm.compactWithLlm(2, new FakeModelClient(), "test-haiku");
209
- assert.ok(llmResult);
210
- assert.equal(llmResult.method, "llm");
211
- // LLM fallback path — error in chat() → mechanical compaction
212
- const fallback = new Session("method-fallback");
213
- fallback.addMessage({ role: "user", content: "a" });
214
- fallback.addMessage({ role: "assistant", content: "b" });
215
- fallback.addMessage({ role: "user", content: "c" });
216
- fallback.addMessage({ role: "assistant", content: "d" });
217
- const failing = {
218
- async chat() {
219
- throw new Error("API down");
220
- },
221
- };
222
- const fallbackResult = await fallback.compactWithLlm(2, failing, "test-haiku");
223
- assert.ok(fallbackResult);
224
- assert.equal(fallbackResult.method, "mechanical", "fallback should report mechanical, not the originally-attempted LLM");
225
- });
226
- //# sourceMappingURL=session.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session.test.js","sourceRoot":"","sources":["../../tests/session.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=structured-output.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"structured-output.test.d.ts","sourceRoot":"","sources":["../../tests/structured-output.test.ts"],"names":[],"mappings":""}
@@ -1,212 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { test } from "node:test";
3
- import { CodingAgent } from "../src/agent/agent.js";
4
- import { extractStructuredOutput, synthesizeRespondTool, validateOutput, validateOutputSchema, } from "../src/agent/structured-output.js";
5
- import { OutputValidationError } from "../src/agent/types.js";
6
- import { ToolRegistry } from "../src/tools/registry.js";
7
- import { createTestAgentConfig } from "./test-utils.js";
8
- const InvoiceSchema = {
9
- name: "Invoice",
10
- description: "Extracted invoice data",
11
- schema: {
12
- type: "object",
13
- properties: {
14
- vendor: { type: "string" },
15
- total: { type: "number" },
16
- },
17
- required: ["vendor", "total"],
18
- additionalProperties: false,
19
- },
20
- };
21
- // ─── Helper module ───────────────────────────────────────────────────────────
22
- test("synthesizeRespondTool builds a ToolSchema with the supplied schema", () => {
23
- const tool = synthesizeRespondTool(InvoiceSchema);
24
- assert.equal(tool.name, "Invoice");
25
- assert.equal(tool.description, "Extracted invoice data");
26
- assert.deepEqual(tool.input_schema, InvoiceSchema.schema);
27
- });
28
- test("synthesizeRespondTool falls back to a default description", () => {
29
- const noDesc = {
30
- name: "Foo",
31
- schema: { type: "object", properties: {}, additionalProperties: false },
32
- };
33
- const tool = synthesizeRespondTool(noDesc);
34
- assert.match(tool.description, /Call this/);
35
- });
36
- test("validateOutputSchema rejects bad names and collisions", () => {
37
- assert.throws(() => validateOutputSchema({ name: "bad name", schema: {} }, []), /must match/);
38
- assert.throws(() => validateOutputSchema({ name: "ok", schema: null }, []), /JSON Schema object/);
39
- const realTool = {
40
- name: "Invoice",
41
- description: "x",
42
- input_schema: { type: "object" },
43
- };
44
- assert.throws(() => validateOutputSchema(InvoiceSchema, [realTool]), /collides with a registered tool/);
45
- });
46
- test("validateOutput returns the value when it matches the schema", () => {
47
- const value = { vendor: "Acme", total: 1234 };
48
- const out = validateOutput(InvoiceSchema, value);
49
- assert.deepEqual(out, value);
50
- });
51
- test("validateOutput throws OutputValidationError with diagnostic info on mismatch", () => {
52
- try {
53
- validateOutput(InvoiceSchema, { vendor: 5 });
54
- assert.fail("expected throw");
55
- }
56
- catch (error) {
57
- assert.ok(error instanceof OutputValidationError);
58
- assert.match(error.message, /Invoice.*failed schema validation/);
59
- assert.ok(error.errors.length > 0);
60
- assert.deepEqual(error.raw, { vendor: 5 });
61
- }
62
- });
63
- test("extractStructuredOutput pulls the synthetic call out and leaves real tool calls", () => {
64
- const result = extractStructuredOutput(InvoiceSchema, [
65
- { id: "1", name: "read_file", input: { path: "x.txt" } },
66
- { id: "2", name: "Invoice", input: { vendor: "Acme", total: 100 } },
67
- { id: "3", name: "write_file", input: { path: "y.txt", content: "ok" } },
68
- ]);
69
- assert.ok(result, "extractStructuredOutput should find the call");
70
- assert.deepEqual(result.output, { vendor: "Acme", total: 100 });
71
- assert.equal(result.remainingToolCalls.length, 2);
72
- assert.deepEqual(result.remainingToolCalls.map((c) => c.name), ["read_file", "write_file"]);
73
- });
74
- test("extractStructuredOutput returns null when the model didn't call the synthetic tool", () => {
75
- const result = extractStructuredOutput(InvoiceSchema, [
76
- { id: "1", name: "read_file", input: { path: "x.txt" } },
77
- ]);
78
- assert.equal(result, null);
79
- });
80
- // ─── Agent integration ───────────────────────────────────────────────────────
81
- class CapturingClient {
82
- toolsLastSeen = [];
83
- outputSchemaLastSeen = undefined;
84
- responses;
85
- constructor(responses) {
86
- this.responses = [...responses];
87
- }
88
- async chat(params) {
89
- this.toolsLastSeen = params.tools;
90
- this.outputSchemaLastSeen = params.outputSchema;
91
- const next = this.responses.shift();
92
- if (!next)
93
- throw new Error("No queued response.");
94
- return next;
95
- }
96
- }
97
- function buildAgentWithRegistry(client, tools = []) {
98
- return new CodingAgent({
99
- config: createTestAgentConfig("/tmp/structured-test"),
100
- modelClient: client,
101
- toolRegistry: new ToolRegistry(tools),
102
- });
103
- }
104
- function makeEchoTool() {
105
- return {
106
- name: "echo_tool",
107
- description: "echo",
108
- inputSchema: {
109
- type: "object",
110
- properties: { value: { type: "string" } },
111
- required: ["value"],
112
- },
113
- execute: async (input) => `echo:${String(input.value)}`,
114
- };
115
- }
116
- test("runTurn forwards outputSchema to the model client", async () => {
117
- // The client is responsible for appending the synthetic tool — but
118
- // when this test uses a fake client, we just verify the schema was
119
- // forwarded so the real clients (covered by their own tests) can do
120
- // their job.
121
- const client = new CapturingClient([
122
- {
123
- text: "",
124
- toolCalls: [
125
- { id: "1", name: "Invoice", input: { vendor: "Acme", total: 99 } },
126
- ],
127
- stopReason: "tool_use",
128
- // The fake client emulates what a real client does: extract the
129
- // synthetic call and surface it as `output`.
130
- output: { vendor: "Acme", total: 99 },
131
- usage: { inputTokens: 5, outputTokens: 5 },
132
- },
133
- ]);
134
- const agent = buildAgentWithRegistry(client);
135
- const result = await agent.runTurn("hi", { outputSchema: InvoiceSchema });
136
- assert.equal(client.outputSchemaLastSeen, InvoiceSchema);
137
- assert.deepEqual(result.output, { vendor: "Acme", total: 99 });
138
- });
139
- test("runTurn terminates on structured output even mid-loop", async () => {
140
- // Step 1: model calls a real tool. Step 2: model calls the synthetic
141
- // respond tool. The agent should execute the real tool and then
142
- // terminate on the structured output.
143
- const client = new CapturingClient([
144
- {
145
- text: "Let me check first.",
146
- toolCalls: [
147
- { id: "1", name: "echo_tool", input: { value: "ping" } },
148
- ],
149
- stopReason: "tool_use",
150
- usage: { inputTokens: 5, outputTokens: 5 },
151
- },
152
- {
153
- text: "",
154
- toolCalls: [],
155
- stopReason: "end_turn",
156
- output: { vendor: "Acme", total: 42 },
157
- usage: { inputTokens: 5, outputTokens: 5 },
158
- },
159
- ]);
160
- const agent = buildAgentWithRegistry(client, [makeEchoTool()]);
161
- const result = await agent.runTurn("extract this", {
162
- outputSchema: InvoiceSchema,
163
- });
164
- assert.deepEqual(result.output, { vendor: "Acme", total: 42 });
165
- assert.equal(result.text, "");
166
- });
167
- test("runTurn returns no output when the model never calls the synthetic tool", async () => {
168
- const client = new CapturingClient([
169
- {
170
- text: "Hello there.",
171
- toolCalls: [],
172
- stopReason: "end_turn",
173
- usage: { inputTokens: 1, outputTokens: 1 },
174
- },
175
- ]);
176
- const agent = buildAgentWithRegistry(client);
177
- const result = await agent.runTurn("hi", { outputSchema: InvoiceSchema });
178
- assert.equal(result.output, undefined);
179
- assert.equal(result.text, "Hello there.");
180
- });
181
- test("runTurn ignores extra real-tool calls when output is set in the same step", async () => {
182
- // Some providers emit multi-tool steps. When the model commits to a
183
- // structured answer, side-effects in the same step are dropped
184
- // rather than executed in a way the model can't see the result of.
185
- let echoCalls = 0;
186
- const echoTool = {
187
- name: "echo_tool",
188
- description: "echo",
189
- inputSchema: { type: "object", properties: {}, additionalProperties: false },
190
- execute: async () => {
191
- echoCalls += 1;
192
- return "echoed";
193
- },
194
- };
195
- const client = new CapturingClient([
196
- {
197
- text: "",
198
- // The synthetic call has been stripped already; the real client's
199
- // extractor leaves only the side-effect call here. The agent
200
- // should NOT dispatch it because output is set.
201
- toolCalls: [{ id: "1", name: "echo_tool", input: {} }],
202
- stopReason: "tool_use",
203
- output: { vendor: "Acme", total: 10 },
204
- usage: { inputTokens: 1, outputTokens: 1 },
205
- },
206
- ]);
207
- const agent = buildAgentWithRegistry(client, [echoTool]);
208
- const result = await agent.runTurn("hi", { outputSchema: InvoiceSchema });
209
- assert.deepEqual(result.output, { vendor: "Acme", total: 10 });
210
- assert.equal(echoCalls, 0, "echo tool must not be executed once output is set");
211
- });
212
- //# sourceMappingURL=structured-output.test.js.map