@namzu/sdk 39.0.0 → 41.0.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 (289) hide show
  1. package/CHANGELOG.md +328 -0
  2. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  3. package/dist/bridge/a2a/mapper.js +8 -0
  4. package/dist/bridge/a2a/mapper.js.map +1 -1
  5. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  6. package/dist/bridge/sse/mapper.js +11 -0
  7. package/dist/bridge/sse/mapper.js.map +1 -1
  8. package/dist/connector/index.d.ts +2 -2
  9. package/dist/connector/index.d.ts.map +1 -1
  10. package/dist/connector/index.js +1 -1
  11. package/dist/connector/index.js.map +1 -1
  12. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  13. package/dist/connector/mcp/adapter.js +112 -10
  14. package/dist/connector/mcp/adapter.js.map +1 -1
  15. package/dist/connector/mcp/audio-admission.d.ts +17 -0
  16. package/dist/connector/mcp/audio-admission.d.ts.map +1 -0
  17. package/dist/connector/mcp/audio-admission.js +171 -0
  18. package/dist/connector/mcp/audio-admission.js.map +1 -0
  19. package/dist/connector/mcp/client.d.ts +252 -1
  20. package/dist/connector/mcp/client.d.ts.map +1 -1
  21. package/dist/connector/mcp/client.js +611 -39
  22. package/dist/connector/mcp/client.js.map +1 -1
  23. package/dist/connector/mcp/envelope.d.ts +91 -0
  24. package/dist/connector/mcp/envelope.d.ts.map +1 -0
  25. package/dist/connector/mcp/envelope.js +173 -0
  26. package/dist/connector/mcp/envelope.js.map +1 -0
  27. package/dist/connector/mcp/era.d.ts +130 -0
  28. package/dist/connector/mcp/era.d.ts.map +1 -0
  29. package/dist/connector/mcp/era.js +304 -0
  30. package/dist/connector/mcp/era.js.map +1 -0
  31. package/dist/connector/mcp/errors.d.ts +106 -0
  32. package/dist/connector/mcp/errors.d.ts.map +1 -0
  33. package/dist/connector/mcp/errors.js +154 -0
  34. package/dist/connector/mcp/errors.js.map +1 -0
  35. package/dist/connector/mcp/http-sse.d.ts +11 -0
  36. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  37. package/dist/connector/mcp/http-sse.js +21 -6
  38. package/dist/connector/mcp/http-sse.js.map +1 -1
  39. package/dist/connector/mcp/index.d.ts +7 -0
  40. package/dist/connector/mcp/index.d.ts.map +1 -1
  41. package/dist/connector/mcp/index.js +10 -0
  42. package/dist/connector/mcp/index.js.map +1 -1
  43. package/dist/connector/mcp/streamable-http.d.ts +83 -0
  44. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  45. package/dist/connector/mcp/streamable-http.js +177 -11
  46. package/dist/connector/mcp/streamable-http.js.map +1 -1
  47. package/dist/connector/mcp/x-mcp-header.d.ts +56 -0
  48. package/dist/connector/mcp/x-mcp-header.d.ts.map +1 -0
  49. package/dist/connector/mcp/x-mcp-header.js +254 -0
  50. package/dist/connector/mcp/x-mcp-header.js.map +1 -0
  51. package/dist/constants/mcp/index.d.ts +123 -15
  52. package/dist/constants/mcp/index.d.ts.map +1 -1
  53. package/dist/constants/mcp/index.js +135 -16
  54. package/dist/constants/mcp/index.js.map +1 -1
  55. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  56. package/dist/manager/agent/lifecycle.js +23 -0
  57. package/dist/manager/agent/lifecycle.js.map +1 -1
  58. package/dist/manager/run/persistence.d.ts +8 -0
  59. package/dist/manager/run/persistence.d.ts.map +1 -1
  60. package/dist/manager/run/persistence.js +12 -0
  61. package/dist/manager/run/persistence.js.map +1 -1
  62. package/dist/prompt/coding-agent-doctrine.d.ts +20 -0
  63. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  64. package/dist/prompt/coding-agent-doctrine.js +19 -3
  65. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  66. package/dist/prompt/index.d.ts +1 -1
  67. package/dist/prompt/index.d.ts.map +1 -1
  68. package/dist/prompt/index.js +1 -1
  69. package/dist/prompt/index.js.map +1 -1
  70. package/dist/public-runtime.d.ts +6 -4
  71. package/dist/public-runtime.d.ts.map +1 -1
  72. package/dist/public-runtime.js +8 -4
  73. package/dist/public-runtime.js.map +1 -1
  74. package/dist/public-tools.d.ts +11 -0
  75. package/dist/public-tools.d.ts.map +1 -1
  76. package/dist/public-tools.js +14 -0
  77. package/dist/public-tools.js.map +1 -1
  78. package/dist/registry/tool/execute.d.ts.map +1 -1
  79. package/dist/registry/tool/execute.js +2 -3
  80. package/dist/registry/tool/execute.js.map +1 -1
  81. package/dist/registry/tool/portable.d.ts +65 -0
  82. package/dist/registry/tool/portable.d.ts.map +1 -0
  83. package/dist/registry/tool/portable.js +244 -0
  84. package/dist/registry/tool/portable.js.map +1 -0
  85. package/dist/registry/tool/schema.d.ts +32 -5
  86. package/dist/registry/tool/schema.d.ts.map +1 -1
  87. package/dist/registry/tool/schema.js +35 -9
  88. package/dist/registry/tool/schema.js.map +1 -1
  89. package/dist/registry/toolset/catalog.js +8 -8
  90. package/dist/registry/toolset/catalog.js.map +1 -1
  91. package/dist/runtime/jobs/awaited-jobs.d.ts +215 -0
  92. package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -0
  93. package/dist/runtime/jobs/awaited-jobs.js +259 -0
  94. package/dist/runtime/jobs/awaited-jobs.js.map +1 -0
  95. package/dist/runtime/jobs/registry.d.ts +33 -2
  96. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  97. package/dist/runtime/jobs/registry.js +37 -0
  98. package/dist/runtime/jobs/registry.js.map +1 -1
  99. package/dist/runtime/query/executor.d.ts +28 -0
  100. package/dist/runtime/query/executor.d.ts.map +1 -1
  101. package/dist/runtime/query/executor.js +39 -1
  102. package/dist/runtime/query/executor.js.map +1 -1
  103. package/dist/runtime/query/file-evidence-context.d.ts.map +1 -1
  104. package/dist/runtime/query/file-evidence-context.js +159 -43
  105. package/dist/runtime/query/file-evidence-context.js.map +1 -1
  106. package/dist/runtime/query/file-evidence-replay.d.ts +260 -0
  107. package/dist/runtime/query/file-evidence-replay.d.ts.map +1 -0
  108. package/dist/runtime/query/file-evidence-replay.js +647 -0
  109. package/dist/runtime/query/file-evidence-replay.js.map +1 -0
  110. package/dist/runtime/query/file-evidence-seed.d.ts +50 -0
  111. package/dist/runtime/query/file-evidence-seed.d.ts.map +1 -0
  112. package/dist/runtime/query/file-evidence-seed.js +100 -0
  113. package/dist/runtime/query/file-evidence-seed.js.map +1 -0
  114. package/dist/runtime/query/index.d.ts.map +1 -1
  115. package/dist/runtime/query/index.js +94 -2
  116. package/dist/runtime/query/index.js.map +1 -1
  117. package/dist/runtime/query/iteration/index.d.ts +87 -9
  118. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  119. package/dist/runtime/query/iteration/index.js +193 -28
  120. package/dist/runtime/query/iteration/index.js.map +1 -1
  121. package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
  122. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  123. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  124. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  125. package/dist/runtime/query/iteration/phases/tool-review.js +5 -1
  126. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  127. package/dist/runtime/query/plugin-hooks.d.ts +14 -0
  128. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  129. package/dist/runtime/query/plugin-hooks.js +18 -0
  130. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  131. package/dist/runtime/query/repeat-call.d.ts +17 -4
  132. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  133. package/dist/runtime/query/repeat-call.js +26 -19
  134. package/dist/runtime/query/repeat-call.js.map +1 -1
  135. package/dist/runtime/query/steering.d.ts +11 -1
  136. package/dist/runtime/query/steering.d.ts.map +1 -1
  137. package/dist/runtime/query/steering.js +12 -1
  138. package/dist/runtime/query/steering.js.map +1 -1
  139. package/dist/runtime/query/tooling.d.ts +2 -0
  140. package/dist/runtime/query/tooling.d.ts.map +1 -1
  141. package/dist/runtime/query/tooling.js +1 -0
  142. package/dist/runtime/query/tooling.js.map +1 -1
  143. package/dist/sandbox/provider/local.d.ts.map +1 -1
  144. package/dist/sandbox/provider/local.js +46 -3
  145. package/dist/sandbox/provider/local.js.map +1 -1
  146. package/dist/scheduler/completion-inbox.d.ts +48 -2
  147. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  148. package/dist/scheduler/completion-inbox.js +102 -10
  149. package/dist/scheduler/completion-inbox.js.map +1 -1
  150. package/dist/scheduler/local.d.ts.map +1 -1
  151. package/dist/scheduler/local.js +8 -0
  152. package/dist/scheduler/local.js.map +1 -1
  153. package/dist/store/run/disk.d.ts +35 -1
  154. package/dist/store/run/disk.d.ts.map +1 -1
  155. package/dist/store/run/disk.js +100 -0
  156. package/dist/store/run/disk.js.map +1 -1
  157. package/dist/tools/builtins/bash.d.ts.map +1 -1
  158. package/dist/tools/builtins/bash.js +4 -10
  159. package/dist/tools/builtins/bash.js.map +1 -1
  160. package/dist/tools/builtins/edit-apply.d.ts +126 -0
  161. package/dist/tools/builtins/edit-apply.d.ts.map +1 -0
  162. package/dist/tools/builtins/edit-apply.js +360 -0
  163. package/dist/tools/builtins/edit-apply.js.map +1 -0
  164. package/dist/tools/builtins/edit.d.ts +143 -1
  165. package/dist/tools/builtins/edit.d.ts.map +1 -1
  166. package/dist/tools/builtins/edit.js +37 -219
  167. package/dist/tools/builtins/edit.js.map +1 -1
  168. package/dist/tools/builtins/index.d.ts +1 -0
  169. package/dist/tools/builtins/index.d.ts.map +1 -1
  170. package/dist/tools/builtins/index.js +9 -3
  171. package/dist/tools/builtins/index.js.map +1 -1
  172. package/dist/tools/builtins/job.js +1 -1
  173. package/dist/tools/builtins/job.js.map +1 -1
  174. package/dist/tools/builtins/read-file.d.ts +2 -2
  175. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  176. package/dist/tools/builtins/read-file.js +50 -65
  177. package/dist/tools/builtins/read-file.js.map +1 -1
  178. package/dist/tools/builtins/read-render.d.ts +56 -0
  179. package/dist/tools/builtins/read-render.d.ts.map +1 -0
  180. package/dist/tools/builtins/read-render.js +73 -0
  181. package/dist/tools/builtins/read-render.js.map +1 -0
  182. package/dist/tools/builtins/wait-for-job-bounds.d.ts +67 -0
  183. package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -0
  184. package/dist/tools/builtins/wait-for-job-bounds.js +108 -0
  185. package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -0
  186. package/dist/tools/builtins/wait-for-job.d.ts +6 -0
  187. package/dist/tools/builtins/wait-for-job.d.ts.map +1 -0
  188. package/dist/tools/builtins/wait-for-job.js +162 -0
  189. package/dist/tools/builtins/wait-for-job.js.map +1 -0
  190. package/dist/tools/builtins/write-file.js +5 -0
  191. package/dist/tools/builtins/write-file.js.map +1 -1
  192. package/dist/tools/coordinator/index.d.ts.map +1 -1
  193. package/dist/tools/coordinator/index.js +1 -7
  194. package/dist/tools/coordinator/index.js.map +1 -1
  195. package/dist/tools/file-read-tracker.d.ts.map +1 -1
  196. package/dist/tools/file-read-tracker.js +88 -10
  197. package/dist/tools/file-read-tracker.js.map +1 -1
  198. package/dist/types/agent/scheduler.d.ts +20 -0
  199. package/dist/types/agent/scheduler.d.ts.map +1 -1
  200. package/dist/types/agent/task.d.ts +20 -0
  201. package/dist/types/agent/task.d.ts.map +1 -1
  202. package/dist/types/connector/mcp.d.ts +205 -0
  203. package/dist/types/connector/mcp.d.ts.map +1 -1
  204. package/dist/types/message/index.d.ts +1 -1
  205. package/dist/types/message/index.d.ts.map +1 -1
  206. package/dist/types/message/index.js +2 -0
  207. package/dist/types/message/index.js.map +1 -1
  208. package/dist/types/run/entity.d.ts +13 -0
  209. package/dist/types/run/entity.d.ts.map +1 -1
  210. package/dist/types/run/events.d.ts +56 -0
  211. package/dist/types/run/events.d.ts.map +1 -1
  212. package/dist/types/run/events.js.map +1 -1
  213. package/dist/types/run/store.d.ts +41 -0
  214. package/dist/types/run/store.d.ts.map +1 -1
  215. package/dist/types/sandbox/index.d.ts +83 -15
  216. package/dist/types/sandbox/index.d.ts.map +1 -1
  217. package/dist/types/sandbox/index.js.map +1 -1
  218. package/dist/types/tool/index.d.ts +109 -0
  219. package/dist/types/tool/index.d.ts.map +1 -1
  220. package/dist/types/tool/index.js.map +1 -1
  221. package/dist/utils/env.d.ts +19 -0
  222. package/dist/utils/env.d.ts.map +1 -0
  223. package/dist/utils/env.js +25 -0
  224. package/dist/utils/env.js.map +1 -0
  225. package/package.json +1 -1
  226. package/src/bridge/a2a/mapper.ts +8 -0
  227. package/src/bridge/sse/mapper.ts +11 -0
  228. package/src/connector/index.ts +27 -0
  229. package/src/connector/mcp/adapter.ts +123 -10
  230. package/src/connector/mcp/audio-admission.ts +173 -0
  231. package/src/connector/mcp/client.ts +694 -45
  232. package/src/connector/mcp/envelope.ts +235 -0
  233. package/src/connector/mcp/era.ts +400 -0
  234. package/src/connector/mcp/errors.ts +171 -0
  235. package/src/connector/mcp/http-sse.ts +23 -6
  236. package/src/connector/mcp/index.ts +37 -0
  237. package/src/connector/mcp/streamable-http.ts +199 -11
  238. package/src/connector/mcp/x-mcp-header.ts +322 -0
  239. package/src/constants/mcp/index.ts +145 -16
  240. package/src/manager/agent/lifecycle.ts +29 -0
  241. package/src/manager/run/persistence.ts +12 -0
  242. package/src/prompt/coding-agent-doctrine.ts +31 -4
  243. package/src/prompt/index.ts +1 -0
  244. package/src/public-runtime.ts +37 -1
  245. package/src/public-tools.ts +18 -0
  246. package/src/registry/tool/execute.ts +2 -4
  247. package/src/registry/tool/portable.ts +264 -0
  248. package/src/registry/tool/schema.ts +38 -8
  249. package/src/registry/toolset/catalog.ts +8 -9
  250. package/src/runtime/jobs/awaited-jobs.ts +271 -0
  251. package/src/runtime/jobs/registry.ts +50 -0
  252. package/src/runtime/query/executor.ts +49 -1
  253. package/src/runtime/query/file-evidence-context.ts +190 -46
  254. package/src/runtime/query/file-evidence-replay.ts +776 -0
  255. package/src/runtime/query/file-evidence-seed.ts +126 -0
  256. package/src/runtime/query/index.ts +104 -2
  257. package/src/runtime/query/iteration/index.ts +202 -28
  258. package/src/runtime/query/iteration/phases/context.ts +10 -0
  259. package/src/runtime/query/iteration/phases/tool-review.ts +4 -0
  260. package/src/runtime/query/plugin-hooks.ts +20 -0
  261. package/src/runtime/query/repeat-call.ts +28 -18
  262. package/src/runtime/query/steering.ts +11 -0
  263. package/src/runtime/query/tooling.ts +3 -0
  264. package/src/sandbox/provider/local.ts +45 -2
  265. package/src/scheduler/completion-inbox.ts +105 -9
  266. package/src/scheduler/local.ts +8 -0
  267. package/src/store/run/disk.ts +108 -0
  268. package/src/tools/builtins/bash.ts +4 -10
  269. package/src/tools/builtins/edit-apply.ts +456 -0
  270. package/src/tools/builtins/edit.ts +39 -270
  271. package/src/tools/builtins/index.ts +9 -3
  272. package/src/tools/builtins/job.ts +1 -1
  273. package/src/tools/builtins/read-file.ts +56 -77
  274. package/src/tools/builtins/read-render.ts +104 -0
  275. package/src/tools/builtins/wait-for-job-bounds.ts +179 -0
  276. package/src/tools/builtins/wait-for-job.ts +184 -0
  277. package/src/tools/builtins/write-file.ts +5 -0
  278. package/src/tools/coordinator/index.ts +1 -7
  279. package/src/tools/file-read-tracker.ts +85 -7
  280. package/src/types/agent/scheduler.ts +21 -0
  281. package/src/types/agent/task.ts +21 -0
  282. package/src/types/connector/mcp.ts +205 -1
  283. package/src/types/message/index.ts +2 -0
  284. package/src/types/run/entity.ts +14 -0
  285. package/src/types/run/events.ts +56 -0
  286. package/src/types/run/store.ts +42 -0
  287. package/src/types/sandbox/index.ts +84 -15
  288. package/src/types/tool/index.ts +104 -0
  289. package/src/utils/env.ts +23 -0
