mixdog 1.3.4 → 1.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 (472) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +17 -2
  3. package/README.md +11 -0
  4. package/package.json +3 -11
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/embed-google-oauth-client.mjs +49 -0
  7. package/scripts/gate-local.mjs +4 -2
  8. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  9. package/scripts/native-release-status.mjs +2 -2
  10. package/scripts/recall-history-cases.json +1 -1
  11. package/scripts/suite-health.mjs +10 -1
  12. package/scripts/test.mjs +12 -11
  13. package/src/agents/reviewer/AGENT.md +7 -11
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/defaults/shipped-history.json +25 -1
  16. package/src/defaults/skills/browser-use/SKILL.md +77 -17
  17. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  18. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  19. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  20. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  21. package/src/defaults/skills/computer-use/SKILL.md +33 -9
  22. package/src/defaults/skills/setup/SKILL.md +29 -2
  23. package/src/defaults/skills/setup/references/actions.md +117 -28
  24. package/src/defaults/skills/setup/references/surfaces.md +77 -35
  25. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  26. package/src/defaults/skills/visualize/SKILL.md +2 -1
  27. package/src/lib/keychain-cjs.cjs +359 -29
  28. package/src/lib/rules-builder.cjs +10 -8
  29. package/src/rules/agent/AGENT.md +6 -6
  30. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  31. package/src/rules/agent-mode/MIXY.md +12 -0
  32. package/src/rules/lead/LEAD.md +18 -20
  33. package/src/rules/shared/05-tool-calls.md +5 -6
  34. package/src/rules/shared/10-tool-workflow.md +2 -0
  35. package/src/rules/shared/60-verification.md +7 -5
  36. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  37. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  38. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  39. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/config.mjs +34 -0
  41. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  42. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
  43. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
  44. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  45. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
  46. package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  49. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  50. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  51. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  53. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
  54. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
  55. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  56. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  60. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +160 -69
  61. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
  63. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  65. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  66. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  67. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  68. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  69. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
  70. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  78. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  79. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  81. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  82. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  83. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  84. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  85. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  86. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  87. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  88. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  89. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  90. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  91. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  92. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  93. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  94. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  95. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  97. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  98. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  99. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  100. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  101. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  103. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +19 -1
  104. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  109. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  113. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  114. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  115. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  116. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  117. package/src/runtime/agent/orchestrator/providers/registry.mjs +43 -3
  118. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  119. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  120. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  121. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
  122. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
  127. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  128. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  131. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  132. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  133. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  134. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  135. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  136. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  137. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  138. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  139. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  140. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
  141. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
  142. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  143. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  144. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +8 -0
  145. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
  146. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
  147. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  148. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
  149. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
  151. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
  152. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
  153. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  154. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
  155. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
  156. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
  157. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  158. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +14 -4
  159. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  163. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
  164. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  165. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  166. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  167. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  168. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  172. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  173. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
  174. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  175. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  176. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
  177. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
  178. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  179. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
  180. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  182. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
  183. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  184. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
  185. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  186. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  187. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  188. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
  189. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
  191. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  192. package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
  193. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  203. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
  207. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
  208. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  209. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
  214. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
  216. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  217. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  218. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  219. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
  225. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
  226. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  227. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  228. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  229. package/src/runtime/browser-bridge/client.mjs +73 -8
  230. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  231. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  232. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  233. package/src/runtime/channels/lib/config.mjs +6 -61
  234. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  235. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  236. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  237. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  238. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  239. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  240. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  241. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  242. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  243. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  244. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  245. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  246. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  247. package/src/runtime/channels/lib/scheduler.mjs +135 -154
  248. package/src/runtime/channels/lib/schedules-db.mjs +83 -11
  249. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  250. package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
  251. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  252. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  253. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  254. package/src/runtime/channels/lib/worker-main.mjs +19 -34
  255. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  256. package/src/runtime/computer-bridge/actions.mjs +9 -1
  257. package/src/runtime/computer-bridge/client.mjs +180 -8
  258. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  259. package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
  260. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  261. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  262. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  263. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  264. package/src/runtime/connectors/google-mcp.mjs +10 -12
  265. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  266. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  268. package/src/runtime/office/com/com-adapter.mjs +17 -1
  269. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  270. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  271. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  272. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  273. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  274. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  275. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  276. package/src/runtime/session-search/session-search-db.mjs +73 -9
  277. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  278. package/src/runtime/shared/abort-race.mjs +89 -0
  279. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  280. package/src/runtime/shared/agent-kind.mjs +4 -3
  281. package/src/runtime/shared/bot-hops.mjs +62 -2
  282. package/src/runtime/shared/bounded-download.mjs +8 -3
  283. package/src/runtime/shared/config.mjs +51 -35
  284. package/src/runtime/shared/connector-accounts.mjs +20 -10
  285. package/src/runtime/shared/connector-catalog.d.mts +33 -2
  286. package/src/runtime/shared/connector-catalog.mjs +166 -8
  287. package/src/runtime/shared/connector-triggers.mjs +22 -19
  288. package/src/runtime/shared/defaults-separation.mjs +2 -14
  289. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  290. package/src/runtime/shared/developer-options.mjs +32 -1
  291. package/src/runtime/shared/err-text.mjs +24 -15
  292. package/src/runtime/shared/file-permissions.d.mts +0 -8
  293. package/src/runtime/shared/file-permissions.mjs +0 -11
  294. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  295. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  296. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  297. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  298. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  299. package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
  300. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  301. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  302. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  303. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  304. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  305. package/src/runtime/shared/mixy-presence.mjs +22 -0
  306. package/src/runtime/shared/orchestration.d.mts +2 -0
  307. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  308. package/src/runtime/shared/profile-config.cjs +1 -1
  309. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  310. package/src/runtime/shared/prompt-origin.mjs +21 -0
  311. package/src/runtime/shared/provider-accounts.mjs +231 -59
  312. package/src/runtime/shared/provider-api-key.mjs +19 -8
  313. package/src/runtime/shared/provider-display-name.mjs +29 -0
  314. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  315. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  316. package/src/runtime/shared/routine-trigger.mjs +52 -0
  317. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  318. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  319. package/src/runtime/shared/session-activity-signal.mjs +34 -1
  320. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  321. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  322. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  323. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  324. package/src/runtime/shared/tool-result-summary.mjs +1 -14
  325. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  326. package/src/runtime/shared/user-data-guard.mjs +30 -2
  327. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  328. package/src/runtime/shared/worktrees/test-support.mjs +9 -4
  329. package/src/runtime/terminal-bridge/client.mjs +10 -1
  330. package/src/runtime/visualize-bridge/client.mjs +27 -8
  331. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  332. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  333. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  334. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  335. package/src/session-runtime/agent-home-delivery.mjs +486 -179
  336. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  337. package/src/session-runtime/agent-task-sessions.mjs +561 -199
  338. package/src/session-runtime/boot/apis.mjs +9 -0
  339. package/src/session-runtime/boot/begin.mjs +3 -2
  340. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  341. package/src/session-runtime/boot/providers.mjs +3 -0
  342. package/src/session-runtime/boot/tools.mjs +8 -1
  343. package/src/session-runtime/bot-chain.mjs +32 -0
  344. package/src/session-runtime/bot-status.mjs +7 -4
  345. package/src/session-runtime/channel-config-api.mjs +63 -17
  346. package/src/session-runtime/config-lifecycle.mjs +6 -0
  347. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  348. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
  349. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
  350. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  351. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  352. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  353. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  354. package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
  355. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  356. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  357. package/src/session-runtime/mcp-glue/server-catalog.mjs +61 -3
  358. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  359. package/src/session-runtime/mixy-heartbeat.mjs +927 -0
  360. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  361. package/src/session-runtime/notification-bus.mjs +31 -117
  362. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  363. package/src/session-runtime/notification-listeners.mjs +76 -0
  364. package/src/session-runtime/owned-automation-run.mjs +35 -13
  365. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  366. package/src/session-runtime/provider-auth/login.mjs +7 -0
  367. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  368. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  369. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  370. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  371. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  372. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  373. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  374. package/src/session-runtime/routine-home-turn.mjs +33 -6
  375. package/src/session-runtime/routine-owner.mjs +40 -9
  376. package/src/session-runtime/schedule-session-run.mjs +7 -3
  377. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  378. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  379. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
  380. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  381. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  382. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  383. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  384. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  385. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  386. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  387. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  388. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  389. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  390. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  391. package/src/session-runtime/services/channel-admin.mjs +73 -31
  392. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  393. package/src/session-runtime/services/channel-worker.mjs +1 -1
  394. package/src/session-runtime/services/provider-admin.mjs +128 -25
  395. package/src/session-runtime/services/schedule-access.mjs +14 -0
  396. package/src/session-runtime/services/seeds.mjs +0 -28
  397. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  398. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  399. package/src/session-runtime/session-create/session-options.mjs +8 -4
  400. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  401. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  402. package/src/session-runtime/settings-system-api.mjs +28 -1
  403. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  404. package/src/session-runtime/setup-tool/executor.mjs +187 -29
  405. package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
  406. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  407. package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
  408. package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
  409. package/src/session-runtime/task-session-route.mjs +99 -0
  410. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  411. package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
  412. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  413. package/src/session-runtime/tool-surface.mjs +4 -0
  414. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  415. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  416. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  417. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  418. package/src/session-runtime/workspace/transitions.mjs +10 -2
  419. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  420. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  421. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  422. package/src/standalone/channel-transport.mjs +1 -1
  423. package/src/standalone/daemon-channels-loader.mjs +10 -8
  424. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  425. package/src/standalone/daemon-session-control/request.mjs +51 -0
  426. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  427. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  428. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  429. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  430. package/src/standalone/daemon-session-control.mjs +161 -157
  431. package/src/standalone/daemon.mjs +33 -2
  432. package/src/standalone/session-client.mjs +7 -3
  433. package/src/standalone/session-protocol.mjs +10 -0
  434. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  435. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  436. package/src/standalone/session-service/quota-resume.mjs +3 -0
  437. package/src/standalone/session-service/retention/busy.mjs +65 -1
  438. package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
  439. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  440. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  441. package/src/standalone/session-service.mjs +13 -0
  442. package/src/standalone/session-tool-output.mjs +21 -10
  443. package/src/tui/app/model-options.mjs +4 -27
  444. package/src/tui/dist/index.mjs +81 -65
  445. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  446. package/src/tui/session/initial-state.mjs +3 -0
  447. package/src/tui/session/notice-surface.mjs +23 -1
  448. package/src/tui/session/queue-helpers.mjs +3 -42
  449. package/src/tui/session/session-api/integrations.mjs +1 -0
  450. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  451. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  452. package/src/tui/session/session-api/routes-write.mjs +5 -1
  453. package/src/tui/session/session-api/routes.mjs +1 -0
  454. package/src/tui/session/session-api/settings.mjs +30 -2
  455. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  456. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  457. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  458. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  459. package/src/tui/session/session-flow/drain.mjs +118 -149
  460. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  461. package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
  462. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  463. package/src/tui/session/tool-approval-request.mjs +39 -0
  464. package/src/tui/session/tool-approval-settle.mjs +62 -0
  465. package/src/tui/session/tool-approval.mjs +69 -115
  466. package/src/tui/session/tui-steering-persist.mjs +8 -1
  467. package/src/tui/session/turn-stream.mjs +36 -3
  468. package/src/tui/session/turn.mjs +23 -2
  469. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  470. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  471. package/scripts/code-graph-description-contract.mjs +0 -188
  472. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -0,0 +1,880 @@
