@vellumai/assistant 0.6.1 → 0.6.3

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 (463) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docker-entrypoint.sh +12 -2
  4. package/docs/architecture/memory.md +1 -1
  5. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  7. package/openapi.yaml +184 -69
  8. package/package.json +41 -41
  9. package/scripts/generate-openapi.ts +1 -2
  10. package/src/__tests__/acp-session.test.ts +43 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +1 -0
  13. package/src/__tests__/app-source-watcher.test.ts +37 -11
  14. package/src/__tests__/approval-routes-http.test.ts +178 -1
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  17. package/src/__tests__/browser-manager.test.ts +40 -27
  18. package/src/__tests__/catalog-files.test.ts +862 -0
  19. package/src/__tests__/channel-approvals.test.ts +53 -0
  20. package/src/__tests__/checker.test.ts +104 -170
  21. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  22. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  23. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  24. package/src/__tests__/config-schema.test.ts +125 -48
  25. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  26. package/src/__tests__/context-overflow-approval.test.ts +21 -6
  27. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  28. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  29. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  30. package/src/__tests__/conversation-attachments.test.ts +80 -4
  31. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  32. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  33. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  34. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  35. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  36. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  37. package/src/__tests__/conversation-queue.test.ts +45 -2
  38. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  39. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  40. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  42. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  43. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  44. package/src/__tests__/conversation-store.test.ts +195 -0
  45. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  46. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
  47. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  48. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  49. package/src/__tests__/credential-vault.test.ts +152 -13
  50. package/src/__tests__/credentials-cli.test.ts +2 -2
  51. package/src/__tests__/date-context.test.ts +4 -4
  52. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  53. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  54. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  55. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  56. package/src/__tests__/gemini-provider.test.ts +2 -2
  57. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  58. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  59. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  60. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  61. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  62. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  63. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  64. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  65. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  66. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  67. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  68. package/src/__tests__/host-browser-routes.test.ts +198 -0
  69. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  70. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  71. package/src/__tests__/host-file-proxy.test.ts +185 -1
  72. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  73. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  74. package/src/__tests__/host-shell-tool.test.ts +1 -11
  75. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  76. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  77. package/src/__tests__/inline-command-runner.test.ts +7 -5
  78. package/src/__tests__/integration-status.test.ts +6 -7
  79. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  80. package/src/__tests__/log-export-workspace.test.ts +190 -0
  81. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  82. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  83. package/src/__tests__/mcp-health-check.test.ts +10 -3
  84. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  85. package/src/__tests__/migration-export-http.test.ts +61 -2
  86. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  87. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  88. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  89. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  90. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  91. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  92. package/src/__tests__/oauth-cli.test.ts +707 -60
  93. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  94. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  95. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  96. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  97. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  98. package/src/__tests__/oauth-store.test.ts +1386 -182
  99. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  100. package/src/__tests__/onboarding-template-contract.test.ts +74 -55
  101. package/src/__tests__/openai-provider.test.ts +2 -2
  102. package/src/__tests__/outlook-categories.test.ts +1 -1
  103. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  104. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  105. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  106. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  107. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  108. package/src/__tests__/outlook-trash.test.ts +1 -1
  109. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  110. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  111. package/src/__tests__/permission-mode.test.ts +28 -56
  112. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  113. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  114. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  115. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  116. package/src/__tests__/require-fresh-approval.test.ts +40 -3
  117. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  118. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  119. package/src/__tests__/schedule-routes.test.ts +162 -0
  120. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  121. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  123. package/src/__tests__/set-permission-mode.test.ts +13 -250
  124. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  125. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  126. package/src/__tests__/slack-channel-config.test.ts +12 -15
  127. package/src/__tests__/subagent-detail.test.ts +44 -2
  128. package/src/__tests__/subagent-disposal.test.ts +1 -0
  129. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  130. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  131. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  132. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  134. package/src/__tests__/subagent-tools.test.ts +1 -0
  135. package/src/__tests__/subagent-types.test.ts +1 -0
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  137. package/src/__tests__/system-prompt.test.ts +72 -1
  138. package/src/__tests__/task-scheduler.test.ts +32 -6
  139. package/src/__tests__/telegram-config.test.ts +10 -13
  140. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  141. package/src/__tests__/terminal-tools.test.ts +11 -5
  142. package/src/__tests__/test-preload.ts +14 -0
  143. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  144. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  145. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  146. package/src/__tests__/tool-executor.test.ts +0 -1
  147. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  148. package/src/__tests__/top-level-renderer.test.ts +73 -1
  149. package/src/__tests__/transport-hints-queue.test.ts +62 -0
  150. package/src/__tests__/trust-store.test.ts +4 -4
  151. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  152. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  153. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  154. package/src/__tests__/workspace-policy.test.ts +2 -7
  155. package/src/acp/client-handler.ts +30 -4
  156. package/src/agent/loop.ts +12 -35
  157. package/src/approvals/guardian-request-resolvers.ts +21 -15
  158. package/src/browser-session/__tests__/manager.test.ts +297 -0
  159. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  160. package/src/browser-session/backends/extension.ts +26 -0
  161. package/src/browser-session/backends/local.ts +24 -0
  162. package/src/browser-session/events.ts +164 -0
  163. package/src/browser-session/index.ts +27 -0
  164. package/src/browser-session/manager.ts +159 -0
  165. package/src/browser-session/types.ts +28 -0
  166. package/src/channels/__tests__/types.test.ts +134 -0
  167. package/src/channels/types.ts +55 -0
  168. package/src/cli/__tests__/run-assistant-command.ts +34 -7
  169. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  170. package/src/cli/commands/browser-relay.ts +339 -409
  171. package/src/cli/commands/credentials.ts +3 -3
  172. package/src/cli/commands/default-action.ts +68 -1
  173. package/src/cli/commands/email.ts +18 -13
  174. package/src/cli/commands/mcp.ts +16 -4
  175. package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
  176. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  177. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  178. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  179. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  180. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  181. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  182. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  183. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  184. package/src/cli/commands/oauth/apps.ts +7 -4
  185. package/src/cli/commands/oauth/connect.ts +16 -2
  186. package/src/cli/commands/oauth/disconnect.ts +1 -1
  187. package/src/cli/commands/oauth/providers.ts +200 -36
  188. package/src/cli/commands/oauth/shared.ts +5 -5
  189. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  190. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  191. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  192. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  193. package/src/cli/commands/platform/index.ts +107 -10
  194. package/src/cli/commands/usage.ts +10 -9
  195. package/src/cli/lib/daemon-credential-client.ts +4 -0
  196. package/src/cli/program.ts +10 -3
  197. package/src/config/assistant-feature-flags.ts +59 -55
  198. package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
  199. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  200. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  201. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  202. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  203. package/src/config/bundled-skills/document/SKILL.md +4 -0
  204. package/src/config/bundled-skills/gmail/SKILL.md +12 -7
  205. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  206. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  207. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  208. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  209. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  210. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  211. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  212. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  213. package/src/config/env-registry.ts +14 -0
  214. package/src/config/env.ts +21 -0
  215. package/src/config/feature-flag-registry.json +46 -7
  216. package/src/config/loader.ts +56 -1
  217. package/src/config/sanitize-for-transfer.ts +47 -0
  218. package/src/config/schema.ts +46 -5
  219. package/src/config/schemas/host-browser.ts +66 -0
  220. package/src/config/schemas/memory-lifecycle.ts +1 -1
  221. package/src/config/schemas/memory-retrieval.ts +103 -0
  222. package/src/config/schemas/security.ts +0 -6
  223. package/src/config/schemas/services.ts +16 -0
  224. package/src/config/types.ts +0 -1
  225. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  226. package/src/context/window-manager.ts +19 -1
  227. package/src/credential-execution/approval-bridge.ts +49 -16
  228. package/src/credential-execution/managed-catalog.ts +3 -7
  229. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  230. package/src/daemon/app-source-watcher.ts +35 -0
  231. package/src/daemon/config-watcher.ts +6 -2
  232. package/src/daemon/context-overflow-approval.ts +5 -1
  233. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  234. package/src/daemon/conversation-agent-loop.ts +74 -19
  235. package/src/daemon/conversation-attachments.ts +40 -1
  236. package/src/daemon/conversation-messaging.ts +3 -0
  237. package/src/daemon/conversation-process.ts +66 -3
  238. package/src/daemon/conversation-queue-manager.ts +8 -0
  239. package/src/daemon/conversation-runtime-assembly.ts +159 -20
  240. package/src/daemon/conversation-surfaces.ts +78 -12
  241. package/src/daemon/conversation-tool-setup.ts +74 -11
  242. package/src/daemon/conversation-workspace.ts +12 -0
  243. package/src/daemon/conversation.ts +227 -11
  244. package/src/daemon/date-context.ts +10 -10
  245. package/src/daemon/first-greeting.ts +3 -2
  246. package/src/daemon/handlers/conversations.ts +9 -139
  247. package/src/daemon/handlers/shared.ts +65 -0
  248. package/src/daemon/handlers/skills.ts +232 -37
  249. package/src/daemon/host-bash-proxy.ts +48 -13
  250. package/src/daemon/host-browser-proxy.ts +191 -0
  251. package/src/daemon/host-cu-proxy.ts +36 -11
  252. package/src/daemon/host-file-proxy.ts +57 -9
  253. package/src/daemon/lifecycle.ts +86 -12
  254. package/src/daemon/message-protocol.ts +7 -0
  255. package/src/daemon/message-types/conversations.ts +59 -13
  256. package/src/daemon/message-types/host-browser.ts +100 -0
  257. package/src/daemon/message-types/messages.ts +5 -6
  258. package/src/daemon/message-types/notifications.ts +12 -0
  259. package/src/daemon/message-types/settings.ts +12 -0
  260. package/src/daemon/message-types/skills.ts +10 -0
  261. package/src/daemon/message-types/subagents.ts +2 -0
  262. package/src/daemon/server.ts +112 -35
  263. package/src/daemon/tool-side-effects.ts +6 -0
  264. package/src/daemon/transport-hints.ts +14 -0
  265. package/src/inbound/platform-callback-registration.ts +18 -17
  266. package/src/index.ts +1 -1
  267. package/src/mcp/client.ts +59 -24
  268. package/src/memory/app-store.ts +31 -1
  269. package/src/memory/conversation-crud.ts +38 -10
  270. package/src/memory/conversation-directories.ts +39 -0
  271. package/src/memory/conversation-group-migration.ts +65 -5
  272. package/src/memory/conversation-starters-cadence.ts +76 -0
  273. package/src/memory/conversation-title-service.ts +5 -2
  274. package/src/memory/db-init.ts +12 -0
  275. package/src/memory/embedding-backend.test.ts +75 -0
  276. package/src/memory/embedding-backend.ts +131 -5
  277. package/src/memory/embedding-gemini.test.ts +54 -0
  278. package/src/memory/embedding-gemini.ts +20 -9
  279. package/src/memory/embedding-local.ts +177 -18
  280. package/src/memory/graph/capability-seed.ts +3 -5
  281. package/src/memory/graph/consolidation.ts +10 -23
  282. package/src/memory/graph/extraction-job.ts +15 -0
  283. package/src/memory/graph/retriever.ts +40 -22
  284. package/src/memory/graph/store.test.ts +7 -3
  285. package/src/memory/graph/store.ts +47 -12
  286. package/src/memory/group-crud.ts +25 -9
  287. package/src/memory/llm-usage-store.ts +45 -4
  288. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  289. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  290. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  291. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  292. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  293. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  294. package/src/memory/migrations/index.ts +6 -0
  295. package/src/memory/migrations/registry.ts +8 -0
  296. package/src/memory/schema/conversations.ts +1 -0
  297. package/src/memory/schema/oauth.ts +18 -13
  298. package/src/messaging/provider.ts +1 -1
  299. package/src/notifications/broadcaster.ts +6 -0
  300. package/src/notifications/conversation-pairing.ts +12 -4
  301. package/src/notifications/emit-signal.ts +14 -0
  302. package/src/notifications/signal.ts +11 -0
  303. package/src/oauth/AGENTS.md +76 -0
  304. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  305. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  306. package/src/oauth/byo-connection.test.ts +8 -8
  307. package/src/oauth/byo-connection.ts +7 -7
  308. package/src/oauth/connect-orchestrator.ts +23 -21
  309. package/src/oauth/connect-types.ts +3 -3
  310. package/src/oauth/connection-resolver.test.ts +17 -4
  311. package/src/oauth/connection-resolver.ts +16 -16
  312. package/src/oauth/connection.ts +1 -1
  313. package/src/oauth/manual-token-connection.ts +13 -13
  314. package/src/oauth/oauth-store.ts +214 -100
  315. package/src/oauth/platform-connection.test.ts +5 -5
  316. package/src/oauth/platform-connection.ts +4 -4
  317. package/src/oauth/provider-serializer.ts +31 -5
  318. package/src/oauth/revoke.ts +76 -0
  319. package/src/oauth/seed-providers.ts +127 -87
  320. package/src/oauth/token-persistence.ts +1 -1
  321. package/src/permissions/checker.ts +3 -3
  322. package/src/permissions/defaults.ts +7 -8
  323. package/src/permissions/permission-mode.ts +4 -11
  324. package/src/permissions/prompter.ts +13 -3
  325. package/src/permissions/v2-consent-policy.ts +87 -0
  326. package/src/platform/client.ts +1 -1
  327. package/src/prompts/system-prompt.ts +18 -21
  328. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  329. package/src/prompts/templates/BOOTSTRAP.md +59 -96
  330. package/src/prompts/templates/SOUL.md +11 -11
  331. package/src/providers/anthropic/client.ts +1 -0
  332. package/src/providers/types.ts +1 -1
  333. package/src/runtime/AGENTS.md +23 -0
  334. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  335. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  336. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  337. package/src/runtime/assistant-event-hub.ts +24 -2
  338. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  339. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  341. package/src/runtime/auth/middleware.ts +98 -0
  342. package/src/runtime/auth/route-policy.ts +6 -7
  343. package/src/runtime/auth/token-service.ts +8 -0
  344. package/src/runtime/capability-tokens.ts +414 -0
  345. package/src/runtime/channel-approvals.ts +18 -5
  346. package/src/runtime/chrome-extension-registry.ts +332 -0
  347. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  348. package/src/runtime/guardian-decision-types.ts +7 -0
  349. package/src/runtime/http-server.ts +425 -70
  350. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  351. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  352. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  353. package/src/runtime/migrations/migration-transport.ts +6 -0
  354. package/src/runtime/migrations/migration-wizard.ts +22 -2
  355. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  356. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  357. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  358. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  359. package/src/runtime/pending-interactions.ts +29 -13
  360. package/src/runtime/routes/approval-routes.ts +90 -16
  361. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  362. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  363. package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
  364. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  365. package/src/runtime/routes/conversation-routes.ts +308 -28
  366. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  367. package/src/runtime/routes/group-routes.ts +22 -8
  368. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  369. package/src/runtime/routes/host-browser-routes.ts +279 -0
  370. package/src/runtime/routes/host-file-routes.ts +9 -1
  371. package/src/runtime/routes/identity-routes.ts +259 -16
  372. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  373. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  374. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  375. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  376. package/src/runtime/routes/log-export-routes.ts +60 -25
  377. package/src/runtime/routes/memory-item-routes.ts +1 -7
  378. package/src/runtime/routes/migration-routes.ts +87 -2
  379. package/src/runtime/routes/oauth-apps.ts +15 -17
  380. package/src/runtime/routes/oauth-providers.ts +4 -0
  381. package/src/runtime/routes/schedule-routes.ts +24 -11
  382. package/src/runtime/routes/settings-routes.ts +9 -97
  383. package/src/runtime/routes/skills-routes.ts +52 -2
  384. package/src/runtime/routes/subagents-routes.ts +14 -10
  385. package/src/runtime/routes/usage-routes.ts +8 -7
  386. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  387. package/src/runtime/routes/workspace-routes.ts +8 -1
  388. package/src/runtime/routes/workspace-utils.ts +2 -0
  389. package/src/schedule/scheduler.ts +7 -5
  390. package/src/security/ces-credential-client.ts +20 -0
  391. package/src/security/ces-rpc-credential-backend.ts +17 -0
  392. package/src/security/credential-backend.ts +5 -0
  393. package/src/security/oauth2.ts +42 -25
  394. package/src/security/secure-keys.ts +118 -25
  395. package/src/security/token-manager.ts +23 -10
  396. package/src/skills/catalog-files.ts +492 -0
  397. package/src/skills/inline-command-runner.ts +12 -14
  398. package/src/subagent/manager.ts +131 -26
  399. package/src/subagent/types.ts +19 -0
  400. package/src/tools/apps/executors.ts +11 -2
  401. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  402. package/src/tools/browser/auth-detector.ts +43 -12
  403. package/src/tools/browser/browser-execution.ts +645 -340
  404. package/src/tools/browser/browser-manager.ts +36 -12
  405. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  406. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  407. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  408. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  409. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  410. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  411. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  412. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  413. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  414. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  415. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  416. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  417. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  418. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  419. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  420. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  421. package/src/tools/browser/cdp-client/errors.ts +34 -0
  422. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  423. package/src/tools/browser/cdp-client/factory.ts +204 -0
  424. package/src/tools/browser/cdp-client/index.ts +14 -0
  425. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  426. package/src/tools/browser/cdp-client/types.ts +52 -0
  427. package/src/tools/filesystem/edit.ts +1 -1
  428. package/src/tools/filesystem/list.ts +1 -1
  429. package/src/tools/filesystem/read.ts +1 -1
  430. package/src/tools/filesystem/write.ts +2 -1
  431. package/src/tools/host-filesystem/edit.ts +1 -1
  432. package/src/tools/host-filesystem/read.ts +12 -15
  433. package/src/tools/host-filesystem/write.ts +1 -1
  434. package/src/tools/host-terminal/host-shell.ts +21 -16
  435. package/src/tools/permission-checker.ts +77 -100
  436. package/src/tools/registry.ts +0 -2
  437. package/src/tools/secret-detection-handler.ts +34 -1
  438. package/src/tools/shared/filesystem/image-read.ts +61 -40
  439. package/src/tools/skills/sandbox-runner.ts +3 -6
  440. package/src/tools/subagent/spawn.ts +47 -3
  441. package/src/tools/subagent/status.ts +2 -0
  442. package/src/tools/system/register.ts +2 -16
  443. package/src/tools/terminal/safe-env.ts +7 -0
  444. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  445. package/src/tools/terminal/sandbox.ts +4 -1
  446. package/src/tools/terminal/shell.ts +24 -21
  447. package/src/tools/tool-approval-handler.ts +48 -2
  448. package/src/tools/types.ts +2 -3
  449. package/src/util/platform.ts +14 -19
  450. package/src/watcher/provider-types.ts +1 -1
  451. package/src/workspace/migrations/029-seed-pkb.ts +1 -0
  452. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  453. package/src/workspace/migrations/registry.ts +2 -0
  454. package/src/workspace/top-level-renderer.ts +19 -1
  455. package/src/__tests__/chrome-cdp.test.ts +0 -419
  456. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  457. package/src/__tests__/permission-mode-store.test.ts +0 -277
  458. package/src/browser-extension-relay/protocol.ts +0 -63
  459. package/src/browser-extension-relay/server.ts +0 -203
  460. package/src/config/schemas/sandbox.ts +0 -14
  461. package/src/permissions/permission-mode-store.ts +0 -180
  462. package/src/tools/browser/chrome-cdp.ts +0 -239
  463. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -49,6 +49,14 @@ export type { FishAudioConfig } from "./schemas/fish-audio.js";
