@vellumai/assistant 0.4.56 → 0.4.57

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 (450) hide show
  1. package/ARCHITECTURE.md +10 -10
  2. package/Dockerfile +3 -0
  3. package/README.md +11 -11
  4. package/docs/architecture/integrations.md +2 -2
  5. package/docs/architecture/memory.md +3 -4
  6. package/docs/credential-execution-service.md +13 -20
  7. package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
  8. package/package.json +1 -1
  9. package/src/__tests__/actor-token-service.test.ts +7 -7
  10. package/src/__tests__/anthropic-provider.test.ts +172 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
  12. package/src/__tests__/approval-cascade.test.ts +2 -2
  13. package/src/__tests__/approval-routes-http.test.ts +3 -4
  14. package/src/__tests__/asset-materialize-tool.test.ts +5 -5
  15. package/src/__tests__/asset-search-tool.test.ts +1 -1
  16. package/src/__tests__/assistant-attachments.test.ts +5 -5
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
  19. package/src/__tests__/attachments-store.test.ts +2 -2
  20. package/src/__tests__/avatar-e2e.test.ts +5 -3
  21. package/src/__tests__/browser-skill-endstate.test.ts +0 -1
  22. package/src/__tests__/call-routes-http.test.ts +2 -2
  23. package/src/__tests__/callback-handoff-copy.test.ts +1 -1
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
  25. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  26. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  27. package/src/__tests__/checker.test.ts +31 -32
  28. package/src/__tests__/chrome-cdp.test.ts +47 -18
  29. package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
  30. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  31. package/src/__tests__/config-schema.test.ts +9 -18
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
  34. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
  35. package/src/__tests__/conversation-agent-loop.test.ts +11 -4
  36. package/src/__tests__/conversation-attachments.test.ts +1 -1
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
  38. package/src/__tests__/conversation-error.test.ts +33 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
  40. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  41. package/src/__tests__/conversation-pairing.test.ts +1 -1
  42. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
  44. package/src/__tests__/conversation-queue.test.ts +23 -14
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +185 -173
  47. package/src/__tests__/conversation-seed-composer.test.ts +1 -1
  48. package/src/__tests__/conversation-slash-queue.test.ts +4 -4
  49. package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
  50. package/src/__tests__/conversation-starter-routes.test.ts +291 -0
  51. package/src/__tests__/conversation-wipe.test.ts +438 -0
  52. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
  53. package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
  54. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
  55. package/src/__tests__/credential-security-e2e.test.ts +20 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault-unit.test.ts +227 -0
  58. package/src/__tests__/credentials-cli.test.ts +3 -0
  59. package/src/__tests__/date-context.test.ts +59 -377
  60. package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
  61. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
  62. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  63. package/src/__tests__/encrypted-store.test.ts +237 -15
  64. package/src/__tests__/ephemeral-permissions.test.ts +4 -5
  65. package/src/__tests__/event-bus.test.ts +3 -3
  66. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  67. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  68. package/src/__tests__/gemini-image-service.test.ts +4 -4
  69. package/src/__tests__/gemini-provider.test.ts +6 -9
  70. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  71. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  72. package/src/__tests__/host-shell-tool.test.ts +6 -6
  73. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  74. package/src/__tests__/intent-routing.test.ts +51 -99
  75. package/src/__tests__/invite-routes-http.test.ts +5 -0
  76. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  77. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  78. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  79. package/src/__tests__/media-generate-image.test.ts +32 -15
  80. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  81. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  82. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  83. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  84. package/src/__tests__/memory-regressions.test.ts +86 -90
  85. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  86. package/src/__tests__/migration-export-http.test.ts +26 -27
  87. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  88. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  89. package/src/__tests__/migration-validate-http.test.ts +16 -16
  90. package/src/__tests__/model-intents.test.ts +1 -1
  91. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  92. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  93. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  94. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  95. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  96. package/src/__tests__/notification-deep-link.test.ts +1 -1
  97. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  98. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  99. package/src/__tests__/oauth-store.test.ts +1 -3
  100. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  101. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  102. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  103. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  104. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  105. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  106. package/src/__tests__/qdrant-manager.test.ts +7 -7
  107. package/src/__tests__/ratelimit.test.ts +0 -74
  108. package/src/__tests__/recording-handler.test.ts +0 -1
  109. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  110. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  111. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  112. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  113. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  114. package/src/__tests__/schema-transforms.test.ts +114 -54
  115. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  116. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  117. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  118. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  119. package/src/__tests__/send-notification-tool.test.ts +2 -2
  120. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  121. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  122. package/src/__tests__/skill-memory.test.ts +547 -0
  123. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  124. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  125. package/src/__tests__/slack-channel-config.test.ts +109 -94
  126. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  127. package/src/__tests__/swarm-recursion.test.ts +2 -2
  128. package/src/__tests__/swarm-tool.test.ts +2 -2
  129. package/src/__tests__/system-prompt.test.ts +19 -66
  130. package/src/__tests__/telegram-config.test.ts +121 -0
  131. package/src/__tests__/terminal-tools.test.ts +1 -1
  132. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  133. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  134. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  135. package/src/__tests__/tool-executor.test.ts +1 -1
  136. package/src/__tests__/trace-emitter.test.ts +8 -1
  137. package/src/__tests__/trust-store.test.ts +7 -8
  138. package/src/__tests__/twilio-routes.test.ts +1 -18
  139. package/src/__tests__/user-reference.test.ts +82 -2
  140. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  141. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  142. package/src/approvals/guardian-request-resolvers.ts +3 -3
  143. package/src/avatar/ascii-renderer.ts +2 -2
  144. package/src/avatar/png-renderer.ts +2 -2
  145. package/src/avatar/resvg-lazy.ts +21 -0
  146. package/src/calls/guardian-dispatch.ts +1 -1
  147. package/src/calls/relay-access-wait.ts +2 -2
  148. package/src/calls/twilio-rest.ts +0 -248
  149. package/src/cli/AGENTS.md +5 -8
  150. package/src/cli/__tests__/notifications.test.ts +5 -5
  151. package/src/cli/commands/avatar.ts +64 -2
  152. package/src/cli/commands/conversations.ts +131 -1
  153. package/src/cli/commands/credentials.ts +2 -0
  154. package/src/cli/commands/notifications.ts +3 -3
  155. package/src/cli.ts +10 -0
  156. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  157. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  158. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  159. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  160. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  161. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  162. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  163. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  164. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  165. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  166. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  167. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  168. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  169. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  170. package/src/config/bundled-skills/document/SKILL.md +4 -4
  171. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  172. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  173. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  174. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  175. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  176. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  177. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  178. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  179. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  180. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  181. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  182. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  183. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  184. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  185. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  186. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  187. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  188. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  189. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  190. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  192. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  193. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  195. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  196. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  197. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  198. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  199. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  200. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  201. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  202. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  203. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  204. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  205. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  206. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  207. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  208. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  209. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  210. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  211. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  212. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  213. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  214. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  215. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  216. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  217. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  218. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  219. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  220. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  221. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  222. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  223. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  224. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  225. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  226. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  227. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  228. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  229. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  230. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  231. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  232. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  233. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  234. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  235. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  236. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  237. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  238. package/src/config/feature-flag-registry.json +33 -17
  239. package/src/config/schemas/sandbox.ts +1 -1
  240. package/src/config/schemas/services.ts +13 -3
  241. package/src/config/schemas/timeouts.ts +0 -10
  242. package/src/contacts/contact-store.ts +63 -0
  243. package/src/contacts/contacts-write.ts +1 -1
  244. package/src/daemon/assistant-attachments.ts +2 -2
  245. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  246. package/src/daemon/conversation-agent-loop.ts +7 -30
  247. package/src/daemon/conversation-error.ts +24 -0
  248. package/src/daemon/conversation-memory.ts +8 -7
  249. package/src/daemon/conversation-runtime-assembly.ts +139 -274
  250. package/src/daemon/conversation-slash.ts +7 -26
  251. package/src/daemon/conversation-surfaces.ts +14 -0
  252. package/src/daemon/conversation-tool-setup.ts +9 -8
  253. package/src/daemon/conversation.ts +2 -0
  254. package/src/daemon/daemon-control.ts +1 -1
  255. package/src/daemon/date-context.ts +10 -83
  256. package/src/daemon/handlers/config-channels.ts +12 -2
  257. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  258. package/src/daemon/handlers/config-telegram.ts +6 -1
  259. package/src/daemon/handlers/conversations.ts +2 -2
  260. package/src/daemon/handlers/skills.ts +4 -0
  261. package/src/daemon/lifecycle.ts +28 -4
  262. package/src/daemon/providers-setup.ts +1 -1
  263. package/src/daemon/server.ts +1 -5
  264. package/src/daemon/shutdown-handlers.ts +9 -3
  265. package/src/daemon/tool-side-effects.ts +40 -0
  266. package/src/daemon/trace-emitter.ts +25 -2
  267. package/src/events/domain-events.ts +1 -1
  268. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  269. package/src/inbound/platform-callback-registration.ts +0 -18
  270. package/src/media/app-icon-generator.ts +15 -8
  271. package/src/media/avatar-router.ts +15 -8
  272. package/src/media/gemini-image-service.ts +125 -21
  273. package/src/memory/attachments-store.ts +3 -3
  274. package/src/memory/channel-verification-sessions.ts +6 -6
  275. package/src/memory/conversation-crud.ts +196 -1
  276. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  277. package/src/memory/conversation-title-service.ts +2 -3
  278. package/src/memory/db-init.ts +25 -1
  279. package/src/memory/invite-store.ts +4 -4
  280. package/src/memory/items-extractor.ts +4 -4
  281. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  282. package/src/memory/jobs-store.ts +3 -2
  283. package/src/memory/jobs-worker.ts +7 -5
  284. package/src/memory/lifecycle-events-store.ts +63 -0
  285. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  286. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  287. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  288. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  289. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  290. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  291. package/src/memory/migrations/index.ts +6 -0
  292. package/src/memory/migrations/registry.ts +13 -0
  293. package/src/memory/retriever.test.ts +223 -96
  294. package/src/memory/retriever.ts +115 -138
  295. package/src/memory/schema/calls.ts +1 -1
  296. package/src/memory/schema/contacts.ts +1 -1
  297. package/src/memory/schema/infrastructure.ts +29 -0
  298. package/src/memory/schema/memory-core.ts +7 -17
  299. package/src/memory/schema/notifications.ts +1 -1
  300. package/src/memory/search/formatting.ts +23 -6
  301. package/src/memory/search/lexical.ts +2 -0
  302. package/src/memory/search/semantic.ts +2 -0
  303. package/src/memory/search/staleness.ts +1 -0
  304. package/src/memory/search/types.ts +4 -0
  305. package/src/memory/task-memory-cleanup.ts +96 -6
  306. package/src/memory/trace-event-store.ts +148 -0
  307. package/src/notifications/README.md +1 -1
  308. package/src/notifications/decision-engine.ts +2 -2
  309. package/src/notifications/emit-signal.ts +4 -4
  310. package/src/notifications/events-store.ts +4 -4
  311. package/src/notifications/signal.ts +1 -1
  312. package/src/oauth/manual-token-connection.ts +49 -25
  313. package/src/permissions/checker.ts +6 -5
  314. package/src/permissions/defaults.ts +4 -4
  315. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  316. package/src/prompts/cache-boundary.ts +8 -0
  317. package/src/prompts/system-prompt.ts +105 -634
  318. package/src/prompts/templates/BOOTSTRAP.md +166 -33
  319. package/src/prompts/templates/IDENTITY.md +8 -23
  320. package/src/prompts/templates/SOUL.md +20 -41
  321. package/src/prompts/templates/USER.md +3 -19
  322. package/src/prompts/user-reference.ts +14 -16
  323. package/src/providers/anthropic/client.ts +46 -2
  324. package/src/providers/gemini/client.ts +6 -9
  325. package/src/providers/managed-proxy/constants.ts +1 -7
  326. package/src/providers/managed-proxy/context.ts +0 -1
  327. package/src/providers/model-intents.ts +5 -5
  328. package/src/providers/openai/client.ts +10 -1
  329. package/src/providers/openrouter/client.ts +1 -0
  330. package/src/providers/ratelimit.ts +0 -35
  331. package/src/providers/registry.ts +3 -5
  332. package/src/providers/retry.ts +18 -1
  333. package/src/runtime/access-request-helper.ts +1 -1
  334. package/src/runtime/auth/route-policy.ts +7 -0
  335. package/src/runtime/channel-verification-service.ts +1 -1
  336. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  337. package/src/runtime/guardian-vellum-migration.ts +63 -1
  338. package/src/runtime/http-server.ts +8 -4
  339. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  340. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  341. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  342. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  343. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  344. package/src/runtime/routes/attachment-routes.ts +2 -2
  345. package/src/runtime/routes/btw-routes.ts +9 -0
  346. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  347. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  348. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  349. package/src/runtime/routes/conversation-routes.ts +49 -5
  350. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  351. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  352. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  353. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  354. package/src/runtime/routes/migration-routes.ts +25 -13
  355. package/src/runtime/routes/secret-routes.ts +18 -0
  356. package/src/runtime/routes/settings-routes.ts +8 -8
  357. package/src/runtime/routes/telemetry-routes.ts +53 -0
  358. package/src/runtime/routes/trace-event-routes.ts +62 -0
  359. package/src/runtime/tool-grant-request-helper.ts +1 -1
  360. package/src/runtime/verification-outbound-actions.ts +47 -31
  361. package/src/security/encrypted-store.ts +263 -78
  362. package/src/skills/catalog-install.ts +10 -0
  363. package/src/skills/managed-store.ts +2 -0
  364. package/src/skills/skill-memory.ts +220 -0
  365. package/src/subagent/manager.ts +1 -4
  366. package/src/telemetry/types.ts +10 -1
  367. package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
  368. package/src/telemetry/usage-telemetry-reporter.ts +51 -4
  369. package/src/tools/AGENTS.md +11 -11
  370. package/src/tools/acp/spawn.ts +1 -1
  371. package/src/tools/apps/executors.ts +8 -8
  372. package/src/tools/apps/registry.ts +1 -1
  373. package/src/tools/assets/materialize.ts +6 -6
  374. package/src/tools/assets/search.ts +10 -10
  375. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  376. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  377. package/src/tools/browser/auth-detector.ts +6 -6
  378. package/src/tools/browser/browser-execution.ts +13 -13
  379. package/src/tools/browser/browser-manager.ts +3 -3
  380. package/src/tools/browser/chrome-cdp.ts +5 -5
  381. package/src/tools/browser/jit-auth.ts +2 -2
  382. package/src/tools/browser/network-recorder.test.ts +2 -2
  383. package/src/tools/browser/network-recorder.ts +3 -3
  384. package/src/tools/browser/runtime-check.ts +3 -3
  385. package/src/tools/claude-code/claude-code.ts +2 -2
  386. package/src/tools/computer-use/definitions.ts +18 -18
  387. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  388. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  389. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  390. package/src/tools/credentials/broker-types.ts +5 -5
  391. package/src/tools/credentials/broker.ts +15 -15
  392. package/src/tools/credentials/metadata-store.ts +2 -2
  393. package/src/tools/credentials/resolve.ts +1 -1
  394. package/src/tools/credentials/selection.ts +1 -1
  395. package/src/tools/credentials/tool-policy.ts +1 -1
  396. package/src/tools/credentials/vault.ts +115 -25
  397. package/src/tools/execution-target.ts +2 -2
  398. package/src/tools/executor.ts +7 -7
  399. package/src/tools/filesystem/edit.ts +2 -2
  400. package/src/tools/filesystem/read.ts +1 -1
  401. package/src/tools/filesystem/write.ts +1 -1
  402. package/src/tools/host-filesystem/edit.ts +2 -1
  403. package/src/tools/host-filesystem/read.ts +2 -1
  404. package/src/tools/host-filesystem/write.ts +1 -1
  405. package/src/tools/host-terminal/host-shell.ts +9 -8
  406. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  407. package/src/tools/memory/definitions.ts +6 -5
  408. package/src/tools/memory/handlers.test.ts +1 -1
  409. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  410. package/src/tools/network/domain-normalize.ts +2 -2
  411. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  412. package/src/tools/network/web-fetch.ts +1 -1
  413. package/src/tools/network/web-search.ts +3 -3
  414. package/src/tools/permission-checker.ts +8 -8
  415. package/src/tools/registry.ts +7 -7
  416. package/src/tools/schedule/list.ts +2 -2
  417. package/src/tools/schema-transforms.ts +31 -21
  418. package/src/tools/secret-detection-handler.ts +1 -1
  419. package/src/tools/sensitive-output-placeholders.ts +1 -1
  420. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  421. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  422. package/src/tools/shared/filesystem/image-read.ts +25 -5
  423. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  424. package/src/tools/shared/shell-output.ts +1 -1
  425. package/src/tools/side-effects.ts +1 -1
  426. package/src/tools/skills/execute.ts +1 -1
  427. package/src/tools/skills/load.ts +3 -3
  428. package/src/tools/skills/sandbox-runner.ts +3 -3
  429. package/src/tools/subagent/read.ts +1 -1
  430. package/src/tools/subagent/spawn.ts +2 -2
  431. package/src/tools/swarm/delegate.ts +3 -3
  432. package/src/tools/system/request-permission.ts +5 -4
  433. package/src/tools/terminal/backends/native.ts +4 -4
  434. package/src/tools/terminal/parser.ts +6 -6
  435. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  436. package/src/tools/terminal/shell.ts +16 -16
  437. package/src/tools/tool-approval-handler.ts +21 -12
  438. package/src/tools/tool-manifest.ts +4 -4
  439. package/src/tools/types.ts +3 -3
  440. package/src/tools/ui-surface/definitions.ts +9 -37
  441. package/src/tools/watcher/list.ts +1 -1
  442. package/src/util/logger.ts +7 -2
  443. package/src/util/retry.ts +29 -1
  444. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  445. package/src/workspace/migrations/registry.ts +2 -0
  446. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  447. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  448. package/src/cli/reference.ts +0 -38
  449. package/src/memory/job-handlers/capability-cards.ts +0 -420
  450. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Host shell tool `host_bash`.