@@ -274,9 +274,17 @@ export {
274
274
  // parses, which is the wire's property. Rendered once, converted at the driver.
275
275
  export { findDraft07Only, toSchemaDialect } from './registry/tool/dialect.js'
276
276
  export type { JsonSchemaDialect } from './registry/tool/dialect.js'
277
+ // Better than converting per wire: emit the INTERSECTION of the dialects, so
278
+ // there is nothing left for a driver to convert and an unmeasured wire is safe
279
+ // by construction. Exported so a driver or a CI gate can assert it.
280
+ export {
281
+ findPortableSchemaViolations,
282
+ toPortableToolSchema,
283
+ } from './registry/tool/portable.js'
284
+ export type { PortableSchemaViolation } from './registry/tool/portable.js'
277
285
  // The renderer itself, so a driver or a contract test can ask what a tool will
278
286
  // actually put on the wire without reaching into the registry.
279
- export { renderToolSchema } from './registry/tool/schema.js'
287
+ export { renderToolSchema, toolWireSchema } from './registry/tool/schema.js'
280
288
  export type { StrictSchemaViolation } from './provider/strict-schema.js'
281
289
  export type { ModelIdGrammar, ModelVersion } from './provider/model-version.js'
282
290
  export { drainQuery, query } from './runtime/query/index.js'
@@ -717,12 +725,29 @@ export {
717
725
  hasDrift,
718
726
  HttpSseTransport,
719
727
  HybridExecutionContext,
728
+ buildEnvelope,
729
+ classifyModernHttpFailure,
730
+ createMcpEraCache,
731
+ decodeResult,
732
+ defaultMcpEraCache,
733
+ encodeMcpHeaderValue,
734
+ isHeaderMismatchError,
735
+ isMissingRequiredClientCapabilityError,
736
+ isRecognizedModernError,
737
+ isResourceNotFoundError,
738
+ isUnsupportedProtocolVersionError,
720
739
  LocalExecutionContext,
740
+ mcpEraCacheKey,
741
+ MCPHttpStatusError,
742
+ MCPInputRequiredError,
743
+ MCPInvalidResultTypeError,
721
744
  MCPClient,
722
745
  MCPMethodNotFound,
723
746
  MCPConnectorBridge,
747
+ MCPProtocolError,
724
748
  MCPServer,
725
749
  MCPToolDiscovery,
750
+ resolveMcpEra,
726
751
  mcpPromptToToolDefinition,
727
752
  renderPromptMessages,
728
753
  mcpJsonSchemaToZod,
@@ -741,10 +766,20 @@ export {
741
766
  toolDefinitionToMCPTool,
742
767
  toolResultToMCPToolResult,
743
768
  toolsHash,
769
+ validateMcpHeaderAnnotations,
744
770
  WebhookConnector,
745
771
  zodToMCPJsonSchema,
746
772
  } from './connector/index.js'
747
773
  export type {
774
+ McpEnvelope,
775
+ McpEnvelopeInput,
776
+ McpEraProbe,
777
+ McpEraProbeAnswer,
778
+ McpEraResolution,
779
+ McpEraResolutionInput,
780
+ McpHeaderAnnotationVerdict,
781
+ McpParamHeaderBinding,
782
+ MCPDecodedResult,
748
783
  MCPToolDiscoveryOptions,
749
784
  MCPToolDrift,
750
785
  MCPToolPolicy,
@@ -1221,6 +1256,7 @@ export {
1221
1256
  export {
1222
1257
  CODING_AGENT_DELEGATION_DOCTRINE,
1223
1258
  CODING_AGENT_DOCTRINE_CONTRIBUTION_ID,
1259
+ CODING_AGENT_ORCHESTRATE_DOCTRINE,
1224
1260
  CODING_AGENT_WORKING_DOCTRINE,
1225
1261
  PLAN_MODE_DOCTRINE,
1226
1262
  PromptContributionCollisionError,
@@ -43,6 +43,11 @@ export { GrepTool } from './tools/builtins/grep.js'
43
43
  // capability: an id with nothing that reads it is the unbacked suggestion
44
44
  // that was removed from bash's schema.
45
45
  export { JobTool } from './tools/builtins/job.js'
46
+ // Blocks until a job `JobTool` started ends, instead of reading it in a
47
+ // loop. Ships in the default builtin set alongside `job` and `bash`, for
48
+ // the same reason `job` does: a job with nothing that can block on it is
49
+ // the same unbacked suggestion `job` itself exists to fix.
50
+ export { WaitForJobTool } from './tools/builtins/wait-for-job.js'
46
51
  // Loads a skill's instructions, and adopts the tool scope it declares.
47
52
  // NOT in the default builtin set: a run with no skills has nothing for it
48
53
  // to do, and offering a tool that can only refuse is worse than not
@@ -128,5 +133,18 @@ export {
128
133
  } from './connector/tools/index.js'
129
134
 
130
135
  export { createFileReadTracker } from './tools/file-read-tracker.js'
136
+ export type { LedgerReplayReport } from './runtime/query/file-evidence-replay.js'
137
+ /**
138
+ * Rebuild a tracker from a conversation's own history, for a host that keeps
139
+ * one per conversation across turns and has just restored one from a store.
140
+ * Reads no file's content — only the paths the history names, canonicalized
141
+ * the way the built-in tools canonicalize them so that the entries land where
142
+ * those tools will look for them. See the SDK's tool-execution documentation
143
+ * for what a replayed observation does and does not establish.
144
+ */
145
+ export {
146
+ type ObservationSeedContext,
147
+ seedObservationLedger,
148
+ } from './runtime/query/file-evidence-seed.js'
131
149
 
132
150
  export { buildResidentToolEvidenceTools } from './tools/resident-tool-evidence.js'
@@ -20,7 +20,7 @@ import type {
20
20
  import { toErrorMessage } from '../../utils/error.js'
21
21
  import { cloneJsonValue as clonePreparedInput } from '../../utils/json-snapshot.js'
22
22
  import { ManagedRegistry } from '../ManagedRegistry.js'
23
- import { renderToolSchema } from './schema.js'
23
+ import { renderToolSchema, toolWireSchema } from './schema.js'
24
24
  import { ToolResultHalted, screenToolResult } from './screen.js'
25
25
 
26
26
  export type { ToolExecutionResult }
@@ -461,9 +461,7 @@ Executable tool names, descriptions, and JSON input schemas are attached through
461
461
  function: {
462
462
  name: tool.name,
463
463
  description: describeWithOutput(description, tool.outputSchema),
464
- parameters:
465
- (tool.modelInputSchema ? structuredClone(tool.modelInputSchema) : undefined) ??
466
- renderToolSchema(tool.inputSchema),
464
+ parameters: toolWireSchema(tool),
467
465
  },
468
466
  }
469
467
  })
@@ -0,0 +1,264 @@
1
+ /**
2
+ * The schema shape every wire namzu speaks reads the same way.
3
+ *
4
+ * `dialect.ts` solves the problem one wire at a time: render draft-07, and let
5
+ * each driver say it again in the dialect it knows its endpoint parses. That
6
+ * works only where a driver HAS a measurement. Of the ten driver packages,
7
+ * three convert; the other seven forward the rendering verbatim, because
8
+ * nobody had measured their wires.
9
+ *
10
+ * One of those seven then got measured, the hard way. Its gateway validates a
11
+ * tool's `parameters` against the JSON Schema 2020-12 metaschema, and `read`'s
12
+ * `readRange` — the only `z.tuple(...)` in the first-party tool surface —
13
+ * renders draft-07 as `items: [a, b]`:
14
+ *
15
+ * [400] Tool 4 function has invalid 'parameters' schema:
16
+ * [{'minimum': 1, 'type': 'integer'}, {'minimum': 1, 'type': 'integer'}]
17
+ * is not of type 'object', 'boolean'
18
+ *
19
+ * The lesson is not "convert in five more drivers". Wiring each driver to a
20
+ * dialect requires a measurement per wire, and the two hardest to measure are
21
+ * precisely the ones nobody can measure on a user's behalf: the driver whose
22
+ * schema field the vendor documents nowhere, and every compatible endpoint a
23
+ * user points the generic HTTP driver at.
24
+ *
25
+ * So the kernel emits the INTERSECTION instead: the subset of JSON Schema that
26
+ * is valid, and means the same thing, in draft-07 and in 2020-12 alike. A
27
+ * schema in that subset needs no conversion anywhere, which is why this runs at
28
+ * the rendering boundary rather than at ten driver boundaries.
29
+ *
30
+ * `toSchemaDialect` is not replaced by this and does not become dead: a driver
31
+ * can still be handed a `parameters` object namzu never rendered (a host
32
+ * passing `ChatCompletionParams` straight in), and converting at the boundary
33
+ * remains the right answer there.
34
+ */
35
+
36
+ export interface PortableSchemaViolation {
37
+ /** Dotted path to the offending keyword, e.g. `properties.readRange.items`. */
38
+ readonly path: string
39
+ readonly keyword: string
40
+ /** What to write instead. */
41
+ readonly remedy: string
42
+ }
43
+
44
+ const NO_TUPLES =
45
+ 'say the array uniformly — one `items` schema plus `minItems`/`maxItems`; a tuple is spelled differently in draft-07 and 2020-12 and is invalid in one of them either way'
46
+
47
+ /**
48
+ * Keywords outside the intersection, and why each one is out.
49
+ *
50
+ * A deny-list, like `findStrictSchemaViolations` and for the same reason: an
51
+ * allow-list would have to enumerate every annotation a schema may carry and
52
+ * would refuse a schema for saying something harmless.
53
+ *
54
+ * Every entry names a wire in the driver matrix that reads it wrong, not a
55
+ * style preference.
56
+ */
57
+ const OUTSIDE_THE_INTERSECTION: ReadonlyMap<string, string> = new Map([
58
+ // 2020-12 moved the positional schemas to `prefixItems` and kept `items`
59
+ // for the tail, so an array-valued `items` does not merely look old — it
60
+ // means something else, and a 2020-12 validator rejects the whole request.
61
+ // Measured on Zen's Console gateway; the quote is in this file's header.
62
+ ['additionalItems', NO_TUPLES],
63
+ // The other spelling of the same tuple. A draft-07 validator does not know
64
+ // the keyword, so it ignores it — which turns a constrained array into an
65
+ // unconstrained one SILENTLY, the worse failure of the two. The strict
66
+ // tool-input subset refuses it outright as well (`strict-schema.ts`), and
67
+ // the function-declaration schema on one of these wires is an OpenAPI 3.0
68
+ // subset that has never documented it.
69
+ ['prefixItems', NO_TUPLES],
70
+ // A rendered tool schema has to stand alone. The renderer already runs with
71
+ // `$refStrategy: 'none'`, and the MCP bridge inlines refs before handing a
72
+ // schema out, because a wire that does not resolve them sees an empty
73
+ // constraint or refuses the document.
74
+ ['$ref', 'inline the referenced schema; a tool schema has to stand alone'],
75
+ ['$defs', 'inline the definitions; a tool schema has to stand alone'],
76
+ ['definitions', 'inline the definitions; a tool schema has to stand alone'],
77
+ ['$id', 'drop it; a tool schema is not a retrievable document'],
78
+ ['$anchor', 'drop it; there are no references to anchor'],
79
+ ['$dynamicRef', 'inline the referenced schema; a tool schema has to stand alone'],
80
+ ['$dynamicAnchor', 'drop it; there are no references to anchor'],
81
+ // Nothing on any wire reads it, and asserting a dialect is the one thing a
82
+ // schema that must work in both must not do. It also rides in the tools
83
+ // block, which renders at position 0 inside the prompt-cache prefix.
84
+ ['$schema', 'drop it; no provider reads it and it asserts a dialect'],
85
+ // 2019-09 vocabulary. Same silent-widening hazard as `prefixItems` on a
86
+ // draft-07 validator.
87
+ ['unevaluatedItems', 'state the constraint with `items` and `maxItems`'],
88
+ ['unevaluatedProperties', 'state the constraint with `additionalProperties`'],
89
+ ])
90
+
91
+ /**
92
+ * Every place a schema leaves the intersection, with its exact path.
93
+ *
94
+ * Exported so a test can sweep every shipped tool and a driver can assert
95
+ * rather than hope. The path is the point: the vendor's error names the tool
96
+ * index and the offending fragment but never where inside the schema it sits.
97
+ */
98
+ export function findPortableSchemaViolations(
99
+ schema: unknown,
100
+ path = '',
101
+ ): PortableSchemaViolation[] {
102
+ if (Array.isArray(schema)) {
103
+ return schema.flatMap((item, index) => findPortableSchemaViolations(item, `${path}[${index}]`))
104
+ }
105
+ if (typeof schema !== 'object' || schema === null) return []
106
+
107
+ const found: PortableSchemaViolation[] = []
108
+ for (const [keyword, value] of Object.entries(schema as Record<string, unknown>)) {
109
+ const here = path ? `${path}.${keyword}` : keyword
110
+ const remedy = OUTSIDE_THE_INTERSECTION.get(keyword)
111
+ if (remedy !== undefined) {
112
+ found.push({ path: here, keyword, remedy })
113
+ continue
114
+ }
115
+ // The draft-07 tuple. Reported once, at the tuple, rather than once per
116
+ // positional schema underneath it — one fixable finding, not a list.
117
+ if (keyword === 'items' && Array.isArray(value)) {
118
+ found.push({ path: here, keyword, remedy: NO_TUPLES })
119
+ continue
120
+ }
121
+ // A union of types is valid JSON Schema in both dialects, but the
122
+ // OpenAPI-3.0-shaped wires namzu speaks take a single type name and
123
+ // either refuse a list or ignore it.
124
+ if (keyword === 'type' && Array.isArray(value)) {
125
+ found.push({
126
+ path: here,
127
+ keyword,
128
+ remedy: 'use `anyOf` of single-typed schemas; several wires take one type name only',
129
+ })
130
+ continue
131
+ }
132
+ found.push(...findPortableSchemaViolations(value, here))
133
+ }
134
+ return found
135
+ }
136
+
137
+ /**
138
+ * Rewrite what can be rewritten, so a tuple cannot reach a wire.
139
+ *
140
+ * Only the tuple spellings and `$schema` are rewritten. The rest of the
141
+ * deny-list is reported and not repaired on purpose: inlining a `$ref` or
142
+ * choosing which member of a `type` list the author meant is a guess about
143
+ * intent, and a guess that silently changes what a tool accepts is worse than
144
+ * the 400 it avoids. Those are caught by the profile test at the source.
145
+ *
146
+ * Returns the input unchanged — the SAME reference — when nothing needs
147
+ * rewriting, which is the overwhelming common case. The tools block sits at
148
+ * position 0 of the prompt-cache prefix, so a fresh, equal object per request
149
+ * would invalidate the cache for the whole run.
150
+ */
151
+ export function toPortableToolSchema(json: Record<string, unknown>): Record<string, unknown> {
152
+ return makePortable(json) as Record<string, unknown>
153
+ }
154
+
155
+ function makePortable(value: unknown): unknown {
156
+ if (Array.isArray(value)) {
157
+ let changed = false
158
+ const out = value.map((item) => {
159
+ const next = makePortable(item)
160
+ if (next !== item) changed = true
161
+ return next
162
+ })
163
+ return changed ? out : value
164
+ }
165
+ if (typeof value !== 'object' || value === null) return value
166
+
167
+ const node = value as Record<string, unknown>
168
+ const positional = Array.isArray(node.prefixItems)
169
+ ? node.prefixItems
170
+ : Array.isArray(node.items)
171
+ ? node.items
172
+ : undefined
173
+ if (positional) return collapseTuple(node, positional)
174
+
175
+ let changed = '$schema' in node
176
+ const out: Record<string, unknown> = {}
177
+ for (const [key, child] of Object.entries(node)) {
178
+ if (key === '$schema') continue
179
+ const next = makePortable(child)
180
+ if (next !== child) changed = true
181
+ out[key] = next
182
+ }
183
+ return changed ? out : node
184
+ }
185
+
186
+ /**
187
+ * Say a positional array uniformly.
188
+ *
189
+ * What is kept: the arity, and every constraint that applies to every member.
190
+ * What is lost: which member sits where. That loss is real and it is the price
191
+ * of a shape both dialects read identically — and it costs nothing in practice,
192
+ * because the tool's Zod schema still parses the call and still refuses a
193
+ * wrongly-ordered array with a message the model can act on. The wire schema is
194
+ * a hint to the model; the parser is the contract.
195
+ */
196
+ function collapseTuple(
197
+ node: Record<string, unknown>,
198
+ positional: readonly unknown[],
199
+ ): Record<string, unknown> {
200
+ // The tail rule, in whichever dialect this node happens to be written in:
201
+ // draft-07 spells it `additionalItems`, 2020-12 spells it `items` and only
202
+ // calls it a tail when `prefixItems` holds the members.
203
+ const tail = Array.isArray(node.prefixItems) ? node.items : node.additionalItems
204
+ const arity = positional.length
205
+ const members = positional.map(makePortable)
206
+
207
+ // A tail that is itself a schema constrains every element past the members,
208
+ // so those elements join the uniform reading rather than closing it.
209
+ const tailSchema =
210
+ tail !== undefined && tail !== true && tail !== false ? makePortable(tail) : undefined
211
+ // `false` closes the array at the members' length; so does a `maxItems` the
212
+ // author already pinned there.
213
+ const closed =
214
+ tailSchema === undefined &&
215
+ (tail === false || (typeof node.maxItems === 'number' && node.maxItems <= arity))
216
+
217
+ // An open tail with no schema says "anything past the members", which no
218
+ // single `items` can express alongside the members themselves. Saying
219
+ // nothing about the elements is the only honest uniform reading; the bounds
220
+ // below still carry whatever the author pinned.
221
+ const candidates =
222
+ tailSchema !== undefined ? dedupe([...members, tailSchema]) : closed ? dedupe(members) : []
223
+
224
+ const element =
225
+ candidates.length === 0
226
+ ? undefined
227
+ : candidates.length === 1
228
+ ? candidates[0]
229
+ : { anyOf: candidates }
230
+
231
+ const out: Record<string, unknown> = {}
232
+ for (const [key, child] of Object.entries(node)) {
233
+ if (key === '$schema') continue
234
+ if (key === 'additionalItems') continue
235
+ if (key === 'prefixItems' || (key === 'items' && Array.isArray(child))) {
236
+ if (element !== undefined) out.items = element
237
+ continue
238
+ }
239
+ // The 2020-12 tail, already folded into `items` above.
240
+ if (key === 'items' && Array.isArray(node.prefixItems)) continue
241
+ if (key === 'maxItems' && closed && typeof child === 'number') {
242
+ out.maxItems = Math.min(child, arity)
243
+ continue
244
+ }
245
+ out[key] = makePortable(child)
246
+ }
247
+ // A tuple closed by `additionalItems: false` rather than by a bound loses
248
+ // its ceiling otherwise: a uniform `items` says nothing about length, so a
249
+ // schema written to forbid a third element would begin to allow any number.
250
+ if (closed && out.maxItems === undefined) out.maxItems = arity
251
+ return out
252
+ }
253
+
254
+ function dedupe(schemas: readonly unknown[]): unknown[] {
255
+ const seen = new Set<string>()
256
+ const out: unknown[] = []
257
+ for (const schema of schemas) {
258
+ const key = JSON.stringify(schema) ?? 'undefined'
259
+ if (seen.has(key)) continue
260
+ seen.add(key)
261
+ out.push(schema)
262
+ }
263
+ return out
264
+ }
@@ -1,5 +1,6 @@
1
1
  import type { z } from 'zod'
2
2
  import { zodToJsonSchema } from 'zod-to-json-schema'
3
+ import { toPortableToolSchema } from './portable.js'
3
4
 
4
5
  /**
5
6
  * The single place a tool's Zod schema becomes the JSON Schema that goes on
@@ -50,17 +51,46 @@ export function renderToolSchema(schema: z.ZodType): Record<string, unknown> {
50
51
  }
51
52
 
52
53
  /**
53
- * Strip what no provider reads.
54
+ * Make the rendering something every wire reads the same way.
54
55
  *
55
- * Only `$schema` today, and only at the root — `zodToJsonSchema` does not
56
- * stamp it on nested nodes. Kept as a named function rather than an inline
57
- * `delete` so the next "providers ignore this" field has an obvious home
58
- * and a place to be justified.
56
+ * Two jobs, both at this one boundary:
57
+ *
58
+ * 1. **Strip what no provider reads.** `$schema` rides in the tools block,
59
+ * which renders at position 0 inside the prompt-cache prefix, once per
60
+ * tool, per request, forever — and it asserts a dialect, which is the one
61
+ * thing a schema that has to work on every wire must not do.
62
+ *
63
+ * 2. **Leave the intersection of draft-07 and 2020-12 intact.** `renderToolSchema`
64
+ * emits draft-07, where a tuple is `items: [a, b]`; a 2020-12 wire reads
65
+ * that as invalid and rejects the whole request, taking every other tool in
66
+ * the call down with it. Five of the ten drivers forward the rendering
67
+ * verbatim, so the only place that can be fixed once is here. See
68
+ * `portable.ts` for the measurement that put it here.
59
69
  */
60
70
  export function normalizeToolSchema(json: Record<string, unknown>): Record<string, unknown> {
61
- if (!('$schema' in json)) return json
62
- const { $schema: _dropped, ...rest } = json
63
- return rest
71
+ return toPortableToolSchema(json)
72
+ }
73
+
74
+ /**
75
+ * The schema a tool actually puts on the wire.
76
+ *
77
+ * A tool may carry an explicit `modelInputSchema` — hand-written JSON Schema,
78
+ * not rendered from Zod — and that schema reaches providers through the same
79
+ * `tools` block as a rendered one. It therefore has to clear the same bar, and
80
+ * the two call sites that build that block (`ToolRegistry.toLLMTools` and the
81
+ * toolset catalog) had each spelled the fallback out on their own. Two paths
82
+ * that agree today are two paths that can disagree tomorrow.
83
+ *
84
+ * The clone is deliberate: a caller may edit the parameters it is handed —
85
+ * `hostModelSchema` does — and the definition's own object must not move
86
+ * underneath the next call.
87
+ */
88
+ export function toolWireSchema(tool: {
89
+ readonly modelInputSchema?: Record<string, unknown>
90
+ readonly inputSchema: z.ZodType
91
+ }): Record<string, unknown> {
92
+ if (tool.modelInputSchema) return toPortableToolSchema(structuredClone(tool.modelInputSchema))
93
+ return renderToolSchema(tool.inputSchema)
64
94
  }
65
95
 
66
96
  /**
@@ -9,7 +9,7 @@ import type {
9
9
  ToolsetDefinition,
10
10
  ToolsetPolicy,
11
11
  } from '../../types/toolset/index.js'
12
- import { renderToolSchema } from '../tool/schema.js'
12
+ import { toolWireSchema } from '../tool/schema.js'
13
13
 
14
14
  export interface ToolCatalogSearchOptions {
15
15
  readonly loading?: readonly ToolLoadingMode[]
@@ -245,17 +245,16 @@ function toolDefinitionToLLMTool(definition: ToolDefinition | undefined): LLMToo
245
245
  function: {
246
246
  name: definition.name,
247
247
  description: definition.description,
248
- // Through `renderToolSchema`, not a second inline conversion. The
248
+ // Through `toolWireSchema`, not a second inline conversion. The
249
249
  // options were already identical, so this was not a different
250
250
  // rendering — it was the same rendering without the guarantees:
251
251
  // no `$schema` stripping (that key rides in the tools block, which
252
- // sits at position 0 inside the prompt-cache prefix), no memoization,
253
- // and no freeze. Two paths that agree today are two paths that can
254
- // disagree tomorrow, and a tool reaching the wire through the catalog
255
- // rather than the registry is not a different tool.
256
- parameters:
257
- (definition.modelInputSchema ? structuredClone(definition.modelInputSchema) : undefined) ??
258
- renderToolSchema(definition.inputSchema),
252
+ // sits at position 0 inside the prompt-cache prefix), no portability
253
+ // normalisation, no memoization, and no freeze. Two paths that agree
254
+ // today are two paths that can disagree tomorrow, and a tool reaching
255
+ // the wire through the catalog rather than the registry is not a
256
+ // different tool.
257
+ parameters: toolWireSchema(definition),
259
258
  },
260
259
  }
261
260
  }