49
49
  export { FishAudioConfigSchema } from "./schemas/fish-audio.js";
50
50
  export type { HeartbeatConfig } from "./schemas/heartbeat.js";
51
51
  export { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
52
+ export type {
53
+ HostBrowserCdpInspectConfig,
54
+ HostBrowserConfig,
55
+ } from "./schemas/host-browser.js";
56
+ export {
57
+ HostBrowserCdpInspectConfigSchema,
58
+ HostBrowserConfigSchema,
59
+ } from "./schemas/host-browser.js";
52
60
  export type {
53
61
  ContextOverflowRecoveryConfig,
54
62
  ContextWindowConfig,
@@ -115,6 +123,7 @@ export {
115
123
  export type { MemoryRetrievalConfig } from "./schemas/memory-retrieval.js";
116
124
  export {
117
125
  MemoryDynamicBudgetConfigSchema,
126
+ MemoryInjectionConfigSchema,
118
127
  MemoryRetrievalConfigSchema,
119
128
  } from "./schemas/memory-retrieval.js";
120
129
  export type {
@@ -139,8 +148,6 @@ export {
139
148
  PlatformConfigSchema,
140
149
  UiConfigSchema,
141
150
  } from "./schemas/platform.js";
142
- export type { SandboxConfig } from "./schemas/sandbox.js";
143
- export { SandboxConfigSchema } from "./schemas/sandbox.js";
144
151
  export type {
145
152
  PermissionsConfig,
146
153
  SecretDetectionConfig,
@@ -206,6 +213,7 @@ import { ElevenLabsConfigSchema } from "./schemas/elevenlabs.js";
206
213
  import { FilingConfigSchema } from "./schemas/filing.js";
207
214
  import { FishAudioConfigSchema } from "./schemas/fish-audio.js";
208
215
  import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
216
+ import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
209
217
  import {
210
218
  ContextWindowConfigSchema,
211
219
  EffortSchema,
@@ -227,7 +235,6 @@ import {
227
235
  PlatformConfigSchema,
228
236
  UiConfigSchema,
229
237
  } from "./schemas/platform.js";
230
- import { SandboxConfigSchema } from "./schemas/sandbox.js";
231
238
  import {
232
239
  PermissionsConfigSchema,
233
240
  SecretDetectionConfigSchema,
@@ -247,7 +254,7 @@ export const AssistantConfigSchema = z
247
254
  .number({ error: "maxTokens must be a number" })
248
255
  .int("maxTokens must be an integer")
249
256
  .positive("maxTokens must be a positive integer")
250
- .default(16000)
257
+ .default(64000)
251
258
  .describe("Maximum number of output tokens per LLM response"),
252
259
  effort: EffortSchema,
253
260
  speed: SpeedSchema,
@@ -261,7 +268,6 @@ export const AssistantConfigSchema = z
261
268
  .default(getDataDir())
262
269
  .describe("Directory for storing assistant data (database, logs, etc.)"),
263
270
  timeouts: TimeoutConfigSchema.default(TimeoutConfigSchema.parse({})),
264
- sandbox: SandboxConfigSchema.default(SandboxConfigSchema.parse({})),
265
271
  rateLimit: RateLimitConfigSchema.default(RateLimitConfigSchema.parse({})),
266
272
  secretDetection: SecretDetectionConfigSchema.default(
267
273
  SecretDetectionConfigSchema.parse({}),
@@ -281,6 +287,9 @@ export const AssistantConfigSchema = z
281
287
  ),
282
288
  filing: FilingConfigSchema.default(FilingConfigSchema.parse({})),
283
289
  heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
290
+ hostBrowser: HostBrowserConfigSchema.default(
291
+ HostBrowserConfigSchema.parse({}),
292
+ ),
284
293
  journal: JournalConfigSchema.default(JournalConfigSchema.parse({})),
285
294
  mcp: McpConfigSchema.default(McpConfigSchema.parse({})),
286
295
  acp: AcpConfigSchema.default(AcpConfigSchema.parse({})),
@@ -321,6 +330,13 @@ export const AssistantConfigSchema = z
321
330
  .max(200, "maxStepsPerSession must be <= 200")
322
331
  .default(50)
323
332
  .describe("Maximum number of computer-use steps per session"),
333
+ systemPromptPrefix: z
334
+ .string({ error: "systemPromptPrefix must be a string" })
335
+ .nullable()
336
+ .default(null)
337
+ .describe(
338
+ "Custom text injected at the very beginning of the system prompt. Defaults to null (no injection).",
339
+ ),
324
340
  })
325
341
  .superRefine((config, ctx) => {
326
342
  if (
@@ -373,6 +389,31 @@ export const AssistantConfigSchema = z
373
389
  "memory.retrieval.dynamicBudget.minInjectTokens must be <= memory.retrieval.dynamicBudget.maxInjectTokens",
374
390
  });
375
391
  }
392
+ const injection = config.memory?.retrieval?.injection;
393
+ const ctxLoad = injection?.contextLoad;
394
+ if (
395
+ ctxLoad &&
396
+ ctxLoad.capabilityReserve + ctxLoad.serendipitySlots >= ctxLoad.maxNodes
397
+ ) {
398
+ ctx.addIssue({
399
+ code: z.ZodIssueCode.custom,
400
+ path: ["memory", "retrieval", "injection", "contextLoad"],
401
+ message:
402
+ "memory.retrieval.injection.contextLoad.capabilityReserve + serendipitySlots must be less than maxNodes",
403
+ });
404
+ }
405
+ const perTurn = injection?.perTurn;
406
+ if (
407
+ perTurn &&
408
+ perTurn.capabilityReserve + perTurn.serendipitySlots >= perTurn.maxNodes
409
+ ) {
410
+ ctx.addIssue({
411
+ code: z.ZodIssueCode.custom,
412
+ path: ["memory", "retrieval", "injection", "perTurn"],
413
+ message:
414
+ "memory.retrieval.injection.perTurn.capabilityReserve + serendipitySlots must be less than maxNodes",
415
+ });
416
+ }
376
417
  });
377
418
 
378
419
  export type AssistantConfig = z.infer<typeof AssistantConfigSchema>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Configuration for the `cdp-inspect` browser backend — connects directly
5
+ * to a host Chrome instance that was launched with `--remote-debugging-port`
6
+ * (e.g. `chrome://inspect`-style remote debugging) as an alternative to the
7
+ * extension or local Playwright backend.
8
+ */
9
+ export const HostBrowserCdpInspectConfigSchema = z
10
+ .object({
11
+ enabled: z
12
+ .boolean({ error: "hostBrowser.cdpInspect.enabled must be a boolean" })
13
+ .default(false)
14
+ .describe(
15
+ "Whether the cdp-inspect backend is enabled. When true, the factory will route browser tool calls through the configured host/port instead of the local Playwright backend.",
16
+ ),
17
+ host: z
18
+ .string({ error: "hostBrowser.cdpInspect.host must be a string" })
19
+ .min(1, "hostBrowser.cdpInspect.host must not be empty")
20
+ .default("localhost")
21
+ .describe(
22
+ "Host name or IP address where the host Chrome instance exposes its remote debugging endpoint.",
23
+ ),
24
+ port: z
25
+ .number({ error: "hostBrowser.cdpInspect.port must be a number" })
26
+ .int("hostBrowser.cdpInspect.port must be an integer")
27
+ .min(1, "hostBrowser.cdpInspect.port must be >= 1")
28
+ .max(65535, "hostBrowser.cdpInspect.port must be <= 65535")
29
+ .default(9222)
30
+ .describe(
31
+ "TCP port for the host Chrome remote-debugging endpoint (matches `--remote-debugging-port`).",
32
+ ),
33
+ probeTimeoutMs: z
34
+ .number({
35
+ error: "hostBrowser.cdpInspect.probeTimeoutMs must be a number",
36
+ })
37
+ .int("hostBrowser.cdpInspect.probeTimeoutMs must be an integer")
38
+ .min(50, "hostBrowser.cdpInspect.probeTimeoutMs must be >= 50")
39
+ .max(5000, "hostBrowser.cdpInspect.probeTimeoutMs must be <= 5000")
40
+ .default(500)
41
+ .describe(
42
+ "Timeout (in milliseconds) for the backend availability probe. Kept small so browser tool calls fail fast when the endpoint is unreachable.",
43
+ ),
44
+ })
45
+ .describe(
46
+ "Settings for the cdp-inspect backend that connects to a host Chrome instance via its remote-debugging endpoint.",
47
+ );
48
+
49
+ export type HostBrowserCdpInspectConfig = z.infer<
50
+ typeof HostBrowserCdpInspectConfigSchema
51
+ >;
52
+
53
+ /**
54
+ * Top-level configuration for host-browser backends. Currently only exposes
55
+ * `cdpInspect`, but the shape leaves room for additional host-browser knobs
56
+ * (e.g. extension-specific settings) without another namespace churn.
57
+ */
58
+ export const HostBrowserConfigSchema = z
59
+ .object({
60
+ cdpInspect: HostBrowserCdpInspectConfigSchema.default(
61
+ HostBrowserCdpInspectConfigSchema.parse({}),
62
+ ),
63
+ })
64
+ .describe("Host-browser backend configuration (cdp-inspect, etc.)");
65
+
66
+ export type HostBrowserConfig = z.infer<typeof HostBrowserConfigSchema>;
@@ -80,7 +80,7 @@ export const MemoryCleanupConfigSchema = z
80
80
  .nonnegative(
81
81
  "memory.cleanup.llmRequestLogRetentionMs must be non-negative",
82
82
  )
83
- .default(7 * 24 * 60 * 60 * 1000)
83
+ .default(1 * 24 * 60 * 60 * 1000)
84
84
  .describe(
85
85
  "Retention period for LLM request/response logs in milliseconds (0 disables pruning)",
86
86
  ),
@@ -184,6 +184,106 @@ const MemoryFreshnessConfigSchema = z
184
184
  "Freshness-based ranking for memory retrieval — down-ranks old items unless recently reinforced",
185
185
  );
186
186
 
187
+ const MemoryContextLoadInjectionSchema = z
188
+ .object({
189
+ maxNodes: z
190
+ .number({
191
+ error:
192
+ "memory.retrieval.injection.contextLoad.maxNodes must be a number",
193
+ })
194
+ .int("memory.retrieval.injection.contextLoad.maxNodes must be an integer")
195
+ .positive(
196
+ "memory.retrieval.injection.contextLoad.maxNodes must be a positive integer",
197
+ )
198
+ .default(25)
199
+ .describe("Maximum number of memory nodes to load at conversation start"),
200
+ serendipitySlots: z
201
+ .number({
202
+ error:
203
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be a number",
204
+ })
205
+ .int(
206
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be an integer",
207
+ )
208
+ .nonnegative(
209
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be non-negative",
210
+ )
211
+ .default(5)
212
+ .describe("Number of random wildcard memory picks at conversation start"),
213
+ capabilityReserve: z
214
+ .number({
215
+ error:
216
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be a number",
217
+ })
218
+ .int(
219
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be an integer",
220
+ )
221
+ .nonnegative(
222
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be non-negative",
223
+ )
224
+ .default(5)
225
+ .describe(
226
+ "Reserved slots for skill/CLI capability nodes at conversation start",
227
+ ),
228
+ })
229
+ .describe("Memory injection limits at conversation start");
230
+
231
+ const MemoryPerTurnInjectionSchema = z
232
+ .object({
233
+ maxNodes: z
234
+ .number({
235
+ error: "memory.retrieval.injection.perTurn.maxNodes must be a number",
236
+ })
237
+ .int("memory.retrieval.injection.perTurn.maxNodes must be an integer")
238
+ .positive(
239
+ "memory.retrieval.injection.perTurn.maxNodes must be a positive integer",
240
+ )
241
+ .default(6)
242
+ .describe(
243
+ "Maximum total memory nodes injected per turn (general + capability + serendipity)",
244
+ ),
245
+ serendipitySlots: z
246
+ .number({
247
+ error:
248
+ "memory.retrieval.injection.perTurn.serendipitySlots must be a number",
249
+ })
250
+ .int(
251
+ "memory.retrieval.injection.perTurn.serendipitySlots must be an integer",
252
+ )
253
+ .nonnegative(
254
+ "memory.retrieval.injection.perTurn.serendipitySlots must be non-negative",
255
+ )
256
+ .default(1)
257
+ .describe("Number of random wildcard memory picks per turn"),
258
+ capabilityReserve: z
259
+ .number({
260
+ error:
261
+ "memory.retrieval.injection.perTurn.capabilityReserve must be a number",
262
+ })
263
+ .int(
264
+ "memory.retrieval.injection.perTurn.capabilityReserve must be an integer",
265
+ )
266
+ .nonnegative(
267
+ "memory.retrieval.injection.perTurn.capabilityReserve must be non-negative",
268
+ )
269
+ .default(2)
270
+ .describe("Reserved slots for skill/CLI capability nodes per turn"),
271
+ })
272
+ .describe("Memory injection limits for mid-conversation turns");
273
+
274
+ export const MemoryInjectionConfigSchema = z
275
+ .object({
276
+ contextLoad: MemoryContextLoadInjectionSchema.default(
277
+ MemoryContextLoadInjectionSchema.parse({}),
278
+ ),
279
+ perTurn: MemoryPerTurnInjectionSchema.default(
280
+ MemoryPerTurnInjectionSchema.parse({}),
281
+ ),
282
+ })
283
+ .describe(
284
+ "Controls how many memory items are injected at conversation start and per turn",
285
+ );
286
+
187
287
  export const MemoryRetrievalConfigSchema = z
188
288
  .object({
189
289
  maxInjectTokens: z
@@ -209,6 +309,9 @@ export const MemoryRetrievalConfigSchema = z
209
309
  dynamicBudget: MemoryDynamicBudgetConfigSchema.default(
210
310
  MemoryDynamicBudgetConfigSchema.parse({}),
211
311
  ),
312
+ injection: MemoryInjectionConfigSchema.default(
313
+ MemoryInjectionConfigSchema.parse({}),
314
+ ),
212
315
  })
213
316
  .describe(
214
317
  "Controls how memories are retrieved and injected into conversations",
@@ -79,12 +79,6 @@ export const PermissionsConfigSchema = z
79
79
  .describe(
80
80
  "Permission mode — 'strict' requires explicit approval for all operations, 'workspace' allows operations within the workspace",
81
81
  ),
82
- askBeforeActing: z
83
- .boolean({
84
- error: "permissions.askBeforeActing must be a boolean",
85
- })
86
- .default(true)
87
- .describe("Whether the assistant should check in before taking actions"),
88
82
  hostAccess: z
89
83
  .boolean({
90
84
  error: "permissions.hostAccess must be a boolean",
@@ -56,6 +56,16 @@ export const OutlookOAuthServiceSchema = BaseServiceSchema.extend({
56
56
  });
57
57
  export type OutlookOAuthService = z.infer<typeof OutlookOAuthServiceSchema>;
58
58
 
59
+ export const LinearOAuthServiceSchema = BaseServiceSchema.extend({
60
+ mode: ServiceModeSchema.default("your-own"),
61
+ });
62
+ export type LinearOAuthService = z.infer<typeof LinearOAuthServiceSchema>;
63
+
64
+ export const GitHubOAuthServiceSchema = BaseServiceSchema.extend({
65
+ mode: ServiceModeSchema.default("your-own"),
66
+ });
67
+ export type GitHubOAuthService = z.infer<typeof GitHubOAuthServiceSchema>;
68
+
59
69
  export const ServicesSchema = z.object({
60
70
  inference: InferenceServiceSchema.default(InferenceServiceSchema.parse({})),
61
71
  "image-generation": ImageGenerationServiceSchema.default(
@@ -70,5 +80,11 @@ export const ServicesSchema = z.object({
70
80
  "outlook-oauth": OutlookOAuthServiceSchema.default(
71
81
  OutlookOAuthServiceSchema.parse({}),
72
82
  ),
83
+ "linear-oauth": LinearOAuthServiceSchema.default(
84
+ LinearOAuthServiceSchema.parse({}),
85
+ ),
86
+ "github-oauth": GitHubOAuthServiceSchema.default(
87
+ GitHubOAuthServiceSchema.parse({}),
88
+ ),
73
89
  });
74
90
  export type Services = z.infer<typeof ServicesSchema>;
@@ -27,7 +27,6 @@ export type {
27
27
  PermissionsConfig,
28
28
  QdrantConfig,
29
29
  RateLimitConfig,
30
- SandboxConfig,
31
30
  SecretDetectionConfig,
32
31
  ServiceMode,
33
32
  Services,
@@ -0,0 +1,176 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ import type {
6
+ ContentBlock,
7
+ Message,
8
+ ToolResultContent,
9
+ ToolUseContent,
10
+ } from "../providers/types.js";
11
+
12
+ /** Minimum content length (chars) before a tool result is eligible for truncation. ~2000 tokens at 4 chars/token. */
13
+ export const THRESHOLD_CHARS = 8_000;
14
+
15
+ /** Target size (chars) for the truncated stub. ~300 tokens at 4 chars/token. */
16
+ export const TARGET_CHARS = 1_200;
17
+
18
+ /** Subdirectory name under the conversation directory for saved full results. */
19
+ export const TOOL_RESULT_DIR = ".tool-results";
20
+
21
+ /** Marker used to detect already-truncated results (idempotency guard). */
22
+ export const TRUNCATION_MARKER = "\u2014 full result:";
23
+
24
+ /**
25
+ * Deterministic file path for a tool result's full content on disk.
26
+ * Uses the first 12 hex chars of the SHA-256 of the tool_use_id.
27
+ */
28
+ export function getToolResultFilePath(
29
+ conversationDir: string,
30
+ toolUseId: string,
31
+ ): string {
32
+ const hash = createHash("sha256").update(toolUseId).digest("hex").slice(0, 12);
33
+ return join(conversationDir, TOOL_RESULT_DIR, `${hash}.txt`);
34
+ }
35
+
36
+ /**
37
+ * Build the truncated stub that replaces a large tool result in context.
38
+ * Preserves the first and last halves of TARGET_CHARS, with a middle marker
39
+ * indicating how many tokens were omitted and where to find the full result.
40
+ */
41
+ export function buildTruncatedContent(
42
+ original: string,
43
+ filePath: string,
44
+ ): string {
45
+ const half = Math.floor(TARGET_CHARS / 2);
46
+ const prefix = original.slice(0, half);
47
+ const suffix = original.slice(-half);
48
+ const omittedChars = original.length - TARGET_CHARS;
49
+ const estimatedTokens = Math.round(omittedChars / 4);
50
+ return `${prefix}\n\n...(${estimatedTokens} tokens omitted ${TRUNCATION_MARKER} ${filePath})\n\n${suffix}`;
51
+ }
52
+
53
+ /**
54
+ * Walk all messages and truncate tool results that exceed `THRESHOLD_CHARS`.
55
+ *
56
+ * For each eligible result:
57
+ * - The full content is persisted to a deterministic file path on disk.
58
+ * - The in-context content is replaced with a prefix/suffix stub.
59
+ *
60
+ * Results are skipped if they are below threshold, are error results,
61
+ * or have already been truncated (contain `TRUNCATION_MARKER`).
62
+ *
63
+ * Returns a shallow-copied messages array (only modified messages are cloned)
64
+ * and the count of results that were truncated.
65
+ */
66
+ export function postTurnTruncateToolResults(
67
+ messages: Message[],
68
+ options: { conversationDir: string },
69
+ ): { messages: Message[]; truncatedCount: number } {
70
+ let truncatedCount = 0;
71
+
72
+ const mapped = messages.map((msg) => {
73
+ let changed = false;
74
+ const nextContent: ContentBlock[] = msg.content.map((block) => {
75
+ if (block.type !== "tool_result") return block;
76
+ const tr = block as ToolResultContent;
77
+
78
+ // Skip short results.
79
+ if (tr.content.length <= THRESHOLD_CHARS) return block;
80
+
81
+ // Skip error results.
82
+ if (tr.is_error) return block;
83
+
84
+ // Skip already-truncated results (idempotency).
85
+ if (tr.content.includes(TRUNCATION_MARKER)) return block;
86
+
87
+ const filePath = getToolResultFilePath(
88
+ options.conversationDir,
89
+ tr.tool_use_id,
90
+ );
91
+
92
+ // Persist full content to disk.
93
+ mkdirSync(join(options.conversationDir, TOOL_RESULT_DIR), {
94
+ recursive: true,
95
+ });
96
+ writeFileSync(filePath, tr.content, "utf-8");
97
+
98
+ changed = true;
99
+ truncatedCount++;
100
+ return {
101
+ ...tr,
102
+ content: buildTruncatedContent(tr.content, filePath),
103
+ } as ContentBlock;
104
+ });
105
+
106
+ return changed ? { ...msg, content: nextContent } : msg;
107
+ });
108
+
109
+ return { messages: truncatedCount > 0 ? mapped : messages, truncatedCount };
110
+ }
111
+
112
+ /** Stub that replaces a re-read of a saved tool result to avoid context duplication. */
113
+ export const REREAD_STUB =
114
+ "(Re-read of saved tool result — original context is preserved above)";
115
+
116
+ /**
117
+ * Deduplicate re-reads of saved tool results.
118
+ *
119
+ * When `postTurnTruncateToolResults` truncates a large result, it saves the full
120
+ * content to a `.tool-results/` file. If the model later calls `file_read` on that
121
+ * saved file, the result is a second copy of content whose truncated prefix/suffix
122
+ * is already in context. This function detects those re-reads and replaces their
123
+ * tool_result content with a short stub to avoid duplication.
124
+ */
125
+ export function derefToolResultReReads(messages: Message[]): {
126
+ messages: Message[];
127
+ dereferencedCount: number;
128
+ } {
129
+ // Build a set of tool_use_ids that are file_read calls targeting .tool-results/ paths.
130
+ const reReadToolUseIds = new Set<string>();
131
+
132
+ for (const msg of messages) {
133
+ if (msg.role !== "assistant") continue;
134
+ for (const block of msg.content) {
135
+ if (block.type !== "tool_use") continue;
136
+ const tu = block as ToolUseContent;
137
+ if (tu.name !== "file_read") continue;
138
+ const filePath = tu.input.path ?? tu.input.file_path;
139
+ if (typeof filePath !== "string") continue;
140
+ if (filePath.includes(`/${TOOL_RESULT_DIR}/`)) {
141
+ reReadToolUseIds.add(tu.id);
142
+ }
143
+ }
144
+ }
145
+
146
+ if (reReadToolUseIds.size === 0) {
147
+ return { messages, dereferencedCount: 0 };
148
+ }
149
+
150
+ let dereferencedCount = 0;
151
+
152
+ const mapped = messages.map((msg) => {
153
+ if (msg.role !== "user") return msg;
154
+
155
+ let changed = false;
156
+ const nextContent: ContentBlock[] = msg.content.map((block) => {
157
+ if (block.type !== "tool_result") return block;
158
+ const tr = block as ToolResultContent;
159
+ if (!reReadToolUseIds.has(tr.tool_use_id)) return block;
160
+
161
+ // Skip error results — preserve diagnostics (e.g. file not found).
162
+ if (tr.is_error) return block;
163
+
164
+ changed = true;
165
+ dereferencedCount++;
166
+ return { ...tr, content: REREAD_STUB } as ContentBlock;
167
+ });
168
+
169
+ return changed ? { ...msg, content: nextContent } : msg;
170
+ });
171
+
172
+ return {
173
+ messages: dereferencedCount > 0 ? mapped : messages,
174
+ dereferencedCount,
175
+ };
176
+ }
@@ -102,6 +102,14 @@ export class ContextWindowManager {
102
102
  private readonly _systemPrompt: string | (() => string);
103
103
  private readonly config: ContextWindowConfig;
104
104
  private readonly toolTokenBudget: number;
105
+ /**
106
+ * Number of leading messages that are non-persisted (injected inherited
107
+ * context from a parent conversation). `countPersistedMessages` subtracts
108
+ * this so `compactedPersistedMessages` only reflects DB-backed messages.
109
+ * Set by `Conversation.injectInheritedContext` and consumed (decremented)
110
+ * after a successful compaction pass.
111
+ */
112
+ nonPersistedPrefixCount = 0;
105
113
  /**
106
114
  * Cached resolved system prompt. Lazily populated on first access via the
107
115
  * `systemPrompt` getter and cleared after each compaction pass so the next
@@ -305,8 +313,12 @@ export class ContextWindowManager {
305
313
  };
306
314
  }
307
315
 
316
+ const injectedInCompactable = Math.min(
317
+ Math.max(0, this.nonPersistedPrefixCount - summaryOffset),
318
+ compactableMessages.length,
319
+ );
308
320
  const compactedPersistedMessages =
309
- countPersistedMessages(compactableMessages);
321
+ countPersistedMessages(compactableMessages) - injectedInCompactable;
310
322
  const rawProjectedMessages = [
311
323
  createContextSummaryMessage(existingSummary ?? "Projected summary"),
312
324
  ...messages.slice(keepPlan.keepFromIndex),
@@ -452,6 +464,12 @@ export class ContextWindowManager {
452
464
  toolTokenBudget: this.toolTokenBudget,
453
465
  },
454
466
  );
467
+ // Consume the injected prefix messages that were compacted away.
468
+ this.nonPersistedPrefixCount = Math.max(
469
+ 0,
470
+ this.nonPersistedPrefixCount - injectedInCompactable,
471
+ );
472
+
455
473
  log.info(
456
474
  {
457
475
  previousEstimatedInputTokens,