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,491 @@
1
+ // Devin OAuth provider: chat models run through a Devin account over the
2
+ // Cascade GetChatMessage stream.
3
+ //
4
+ // Per send: the stored Devin session token (devin-auth.mjs) is exchanged for a
5
+ // fresh user JWT, a router model is assigned (AssignModel), the transcript is
6
+ // lowered by devin-wire-request.mjs, and the decoded response deltas are
7
+ // projected onto chat-completions chunks so the shared compat consumer owns
8
+ // live text, tool-call assembly (dispatched only once the stream ended and
9
+ // their JSON is complete), exposure flags and watchdogs.
10
+ import { createHash, randomUUID } from 'node:crypto';
11
+ import { noteAbandonedUsage } from '../../../shared/llm/usage-context.mjs';
12
+ import { REAUTH_GUIDANCE, resolveDevinOAuthAccessToken } from './devin-auth.mjs';
13
+ import { DEVIN_ENUMS } from './devin-wire-protobuf.mjs';
14
+ import {
15
+ DEVIN_ASSIGN_MODEL_PATH,
16
+ DEVIN_DEFAULT_BASE_URL,
17
+ devinRequestMetadata,
18
+ exchangeDevinUserJwt,
19
+ } from './devin-wire-session.mjs';
20
+ import { DevinWireError, devinStream, devinUnary } from './devin-wire-transport.mjs';
21
+ import { fetchDevinModels, normalizeDevinModels } from './devin-wire-models.mjs';
22
+ import {
23
+ DEVIN_LARGE_HISTORY_RECOVERY_BYTES,
24
+ DEVIN_PROVIDER_ID,
25
+ DEVIN_REPLAY_ITEM_TYPE,
26
+ buildDevinChatRequest,
27
+ devinHistoryBytes,
28
+ devinRouterPrompt,
29
+ } from './devin-wire-request.mjs';
30
+ import { preparePdfTextForProvider } from './media-normalization.mjs';
31
+ import { consumeCompatChatCompletionStream } from './openai-compat-stream.mjs';
32
+ import { resolveCompatMaxOutputTokens } from './openai-compat-wire.mjs';
33
+ import { parseDevinToolCalls } from './devin-wire-tool-args.mjs';
34
+ import { createProviderReplay } from './lib/provider-replay.mjs';
35
+
36
+ export const DEVIN_CHAT_PATH = '/exa.api_server_pb.ApiServerService/GetChatMessage';
37
+ // The opaque rejection Devin answers some oversized requests with.
38
+ const OPAQUE_INTERNAL_RE = /\binternal error\b/i;
39
+ const { StopReason } = DEVIN_ENUMS;
40
+
41
+ function accountKey(sessionToken) {
42
+ return createHash('sha256').update(String(sessionToken)).digest('hex').slice(0, 24);
43
+ }
44
+
45
+ function abortReason(signal) {
46
+ return signal.reason instanceof Error ? signal.reason : new Error('Devin request aborted');
47
+ }
48
+
49
+ /**
50
+ * Mixdog usage from a ModelUsageStats frame (input excludes cache reads and
51
+ * writes), carrying the turn's Devin credit charges when the stream reported any.
52
+ */
53
+ export function devinUsage(stats, credits = null) {
54
+ if (!stats) return undefined;
55
+ const input = Number(stats.inputTokens || 0);
56
+ const cacheRead = Number(stats.cacheReadTokens || 0);
57
+ const cacheWrite = Number(stats.cacheWriteTokens || 0);
58
+ return {
59
+ inputTokens: input,
60
+ outputTokens: Number(stats.outputTokens || 0),
61
+ cachedTokens: cacheRead,
62
+ cacheWriteTokens: cacheWrite,
63
+ promptTokens: input + cacheRead + cacheWrite,
64
+ ...(credits ? { credits: { ...credits } } : {}),
65
+ // 64-bit counters decode as bigint; usage leaves this boundary as numbers.
66
+ raw: Object.fromEntries(
67
+ Object.entries(stats).map(([key, value]) => [key, typeof value === 'bigint' ? Number(value) : value])
68
+ ),
69
+ };
70
+ }
71
+
72
+ // Collapsed effort families advertise their tiers the way other providers do.
73
+ function catalogModel(row, provider) {
74
+ const levels = Array.isArray(row.reasoningLevels) ? row.reasoningLevels : [];
75
+ return {
76
+ ...(levels.length
77
+ ? {
78
+ reasoningLevels: levels,
79
+ reasoningOptions: [{ type: 'effort', values: levels }],
80
+ defaultEffort: row.defaultEffort || null,
81
+ // No thinking-off route: 'none' is absent from the levels.
82
+ ...(row.requiresEffort ? { requiresEffort: true } : {}),
83
+ }
84
+ : {}),
85
+ ...(row.isDefault ? { isDefault: true } : {}),
86
+ id: row.id,
87
+ display: row.name,
88
+ provider,
89
+ mode: 'chat',
90
+ contextWindow: row.contextWindow,
91
+ outputTokens: row.maxOutputTokens,
92
+ description: row.description,
93
+ supportsVision: row.supportsVision,
94
+ supportsFunctionCalling: row.supportsTools,
95
+ reasoning: row.reasoning,
96
+ supportsReasoning: row.supportsReasoning,
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Per-turn projection of decoded GetChatMessageResponse frames onto
102
+ * chat-completions chunks. Tool calls are keyed by their wire id; a frame
103
+ * without an id continues the last call, and one with neither is dropped.
104
+ * Arguments may arrive as deltas or as growing snapshots.
105
+ */
106
+ export function createDevinTurn({ onReasoningDelta } = {}) {
107
+ const calls = new Map();
108
+ let activeCall = '';
109
+ let inThinking = false;
110
+ const signatures = [];
111
+ let signatureType = '';
112
+ const turn = {
113
+ sawOutput: false,
114
+ messageId: '',
115
+ thinking: '',
116
+ stopReason: StopReason.UNSPECIFIED,
117
+ usage: null,
118
+ // The concrete model that served the turn: the router assignment, then
119
+ // the latest uid the stream reports (fallbacks, capacity routing).
120
+ upstreamModel: '',
121
+ // Credit charges { cost, committedCost, acuCost }; each nonzero report replaces its field.
122
+ credits: null,
123
+ };
124
+
125
+ const toolDeltas = (deltaToolCalls) => {
126
+ const out = [];
127
+ for (const call of deltaToolCalls || []) {
128
+ const id = String(call.id || '') || activeCall;
129
+ if (!id) continue;
130
+ let entry = calls.get(id);
131
+ const delta = {};
132
+ if (!entry) {
133
+ entry = { index: calls.size, args: '', name: '' };
134
+ calls.set(id, entry);
135
+ Object.assign(delta, { id, type: 'function' });
136
+ }
137
+ activeCall = id;
138
+ // The last name a call is given wins; names go out with the terminal chunk.
139
+ if (call.name) entry.name = call.name;
140
+ // Arguments the server could not parse arrive as invalidJsonStr instead;
141
+ // they take the same repair-or-marker path, never an empty `{}`.
142
+ const raw = String(call.argumentsJson || call.invalidJsonStr || '');
143
+ const merged = raw.startsWith(entry.args) ? raw : entry.args + raw;
144
+ const piece = raw ? merged.slice(entry.args.length) : '';
145
+ if (raw) entry.args = merged;
146
+ out.push({ index: entry.index, ...delta, function: { arguments: piece } });
147
+ }
148
+ return out;
149
+ };
150
+
151
+ // Each call's final name, attached once the stream ended.
152
+ turn.finalToolNames = () =>
153
+ [...calls.values()].map((entry) => ({ index: entry.index, function: { name: entry.name, arguments: '' } }));
154
+
155
+ turn.chunk = (msg) => {
156
+ if (msg.messageId && !turn.messageId) turn.messageId = msg.messageId;
157
+ if (msg.stopReason) turn.stopReason = msg.stopReason;
158
+ if (msg.usage) turn.usage = msg.usage;
159
+ if (msg.actualModelUid) turn.upstreamModel = msg.actualModelUid;
160
+ const cost = Number(msg.creditCost || 0);
161
+ const committedCost = Number(msg.committedCreditCost || 0);
162
+ const acuCost = Number(msg.committedAcuCost || 0);
163
+ if (cost || committedCost || acuCost) {
164
+ turn.credits ??= {};
165
+ if (cost) turn.credits.cost = cost;
166
+ if (committedCost) turn.credits.committedCost = committedCost;
167
+ if (acuCost) turn.credits.acuCost = acuCost;
168
+ }
169
+ const delta = {};
170
+ if (msg.deltaThinking) {
171
+ if (!inThinking) signatures.push('');
172
+ inThinking = true;
173
+ turn.thinking += msg.deltaThinking;
174
+ delta.reasoning_content = msg.deltaThinking;
175
+ try {
176
+ onReasoningDelta?.(msg.deltaThinking);
177
+ } catch {}
178
+ }
179
+ // Signatures stream as deltas and may arrive after the thinking they sign
180
+ // (behind its text or tool calls): every fragment extends the latest
181
+ // thinking block's signature.
182
+ if (msg.deltaSignature) {
183
+ if (!signatures.length) signatures.push('');
184
+ signatures[signatures.length - 1] += msg.deltaSignature;
185
+ }
186
+ if (msg.deltaSignatureType) signatureType = msg.deltaSignatureType;
187
+ if (msg.deltaText) {
188
+ inThinking = false;
189
+ delta.content = msg.deltaText;
190
+ }
191
+ const toolCalls = toolDeltas(msg.deltaToolCalls);
192
+ if (msg.deltaToolCalls?.length) inThinking = false;
193
+ if (toolCalls.length) delta.tool_calls = toolCalls;
194
+ if (msg.deltaThinking || msg.deltaText || msg.deltaToolCalls?.length) turn.sawOutput = true;
195
+ return { ...(msg.messageId ? { id: msg.messageId } : {}), choices: [{ index: 0, delta }] };
196
+ };
197
+
198
+ // The terminal finish reason, once the stream ended with a clean trailer.
199
+ turn.finishReason = () => {
200
+ if (calls.size) return 'tool_calls';
201
+ return turn.stopReason === StopReason.MAX_TOKENS ? 'length' : 'stop';
202
+ };
203
+
204
+ // Replay record for the next request: native message id, thinking and the
205
+ // first thinking block's signature (with the signature type the stream
206
+ // reported), bound to the model that produced them.
207
+ turn.replay = (model) => {
208
+ const signature = signatures.find(Boolean);
209
+ return createProviderReplay(DEVIN_PROVIDER_ID, [
210
+ {
211
+ type: DEVIN_REPLAY_ITEM_TYPE,
212
+ model,
213
+ ...(turn.messageId ? { messageId: turn.messageId } : {}),
214
+ ...(turn.thinking ? { thinking: turn.thinking } : {}),
215
+ ...(signature ? { signature, ...(signatureType ? { signatureType } : {}) } : {}),
216
+ },
217
+ ]);
218
+ };
219
+ return turn;
220
+ }
221
+
222
+ /** The concrete wire uid of a catalog row at `effort`: its effort route, else its default uid. */
223
+ export function devinWireUid(row, modelId, effort) {
224
+ return (effort && row?.effortUids?.[effort]) || row?.uid || modelId;
225
+ }
226
+
227
+ // The transport ends `frames` only after the end-of-stream trailer, so the
228
+ // terminal chunk (and with it tool dispatch) follows a complete response.
229
+ async function* devinChunks(frames, turn) {
230
+ for await (const msg of frames) yield turn.chunk(msg);
231
+ const names = turn.finalToolNames();
232
+ yield {
233
+ choices: [{ index: 0, delta: names.length ? { tool_calls: names } : {}, finish_reason: turn.finishReason() }],
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Typed Mixdog contract on a Devin failure: a rejected sign-in names the
239
+ * re-auth step; an oversized request is a context overflow so compaction
240
+ * runs; a stream cut short without its trailer is a truncated stream.
241
+ */
242
+ export function devinProviderError(error, { reauth = false } = {}) {
243
+ if (!(error instanceof DevinWireError)) return error;
244
+ if (error.code === 'unauthenticated' && reauth && !error.reauthRequired) {
245
+ error.reauthRequired = true;
246
+ error.message = `Devin rejected the sign-in (${error.message}). ${REAUTH_GUIDANCE}`;
247
+ } else if (error.code === 'request_too_large') {
248
+ error.providerError = { code: 'context_length_exceeded', message: error.message };
249
+ } else if (error.code === 'protocol' && error.retryable) {
250
+ error.truncatedStream = true;
251
+ }
252
+ return error;
253
+ }
254
+
255
+ // An opaque `internal error` invalid_argument rejected by the stream trailer
256
+ // before any output: a context overflow when the compactable history is
257
+ // large, a transient failure otherwise.
258
+ function classifyOpaqueRejection(error, { request, activeTail }) {
259
+ if (!(error instanceof DevinWireError) || error.code !== 'invalid_argument') return;
260
+ if (!OPAQUE_INTERNAL_RE.test(error.detail || '')) return;
261
+ const overflow = devinHistoryBytes(request, activeTail) >= DEVIN_LARGE_HISTORY_RECOVERY_BYTES;
262
+ error.providerError = { code: overflow ? 'context_length_exceeded' : 'internal_error', message: error.message };
263
+ }
264
+
265
+ export class DevinOAuthProvider {
266
+ // Cascade carries no document block: PDFs lower to their text.
267
+ nativePdf = false;
268
+ // ModelUsageStats input tokens exclude cache reads and writes.
269
+ static inputExcludesCache = true;
270
+ name = DEVIN_PROVIDER_ID;
271
+ config;
272
+ _catalogs = new Map();
273
+ _lastCatalogKey = null;
274
+
275
+ constructor(config = {}) {
276
+ this.config = config || {};
277
+ }
278
+
279
+ get _fetch() {
280
+ return this.config.fetchFn || fetch;
281
+ }
282
+
283
+ get _baseUrl() {
284
+ return this.config.baseUrl || DEVIN_DEFAULT_BASE_URL;
285
+ }
286
+
287
+ async _sessionToken() {
288
+ return this.config.accessToken || resolveDevinOAuthAccessToken();
289
+ }
290
+
291
+ // A fresh user JWT (plus the accepted api key and chat host) for one turn.
292
+ async _userSession(sessionToken, signal) {
293
+ try {
294
+ return await exchangeDevinUserJwt({ sessionToken, fetchFn: this._fetch, signal, baseUrl: this._baseUrl });
295
+ } catch (error) {
296
+ throw devinProviderError(error, { reauth: true });
297
+ }
298
+ }
299
+
300
+ async _catalog(key, sessionToken, signal) {
301
+ let catalog = this._catalogs.get(key);
302
+ if (!catalog) {
303
+ const configs = await fetchDevinModels({ sessionToken, fetchFn: this._fetch, signal, baseUrl: this._baseUrl });
304
+ const rows = normalizeDevinModels(configs, { defaultModelUid: configs?.defaultModelUid });
305
+ catalog = {
306
+ rows: new Map(rows.map((row) => [row.id, row])),
307
+ models: rows.map((row) => catalogModel(row, this.name)),
308
+ };
309
+ // An empty answer is not pinned: the next lookup asks again.
310
+ if (rows.length) this._catalogs.set(key, catalog);
311
+ }
312
+ this._lastCatalogKey = key;
313
+ return catalog;
314
+ }
315
+
316
+ getCachedModelInfo(model) {
317
+ return this._catalogs.get(this._lastCatalogKey)?.models.find((entry) => entry.id === model) || null;
318
+ }
319
+
320
+ async listModels() {
321
+ const sessionToken = await this._sessionToken();
322
+ return (await this._catalog(accountKey(sessionToken), sessionToken, null)).models;
323
+ }
324
+
325
+ async _refreshModelCache() {
326
+ this._catalogs.clear();
327
+ return this.listModels();
328
+ }
329
+
330
+ // A router row is not a chat model: AssignModel resolves it, per turn, into
331
+ // a concrete uid plus the JWT that authorizes it on the chat sharing the
332
+ // cascade id. An incomplete assignment fails the turn.
333
+ async _assignModel({ session, routerUid, cascadeId, messages, vision, signal }) {
334
+ const response = await devinUnary({
335
+ baseUrl: session.apiHost || this._baseUrl,
336
+ path: DEVIN_ASSIGN_MODEL_PATH,
337
+ requestType: 'AssignModelRequest',
338
+ responseType: 'AssignModelResponse',
339
+ message: {
340
+ metadata: devinRequestMetadata({ apiKey: session.apiKey, client: 'cli' }),
341
+ modelRouterUid: routerUid,
342
+ cascadeId,
343
+ chatMessagePrompt: devinRouterPrompt(messages, { vision }),
344
+ },
345
+ fetchFn: this._fetch,
346
+ signal,
347
+ });
348
+ const assignment = response.assignment;
349
+ if (!assignment?.assignmentJwt || !assignment?.modelUid) {
350
+ throw new DevinWireError('Devin AssignModel returned no assignment JWT and model uid', { code: 'protocol' });
351
+ }
352
+ return assignment;
353
+ }
354
+
355
+ // One streamed GetChatMessage. An error after live text or a dispatched
356
+ // tool call is marked unsafe to retry by the compat consumer.
357
+ async _streamTurn({ session, messages, model, wireUid, modelRow, tools, sendOpts, cascadeId, turn, signal }) {
358
+ const assignment = modelRow?.router
359
+ ? await this._assignModel({
360
+ session,
361
+ routerUid: wireUid,
362
+ cascadeId,
363
+ messages,
364
+ vision: modelRow.supportsVision === true,
365
+ signal,
366
+ })
367
+ : null;
368
+ if (assignment) turn.upstreamModel = assignment.modelUid;
369
+ const { request, activeTail } = buildDevinChatRequest(messages, {
370
+ model,
371
+ chatModelUid: assignment?.modelUid || wireUid,
372
+ ...(assignment ? { modelAssignmentJwt: assignment.assignmentJwt } : {}),
373
+ modelRow,
374
+ tools,
375
+ metadata: devinRequestMetadata({ apiKey: session.apiKey, userJwt: session.jwt, client: 'cli' }),
376
+ cascadeId,
377
+ maxOutputTokens: resolveCompatMaxOutputTokens(sendOpts),
378
+ temperature: sendOpts.temperature,
379
+ topP: sendOpts.topP,
380
+ stopSequences: sendOpts.stopSequences,
381
+ });
382
+ try {
383
+ sendOpts.onStageChange?.('requesting');
384
+ } catch {}
385
+ // Whether the server accepted the request: a failure after that came
386
+ // from the stream itself (its trailer), not from the HTTP status.
387
+ let accepted = false;
388
+ const frames = devinStream({
389
+ baseUrl: session.apiHost || this._baseUrl,
390
+ path: DEVIN_CHAT_PATH,
391
+ requestType: 'GetChatMessageRequest',
392
+ responseType: 'GetChatMessageResponse',
393
+ message: request,
394
+ fetchFn: async (...args) => {
395
+ const response = await this._fetch(...args);
396
+ accepted = response.ok;
397
+ return response;
398
+ },
399
+ signal,
400
+ });
401
+ let liveTextEmitted = false;
402
+ let streaming = false;
403
+ try {
404
+ return await consumeCompatChatCompletionStream(devinChunks(frames, turn), {
405
+ signal,
406
+ label: this.name,
407
+ providerName: this.name,
408
+ onStreamDelta: (delta) => {
409
+ if (!streaming) {
410
+ streaming = true;
411
+ try {
412
+ sendOpts.onStageChange?.('streaming');
413
+ } catch {}
414
+ }
415
+ sendOpts.onStreamDelta?.(delta);
416
+ },
417
+ onToolCall: (call) => sendOpts.onToolCall?.(call),
418
+ onTextDelta: (text) => {
419
+ if (text) liveTextEmitted = true;
420
+ sendOpts.onTextDelta?.(text);
421
+ },
422
+ onStreamItemStart: sendOpts.onStreamItemStart,
423
+ parseToolCalls: parseDevinToolCalls,
424
+ // Text stays text: only deltaToolCalls produce tool calls.
425
+ leakedToolCallRecovery: false,
426
+ });
427
+ } catch (error) {
428
+ if (liveTextEmitted) Object.assign(error, { liveTextEmitted: true, unsafeToRetry: true });
429
+ if (accepted && !turn.sawOutput) classifyOpaqueRejection(error, { request, activeTail });
430
+ const usage = devinUsage(turn.usage, turn.credits);
431
+ const servedModel = turn.upstreamModel || model;
432
+ if (usage && !error.partialUsage) {
433
+ if (signal?.aborted) noteAbandonedUsage(usage, servedModel);
434
+ else Object.assign(error, { partialUsage: usage, partialModel: servedModel });
435
+ }
436
+ throw error;
437
+ }
438
+ }
439
+
440
+ async send(messages, model, tools, sendOpts = {}) {
441
+ const signal = sendOpts.signal || null;
442
+ if (signal?.aborted) throw abortReason(signal);
443
+ const modelId = String(model || '').trim();
444
+ if (!modelId) throw new Error('Devin requires a model id. Pick a Devin model in Mixdog.');
445
+ const sessionToken = await this._sessionToken();
446
+ const key = accountKey(sessionToken);
447
+ const catalog = await this._catalog(key, sessionToken, signal);
448
+ const modelRow = catalog.rows.get(modelId) || null;
449
+ const wireUid = devinWireUid(modelRow, modelId, sendOpts.effort);
450
+ const prepared = await preparePdfTextForProvider(messages, this);
451
+ // The server threads turns that share one cascade id.
452
+ const cascadeId = String(sendOpts.transportScope || sendOpts.sessionId || randomUUID());
453
+ const attempt = async (session) => {
454
+ const turn = createDevinTurn({ onReasoningDelta: sendOpts.onReasoningDelta });
455
+ const args = {
456
+ session,
457
+ messages: prepared,
458
+ model: modelId,
459
+ wireUid,
460
+ modelRow,
461
+ tools,
462
+ sendOpts,
463
+ cascadeId,
464
+ turn,
465
+ signal,
466
+ };
467
+ return { turn, assembled: await this._streamTurn(args) };
468
+ };
469
+ // Every turn exchanges a fresh user JWT; a refused one is a re-auth.
470
+ const session = await this._userSession(sessionToken, signal);
471
+ let outcome;
472
+ try {
473
+ outcome = await attempt(session);
474
+ } catch (error) {
475
+ if (signal?.aborted) throw abortReason(signal);
476
+ throw devinProviderError(error, { reauth: true });
477
+ }
478
+ const { turn, assembled } = outcome;
479
+ return {
480
+ content: assembled.content || '',
481
+ // The served model, as other providers report the response's model.
482
+ model: turn.upstreamModel || modelId,
483
+ ...(turn.credits ? { credits: { ...turn.credits } } : {}),
484
+ toolCalls: assembled.toolCalls,
485
+ stopReason: assembled.stopReason,
486
+ ...(assembled.reasoningContent ? { reasoningContent: assembled.reasoningContent } : {}),
487
+ providerReplay: turn.replay(modelId),
488
+ usage: devinUsage(turn.usage, turn.credits),
489
+ };
490
+ }
491
+ }
@@ -58,6 +58,9 @@ export function markEffortConfigurationUnsupported(provider, model) {
58
58
  export function isEffortConfigurationRejection(status, text) {
59
59
  const message = String(text || '');
60
60
  if (status !== 400) return false;
61
+ // A turn-scoped system message (tail reminder) error is not about the effort
62
+ // update, even when it names output_config or the mid-conversation beta.
63
+ if (/clear[_-]at|turn-scoped/i.test(message)) return false;
61
64
  if (/mid-conversation|configuration_update|reasoning_effort_update/i.test(message)) return true;
62
65
  // A rejected `output_config.effort` VALUE (the error quotes a level) belongs
63
66
  // to the effort-rejection fallback (effort-rejection.mjs); a rejected field
@@ -0,0 +1,46 @@
1
+ /**
2
+ * gemini-output-limit.mjs — the `generationConfig.maxOutputTokens` a Gemini
3
+ * request carries, shared by the API-key and Antigravity builders.
4
+ *
5
+ * Thought tokens count against this cap, so a request that names none leaves
6
+ * the server on a small default and long answers (or long thinking) are cut
7
+ * off mid-turn. A request therefore carries the model's declared output limit
8
+ * when one is known; an explicit caller value wins but never passes a known
9
+ * ceiling. With no known ceiling nothing is imposed: no guessed value is sent
10
+ * (an oversized one is refused by models with a smaller limit).
11
+ */
12
+ import { getModelMetadataSync } from '../../../shared/llm/model-catalog.mjs';
13
+
14
+ const positiveInt = (value) => {
15
+ const n = Number(value);
16
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
17
+ };
18
+
19
+ /**
20
+ * The per-model ceiling: the declared catalog limit (`outputLimit` from a
21
+ * provider roster first, then the shared catalog), clamped to `gatewayLimit` —
22
+ * the limit a relay gateway declared for the model — when both exist; else
23
+ * whichever is known, else null (nothing known, nothing imposed).
24
+ */
25
+ function geminiOutputCeiling(model, outputLimit = null, gatewayLimit = null) {
26
+ const id = String(model || '').replace(/^models\//, '');
27
+ const declared = positiveInt(outputLimit) ?? positiveInt(getModelMetadataSync(id, 'gemini')?.outputTokens);
28
+ const gateway = positiveInt(gatewayLimit);
29
+ if (declared == null) return gateway;
30
+ return gateway == null ? declared : Math.min(declared, gateway);
31
+ }
32
+
33
+ /**
34
+ * maxOutputTokens for one request: the explicit `opts` value (validated, then
35
+ * clamped to the ceiling) or the ceiling itself; undefined when neither exists.
36
+ */
37
+ export function geminiMaxOutputTokens(model, opts, outputLimit = null, gatewayLimit = null) {
38
+ const ceiling = geminiOutputCeiling(model, outputLimit, gatewayLimit);
39
+ const requested = opts?.maxOutputTokens ?? opts?.max_output_tokens;
40
+ if (requested === undefined || requested === null) return ceiling ?? undefined;
41
+ const max = Number(requested);
42
+ if (!Number.isInteger(max) || max <= 0) {
43
+ throw new TypeError('maxOutputTokens must be a positive integer (it includes thinking tokens).');
44
+ }
45
+ return ceiling == null ? max : Math.min(max, ceiling);
46
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * gemini-reasoning-relay.mjs — the thought-summary relay of one Gemini send.
3
+ *
4
+ * Thought text streams to the caller's `onReasoningDelta`. A stream that is
5
+ * re-issued (retry, empty-answer re-ask, non-streaming recovery) would show
6
+ * its thinking twice, so before each new attempt the thinking already shown
7
+ * is retracted through `onTextReset` — reasoning only, no answer text, which
8
+ * the loop's own replay retraction also accepts without an owner ack.
9
+ */
10
+ export function createGeminiReasoningRelay(opts) {
11
+ let relayed = false;
12
+ return {
13
+ // Relayed through opts so the callback keeps its original receiver.
14
+ onReasoningDelta:
15
+ typeof opts?.onReasoningDelta === 'function'
16
+ ? (text) => {
17
+ relayed = true;
18
+ opts.onReasoningDelta(text);
19
+ }
20
+ : null,
21
+ retract() {
22
+ if (!relayed) return;
23
+ relayed = false;
24
+ if (typeof opts?.onTextReset !== 'function') return;
25
+ try {
26
+ Promise.resolve(opts.onTextReset({ chars: 0, reasoning: true, reason: 'gemini-stream-retry' })).catch(() => {});
27
+ } catch {}
28
+ },
29
+ };
30
+ }
@@ -9,6 +9,7 @@
9
9
  * gemini-schema.mjs.
10
10
  */
11
11
  import { geminiThinkingConfig } from './gemini-thinking.mjs';
12
+ import { geminiMaxOutputTokens } from './gemini-output-limit.mjs';
12
13
  import { toGeminiContents, toGeminiRequestTools, toGeminiToolConfig } from './gemini-schema.mjs';
13
14
 
14
15
  // Request pieces shared by the cached REST path and the SDK path.
@@ -16,16 +17,10 @@ import { toGeminiContents, toGeminiRequestTools, toGeminiToolConfig } from './ge
16
17
  // maxOutputTokens counts thought tokens too (see the thinking docs). Anything
17
18
  // invalid is rejected here instead of being dropped. (safetySettings is a
18
19
  // request-level field, forwarded separately.)
19
- function geminiGenerationControls(opts) {
20
+ function geminiGenerationControls(opts, useModel, outputLimit) {
20
21
  const controls = {};
21
- const maxRaw = opts.maxOutputTokens ?? opts.max_output_tokens;
22
- if (maxRaw !== undefined && maxRaw !== null) {
23
- const max = Number(maxRaw);
24
- if (!Number.isInteger(max) || max <= 0) {
25
- throw new TypeError('maxOutputTokens must be a positive integer (it includes thinking tokens).');
26
- }
27
- controls.maxOutputTokens = max;
28
- }
22
+ const maxOutputTokens = geminiMaxOutputTokens(useModel, opts, outputLimit);
23
+ if (maxOutputTokens !== undefined) controls.maxOutputTokens = maxOutputTokens;
29
24
  if (opts.temperature !== undefined && opts.temperature !== null) {
30
25
  const temperature = Number(opts.temperature);
31
26
  if (!Number.isFinite(temperature) || temperature < 0 || temperature > 2) {
@@ -36,14 +31,15 @@ function geminiGenerationControls(opts) {
36
31
  return controls;
37
32
  }
38
33
 
39
- export function buildGeminiRequest(messages, useModel, tools, opts) {
34
+ // `outputLimit` is the provider roster's declared output limit for the model.
35
+ export function buildGeminiRequest(messages, useModel, tools, opts, outputLimit = null) {
40
36
  // Gemini returns thought summaries only when the request asks for them.
41
37
  // Without this the reasoning channel stays empty for the whole turn and
42
38
  // the model's only visible output is the plain pre-tool text, so every
43
39
  // round reads as another preamble. On by default for every model; an
44
40
  // explicit opts.includeThoughts still wins.
45
41
  const thinkingConfig = geminiThinkingConfig(useModel, opts, { includeThoughts: true });
46
- const controls = geminiGenerationControls(opts);
42
+ const controls = geminiGenerationControls(opts, useModel, outputLimit);
47
43
  let generationConfig;
48
44
  if (thinkingConfig || Object.keys(controls).length) {
49
45
  generationConfig = { ...(thinkingConfig ? { thinkingConfig } : {}), ...controls };