2
+ * Host shell tool - `host_bash`.
3
3
  *
4
4
  * Unlike the sandboxed `bash` tool, `host_bash` runs commands directly on the
5
5
  * host machine without the OS-level sandbox. Under CES shell lockdown for
6
6
  * untrusted actors, `host_bash` remains available as a user-approved escape
7
- * hatch the guardian must explicitly approve each invocation. It is NOT part
7
+ * hatch - the guardian must explicitly approve each invocation. It is NOT part
8
8
  * of the strong CES secrecy guarantee because it runs unsandboxed and could
9
9
  * access protected paths or credential material on disk.
10
10
  *
@@ -48,7 +48,8 @@ function buildHostShellEnv(): Record<string, string> {
48
48
 
49
49
  class HostShellTool implements Tool {
50
50
  name = "host_bash";
51
- description = "Execute a shell command on the host machine";
51
+ description =
52
+ "LAST RESORT — Execute a shell command directly on the user's host machine. You MUST strongly prefer the regular `bash` tool for all commands. Only use `host_bash` when you are absolutely certain the command MUST run on the user's host machine and CANNOT run in the workspace (e.g., managing host-level system services, accessing host-only peripherals, or interacting with host paths outside the workspace). If in doubt, use `bash` instead. Approval-gated: your user must allow each invocation. Do not use for commands that require injected credentials or secrets.";
52
53
  category = "host-terminal";
53
54
  // host_bash is a weaker-tier escape hatch under CES lockdown. It remains
54
55
  // Medium risk by default but persistent approvals are disabled for
@@ -64,9 +65,9 @@ class HostShellTool implements Tool {
64
65
  properties: {
65
66
  command: {
66
67
  type: "string",
67
- description: "The host shell command to execute",
68
+ description: "The host shell command to execute.",
68
69
  },
69
- reason: {
70
+ activity: {
70
71
  type: "string",
71
72
  description:
72
73
  'Brief non-technical explanation of what this command does and why, shown to a non-technical user in the permission prompt. Avoid jargon and technical terms. Good: "to check if a required program is installed on your computer". Bad: "to check if gcloud CLI is installed". Good: "to download a helper program". Bad: "to run npm install".',
@@ -82,7 +83,7 @@ class HostShellTool implements Tool {
82
83
  "Optional timeout in seconds. Uses configured default and max limits.",
83
84
  },
84
85
  },
85
- required: ["command", "reason"],
86
+ required: ["command", "activity"],
86
87
  },
87
88
  };
88
89
  }
@@ -128,7 +129,7 @@ class HostShellTool implements Tool {
128
129
  // lockdown is active for untrusted actors, persistent approvals are
129
130
  // disabled (every invocation requires fresh guardian approval) and the
130
131
  // VELLUM_UNTRUSTED_SHELL flag is injected to self-deny raw-secret CLI
131
- // commands. This does NOT provide the strong CES secrecy guarantee
132
+ // commands. This does NOT provide the strong CES secrecy guarantee -
132
133
  // the subprocess runs unsandboxed and could access protected paths.
133
134
  //
134
135
  // NOTE: forcePromptSideEffects is set in executor.ts BEFORE the
@@ -260,7 +261,7 @@ class HostShellTool implements Tool {
260
261
  if ((err as NodeJS.ErrnoException).code === "ENOENT") {
261
262
  hint = !existsSync(workingDir)
262
263
  ? `. The working directory does not exist: ${workingDir}`
263
- : ". The command was not found check that it is installed and in PATH.";
264
+ : ". The command was not found - check that it is installed and in PATH.";
264
265
  }
265
266
  resolve({
266
267
  content: `Error spawning command: ${err.message}${hint}`,
@@ -37,9 +37,10 @@ export function createMcpTool(
37
37
  ): Tool {
38
38
  const namespacedName = mcpToolName(serverId, metadata.name);
39
39
  const riskLevel = riskMap[serverConfig.defaultRiskLevel] ?? RiskLevel.High;
40
- const serverDefinesReason = schemaDefinesProperty(
40
+ const serverDefinesActivity = schemaDefinesProperty(
41
41
  metadata.inputSchema,
42
- "reason",
42
+ "activity",
43
+ { refBehavior: "assume-defined" },
43
44
  );
44
45
 
45
46
  return {
@@ -64,14 +65,14 @@ export function createMcpTool(
64
65
  _context: ToolContext,
65
66
  ): Promise<ToolExecutionResult> {
66
67
  try {
67
- // Strip injected reason before sending to MCP server
68
- const { reason: _reason, ...mcpInput } = input as Record<
68
+ // Strip injected activity before sending to MCP server
69
+ const { activity: _activity, ...mcpInput } = input as Record<
69
70
  string,
70
71
  unknown
71
72
  > & {
72
- reason?: unknown;
73
+ activity?: unknown;
73
74
  };
74
- const forwardInput = serverDefinesReason ? input : mcpInput;
75
+ const forwardInput = serverDefinesActivity ? input : mcpInput;
75
76
  const result = await manager.callTool(
76
77
  serverId,
77
78
  metadata.name,
@@ -3,19 +3,19 @@ import type { ToolDefinition } from "../../providers/types.js";
3
3
  export const memoryRecallDefinition: ToolDefinition = {
4
4
  name: "memory_recall",
5
5
  description:
6
- "Hybrid search across memory (semantic and recency) for specific information. Use this when you need to recall details about past conversations, decisions, preferences, project context, or any prior knowledge. Returns formatted memory context with item IDs for use with memory_manage.",
6
+ "Hybrid search across memory (semantic and recency) for specific information. Relevant memories are auto-injected each turn, so only call this when the auto-injected context doesn't contain what you need - e.g. the user references a past session, or you need deeper recall. Be specific in your query for best results. Returns formatted memory context with item IDs for use with memory_manage.",
7
7
  input_schema: {
8
8
  type: "object",
9
9
  properties: {
10
10
  query: {
11
11
  type: "string",
12
- description: "The search query be specific and descriptive",
12
+ description: "The search query - be specific and descriptive",
13
13
  },
14
14
  scope: {
15
15
  type: "string",
16
16
  enum: ["default", "conversation"],
17
17
  description:
18
- 'Scope to search "default" searches all memory, "conversation" restricts to current conversation',
18
+ 'Scope to search - "default" searches all memory, "conversation" restricts to current conversation',
19
19
  },
20
20
  },
21
21
  required: ["query"],
@@ -47,7 +47,8 @@ const memoryManageProperties = {
47
47
  "constraint",
48
48
  "event",
49
49
  ],
50
- description: "Category of the memory item (required for save)",
50
+ description:
51
+ 'Category of the memory item (required for save). Use "constraint" for mistakes, gotchas, discoveries, and working solutions - write as advice to your future self.',
51
52
  },
52
53
  subject: {
53
54
  type: "string" as const,
@@ -58,7 +59,7 @@ const memoryManageProperties = {
58
59
  export const memoryManageDefinition: ToolDefinition = {
59
60
  name: "memory_manage",
60
61
  description:
61
- "Save, update, or delete memory items. Use 'save' for new information worth remembering, 'update' to correct existing items, 'delete' to remove outdated items.",
62
+ "Save, update, or delete memory items. Memory does not survive session restarts - if you want to remember something, save it now. Use 'save' for new information worth remembering (facts, preferences, mistakes, discoveries, gotchas), 'update' to correct existing items, 'delete' to remove outdated items. When a user says 'remember this', save immediately. For user profile or personality changes, update workspace files (USER.md, SOUL.md) instead.",
62
63
  input_schema: {
63
64
  type: "object",
64
65
  properties: memoryManageProperties,
@@ -305,7 +305,7 @@ describe("handleMemoryRecall", () => {
305
305
  // ── Empty results ─────────────────────────────────────────────────
306
306
 
307
307
  test("returns empty result when no memories match", async () => {
308
- // No items seeded tables cleared in beforeEach
308
+ // No items seeded - tables cleared in beforeEach
309
309
  const result = await handleMemoryRecall(
310
310
  { query: "quantum physics" },
311
311
  TEST_CONFIG,
@@ -1,6 +1,6 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
- // Mutable mock state set per test
3
+ // Mutable mock state - set per test
4
4
  let mockWebSearchProvider: string | undefined = "perplexity";
5
5
  let mockBraveSecureKey: string | undefined;
6
6
  let mockPerplexitySecureKey: string | undefined;
@@ -383,8 +383,8 @@ describe("web_search tool", () => {
383
383
  expect(capturedUrl).toContain("perplexity");
384
384
  });
385
385
 
386
- test("maps anthropic-native to perplexity", async () => {
387
- mockWebSearchProvider = "anthropic-native";
386
+ test("maps inference-provider-native to perplexity", async () => {
387
+ mockWebSearchProvider = "inference-provider-native";
388
388
  mockPerplexitySecureKey = "pplx-key";
389
389
  let capturedUrl = "";
390
390
  globalThis.fetch = (async (url: string) => {
@@ -55,13 +55,13 @@ export function normalizeDomain(input: string): DomainInfo | null {
55
55
 
56
56
  if (!hostname) return null;
57
57
 
58
- // Reject IP addresses and localhost they don't have registrable domains
58
+ // Reject IP addresses and localhost - they don't have registrable domains
59
59
  if (isIPAddress(hostname) || hostname === "localhost") {
60
60
  return null;
61
61
  }
62
62
 
63
63
  // Reject malformed hostnames. Each DNS label must start and end with an
64
- // alphanumeric and contain only alphanumerics/hyphens no consecutive dots,
64
+ // alphanumeric and contain only alphanumerics/hyphens - no consecutive dots,
65
65
  // no labels starting or ending with hyphens.
66
66
  if (
67
67
  !/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/.test(
@@ -128,7 +128,7 @@ function resolveInjectionTemplates(
128
128
  }
129
129
 
130
130
  // ---------------------------------------------------------------------------
131
- // Session start hooks wires assistant credential resolution into core
131
+ // Session start hooks - wires assistant credential resolution into core
132
132
  // ---------------------------------------------------------------------------
133
133
 
134
134
  function buildSessionStartHooks(): SessionStartHooks {
@@ -216,13 +216,13 @@ function buildSessionStartHooks(): SessionStartHooks {
216
216
  if (bestCandidates.length === 1) {
217
217
  perCredentialBest.push({ credId, tpl: bestCandidates[0] });
218
218
  } else if (bestCandidates.length > 1) {
219
- // Same credential, same-specificity tie ambiguous, block
219
+ // Same credential, same-specificity tie - ambiguous, block
220
220
  return null;
221
221
  }
222
222
  }
223
223
 
224
224
  if (perCredentialBest.length === 0) return req.headers;
225
- // Cross-credential ambiguity block
225
+ // Cross-credential ambiguity - block
226
226
  if (perCredentialBest.length > 1) return null;
227
227
 
228
228
  const { credId, tpl } = perCredentialBest[0];
@@ -245,7 +245,7 @@ function buildSessionStartHooks(): SessionStartHooks {
245
245
  if (!headerValue) {
246
246
  log.warn(
247
247
  { host: req.hostname, credentialId: credId },
248
- "MITM rewrite: blocking request composeWith credential missing",
248
+ "MITM rewrite: blocking request - composeWith credential missing",
249
249
  );
250
250
  return null;
251
251
  }
@@ -325,7 +325,7 @@ function buildSessionStartHooks(): SessionStartHooks {
325
325
  if (!headerValue) {
326
326
  log.warn(
327
327
  { hostname, credentialId },
328
- "Policy: blocking matched request composeWith credential missing",
328
+ "Policy: blocking matched request - composeWith credential missing",
329
329
  );
330
330
  return null;
331
331
  }
@@ -334,7 +334,7 @@ function buildSessionStartHooks(): SessionStartHooks {
334
334
  return {};
335
335
  }
336
336
  case "ambiguous":
337
- return null; // block can't auto-resolve
337
+ return null; // block - can't auto-resolve
338
338
  case "ask_missing_credential":
339
339
  case "ask_unauthenticated":
340
340
  if (managed.approvalCallback) {
@@ -364,7 +364,7 @@ function buildSessionStartHooks(): SessionStartHooks {
364
364
  }
365
365
 
366
366
  // ---------------------------------------------------------------------------
367
- // Public API thin wrappers that delegate to session-core with the store
367
+ // Public API - thin wrappers that delegate to session-core with the store
368
368
  // ---------------------------------------------------------------------------
369
369
 
370
370
  /**
@@ -389,7 +389,7 @@ export function createSession(
389
389
  }
390
390
 
391
391
  /**
392
- * Start the proxy session opens an HTTP server on an ephemeral port.
392
+ * Start the proxy session - opens an HTTP server on an ephemeral port.
393
393
  */
394
394
  export async function startSession(
395
395
  sessionId: ProxySessionId,
@@ -399,7 +399,7 @@ export async function startSession(
399
399
  }
400
400
 
401
401
  /**
402
- * Gracefully stop a session closes the HTTP server and clears the idle timer.
402
+ * Gracefully stop a session - closes the HTTP server and clears the idle timer.
403
403
  */
404
404
  export async function stopSession(sessionId: ProxySessionId): Promise<void> {
405
405
  return coreStopSession(sessionId, store);
@@ -414,7 +414,7 @@ export function getSessionEnv(sessionId: ProxySessionId): ProxyEnvVars {
414
414
  }
415
415
 
416
416
  /**
417
- * Atomically acquire a proxy session for a conversation reuses an active
417
+ * Atomically acquire a proxy session for a conversation - reuses an active
418
418
  * session or creates + starts a new one.
419
419
  */
420
420
  export async function getOrStartSession(
@@ -309,7 +309,7 @@ function normalizeText(text: string): string {
309
309
  }
310
310
 
311
311
  // Lighter normalization for markdown that preserves indentation, multiple spaces,
312
- // and trailing whitespace all of which carry semantic meaning in markdown
312
+ // and trailing whitespace - all of which carry semantic meaning in markdown
313
313
  // (code blocks, nested lists, table alignment, line breaks).
314
314
  function normalizeMarkdown(text: string): string {
315
315
  return text
@@ -44,9 +44,9 @@ interface PerplexityResponse {
44
44
  function getWebSearchProvider(): WebSearchProvider {
45
45
  const config = getConfig();
46
46
  const configured = config.services["web-search"].provider ?? "perplexity";
47
- // 'anthropic-native' is handled by the Anthropic client directly;
48
- // fall back to perplexity for other providers.
49
- if (configured === "anthropic-native") return "perplexity";
47
+ // 'inference-provider-native' is handled by the inference provider client
48
+ // directly; fall back to perplexity for other providers.
49
+ if (configured === "inference-provider-native") return "perplexity";
50
50
  return configured as WebSearchProvider;
51
51
  }
52
52
 
@@ -90,7 +90,7 @@ export class PermissionChecker {
90
90
  );
91
91
 
92
92
  // Private conversations force prompting for side-effect tools even when a
93
- // trust/allow rule would auto-allow. Deny decisions are preserved
93
+ // trust/allow rule would auto-allow. Deny decisions are preserved -
94
94
  // only allow → prompt promotion happens here.
95
95
  if (
96
96
  context.forcePromptSideEffects &&
@@ -139,8 +139,8 @@ export class PermissionChecker {
139
139
  if (result.decision === "prompt") {
140
140
  // Guardian-trust sessions (e.g. scheduled jobs, reminders) should be
141
141
  // able to use bundled tools without interactive approval. The guardian
142
- // is the owner prompting makes no sense when there is no client.
143
- // Exception: requireFreshApproval tools cannot be auto-approved
142
+ // is the owner - prompting makes no sense when there is no client.
143
+ // Exception: requireFreshApproval tools cannot be auto-approved -
144
144
  // without a human present, bundle installation must be denied.
145
145
  if (
146
146
  context.isInteractive === false &&
@@ -158,7 +158,7 @@ export class PermissionChecker {
158
158
  };
159
159
  }
160
160
 
161
- // Non-interactive sessions have no client to respond to prompts
161
+ // Non-interactive sessions have no client to respond to prompts -
162
162
  // deny immediately instead of blocking for the full permission timeout.
163
163
  if (context.isInteractive === false) {
164
164
  const durationMs = Date.now() - startTime;
@@ -190,9 +190,9 @@ export class PermissionChecker {
190
190
  // Temporary approval override: if the guardian has enabled a
191
191
  // conversation-scoped "allow all" mode (allow_10m or allow_conversation),
192
192
  // skip the interactive prompt and auto-approve. Only applies to
193
- // guardian actors untrusted actors cannot leverage this to bypass
193
+ // guardian actors - untrusted actors cannot leverage this to bypass
194
194
  // guardian-required gates (those are enforced in pre-execution gates).
195
- // Exception: requireFreshApproval tools must always show the prompt
195
+ // Exception: requireFreshApproval tools must always show the prompt -
196
196
  // cached temporary overrides cannot substitute for per-invocation
197
197
  // human review.
198
198
  if (
@@ -206,7 +206,7 @@ export class PermissionChecker {
206
206
  riskLevel,
207
207
  conversationId: context.conversationId,
208
208
  },
209
- "Temporary approval override active auto-approving without prompt",
209
+ "Temporary approval override active - auto-approving without prompt",
210
210
  );
211
211
  return { allowed: true, decision: "temporary_override", riskLevel };
212
212
  }
@@ -237,7 +237,7 @@ export class PermissionChecker {
237
237
  const persistentDecisionsAllowed = !context.requireFreshApproval;
238
238
 
239
239
  // Offer temporary approval options to guardians. Suppressed when
240
- // requireFreshApproval is true temporary overrides would be
240
+ // requireFreshApproval is true - temporary overrides would be
241
241
  // misleading since future invocations still require fresh approval.
242
242
  const temporaryOptionsAvailable:
243
243
  | Array<"allow_10m" | "allow_conversation">
@@ -65,7 +65,7 @@ export function registerSkillTools(newTools: Tool[]): Tool[] {
65
65
  );
66
66
  continue;
67
67
  }
68
- // Existing is also a skill tool only allow replacement from the same owner.
68
+ // Existing is also a skill tool - only allow replacement from the same owner.
69
69
  if (existing.ownerSkillId !== tool.ownerSkillId) {
70
70
  throw new Error(
71
71
  `Skill tool "${tool.name}" is already registered by skill "${existing.ownerSkillId}"`,
@@ -108,7 +108,7 @@ export function unregisterSkillTools(skillId: string): void {
108
108
  return;
109
109
  }
110
110
 
111
- // Last reference actually remove the tools
111
+ // Last reference - actually remove the tools
112
112
  skillRefCount.delete(skillId);
113
113
  for (const [name, tool] of tools) {
114
114
  if (tool.origin === "skill" && tool.ownerSkillId === skillId) {
@@ -210,9 +210,9 @@ export function getSkillRefCount(skillId: string): number {
210
210
  }
211
211
 
212
212
  export function getAllToolDefinitions(): ToolDefinition[] {
213
- // Exclude proxy tools (e.g. computer_use_* tools) they are projected
213
+ // Exclude proxy tools (e.g. computer_use_* tools) - they are projected
214
214
  // into sessions by the skill system, not via the global tool list.
215
- // Exclude skill-origin tools they are managed by the session-level
215
+ // Exclude skill-origin tools - they are managed by the session-level
216
216
  // skill projection system (projectSkillTools) and must not leak into
217
217
  // the base tool list, which is shared across sessions via the global
218
218
  // registry. Including them here causes "Tool names must be unique"
@@ -239,7 +239,7 @@ export async function initializeTools(): Promise<void> {
239
239
  // Import tool modules to trigger registration side effects.
240
240
  await loadEagerModules();
241
241
 
242
- // Explicit tool instances no side-effect import required.
242
+ // Explicit tool instances - no side-effect import required.
243
243
  for (const tool of explicitTools) {
244
244
  registerTool(tool);
245
245
  }
@@ -256,7 +256,7 @@ export async function initializeTools(): Promise<void> {
256
256
  registerTool(tool);
257
257
  }
258
258
 
259
- // CES tools registered only when the CES feature flag is enabled.
259
+ // CES tools - registered only when the CES feature flag is enabled.
260
260
  const activeCesTools = getCesToolsIfEnabled();
261
261
  for (const tool of activeCesTools) {
262
262
  registerTool(tool);
@@ -298,7 +298,7 @@ export async function initializeTools(): Promise<void> {
298
298
 
299
299
  /**
300
300
  * Reset registry to its post-initializeTools() baseline. Exposed
301
- * exclusively for test isolation prevents cross-file contamination
301
+ * exclusively for test isolation - prevents cross-file contamination
302
302
  * when multiple test suites share a single Bun process.
303
303
  *
304
304
  * Restores core tools from a snapshot taken after the first
@@ -116,14 +116,14 @@ export async function executeScheduleList(
116
116
  if (oneShot) {
117
117
  const fireTime = formatLocalDate(job.nextRunAt);
118
118
  lines.push(
119
- ` - [${status}] ${job.name} (id: ${job.id}) (one-shot, ${job.mode}) fire at: ${fireTime} [${job.status}]`,
119
+ ` - [${status}] ${job.name} (id: ${job.id}) (one-shot, ${job.mode}) - fire at: ${fireTime} [${job.status}]`,
120
120
  );
121
121
  } else {
122
122
  const next = job.enabled ? formatLocalDate(job.nextRunAt) : "n/a";
123
123
  lines.push(
124
124
  ` - [${status}] ${job.name} (id: ${job.id}) ([${
125
125
  job.syntax
126
- }] ${describeSchedule(job)}, ${job.mode}) next: ${next}`,
126
+ }] ${describeSchedule(job)}, ${job.mode}) - next: ${next}`,
127
127
  );
128
128
  }
129
129
  }
@@ -1,26 +1,22 @@
1
1
  import type { ToolDefinition } from "../providers/types.js";
2
2
 
3
3
  /**
4
- * Tools that should never have a `reason` field injected into their schema.
4
+ * Tools that should never have an `activity` field injected into their schema.
5
+ * Now empty — all tools define their own `activity` property or get it injected.
5
6
  */
6
- export const REASON_SKIP_SET = new Set<string>([
7
- "skill_execute",
8
- "bash",
9
- "host_bash",
10
- "request_system_permission",
11
- ]);
7
+ export const ACTIVITY_SKIP_SET = new Set<string>();
12
8
 
13
9
  /**
14
- * Injects a `reason` string property into each tool definition's input schema,
15
- * unless the tool is in the skip set, already has a reason field, or has a
16
- * non-object schema.
10
+ * Injects an `activity` string property into each tool definition's input
11
+ * schema, unless the tool is in the skip set, already has an activity field,
12
+ * or has a non-object schema.
17
13
  *
18
- * CRITICAL: Never mutates the input definitions always returns deep clones
14
+ * CRITICAL: Never mutates the input definitions - always returns deep clones
19
15
  * for any modified definition, since `getDefinition()` returns shared refs.
20
16
  */
21
- export function injectReasonField(
17
+ export function injectActivityField(
22
18
  definitions: ToolDefinition[],
23
- skip: Set<string> = REASON_SKIP_SET,
19
+ skip: Set<string> = ACTIVITY_SKIP_SET,
24
20
  ): ToolDefinition[] {
25
21
  return definitions.map((def) => {
26
22
  if (skip.has(def.name)) {
@@ -33,15 +29,22 @@ export function injectReasonField(
33
29
  }
34
30
 
35
31
  const properties = schema.properties as Record<string, unknown>;
36
- if (schemaDefinesProperty(schema, "reason")) {
32
+ if (schemaDefinesProperty(schema, "activity")) {
37
33
  return def;
38
34
  }
39
35
 
40
36
  // Deep clone to avoid mutating shared refs
41
- const newProperties = { ...properties, reason: { type: "string" } };
37
+ const newProperties = {
38
+ ...properties,
39
+ activity: {
40
+ type: "string",
41
+ description:
42
+ "Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
43
+ },
44
+ };
42
45
  const existingRequired = Array.isArray(schema.required)
43
- ? [...schema.required, "reason"]
44
- : ["reason"];
46
+ ? [...schema.required, "activity"]
47
+ : ["activity"];
45
48
 
46
49
  return {
47
50
  ...def,
@@ -57,21 +60,28 @@ export function injectReasonField(
57
60
  /**
58
61
  * Checks whether a JSON Schema defines a given property name.
59
62
  * Walks `allOf`, `oneOf`, `anyOf` recursively.
60
- * Fail-closed on `$ref`: returns false if a `$ref` is encountered.
63
+ *
64
+ * `$ref` handling is configurable via `refBehavior`:
65
+ * - `'assume-undefined'` (default): fail-closed, treat `$ref` as not defining
66
+ * the property. Good for injection (safe to double-inject).
67
+ * - `'assume-defined'`: fail-open, treat `$ref` as possibly defining the
68
+ * property. Good for stripping decisions (don't strip what the server may need).
61
69
  */
62
70
  export function schemaDefinesProperty(
63
71
  schema: unknown,
64
72
  propertyName: string,
73
+ options?: { refBehavior?: "assume-defined" | "assume-undefined" },
65
74
  ): boolean {
66
75
  if (schema == null || typeof schema !== "object") {
67
76
  return false;
68
77
  }
69
78
 
70
79
  const s = schema as Record<string, unknown>;
80
+ const refBehavior = options?.refBehavior ?? "assume-undefined";
71
81
 
72
- // Fail-closed on $ref we can't resolve it, so treat as "doesn't define it"
82
+ // $ref: we can't resolve it, so use the configured behavior
73
83
  if ("$ref" in s) {
74
- return false;
84
+ return refBehavior === "assume-defined";
75
85
  }
76
86
 
77
87
  // Check direct properties
@@ -88,7 +98,7 @@ export function schemaDefinesProperty(
88
98
  const arr = s[keyword];
89
99
  if (Array.isArray(arr)) {
90
100
  for (const member of arr) {
91
- if (schemaDefinesProperty(member, propertyName)) {
101
+ if (schemaDefinesProperty(member, propertyName, options)) {
92
102
  return true;
93
103
  }
94
104
  }
@@ -371,7 +371,7 @@ export class SecretDetectionHandler {
371
371
  };
372
372
  }
373
373
 
374
- // User allowed pass content through unchanged
374
+ // User allowed - pass content through unchanged
375
375
  return { result: execResult, earlyReturn: false };
376
376
  }
377
377
  }
@@ -43,7 +43,7 @@ const VALID_KINDS = new Set<string>(Object.keys(KIND_PREFIX));
43
43
 
44
44
  /**
45
45
  * Generate an 8-char uppercase base-36 short ID.
46
- * Provides ~41 bits of entropy sufficient for intra-request uniqueness.
46
+ * Provides ~41 bits of entropy - sufficient for intra-request uniqueness.
47
47
  */
48
48
  function generateShortId(): string {
49
49
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -29,7 +29,7 @@ export type EditEngineResult =
29
29
  * Core match/replace logic shared by both sandbox and host edit tools,
30
30
  * and by the executor's preview-diff computation.
31
31
  *
32
- * This function is pure it takes file content and edit parameters and
32
+ * This function is pure - it takes file content and edit parameters and
33
33
  * returns the result without performing any I/O.
34
34
  */
35
35
  export function applyEdit(
@@ -132,7 +132,7 @@ export class FileSystemOps {
132
132
  try {
133
133
  oldContent = readFileSync(filePath, "utf-8");
134
134
  } catch {
135
- // Unreadable existing file keep oldContent as empty string.
135
+ // Unreadable existing file - keep oldContent as empty string.
136
136
  }
137
137
  }
138
138
 
@@ -167,14 +167,14 @@ export class FileSystemOps {
167
167
  }
168
168
  const filePath = pathCheck.resolved;
169
169
 
170
- // Size-check the file on disk (swallow ENOENT readFileSync gives a clearer error)
170
+ // Size-check the file on disk (swallow ENOENT - readFileSync gives a clearer error)
171
171
  try {
172
172
  const sizeErr = checkFileSizeOnDisk(filePath, this.sizeLimit);
173
173
  if (sizeErr) {
174
174
  return { ok: false, error: Err.sizeLimitExceeded(filePath, sizeErr) };
175
175
  }
176
176
  } catch {
177
- // Fall through the readFileSync below will surface NOT_FOUND.
177
+ // Fall through - the readFileSync below will surface NOT_FOUND.
178
178
  }
179
179
 
180
180
  let content: string;
@@ -14,7 +14,8 @@ export const IMAGE_EXTENSIONS = new Set([
14
14
  ".webp",
15
15
  ]);
16
16
 
17
- const MAX_SIZE_BYTES = 20 * 1024 * 1024; // 20 MB
17
+ const MAX_SIZE_BYTES = 20 * 1024 * 1024; // 20 MB — LLM API transport limit (post-optimization)
18
+ const MAX_SOURCE_SIZE_BYTES = 100 * 1024 * 1024; // 100 MB — pre-optimization guard
18
19
 
19
20
  // Images above this threshold get auto-optimized via sips (macOS) to avoid
20
21
  // sending multi-MB base64 payloads to the LLM API.
@@ -102,7 +103,7 @@ function optimizeWithSips(srcPath: string): string | null {
102
103
  * Read an image file from disk, optionally optimize it, and return a
103
104
  * ToolExecutionResult with base64-encoded image content blocks.
104
105
  *
105
- * The caller is responsible for path resolution and sandbox enforcement
106
+ * The caller is responsible for path resolution and sandbox enforcement -
106
107
  * `resolvedPath` must be an already-validated absolute path.
107
108
  */
108
109
  export function readImageFile(resolvedPath: string): ToolExecutionResult {
@@ -120,10 +121,10 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
120
121
  return { content: `Error: ${resolvedPath} is not a file`, isError: true };
121
122
  }
122
123
 
123
- if (stat.size > MAX_SIZE_BYTES) {
124
+ if (stat.size > MAX_SOURCE_SIZE_BYTES) {
124
125
  const sizeMB = (stat.size / (1024 * 1024)).toFixed(1);
125
126
  return {
126
- content: `Error: image too large (${sizeMB} MB). Maximum is 20 MB.`,
127
+ content: `Error: image too large (${sizeMB} MB). Maximum source file size is 100 MB.`,
127
128
  isError: true,
128
129
  };
129
130
  }
@@ -139,6 +140,14 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
139
140
  buffer = readFileSync(tmpPath) as Buffer;
140
141
  optimized = true;
141
142
  } else {
143
+ // sips unavailable — fast-fail if original file exceeds the transport limit
144
+ if (stat.size > MAX_SIZE_BYTES) {
145
+ const sizeMB = (stat.size / (1024 * 1024)).toFixed(1);
146
+ return {
147
+ content: `Error: image too large (${sizeMB} MB). Maximum is 20 MB. Image optimization (sips) is unavailable on this platform.`,
148
+ isError: true,
149
+ };
150
+ }
142
151
  buffer = readFileSync(resolvedPath) as Buffer;
143
152
  }
144
153
  } else {
@@ -157,7 +166,18 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
157
166
  }
158
167
  }
159
168
 
160
- // Detect actual format from magic bytes — never trust the file extension
169
+ if (buffer.length > MAX_SIZE_BYTES) {
170
+ const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
171
+ const msg = optimized
172
+ ? `Error: image too large after optimization (${sizeMB} MB). Maximum is 20 MB.`
173
+ : `Error: image too large (${sizeMB} MB). Maximum is 20 MB.`;
174
+ return {
175
+ content: msg,
176
+ isError: true,
177
+ };
178
+ }
179
+
180
+ // Detect actual format from magic bytes - never trust the file extension
161
181
  // alone, since sips converts to JPEG and files can be misnamed.
162
182
  const detectedType = detectMediaType(buffer);
163
183
  if (!detectedType) {