1
+ // Tool parameter schemas on the Devin wire.
2
+ //
3
+ // devinToolWireSchema: every tool's JSON Schema upgraded to draft 2020-12
4
+ // (definitions → $defs, tuple items → prefixItems, dependencies split,
5
+ // OpenAPI `nullable` → null unions), nullable scalar unions folded into a
6
+ // type array, bare enums typed, homogeneous const unions folded into an enum,
7
+ // and empty subschemas written as `true`.
8
+ //
9
+ // devinGoogleToolSchema: the projection Gemini backends accept: refs inlined,
10
+ // unsupported keywords stripped (the human-meaningful ones spilled into the
11
+ // description), type arrays scalarized with `nullable`, const unions folded
12
+ // into string enums, object property order made explicit.
13
+
14
+ // ── JSON helpers ─────────────────────────────────────────────────────────────
15
+ const isJsonObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
16
+ const isEmptyObject = (value) => isJsonObject(value) && Object.keys(value).length === 0;
17
+
18
+ function jsonEqual(left, right) {
19
+ if (Object.is(left, right)) return true;
20
+ if (Array.isArray(left) || Array.isArray(right)) {
21
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
22
+ return left.every((entry, index) => jsonEqual(entry, right[index]));
23
+ }
24
+ if (!isJsonObject(left) || !isJsonObject(right)) return false;
25
+ const leftKeys = Object.keys(left);
26
+ if (leftKeys.length !== Object.keys(right).length) return false;
27
+ return leftKeys.every((key) => key in right && jsonEqual(left[key], right[key]));
28
+ }
29
+
30
+ // RFC 6901 tokens of a local `$ref` fragment; undefined for a non-local ref.
31
+ function parseLocalRefPointer(ref) {
32
+ if (!ref.startsWith('#')) return undefined;
33
+ let pointer;
34
+ try {
35
+ pointer = decodeURIComponent(ref.slice(1));
36
+ } catch {
37
+ return undefined;
38
+ }
39
+ if (pointer.length > 0 && !pointer.startsWith('/')) return undefined;
40
+ return pointer
41
+ .split('/')
42
+ .slice(1)
43
+ .map((token) => token.replace(/~1/g, '/').replace(/~0/g, '~'));
44
+ }
45
+
46
+ function formatLocalRefPointer(tokens) {
47
+ if (!tokens.length) return '#';
48
+ const encoded = tokens
49
+ .map((token) => encodeURIComponent(token.replace(/~/g, '~0').replace(/\//g, '~1')))
50
+ .map((token) => token.replace(/%24/g, '$'));
51
+ return `#/${encoded.join('/')}`;
52
+ }
53
+
54
+ // ── Draft 2020-12 upgrade ────────────────────────────────────────────────────
55
+ const DRAFT_07_SCHEMA_URIS = new Set([
56
+ 'http://json-schema.org/draft-07/schema#',
57
+ 'https://json-schema.org/draft-07/schema#',
58
+ 'http://json-schema.org/draft-07/schema',
59
+ 'https://json-schema.org/draft-07/schema',
60
+ ]);
61
+ const DRAFT_2020_12_URI = 'https://json-schema.org/draft/2020-12/schema';
62
+ const UPGRADE_MAP_KEYS = new Set(['properties', 'patternProperties', 'dependentSchemas']);
63
+ const UPGRADE_VALUE_KEYS = new Set([
64
+ 'const',
65
+ 'default',
66
+ 'enum',
67
+ 'example',
68
+ 'examples',
69
+ 'required',
70
+ 'dependentRequired',
71
+ 'type',
72
+ ]);
73
+
74
+ function needsUpgrade(value, seen) {
75
+ if (Array.isArray(value)) {
76
+ if (seen.has(value)) return false;
77
+ seen.add(value);
78
+ return value.some((entry) => needsUpgrade(entry, seen));
79
+ }
80
+ if (!isJsonObject(value) || seen.has(value)) return false;
81
+ seen.add(value);
82
+ for (const key in value) {
83
+ const entry = value[key];
84
+ if (key === '$schema') {
85
+ if (typeof entry === 'string' && DRAFT_07_SCHEMA_URIS.has(entry)) return true;
86
+ continue;
87
+ }
88
+ if (key === 'definitions' || key === 'dependencies' || key === 'additionalItems' || key === 'nullable') return true;
89
+ if (key === '$ref') {
90
+ if (typeof entry === 'string' && entry.startsWith('#/definitions/')) return true;
91
+ continue;
92
+ }
93
+ if (key === 'items' && Array.isArray(entry)) return true;
94
+ if (key === '$defs' || UPGRADE_MAP_KEYS.has(key)) {
95
+ if (isJsonObject(entry) && Object.values(entry).some((child) => needsUpgrade(child, seen))) return true;
96
+ continue;
97
+ }
98
+ if (UPGRADE_VALUE_KEYS.has(key)) continue;
99
+ if (needsUpgrade(entry, seen)) return true;
100
+ }
101
+ return false;
102
+ }
103
+
104
+ function objectMap(target, key) {
105
+ if (isJsonObject(target[key])) return target[key];
106
+ target[key] = {};
107
+ return target[key];
108
+ }
109
+
110
+ function combineSchemas(left, right) {
111
+ if (left === undefined || left === true) return right;
112
+ if (right === undefined || right === true) return left;
113
+ if (left === false || right === false) return false;
114
+ if (jsonEqual(left, right)) return left;
115
+ return { allOf: [left, right] };
116
+ }
117
+
118
+ function makeNullable(schema) {
119
+ const { type } = schema;
120
+ if (typeof type === 'string') {
121
+ if (type !== 'null') schema.type = [type, 'null'];
122
+ return schema;
123
+ }
124
+ if (Array.isArray(type)) {
125
+ if (!type.includes('null')) schema.type = [...type, 'null'];
126
+ return schema;
127
+ }
128
+ if (Array.isArray(schema.anyOf)) {
129
+ const hasNull = schema.anyOf.some(
130
+ (variant) =>
131
+ isJsonObject(variant) &&
132
+ (variant.type === 'null' || (Array.isArray(variant.type) && variant.type.includes('null')))
133
+ );
134
+ if (!hasNull) schema.anyOf = [...schema.anyOf, { type: 'null' }];
135
+ return schema;
136
+ }
137
+ return { anyOf: [schema, { type: 'null' }] };
138
+ }
139
+
140
+ function upgradeNode(value, cache) {
141
+ if (Array.isArray(value)) {
142
+ if (cache.has(value)) return cache.get(value);
143
+ const result = [];
144
+ cache.set(value, result);
145
+ for (const entry of value) result.push(upgradeNode(entry, cache));
146
+ return result;
147
+ }
148
+ if (!isJsonObject(value)) return value;
149
+ if (cache.has(value)) return cache.get(value);
150
+ const result = {};
151
+ cache.set(value, result);
152
+ const mergeMap = (key, map) => {
153
+ const target = objectMap(result, key);
154
+ for (const name in map) target[name] = upgradeNode(map[name], cache);
155
+ };
156
+ for (const key in value) {
157
+ const entry = value[key];
158
+ if (key === 'definitions' || key === '$defs') {
159
+ if (isJsonObject(entry)) mergeMap('$defs', entry);
160
+ continue;
161
+ }
162
+ if (UPGRADE_MAP_KEYS.has(key)) {
163
+ if (isJsonObject(entry)) mergeMap(key, entry);
164
+ else result[key] = entry;
165
+ continue;
166
+ }
167
+ if (UPGRADE_VALUE_KEYS.has(key)) {
168
+ result[key] = entry;
169
+ continue;
170
+ }
171
+ if (key === 'dependencies' || key === 'additionalItems' || key === 'nullable') continue;
172
+ if (key === '$schema') {
173
+ result.$schema = typeof entry === 'string' && DRAFT_07_SCHEMA_URIS.has(entry) ? DRAFT_2020_12_URI : entry;
174
+ continue;
175
+ }
176
+ if (key === '$ref' && typeof entry === 'string') {
177
+ const pointer = parseLocalRefPointer(entry);
178
+ result.$ref =
179
+ pointer === undefined || pointer[0] !== 'definitions'
180
+ ? entry
181
+ : formatLocalRefPointer(['$defs', ...pointer.slice(1)]);
182
+ continue;
183
+ }
184
+ if (key === 'items' && Array.isArray(entry)) continue;
185
+ result[key] = upgradeNode(entry, cache);
186
+ }
187
+ if (Array.isArray(value.items)) {
188
+ const converted = upgradeNode(value.items, cache);
189
+ if (Array.isArray(result.prefixItems)) {
190
+ const merged = [...result.prefixItems];
191
+ converted.forEach((item, index) => {
192
+ merged[index] = index in merged ? combineSchemas(merged[index], item) : item;
193
+ });
194
+ result.prefixItems = merged;
195
+ } else {
196
+ result.prefixItems = converted;
197
+ }
198
+ if (value.additionalItems !== undefined && value.additionalItems !== true) {
199
+ result.items = upgradeNode(value.additionalItems, cache);
200
+ } else {
201
+ delete result.items;
202
+ }
203
+ }
204
+ if (isJsonObject(value.dependencies)) {
205
+ for (const key in value.dependencies) {
206
+ const converted = upgradeNode(value.dependencies[key], cache);
207
+ if (Array.isArray(converted)) {
208
+ const required = objectMap(result, 'dependentRequired');
209
+ const existing = required[key];
210
+ if (existing === undefined) required[key] = converted;
211
+ else if (Array.isArray(existing)) {
212
+ const merged = [...existing];
213
+ for (const dep of converted) if (!merged.some((item) => jsonEqual(item, dep))) merged.push(dep);
214
+ required[key] = merged;
215
+ }
216
+ } else {
217
+ const schemas = objectMap(result, 'dependentSchemas');
218
+ schemas[key] = combineSchemas(schemas[key], converted);
219
+ }
220
+ }
221
+ }
222
+ if (value.nullable === true) {
223
+ const nullable = makeNullable(result);
224
+ if (nullable !== result) cache.set(value, nullable);
225
+ return nullable;
226
+ }
227
+ return result;
228
+ }
229
+
230
+ function upgradeTo202012(schema) {
231
+ return needsUpgrade(schema, new Set()) ? upgradeNode(schema, new Map()) : schema;
232
+ }
233
+
234
+ // ── Wire post-processing ─────────────────────────────────────────────────────
235
+ const NULLABLE_SCALAR_TYPES = new Set(['string', 'number', 'integer', 'boolean']);
236
+ const SCHEMA_DEFINING_SIBLING_KEYS = new Set([
237
+ '$ref',
238
+ 'additionalProperties',
239
+ 'allOf',
240
+ 'anyOf',
241
+ 'const',
242
+ 'contains',
243
+ 'enum',
244
+ 'if',
245
+ 'items',
246
+ 'not',
247
+ 'oneOf',
248
+ 'patternProperties',
249
+ 'prefixItems',
250
+ 'properties',
251
+ 'propertyNames',
252
+ 'then',
253
+ 'else',
254
+ 'unevaluatedItems',
255
+ 'unevaluatedProperties',
256
+ ]);
257
+ const WIRE_VALUE_KEYS = [
258
+ 'additionalProperties',
259
+ 'unevaluatedProperties',
260
+ 'unevaluatedItems',
261
+ 'items',
262
+ 'contains',
263
+ 'propertyNames',
264
+ 'if',
265
+ 'then',
266
+ 'else',
267
+ 'not',
268
+ ];
269
+ const WIRE_MAP_KEYS = ['properties', 'patternProperties', '$defs', 'definitions'];
270
+ const WIRE_ARRAY_KEYS = ['anyOf', 'oneOf', 'allOf', 'prefixItems'];
271
+
272
+ const hasSchemaDefiningSibling = (schema) =>
273
+ Object.keys(schema).some((key) => key !== 'anyOf' && SCHEMA_DEFINING_SIBLING_KEYS.has(key));
274
+
275
+ function homogeneousScalarType(values) {
276
+ if (!values.length) return undefined;
277
+ let inferred;
278
+ for (const value of values) {
279
+ const type = typeof value;
280
+ if (type !== 'string' && type !== 'boolean' && type !== 'number') return undefined;
281
+ if (inferred === undefined) inferred = type;
282
+ else if (inferred !== type) return undefined;
283
+ }
284
+ return inferred;
285
+ }
286
+
287
+ // `anyOf: [{type: T, ...}, {type: 'null'}]` → `type: [T, 'null']`.
288
+ function rewriteNullableScalarAnyOf(schema) {
289
+ if (hasSchemaDefiningSibling(schema)) return;
290
+ const variants = schema.anyOf;
291
+ if (!Array.isArray(variants) || variants.length !== 2) return;
292
+ let scalar;
293
+ let sawNull = false;
294
+ for (const variant of variants) {
295
+ if (!isJsonObject(variant)) return;
296
+ if (variant.type === 'null' && Object.keys(variant).length === 1) {
297
+ if (sawNull) return;
298
+ sawNull = true;
299
+ continue;
300
+ }
301
+ if (!(typeof variant.type === 'string' && NULLABLE_SCALAR_TYPES.has(variant.type)) || scalar) return;
302
+ scalar = variant;
303
+ }
304
+ if (!sawNull || !scalar) return;
305
+ delete schema.anyOf;
306
+ for (const key in scalar) {
307
+ if (key === 'type' || key === 'enum' || key === 'const' || Object.hasOwn(schema, key)) continue;
308
+ schema[key] = scalar[key];
309
+ }
310
+ if (Object.hasOwn(scalar, 'const')) schema.enum = [scalar.const, null];
311
+ else if (Array.isArray(scalar.enum)) schema.enum = scalar.enum.includes(null) ? scalar.enum : [...scalar.enum, null];
312
+ schema.type = [scalar.type, 'null'];
313
+ }
314
+
315
+ function inferBareEnumScalarType(schema) {
316
+ if ('type' in schema || !Array.isArray(schema.enum)) return;
317
+ const inferred = homogeneousScalarType(schema.enum);
318
+ if (inferred !== undefined) schema.type = inferred;
319
+ }
320
+
321
+ // A homogeneous `anyOf` of bare `{ const }` branches → `{ type, enum }`.
322
+ function collapseConstUnionAnyOf(schema) {
323
+ if (hasSchemaDefiningSibling(schema) || 'type' in schema) return;
324
+ const variants = schema.anyOf;
325
+ if (!Array.isArray(variants) || variants.length < 2) return;
326
+ const values = [];
327
+ let branchDescription;
328
+ let described = 0;
329
+ for (const variant of variants) {
330
+ if (!isJsonObject(variant) || !Object.hasOwn(variant, 'const')) return;
331
+ if (Object.keys(variant).some((key) => key !== 'const' && key !== 'description')) return;
332
+ if (typeof variant.description === 'string') {
333
+ if (described === 0) branchDescription = variant.description;
334
+ else if (variant.description !== branchDescription) return;
335
+ described += 1;
336
+ }
337
+ values.push(variant.const);
338
+ }
339
+ if (described !== 0 && described !== variants.length) return;
340
+ if (
341
+ described === variants.length &&
342
+ typeof schema.description === 'string' &&
343
+ schema.description !== branchDescription
344
+ ) {
345
+ return;
346
+ }
347
+ const type = homogeneousScalarType(values);
348
+ if (type === undefined) return;
349
+ delete schema.anyOf;
350
+ schema.type = type;
351
+ schema.enum = values;
352
+ if (typeof schema.description !== 'string' && branchDescription !== undefined) schema.description = branchDescription;
353
+ }
354
+
355
+ function walkWire(node) {
356
+ if (Array.isArray(node)) {
357
+ for (const child of node) walkWire(child);
358
+ return;
359
+ }
360
+ if (!node || typeof node !== 'object') return;
361
+ rewriteNullableScalarAnyOf(node);
362
+ inferBareEnumScalarType(node);
363
+ collapseConstUnionAnyOf(node);
364
+ for (const key in node) walkWire(node[key]);
365
+ }
366
+
367
+ // `name /** description */` property keys carry their description inline.
368
+ function parseCommentKey(key) {
369
+ const match = /^(.*?)\s*\/\*\*\s*([\s\S]*?)\s*\*\/\s*$/.exec(key);
370
+ return match ? { name: match[1].trim(), description: match[2].trim() } : { name: key };
371
+ }
372
+
373
+ function withKeyDescription(schema, description) {
374
+ if (!description) return schema;
375
+ if (isJsonObject(schema)) {
376
+ if (typeof schema.description !== 'string') schema.description = description;
377
+ return schema;
378
+ }
379
+ return { anyOf: [schema], description };
380
+ }
381
+
382
+ function normalizePropertyComments(node) {
383
+ if (Array.isArray(node)) {
384
+ for (const child of node) normalizePropertyComments(child);
385
+ return;
386
+ }
387
+ if (!isJsonObject(node)) return;
388
+ if (isJsonObject(node.properties)) {
389
+ const { properties } = node;
390
+ if (Array.isArray(node.required)) {
391
+ node.required = node.required.map((key) => (typeof key === 'string' ? parseCommentKey(key).name : key));
392
+ }
393
+ for (const key of Object.keys(properties)) {
394
+ const parsed = parseCommentKey(key);
395
+ let schema = properties[key];
396
+ if (parsed.description) {
397
+ schema = withKeyDescription(schema, parsed.description);
398
+ delete properties[key];
399
+ properties[parsed.name] = schema;
400
+ }
401
+ normalizePropertyComments(schema);
402
+ }
403
+ }
404
+ for (const key of WIRE_VALUE_KEYS) if (Object.hasOwn(node, key)) normalizePropertyComments(node[key]);
405
+ for (const key of WIRE_MAP_KEYS) {
406
+ if (key === 'properties' || !isJsonObject(node[key])) continue;
407
+ for (const name in node[key]) normalizePropertyComments(node[key][name]);
408
+ }
409
+ for (const key of WIRE_ARRAY_KEYS)
410
+ if (Array.isArray(node[key])) for (const child of node[key]) normalizePropertyComments(child);
411
+ }
412
+
413
+ // `{}` (unconstrained) → `true` in every schema-valued position.
414
+ function normalizeEmptySchemas(node) {
415
+ if (Array.isArray(node)) {
416
+ for (const child of node) normalizeEmptySchemas(child);
417
+ return;
418
+ }
419
+ if (!node || typeof node !== 'object') return;
420
+ for (const key of WIRE_VALUE_KEYS) if (Object.hasOwn(node, key) && isEmptyObject(node[key])) node[key] = true;
421
+ for (const key of WIRE_MAP_KEYS) {
422
+ const map = node[key];
423
+ if (!map || typeof map !== 'object' || Array.isArray(map)) continue;
424
+ for (const name in map) if (isEmptyObject(map[name])) map[name] = true;
425
+ }
426
+ for (const key of WIRE_ARRAY_KEYS) {
427
+ const list = node[key];
428
+ if (Array.isArray(list)) for (let i = 0; i < list.length; i += 1) if (isEmptyObject(list[i])) list[i] = true;
429
+ }
430
+ for (const key in node) normalizeEmptySchemas(node[key]);
431
+ }
432
+
433
+ /** A tool's input schema as every Devin request carries it (a fresh copy). */
434
+ export function devinToolWireSchema(inputSchema) {
435
+ const copy = JSON.parse(JSON.stringify(inputSchema ?? {}));
436
+ const upgraded = upgradeTo202012(copy);
437
+ walkWire(upgraded);
438
+ normalizePropertyComments(upgraded);
439
+ normalizeEmptySchemas(upgraded);
440
+ return upgraded;
441
+ }
442
+
443
+ // ── Ref inlining ─────────────────────────────────────────────────────────────
444
+ const DEREF_MAP_KEYS = new Set(['properties', 'patternProperties', 'dependencies', 'dependentSchemas']);
445
+ const DEREF_ARRAY_KEYS = new Set(['anyOf', 'oneOf', 'allOf', 'prefixItems']);
446
+ const DEREF_VALUE_KEYS = new Set([
447
+ 'items',
448
+ 'additionalItems',
449
+ 'contains',
450
+ 'contentSchema',
451
+ 'propertyNames',
452
+ 'if',
453
+ 'then',
454
+ 'else',
455
+ 'not',
456
+ 'additionalProperties',
457
+ 'unevaluatedItems',
458
+ 'unevaluatedProperties',
459
+ ]);
460
+
461
+ function dereferenceKeyword(key, value, root, visiting) {
462
+ if (DEREF_MAP_KEYS.has(key) && isJsonObject(value)) {
463
+ const result = {};
464
+ for (const name in value) result[name] = dereferenceNode(value[name], root, visiting);
465
+ return result;
466
+ }
467
+ if ((DEREF_ARRAY_KEYS.has(key) || key === 'items') && Array.isArray(value)) {
468
+ return value.map((item) => dereferenceNode(item, root, visiting));
469
+ }
470
+ if (DEREF_VALUE_KEYS.has(key)) return dereferenceNode(value, root, visiting);
471
+ return value;
472
+ }
473
+
474
+ function resolveLocalRef(ref, root) {
475
+ const pointer = parseLocalRefPointer(ref);
476
+ if (pointer === undefined || pointer.length !== 2) return undefined;
477
+ const [defsKey, name] = pointer;
478
+ if (defsKey !== '$defs' && defsKey !== 'definitions') return undefined;
479
+ const defs = root[defsKey];
480
+ if (!isJsonObject(defs)) return undefined;
481
+ return isJsonObject(defs[name]) ? defs[name] : undefined;
482
+ }
483
+
484
+ function dereferenceNode(node, root, visiting) {
485
+ if (!isJsonObject(node)) return node;
486
+ const ref = node.$ref;
487
+ if (typeof ref === 'string') {
488
+ if (visiting.has(ref)) return {};
489
+ const resolved = resolveLocalRef(ref, root);
490
+ if (!resolved) return node;
491
+ visiting.add(ref);
492
+ const inlined = dereferenceNode(resolved, root, visiting);
493
+ visiting.delete(ref);
494
+ const siblings = Object.keys(node).filter((key) => key !== '$ref' && key !== '$defs' && key !== 'definitions');
495
+ if (!siblings.length || !isJsonObject(inlined)) return inlined;
496
+ const merged = { ...inlined };
497
+ for (const key of siblings) merged[key] = dereferenceKeyword(key, node[key], root, visiting);
498
+ return merged;
499
+ }
500
+ const result = {};
501
+ for (const key in node) {
502
+ if (key === '$defs' || key === 'definitions') continue;
503
+ result[key] = dereferenceKeyword(key, node[key], root, visiting);
504
+ }
505
+ return result;
506
+ }
507
+
508
+ function dereferenceSchema(schema) {
509
+ if (!isJsonObject(schema) || (schema.$defs === undefined && schema.definitions === undefined)) return schema;
510
+ return dereferenceNode(schema, schema, new Set());
511
+ }
512
+
513
+ // ── Google projection ────────────────────────────────────────────────────────
514
+ const GOOGLE_UNSUPPORTED_FIELDS = new Set([
515
+ '$schema',
516
+ '$id',
517
+ '$anchor',
518
+ '$ref',
519
+ '$defs',
520
+ '$dynamicRef',
521
+ '$dynamicAnchor',
522
+ 'examples',
523
+ 'prefixItems',
524
+ 'unevaluatedProperties',
525
+ 'unevaluatedItems',
526
+ 'patternProperties',
527
+ 'additionalProperties',
528
+ 'propertyNames',
529
+ 'minItems',
530
+ 'maxItems',
531
+ 'uniqueItems',
532
+ 'contains',
533
+ 'minContains',
534
+ 'maxContains',
535
+ 'additionalItems',
536
+ 'minLength',
537
+ 'maxLength',
538
+ 'minimum',
539
+ 'maximum',
540
+ 'exclusiveMinimum',
541
+ 'exclusiveMaximum',
542
+ 'multipleOf',
543
+ 'pattern',
544
+ 'format',
545
+ 'contentEncoding',
546
+ 'contentMediaType',
547
+ 'contentSchema',
548
+ 'dependencies',
549
+ 'dependentSchemas',
550
+ 'dependentRequired',
551
+ 'x-mcp-header',
552
+ 'deprecated',
553
+ 'readOnly',
554
+ 'writeOnly',
555
+ '$comment',
556
+ ]);
557
+ // Stripped keywords whose meaning is kept as text in the description.
558
+ const DESCRIPTION_SPILL_FIELDS = new Set([
559
+ 'pattern',
560
+ 'format',
561
+ 'minLength',
562
+ 'maxLength',
563
+ 'minimum',
564
+ 'maximum',
565
+ 'exclusiveMinimum',
566
+ 'exclusiveMaximum',
567
+ 'multipleOf',
568
+ 'minItems',
569
+ 'maxItems',
570
+ 'uniqueItems',
571
+ 'minProperties',
572
+ 'maxProperties',
573
+ 'default',
574
+ 'examples',
575
+ ]);
576
+ const SNAKE_TO_CAMEL = new Map([
577
+ ['additional_properties', 'additionalProperties'],
578
+ ['any_of', 'anyOf'],
579
+ ['prefix_items', 'prefixItems'],
580
+ ['property_ordering', 'propertyOrdering'],
581
+ ]);
582
+ const TYPE_SPECIFIC_KEYS = Object.freeze({
583
+ array: new Set([
584
+ 'items',
585
+ 'prefixItems',
586
+ 'contains',
587
+ 'minContains',
588
+ 'maxContains',
589
+ 'minItems',
590
+ 'maxItems',
591
+ 'uniqueItems',
592
+ 'unevaluatedItems',
593
+ ]),
594
+ object: new Set([
595
+ 'properties',
596
+ 'required',
597
+ 'additionalProperties',
598
+ 'patternProperties',
599
+ 'propertyNames',
600
+ 'minProperties',
601
+ 'maxProperties',
602
+ 'dependentRequired',
603
+ 'dependentSchemas',
604
+ 'unevaluatedProperties',
605
+ ]),
606
+ string: new Set(['minLength', 'maxLength', 'pattern', 'format', 'contentEncoding', 'contentMediaType']),
607
+ number: new Set(['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf']),
608
+ integer: new Set(['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf']),
609
+ boolean: new Set(),
610
+ null: new Set(),
611
+ });
612
+ const ALL_TYPE_SPECIFIC_KEYS = new Set(Object.values(TYPE_SPECIFIC_KEYS).flatMap((keys) => [...keys]));
613
+ const CHILD_VALUE_KEYS = new Set([
614
+ 'items',
615
+ 'additionalItems',
616
+ 'unevaluatedItems',
617
+ 'not',
618
+ 'if',
619
+ 'then',
620
+ 'else',
621
+ 'contains',
622
+ 'propertyNames',
623
+ 'contentSchema',
624
+ ]);
625
+ const CHILD_OR_BOOLEAN_KEYS = new Set(['additionalProperties', 'unevaluatedProperties']);
626
+ const CHILD_ARRAY_KEYS = new Set(['anyOf', 'oneOf', 'allOf', 'prefixItems']);
627
+ const CHILD_MAP_KEYS = new Set([
628
+ 'properties',
629
+ 'patternProperties',
630
+ 'dependencies',
631
+ 'dependentSchemas',
632
+ '$defs',
633
+ 'definitions',
634
+ ]);
635
+
636
+ // 'schema' / 'map' for a JSON Schema-valued child; undefined for instance data.
637
+ function childKind(key, value, insideMap) {
638
+ if (insideMap) return 'schema';
639
+ const name = SNAKE_TO_CAMEL.get(key) ?? key;
640
+ if (CHILD_MAP_KEYS.has(name)) return 'map';
641
+ if (CHILD_VALUE_KEYS.has(name) || CHILD_ARRAY_KEYS.has(name)) return 'schema';
642
+ if (CHILD_OR_BOOLEAN_KEYS.has(name) && isJsonObject(value)) return 'schema';
643
+ return undefined;
644
+ }
645
+
646
+ // Whether a `not` subtree constrains values Google's string-only enums cannot express.
647
+ function hasNonStringEnumConstraint(value, insideMap = false, seen = new Set()) {
648
+ if (Array.isArray(value)) {
649
+ if (seen.has(value)) return false;
650
+ seen.add(value);
651
+ return value.some((entry) => hasNonStringEnumConstraint(entry, false, seen));
652
+ }
653
+ if (!isJsonObject(value) || seen.has(value)) return false;
654
+ seen.add(value);
655
+ if (insideMap) return Object.values(value).some((entry) => hasNonStringEnumConstraint(entry, false, seen));
656
+ if (Array.isArray(value.enum) && (value.enum.length === 0 || value.enum.some((entry) => typeof entry !== 'string'))) {
657
+ return true;
658
+ }
659
+ if (Object.hasOwn(value, 'const') && typeof value.const !== 'string') return true;
660
+ for (const key in value) {
661
+ const kind = childKind(key, value[key], false);
662
+ if (kind && hasNonStringEnumConstraint(value[key], kind === 'map', seen)) return true;
663
+ }
664
+ return false;
665
+ }
666
+
667
+ function renameSnakeKeys(obj) {
668
+ if (!Object.keys(obj).some((key) => SNAKE_TO_CAMEL.has(key))) return obj;
669
+ const out = {};
670
+ for (const key in obj) {
671
+ const renamed = SNAKE_TO_CAMEL.get(key);
672
+ if (renamed !== undefined) out[renamed] = obj[key];
673
+ else if (!Object.hasOwn(out, key)) out[key] = obj[key];
674
+ }
675
+ return out;
676
+ }
677
+
678
+ // `type: 'null'` → `nullable`; a null branch of `anyOf` → `nullable`.
679
+ function preHandleNullFields(obj) {
680
+ if (obj.type === 'null') {
681
+ const out = {};
682
+ for (const key in obj) if (key !== 'type') out[key] = obj[key];
683
+ out.nullable = true;
684
+ return out;
685
+ }
686
+ if (!Array.isArray(obj.anyOf)) return obj;
687
+ const kept = obj.anyOf.filter((variant) => !(isJsonObject(variant) && variant.type === 'null'));
688
+ if (kept.length === obj.anyOf.length) return obj;
689
+ const out = { ...obj, nullable: true };
690
+ if (!kept.length) delete out.anyOf;
691
+ else if (kept.length === 1 && isJsonObject(kept[0])) {
692
+ delete out.anyOf;
693
+ for (const key in kept[0]) if (!Object.hasOwn(out, key)) out[key] = kept[0][key];
694
+ } else out.anyOf = kept;
695
+ return out;
696
+ }
697
+
698
+ // A multi-type array → one `anyOf` branch per non-null type with its own keywords.
699
+ function splitTypeArray(obj) {
700
+ if (!Array.isArray(obj.type) || Array.isArray(obj.anyOf)) return obj;
701
+ const types = [];
702
+ for (const type of obj.type)
703
+ if (typeof type === 'string' && type !== 'null' && !types.includes(type)) types.push(type);
704
+ if (types.length < 2) return obj;
705
+ const branches = types.map((type) => ({ schema: { type }, keys: TYPE_SPECIFIC_KEYS[type] ?? new Set() }));
706
+ const out = {};
707
+ for (const key in obj) {
708
+ if (key === 'type') continue;
709
+ if (!ALL_TYPE_SPECIFIC_KEYS.has(key)) {
710
+ out[key] = obj[key];
711
+ continue;
712
+ }
713
+ for (const branch of branches) if (branch.keys.has(key)) branch.schema[key] = obj[key];
714
+ }
715
+ if (obj.type.includes('null')) out.nullable = true;
716
+ out.anyOf = branches.map((branch) => branch.schema);
717
+ return out;
718
+ }
719
+
720
+ function inferTypeFromValue(value) {
721
+ if (value === null) return 'null';
722
+ if (Array.isArray(value)) return 'array';
723
+ const type = typeof value;
724
+ return type === 'string' || type === 'number' || type === 'boolean' || type === 'object' ? type : undefined;
725
+ }
726
+
727
+ function pushUnique(values, value) {
728
+ if (!values.some((existing) => jsonEqual(existing, value))) values.push(value);
729
+ }
730
+
731
+ function spillToDescription(node, entries) {
732
+ const spilled = entries.filter(([, value]) => value !== undefined);
733
+ if (!spilled.length) return;
734
+ const formatted = `{${spilled.map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(', ')}}`;
735
+ const existing = typeof node.description === 'string' ? node.description : '';
736
+ node.description = existing ? `${existing}\n\n${formatted}` : formatted;
737
+ }
738
+
739
+ function googleNode(value, ctx, path) {
740
+ if (Array.isArray(value)) {
741
+ if (path.has(value)) return [];
742
+ path.add(value);
743
+ try {
744
+ return value.map((entry) => googleNode(entry, ctx, path));
745
+ } finally {
746
+ path.delete(value);
747
+ }
748
+ }
749
+ if (typeof value === 'boolean') {
750
+ if (!ctx.subschema) return value;
751
+ return value ? {} : { not: {} };
752
+ }
753
+ if (!isJsonObject(value)) return value;
754
+ if (path.has(value)) return {};
755
+ path.add(value);
756
+ try {
757
+ return googleObject(value, ctx, path);
758
+ } finally {
759
+ path.delete(value);
760
+ }
761
+ }
762
+
763
+ function googleChild(key, entry, ctx, path) {
764
+ const kind = childKind(key, entry, ctx.insideMap);
765
+ return kind ? googleNode(entry, { insideMap: kind === 'map', subschema: kind === 'schema' }, path) : entry;
766
+ }
767
+
768
+ // Copies one keyword onto `result`, or records it for the description spill.
769
+ function copyKeyword(result, key, entry, ctx, path, spill) {
770
+ if (!ctx.insideMap && GOOGLE_UNSUPPORTED_FIELDS.has(key)) {
771
+ if (DESCRIPTION_SPILL_FIELDS.has(key)) spill.push([key, entry]);
772
+ return;
773
+ }
774
+ if (!ctx.insideMap && key === 'not' && hasNonStringEnumConstraint(entry)) return;
775
+ result[key] = googleChild(key, entry, ctx, path);
776
+ }
777
+
778
+ // Google's enum takes strings only: any other enum is omitted, the type kept.
779
+ function finishNode(result, ctx) {
780
+ if (ctx.subschema && Array.isArray(result.enum)) {
781
+ const stringEnum = result.enum.length > 0 && result.enum.every((value) => typeof value === 'string');
782
+ if (!stringEnum) {
783
+ const { enum: _dropped, ...rest } = result;
784
+ return rest;
785
+ }
786
+ }
787
+ return result;
788
+ }
789
+
790
+ function googleObject(value, ctx, path) {
791
+ let obj = ctx.insideMap ? value : renameSnakeKeys(value);
792
+ if (!ctx.insideMap) obj = preHandleNullFields(splitTypeArray(obj));
793
+ const result = {};
794
+ const spill = [];
795
+
796
+ // An `anyOf`/`oneOf` of const branches becomes one enum.
797
+ for (const combiner of ['anyOf', 'oneOf']) {
798
+ const variants = obj[combiner];
799
+ if (!Array.isArray(variants) || !variants.length || !variants.every((v) => isJsonObject(v) && 'const' in v))
800
+ continue;
801
+ const values = [];
802
+ for (const variant of variants) pushUnique(values, variant.const);
803
+ result.enum = values;
804
+ const explicit = variants.map((variant) => variant.type).filter((type) => typeof type === 'string');
805
+ if (explicit.length === variants.length && explicit.every((type) => type === explicit[0]) && explicit[0]) {
806
+ result.type = explicit[0];
807
+ } else {
808
+ const inferred = values.map(inferTypeFromValue).filter((type) => type !== undefined);
809
+ if (new Set(inferred).size === 1) result.type = inferred[0];
810
+ else {
811
+ const nonNull = inferred.filter((type) => type !== 'null');
812
+ if (inferred.includes('null') && new Set(nonNull).size === 1) {
813
+ result.type = nonNull[0];
814
+ result.nullable = true;
815
+ }
816
+ }
817
+ }
818
+ for (const key in obj) {
819
+ if (key === combiner || Object.hasOwn(result, key)) continue;
820
+ copyKeyword(result, key, obj[key], ctx, path, spill);
821
+ }
822
+ spillToDescription(result, spill);
823
+ return finishNode(result, ctx);
824
+ }
825
+
826
+ let constValue;
827
+ for (const key in obj) {
828
+ if (!ctx.insideMap && GOOGLE_UNSUPPORTED_FIELDS.has(key)) {
829
+ if (DESCRIPTION_SPILL_FIELDS.has(key)) spill.push([key, obj[key]]);
830
+ continue;
831
+ }
832
+ if (key === 'const') {
833
+ constValue = obj[key];
834
+ continue;
835
+ }
836
+ copyKeyword(result, key, obj[key], ctx, path, spill);
837
+ }
838
+ if (Array.isArray(result.type)) {
839
+ const types = result.type.filter((type) => typeof type === 'string');
840
+ const nonNull = types.filter((type) => type !== 'null');
841
+ if (types.includes('null')) result.nullable = true;
842
+ result.type = nonNull[0] ?? types[0];
843
+ if (typeof result.type === 'string') {
844
+ const allowed = TYPE_SPECIFIC_KEYS[result.type] ?? new Set();
845
+ for (const key in result) if (ALL_TYPE_SPECIFIC_KEYS.has(key) && !allowed.has(key)) delete result[key];
846
+ }
847
+ }
848
+ if (constValue !== undefined) {
849
+ const values = Array.isArray(result.enum) ? result.enum : [];
850
+ pushUnique(values, constValue);
851
+ result.enum = values;
852
+ if (!result.type) result.type = inferTypeFromValue(constValue);
853
+ }
854
+ if (
855
+ !result.type &&
856
+ !Array.isArray(result.anyOf) &&
857
+ !Array.isArray(result.oneOf) &&
858
+ Array.isArray(result.enum) &&
859
+ result.enum.length > 0
860
+ ) {
861
+ const types = result.enum.map(inferTypeFromValue);
862
+ if (types.every((type) => typeof type === 'string') && new Set(types).size === 1) result.type = types[0];
863
+ }
864
+ if (result.type === 'null') {
865
+ delete result.type;
866
+ result.nullable = true;
867
+ }
868
+ if (result.type === 'object' && !Object.hasOwn(result, 'propertyOrdering') && isJsonObject(result.properties)) {
869
+ const keys = Object.keys(result.properties);
870
+ if (keys.length > 1) result.propertyOrdering = keys;
871
+ }
872
+ if (result.type === 'object' && !Object.hasOwn(result, 'properties')) result.properties = {};
873
+ spillToDescription(result, spill);
874
+ return finishNode(result, ctx);
875
+ }
876
+
877
+ /** `schema` projected onto the JSON Schema subset Gemini backends accept. */
878
+ export function devinGoogleToolSchema(schema) {
879
+ return googleNode(dereferenceSchema(upgradeTo202012(schema)), { insideMap: false, subschema: true }, new Set());
880
+ }