@vellumai/assistant 0.4.56 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) 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 +204 -185
  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 +249 -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__/file-read-tool.test.ts +40 -0
  67. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  68. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  69. package/src/__tests__/gemini-image-service.test.ts +4 -4
  70. package/src/__tests__/gemini-provider.test.ts +6 -9
  71. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  72. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  73. package/src/__tests__/host-file-read-tool.test.ts +87 -0
  74. package/src/__tests__/host-shell-tool.test.ts +6 -6
  75. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  76. package/src/__tests__/identity-intro-cache.test.ts +209 -0
  77. package/src/__tests__/intent-routing.test.ts +51 -99
  78. package/src/__tests__/invite-routes-http.test.ts +5 -0
  79. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  80. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  81. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  82. package/src/__tests__/media-generate-image.test.ts +32 -15
  83. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  84. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  86. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  87. package/src/__tests__/memory-regressions.test.ts +86 -90
  88. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  89. package/src/__tests__/migration-export-http.test.ts +26 -27
  90. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  91. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  92. package/src/__tests__/migration-validate-http.test.ts +16 -16
  93. package/src/__tests__/model-intents.test.ts +2 -2
  94. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  95. package/src/__tests__/non-member-access-request.test.ts +3 -3
  96. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  97. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  98. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  99. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  100. package/src/__tests__/notification-deep-link.test.ts +1 -1
  101. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  102. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  103. package/src/__tests__/oauth-store.test.ts +1 -3
  104. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  105. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  106. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  107. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  108. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  109. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  110. package/src/__tests__/qdrant-manager.test.ts +7 -7
  111. package/src/__tests__/ratelimit.test.ts +0 -74
  112. package/src/__tests__/recording-handler.test.ts +0 -1
  113. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  115. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  116. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  117. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  118. package/src/__tests__/schema-transforms.test.ts +114 -54
  119. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  120. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  121. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  122. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  123. package/src/__tests__/send-notification-tool.test.ts +2 -2
  124. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  125. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  126. package/src/__tests__/skill-memory.test.ts +549 -0
  127. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  128. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  129. package/src/__tests__/slack-channel-config.test.ts +109 -94
  130. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  131. package/src/__tests__/swarm-recursion.test.ts +2 -2
  132. package/src/__tests__/swarm-tool.test.ts +2 -2
  133. package/src/__tests__/system-prompt.test.ts +19 -66
  134. package/src/__tests__/telegram-config.test.ts +121 -0
  135. package/src/__tests__/terminal-tools.test.ts +1 -1
  136. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  138. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  139. package/src/__tests__/tool-executor.test.ts +1 -1
  140. package/src/__tests__/trace-emitter.test.ts +8 -1
  141. package/src/__tests__/trust-store.test.ts +7 -8
  142. package/src/__tests__/twilio-routes.test.ts +1 -18
  143. package/src/__tests__/user-reference.test.ts +82 -2
  144. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  145. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  146. package/src/approvals/guardian-request-resolvers.ts +3 -3
  147. package/src/avatar/ascii-renderer.ts +2 -2
  148. package/src/avatar/png-renderer.ts +2 -2
  149. package/src/avatar/resvg-lazy.ts +21 -0
  150. package/src/calls/guardian-dispatch.ts +1 -1
  151. package/src/calls/relay-access-wait.ts +2 -2
  152. package/src/calls/twilio-rest.ts +0 -248
  153. package/src/cli/AGENTS.md +5 -8
  154. package/src/cli/__tests__/notifications.test.ts +5 -5
  155. package/src/cli/commands/avatar.ts +64 -2
  156. package/src/cli/commands/conversations.ts +131 -1
  157. package/src/cli/commands/credentials.ts +2 -0
  158. package/src/cli/commands/notifications.ts +3 -3
  159. package/src/cli.ts +10 -0
  160. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  161. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  162. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  163. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  164. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  165. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  166. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  167. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  168. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  169. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  170. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  171. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  172. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  173. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  174. package/src/config/bundled-skills/document/SKILL.md +4 -4
  175. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  176. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  177. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  178. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  179. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  180. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  181. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  182. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  183. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  184. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  185. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  186. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  187. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  188. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  189. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  190. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  192. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  193. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  195. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  196. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  197. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  198. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  199. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  200. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  201. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  202. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  203. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  204. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  205. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  206. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  207. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  208. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  209. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  210. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  211. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  212. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  213. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  214. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  215. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  216. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  217. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  218. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  219. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  220. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  221. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  222. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  223. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  224. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  225. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  226. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  227. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  228. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  229. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  230. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  231. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  232. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  233. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  234. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  235. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  236. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  237. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  238. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  240. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  241. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  242. package/src/config/feature-flag-registry.json +33 -17
  243. package/src/config/schemas/sandbox.ts +1 -1
  244. package/src/config/schemas/services.ts +13 -3
  245. package/src/config/schemas/timeouts.ts +0 -10
  246. package/src/contacts/contact-store.ts +63 -0
  247. package/src/contacts/contacts-write.ts +1 -1
  248. package/src/daemon/assistant-attachments.ts +2 -2
  249. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  250. package/src/daemon/conversation-agent-loop.ts +7 -30
  251. package/src/daemon/conversation-error.ts +24 -0
  252. package/src/daemon/conversation-memory.ts +8 -7
  253. package/src/daemon/conversation-runtime-assembly.ts +141 -275
  254. package/src/daemon/conversation-slash.ts +7 -26
  255. package/src/daemon/conversation-surfaces.ts +14 -0
  256. package/src/daemon/conversation-tool-setup.ts +9 -8
  257. package/src/daemon/conversation.ts +2 -0
  258. package/src/daemon/daemon-control.ts +1 -1
  259. package/src/daemon/date-context.ts +10 -83
  260. package/src/daemon/handlers/config-channels.ts +12 -2
  261. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  262. package/src/daemon/handlers/config-telegram.ts +6 -1
  263. package/src/daemon/handlers/conversations.ts +2 -2
  264. package/src/daemon/handlers/skills.ts +4 -0
  265. package/src/daemon/lifecycle.ts +28 -4
  266. package/src/daemon/providers-setup.ts +1 -1
  267. package/src/daemon/server.ts +1 -5
  268. package/src/daemon/shutdown-handlers.ts +9 -3
  269. package/src/daemon/tool-side-effects.ts +40 -0
  270. package/src/daemon/trace-emitter.ts +26 -2
  271. package/src/events/domain-events.ts +1 -1
  272. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  273. package/src/inbound/platform-callback-registration.ts +0 -18
  274. package/src/media/app-icon-generator.ts +15 -8
  275. package/src/media/avatar-router.ts +15 -8
  276. package/src/media/gemini-image-service.ts +125 -21
  277. package/src/memory/attachments-store.ts +3 -3
  278. package/src/memory/channel-verification-sessions.ts +6 -6
  279. package/src/memory/conversation-crud.ts +196 -1
  280. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  281. package/src/memory/conversation-title-service.ts +2 -3
  282. package/src/memory/db-init.ts +25 -1
  283. package/src/memory/invite-store.ts +4 -4
  284. package/src/memory/items-extractor.ts +4 -4
  285. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  286. package/src/memory/jobs-store.ts +3 -2
  287. package/src/memory/jobs-worker.ts +7 -5
  288. package/src/memory/lifecycle-events-store.ts +63 -0
  289. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  290. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  291. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  292. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  293. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  294. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  295. package/src/memory/migrations/index.ts +6 -0
  296. package/src/memory/migrations/registry.ts +13 -0
  297. package/src/memory/retriever.test.ts +223 -96
  298. package/src/memory/retriever.ts +115 -138
  299. package/src/memory/schema/calls.ts +1 -1
  300. package/src/memory/schema/contacts.ts +1 -1
  301. package/src/memory/schema/infrastructure.ts +29 -0
  302. package/src/memory/schema/memory-core.ts +7 -17
  303. package/src/memory/schema/notifications.ts +1 -1
  304. package/src/memory/search/formatting.ts +23 -6
  305. package/src/memory/search/lexical.ts +2 -0
  306. package/src/memory/search/semantic.ts +2 -0
  307. package/src/memory/search/staleness.ts +5 -1
  308. package/src/memory/search/types.ts +4 -0
  309. package/src/memory/task-memory-cleanup.ts +96 -6
  310. package/src/memory/trace-event-store.ts +148 -0
  311. package/src/notifications/README.md +1 -1
  312. package/src/notifications/decision-engine.ts +45 -4
  313. package/src/notifications/emit-signal.ts +5 -4
  314. package/src/notifications/events-store.ts +4 -4
  315. package/src/notifications/signal.ts +1 -1
  316. package/src/oauth/manual-token-connection.ts +49 -25
  317. package/src/permissions/checker.ts +6 -5
  318. package/src/permissions/defaults.ts +4 -4
  319. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  320. package/src/prompts/cache-boundary.ts +8 -0
  321. package/src/prompts/system-prompt.ts +105 -634
  322. package/src/prompts/templates/BOOTSTRAP.md +172 -33
  323. package/src/prompts/templates/IDENTITY.md +8 -24
  324. package/src/prompts/templates/SOUL.md +20 -41
  325. package/src/prompts/templates/USER.md +3 -19
  326. package/src/prompts/user-reference.ts +14 -16
  327. package/src/providers/anthropic/client.ts +51 -19
  328. package/src/providers/gemini/client.ts +6 -9
  329. package/src/providers/managed-proxy/constants.ts +1 -7
  330. package/src/providers/managed-proxy/context.ts +0 -1
  331. package/src/providers/model-intents.ts +5 -5
  332. package/src/providers/openai/client.ts +10 -1
  333. package/src/providers/openrouter/client.ts +1 -0
  334. package/src/providers/ratelimit.ts +0 -35
  335. package/src/providers/registry.ts +3 -5
  336. package/src/providers/retry.ts +18 -1
  337. package/src/runtime/access-request-helper.ts +16 -2
  338. package/src/runtime/auth/route-policy.ts +7 -0
  339. package/src/runtime/channel-verification-service.ts +1 -1
  340. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  341. package/src/runtime/guardian-vellum-migration.ts +61 -1
  342. package/src/runtime/http-server.ts +8 -4
  343. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  344. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  345. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  346. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  347. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  348. package/src/runtime/routes/attachment-routes.ts +2 -2
  349. package/src/runtime/routes/btw-routes.ts +93 -0
  350. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  351. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  352. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-routes.ts +49 -5
  354. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  355. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  356. package/src/runtime/routes/identity-intro-cache.ts +105 -0
  357. package/src/runtime/routes/identity-routes.ts +51 -0
  358. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  359. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  360. package/src/runtime/routes/migration-routes.ts +25 -13
  361. package/src/runtime/routes/secret-routes.ts +18 -0
  362. package/src/runtime/routes/settings-routes.ts +9 -9
  363. package/src/runtime/routes/telemetry-routes.ts +53 -0
  364. package/src/runtime/routes/trace-event-routes.ts +62 -0
  365. package/src/runtime/tool-grant-request-helper.ts +1 -1
  366. package/src/runtime/verification-outbound-actions.ts +47 -31
  367. package/src/security/encrypted-store.ts +262 -78
  368. package/src/skills/catalog-install.ts +10 -0
  369. package/src/skills/managed-store.ts +2 -0
  370. package/src/skills/skill-memory.ts +222 -0
  371. package/src/subagent/manager.ts +1 -4
  372. package/src/telemetry/types.ts +10 -1
  373. package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
  374. package/src/telemetry/usage-telemetry-reporter.ts +53 -4
  375. package/src/tools/AGENTS.md +11 -11
  376. package/src/tools/acp/spawn.ts +1 -1
  377. package/src/tools/apps/executors.ts +8 -8
  378. package/src/tools/apps/registry.ts +1 -1
  379. package/src/tools/assets/materialize.ts +6 -6
  380. package/src/tools/assets/search.ts +10 -10
  381. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  382. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  383. package/src/tools/browser/auth-detector.ts +6 -6
  384. package/src/tools/browser/browser-execution.ts +13 -13
  385. package/src/tools/browser/browser-manager.ts +3 -3
  386. package/src/tools/browser/chrome-cdp.ts +5 -5
  387. package/src/tools/browser/jit-auth.ts +2 -2
  388. package/src/tools/browser/network-recorder.test.ts +2 -2
  389. package/src/tools/browser/network-recorder.ts +3 -3
  390. package/src/tools/browser/runtime-check.ts +3 -3
  391. package/src/tools/claude-code/claude-code.ts +2 -2
  392. package/src/tools/computer-use/definitions.ts +18 -18
  393. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  394. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  395. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  396. package/src/tools/credentials/broker-types.ts +5 -5
  397. package/src/tools/credentials/broker.ts +15 -15
  398. package/src/tools/credentials/metadata-store.ts +2 -2
  399. package/src/tools/credentials/resolve.ts +1 -1
  400. package/src/tools/credentials/selection.ts +1 -1
  401. package/src/tools/credentials/tool-policy.ts +1 -1
  402. package/src/tools/credentials/vault.ts +115 -25
  403. package/src/tools/execution-target.ts +2 -2
  404. package/src/tools/executor.ts +7 -7
  405. package/src/tools/filesystem/edit.ts +2 -2
  406. package/src/tools/filesystem/read.ts +15 -4
  407. package/src/tools/filesystem/write.ts +1 -1
  408. package/src/tools/host-filesystem/edit.ts +2 -1
  409. package/src/tools/host-filesystem/read.ts +18 -1
  410. package/src/tools/host-filesystem/write.ts +1 -1
  411. package/src/tools/host-terminal/host-shell.ts +9 -8
  412. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  413. package/src/tools/memory/definitions.ts +6 -5
  414. package/src/tools/memory/handlers.test.ts +1 -1
  415. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  416. package/src/tools/network/domain-normalize.ts +2 -2
  417. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  418. package/src/tools/network/web-fetch.ts +1 -1
  419. package/src/tools/network/web-search.ts +3 -3
  420. package/src/tools/permission-checker.ts +8 -8
  421. package/src/tools/registry.ts +7 -7
  422. package/src/tools/schedule/list.ts +2 -2
  423. package/src/tools/schema-transforms.ts +31 -21
  424. package/src/tools/secret-detection-handler.ts +1 -1
  425. package/src/tools/sensitive-output-placeholders.ts +1 -1
  426. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  427. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  428. package/src/tools/shared/filesystem/image-read.ts +25 -5
  429. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  430. package/src/tools/shared/shell-output.ts +1 -1
  431. package/src/tools/side-effects.ts +1 -1
  432. package/src/tools/skills/execute.ts +1 -1
  433. package/src/tools/skills/load.ts +3 -3
  434. package/src/tools/skills/sandbox-runner.ts +3 -3
  435. package/src/tools/subagent/read.ts +1 -1
  436. package/src/tools/subagent/spawn.ts +2 -2
  437. package/src/tools/swarm/delegate.ts +3 -3
  438. package/src/tools/system/request-permission.ts +5 -4
  439. package/src/tools/terminal/backends/native.ts +4 -4
  440. package/src/tools/terminal/parser.ts +6 -6
  441. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  442. package/src/tools/terminal/shell.ts +16 -16
  443. package/src/tools/tool-approval-handler.ts +21 -12
  444. package/src/tools/tool-manifest.ts +4 -4
  445. package/src/tools/types.ts +3 -3
  446. package/src/tools/ui-surface/definitions.ts +9 -37
  447. package/src/tools/watcher/list.ts +1 -1
  448. package/src/util/logger.ts +7 -2
  449. package/src/util/pricing.ts +4 -0
  450. package/src/util/retry.ts +29 -1
  451. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  452. package/src/workspace/migrations/registry.ts +2 -0
  453. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  454. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  455. package/src/cli/reference.ts +0 -38
  456. package/src/memory/job-handlers/capability-cards.ts +0 -420
  457. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -10,18 +10,9 @@ import {
10
10
  /** Wednesday 2026-02-18 12:00 UTC */
11
11
  const WED_FEB_18 = Date.UTC(2026, 1, 18, 12, 0, 0);
12
12
 
13
- /** Saturday 2026-02-21 12:00 UTC */
14
- const SAT_FEB_21 = Date.UTC(2026, 1, 21, 12, 0, 0);
15
-
16
- /** Sunday 2026-02-22 12:00 UTC */
17
- const SUN_FEB_22 = Date.UTC(2026, 1, 22, 12, 0, 0);
18
-
19
- /** Tuesday 2026-12-29 12:00 UTC — year boundary */
13
+ /** Tuesday 2026-12-29 12:00 UTC - year boundary */
20
14
  const TUE_DEC_29 = Date.UTC(2026, 11, 29, 12, 0, 0);
21
15
 
22
- /** Friday 2026-02-27 12:00 UTC */
23
- const FRI_FEB_27 = Date.UTC(2026, 1, 27, 12, 0, 0);
24
-
25
16
  // ---------------------------------------------------------------------------
26
17
  // Basic structure
27
18
  // ---------------------------------------------------------------------------
@@ -56,9 +47,17 @@ describe("buildTemporalContext", () => {
56
47
  expect(result).toContain("Current UTC time: 2026-02-18T12:00:00.000Z");
57
48
  });
58
49
 
59
- test("documents assistant host as the authoritative clock source", () => {
50
+ test("includes timezone source", () => {
51
+ const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
52
+ expect(result).toContain("Timezone source:");
53
+ });
54
+
55
+ test("does not include week definitions, next weekend, next work week, or horizon dates", () => {
60
56
  const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
61
- expect(result).toContain("Clock source: assistant host machine");
57
+ expect(result).not.toContain("Week definitions");
58
+ expect(result).not.toContain("Next weekend");
59
+ expect(result).not.toContain("Next work week");
60
+ expect(result).not.toContain("Upcoming dates");
62
61
  });
63
62
 
64
63
  test("uses user timezone when provided and records source metadata", () => {
@@ -69,11 +68,48 @@ describe("buildTemporalContext", () => {
69
68
  });
70
69
  expect(result).toContain("Timezone: America/New_York");
71
70
  expect(result).toContain("Current local time: 2026-02-18T07:00:00-05:00");
72
- expect(result).toContain("Assistant host timezone: UTC");
73
- expect(result).toContain("User timezone: America/New_York");
74
71
  expect(result).toContain("Timezone source: user_profile_memory");
75
72
  });
76
73
 
74
+ test("shows user timezone only when different from primary timezone", () => {
75
+ // When user timezone equals the primary timezone, omit it
76
+ const sameResult = buildTemporalContext({
77
+ nowMs: WED_FEB_18,
78
+ hostTimeZone: "UTC",
79
+ configuredUserTimeZone: "UTC",
80
+ });
81
+ expect(sameResult).not.toContain("User timezone:");
82
+
83
+ // When user timezone differs from host, it becomes the primary timezone
84
+ // and the host timezone is shown as a secondary annotation
85
+ const diffResult = buildTemporalContext({
86
+ nowMs: WED_FEB_18,
87
+ hostTimeZone: "UTC",
88
+ userTimeZone: "America/New_York",
89
+ });
90
+ expect(diffResult).toContain("Timezone: America/New_York");
91
+ expect(diffResult).toContain("Assistant host timezone: UTC");
92
+ expect(diffResult).not.toContain("User timezone:");
93
+ });
94
+
95
+ test("shows assistant host timezone only when different from primary timezone", () => {
96
+ // When host timezone equals the primary timezone, omit it
97
+ const sameResult = buildTemporalContext({
98
+ nowMs: WED_FEB_18,
99
+ hostTimeZone: "UTC",
100
+ timeZone: "UTC",
101
+ });
102
+ expect(sameResult).not.toContain("Assistant host timezone:");
103
+
104
+ // When different, include it
105
+ const diffResult = buildTemporalContext({
106
+ nowMs: WED_FEB_18,
107
+ hostTimeZone: "UTC",
108
+ userTimeZone: "America/New_York",
109
+ });
110
+ expect(diffResult).toContain("Assistant host timezone: UTC");
111
+ });
112
+
77
113
  test("uses configured user timezone when profile timezone is unavailable", () => {
78
114
  const result = buildTemporalContext({
79
115
  nowMs: WED_FEB_18,
@@ -83,7 +119,6 @@ describe("buildTemporalContext", () => {
83
119
  });
84
120
  expect(result).toContain("Timezone: America/Chicago");
85
121
  expect(result).toContain("Current local time: 2026-02-18T06:00:00-06:00");
86
- expect(result).toContain("User timezone: America/Chicago");
87
122
  expect(result).toContain("Timezone source: user_settings");
88
123
  });
89
124
 
@@ -96,7 +131,6 @@ describe("buildTemporalContext", () => {
96
131
  });
97
132
  expect(result).toContain("Timezone: America/Los_Angeles");
98
133
  expect(result).toContain("Current local time: 2026-02-18T04:00:00-08:00");
99
- expect(result).toContain("User timezone: America/Los_Angeles");
100
134
  expect(result).toContain("Timezone source: user_settings");
101
135
  });
102
136
 
@@ -107,7 +141,6 @@ describe("buildTemporalContext", () => {
107
141
  userTimeZone: null,
108
142
  });
109
143
  expect(result).toContain("Timezone: UTC");
110
- expect(result).toContain("User timezone: unknown");
111
144
  expect(result).toContain("Timezone source: assistant_host_fallback");
112
145
  });
113
146
 
@@ -119,7 +152,6 @@ describe("buildTemporalContext", () => {
119
152
  });
120
153
  expect(result).toContain("Timezone: Etc/GMT-2");
121
154
  expect(result).toContain("Current local time: 2026-02-18T14:00:00+02:00");
122
- expect(result).toContain("User timezone: Etc/GMT-2");
123
155
  expect(result).toContain("Timezone source: user_profile_memory");
124
156
  });
125
157
 
@@ -131,16 +163,9 @@ describe("buildTemporalContext", () => {
131
163
  });
132
164
  expect(result).toContain("Timezone: +05:30");
133
165
  expect(result).toContain("Current local time: 2026-02-18T17:30:00+05:30");
134
- expect(result).toContain("User timezone: +05:30");
135
166
  expect(result).toContain("Timezone source: user_profile_memory");
136
167
  });
137
168
 
138
- test("includes week definitions", () => {
139
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
140
- expect(result).toContain("work week = Monday–Friday");
141
- expect(result).toContain("weekend = Saturday–Sunday");
142
- });
143
-
144
169
  test("formats midnight hours as 00 (never 24) in local ISO output", () => {
145
170
  const justAfterMidnight = Date.UTC(2026, 1, 19, 0, 5, 0);
146
171
  const result = buildTemporalContext({
@@ -150,151 +175,16 @@ describe("buildTemporalContext", () => {
150
175
  expect(result).toContain("Current local time: 2026-02-19T00:05:00+00:00");
151
176
  expect(result).not.toContain("T24:05:00");
152
177
  });
153
- });
154
-
155
- // ---------------------------------------------------------------------------
156
- // Weekday baseline — today is Wednesday
157
- // ---------------------------------------------------------------------------
158
178
 
159
- describe("weekday baseline (Wednesday)", () => {
160
- test("next weekend is the upcoming Saturday-Sunday", () => {
179
+ test("Today line includes full YYYY-MM-DD format with year", () => {
161
180
  const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
162
- // Wednesday Feb 18 → next Saturday is Feb 21, Sunday is Feb 22
163
- expect(result).toContain("Next weekend: 2026-02-21 – 2026-02-22");
164
- });
165
-
166
- test("next work week is the following Monday-Friday", () => {
167
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
168
- // Wednesday Feb 18 → next Monday is Feb 23, Friday is Feb 27
169
- expect(result).toContain("Next work week: 2026-02-23 – 2026-02-27");
170
- });
171
- });
172
-
173
- // ---------------------------------------------------------------------------
174
- // Weekend baseline — today is Saturday
175
- // ---------------------------------------------------------------------------
176
-
177
- describe("weekend baseline (Saturday)", () => {
178
- test("next weekend is the *following* Saturday-Sunday, not today", () => {
179
- const result = buildTemporalContext({ nowMs: SAT_FEB_21, timeZone: "UTC" });
180
- // Saturday Feb 21 → next Saturday is Feb 28, Sunday is Mar 1
181
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
182
- });
183
-
184
- test("next work week is the upcoming Monday-Friday", () => {
185
- const result = buildTemporalContext({ nowMs: SAT_FEB_21, timeZone: "UTC" });
186
- // Saturday Feb 21 → next Monday is Feb 23, Friday is Feb 27
187
- expect(result).toContain("Next work week: 2026-02-23 – 2026-02-27");
188
- });
189
- });
190
-
191
- // ---------------------------------------------------------------------------
192
- // Weekend baseline — today is Sunday
193
- // ---------------------------------------------------------------------------
194
-
195
- describe("weekend baseline (Sunday)", () => {
196
- test("next weekend is the following Saturday-Sunday", () => {
197
- const result = buildTemporalContext({ nowMs: SUN_FEB_22, timeZone: "UTC" });
198
- // Sunday Feb 22 → next Saturday is Feb 28, Sunday is Mar 1
199
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
200
- });
201
-
202
- test("next work week is the upcoming Monday-Friday", () => {
203
- const result = buildTemporalContext({ nowMs: SUN_FEB_22, timeZone: "UTC" });
204
- // Sunday Feb 22 → next Monday is Feb 23, Friday is Feb 27
205
- expect(result).toContain("Next work week: 2026-02-23 – 2026-02-27");
206
- });
207
- });
208
-
209
- // ---------------------------------------------------------------------------
210
- // Friday baseline
211
- // ---------------------------------------------------------------------------
212
-
213
- describe("Friday baseline", () => {
214
- test("next weekend is tomorrow (Saturday) and Sunday", () => {
215
- const result = buildTemporalContext({ nowMs: FRI_FEB_27, timeZone: "UTC" });
216
- // Friday Feb 27 → next Saturday is Feb 28, Sunday is Mar 1
217
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
218
- });
219
-
220
- test("next work week is the following Monday-Friday", () => {
221
- const result = buildTemporalContext({ nowMs: FRI_FEB_27, timeZone: "UTC" });
222
- // Friday Feb 27 → next Monday is Mar 2, Friday is Mar 6
223
- expect(result).toContain("Next work week: 2026-03-02 – 2026-03-06");
181
+ expect(result).toMatch(/Today: \d{4}-\d{2}-\d{2} \(\w+\)/);
182
+ expect(result).toContain("2026-02-18");
224
183
  });
225
- });
226
184
 
227
- // ---------------------------------------------------------------------------
228
- // Month / year boundary
229
- // ---------------------------------------------------------------------------
230
-
231
- describe("month/year boundary", () => {
232
185
  test("handles year boundary correctly", () => {
233
186
  const result = buildTemporalContext({ nowMs: TUE_DEC_29, timeZone: "UTC" });
234
187
  expect(result).toContain("Today: 2026-12-29 (Tuesday)");
235
- // Tuesday Dec 29 → next Saturday is Jan 2 2027
236
- expect(result).toContain("Next weekend: 2027-01-02 – 2027-01-03");
237
- // Next Monday is Jan 4 2027 (skips current work week)
238
- // Wait — Dec 29 is Tuesday, so next Monday = Jan 4? Let me think:
239
- // Dec 29 Tue → Mon is (1-2+7)%7 = 6 days → Jan 4 Mon
240
- expect(result).toContain("Next work week: 2027-01-04 – 2027-01-08");
241
- });
242
-
243
- test("horizon entries cross year boundary", () => {
244
- const result = buildTemporalContext({
245
- nowMs: TUE_DEC_29,
246
- timeZone: "UTC",
247
- horizonDays: 5,
248
- });
249
- expect(result).toContain("2026-12-30 Wednesday");
250
- expect(result).toContain("2026-12-31 Thursday");
251
- expect(result).toContain("2027-01-01 Friday");
252
- expect(result).toContain("2027-01-02 Saturday");
253
- expect(result).toContain("2027-01-03 Sunday");
254
- });
255
- });
256
-
257
- // ---------------------------------------------------------------------------
258
- // Output size caps
259
- // ---------------------------------------------------------------------------
260
-
261
- describe("output size caps", () => {
262
- test("output is at most 1500 characters", () => {
263
- const result = buildTemporalContext({
264
- nowMs: WED_FEB_18,
265
- timeZone: "UTC",
266
- horizonDays: 14,
267
- });
268
- expect(result.length).toBeLessThanOrEqual(1500);
269
- });
270
-
271
- test("horizon entries are capped at 14 even if more requested", () => {
272
- const result = buildTemporalContext({
273
- nowMs: WED_FEB_18,
274
- timeZone: "UTC",
275
- horizonDays: 30,
276
- });
277
- const horizonMatches = result.match(/^\s+\d{4}-\d{2}-\d{2} \w+$/gm);
278
- expect(horizonMatches).not.toBeNull();
279
- expect(horizonMatches!.length).toBeLessThanOrEqual(14);
280
- });
281
-
282
- test("default horizon is 14 days", () => {
283
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
284
- const horizonMatches = result.match(/^\s+\d{4}-\d{2}-\d{2} \w+$/gm);
285
- expect(horizonMatches).not.toBeNull();
286
- expect(horizonMatches!.length).toBe(14);
287
- });
288
-
289
- test("respects smaller horizonDays", () => {
290
- const result = buildTemporalContext({
291
- nowMs: WED_FEB_18,
292
- timeZone: "UTC",
293
- horizonDays: 3,
294
- });
295
- const horizonMatches = result.match(/^\s+\d{4}-\d{2}-\d{2} \w+$/gm);
296
- expect(horizonMatches).not.toBeNull();
297
- expect(horizonMatches!.length).toBe(3);
298
188
  });
299
189
  });
300
190
 
@@ -304,7 +194,6 @@ describe("output size caps", () => {
304
194
 
305
195
  describe("DST-safe timezone behavior", () => {
306
196
  test("date labels are correct in US Eastern timezone", () => {
307
- // Feb 18 12:00 UTC = Feb 18 07:00 EST (same calendar date)
308
197
  const result = buildTemporalContext({
309
198
  nowMs: WED_FEB_18,
310
199
  timeZone: "America/New_York",
@@ -314,7 +203,6 @@ describe("DST-safe timezone behavior", () => {
314
203
  });
315
204
 
316
205
  test("date labels are correct in timezone ahead of UTC", () => {
317
- // Use a timestamp near midnight UTC so the local date differs
318
206
  // Feb 18 23:00 UTC = Feb 19 08:00 JST
319
207
  const nearMidnight = Date.UTC(2026, 1, 18, 23, 0, 0);
320
208
  const result = buildTemporalContext({
@@ -324,57 +212,6 @@ describe("DST-safe timezone behavior", () => {
324
212
  expect(result).toContain("Today: 2026-02-19 (Thursday)");
325
213
  });
326
214
 
327
- test("addDays is correct across DST spring-forward boundary", () => {
328
- // 2026-03-08 is spring-forward day in America/New_York (clocks jump 2:00→3:00 AM).
329
- // Use a timestamp at local 23:30 on Friday March 6 (04:30 UTC March 7).
330
- const preDST = Date.UTC(2026, 2, 7, 4, 30, 0); // local: Fri Mar 6 23:30 EST
331
- const result = buildTemporalContext({
332
- nowMs: preDST,
333
- timeZone: "America/New_York",
334
- horizonDays: 5,
335
- });
336
- // Today should be Friday March 6
337
- expect(result).toContain("Today: 2026-03-06 (Friday)");
338
- // Horizon should have 5 consecutive days with no duplicates/skips
339
- expect(result).toContain("2026-03-07 Saturday");
340
- expect(result).toContain("2026-03-08 Sunday");
341
- expect(result).toContain("2026-03-09 Monday");
342
- expect(result).toContain("2026-03-10 Tuesday");
343
- expect(result).toContain("2026-03-11 Wednesday");
344
- });
345
-
346
- test("addDays is correct across DST fall-back boundary", () => {
347
- // 2026-11-01 is fall-back day in America/New_York (clocks jump 2:00→1:00 AM).
348
- // Use a timestamp at local 00:30 on Sunday Nov 1 (04:30 UTC Nov 1).
349
- const preFallback = Date.UTC(2026, 10, 1, 4, 30, 0); // local: Sun Nov 1 00:30 EDT
350
- const result = buildTemporalContext({
351
- nowMs: preFallback,
352
- timeZone: "America/New_York",
353
- horizonDays: 3,
354
- });
355
- // Today should be Sunday Nov 1
356
- expect(result).toContain("Today: 2026-11-01 (Sunday)");
357
- // Horizon should have 3 consecutive days
358
- expect(result).toContain("2026-11-02 Monday");
359
- expect(result).toContain("2026-11-03 Tuesday");
360
- expect(result).toContain("2026-11-04 Wednesday");
361
- });
362
-
363
- test("dates are correct in far-east UTC+13 timezone (Pacific/Auckland NZDT)", () => {
364
- // Feb 18 12:00 UTC = Feb 19 01:00 NZDT (UTC+13 during daylight saving)
365
- const result = buildTemporalContext({
366
- nowMs: WED_FEB_18,
367
- timeZone: "Pacific/Auckland",
368
- horizonDays: 3,
369
- });
370
- // In Auckland, Feb 18 12:00 UTC is already Feb 19 (Thursday)
371
- expect(result).toContain("Today: 2026-02-19 (Thursday)");
372
- // Horizon should show consecutive days without +1 shift
373
- expect(result).toContain("2026-02-20 Friday");
374
- expect(result).toContain("2026-02-21 Saturday");
375
- expect(result).toContain("2026-02-22 Sunday");
376
- });
377
-
378
215
  test("local offset tracks daylight saving changes", () => {
379
216
  // Jul 1 12:00 UTC = Jul 1 08:00 EDT
380
217
  const summer = Date.UTC(2026, 6, 1, 12, 0, 0);
@@ -386,160 +223,6 @@ describe("DST-safe timezone behavior", () => {
386
223
  });
387
224
  });
388
225
 
389
- // ---------------------------------------------------------------------------
390
- // Trip-planning regression: "next weekend" resolution
391
- // ---------------------------------------------------------------------------
392
-
393
- describe("trip-planning: next weekend resolution", () => {
394
- test('Wednesday → "next weekend" anchors resolve to upcoming Sat-Sun', () => {
395
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
396
- // A user asking "plan a trip for next weekend" on Wednesday Feb 18
397
- // expects Sat Feb 21 – Sun Feb 22.
398
- expect(result).toContain("Next weekend: 2026-02-21 – 2026-02-22");
399
- // Both dates must appear in the horizon so the model can reference them.
400
- expect(result).toContain("2026-02-21 Saturday");
401
- expect(result).toContain("2026-02-22 Sunday");
402
- });
403
-
404
- test('Saturday → "next weekend" skips current weekend', () => {
405
- const result = buildTemporalContext({ nowMs: SAT_FEB_21, timeZone: "UTC" });
406
- // Already on Saturday → "next weekend" means the *following* weekend.
407
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
408
- });
409
-
410
- test('Sunday → "next weekend" skips current weekend', () => {
411
- const result = buildTemporalContext({ nowMs: SUN_FEB_22, timeZone: "UTC" });
412
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
413
- });
414
-
415
- test('Friday → "next weekend" is tomorrow', () => {
416
- const result = buildTemporalContext({ nowMs: FRI_FEB_27, timeZone: "UTC" });
417
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
418
- });
419
- });
420
-
421
- // ---------------------------------------------------------------------------
422
- // Trip-planning regression: "next work week" resolution
423
- // ---------------------------------------------------------------------------
424
-
425
- describe("trip-planning: next work week resolution", () => {
426
- test('Wednesday → "next work week" skips remainder of current week', () => {
427
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
428
- expect(result).toContain("Next work week: 2026-02-23 – 2026-02-27");
429
- });
430
-
431
- test('Monday → "next work week" is the following Monday-Friday', () => {
432
- /** Monday 2026-02-23 12:00 UTC */
433
- const MON_FEB_23 = Date.UTC(2026, 1, 23, 12, 0, 0);
434
- const result = buildTemporalContext({ nowMs: MON_FEB_23, timeZone: "UTC" });
435
- expect(result).toContain("Next work week: 2026-03-02 – 2026-03-06");
436
- });
437
-
438
- test('Saturday → "next work week" is the upcoming Monday-Friday', () => {
439
- const result = buildTemporalContext({ nowMs: SAT_FEB_21, timeZone: "UTC" });
440
- expect(result).toContain("Next work week: 2026-02-23 – 2026-02-27");
441
- });
442
- });
443
-
444
- // ---------------------------------------------------------------------------
445
- // Trip-planning regression: month-without-year disambiguation
446
- // ---------------------------------------------------------------------------
447
-
448
- describe("trip-planning: month-without-year disambiguation via temporal anchors", () => {
449
- test("Today line includes full YYYY-MM-DD format with year for month disambiguation", () => {
450
- const result = buildTemporalContext({ nowMs: WED_FEB_18, timeZone: "UTC" });
451
- // The Today line must include the full year so the model can resolve bare
452
- // month names (e.g. "May" → May 2026 because today is Feb 2026).
453
- // Regex ensures YYYY-MM-DD format is present (regression if year is dropped).
454
- expect(result).toMatch(/Today: \d{4}-\d{2}-\d{2} \(\w+\)/);
455
- expect(result).toContain("2026-02-18");
456
- });
457
-
458
- test("future-month anchors: horizon dates are all in the future relative to today", () => {
459
- const result = buildTemporalContext({
460
- nowMs: WED_FEB_18,
461
- timeZone: "UTC",
462
- horizonDays: 14,
463
- });
464
- // Extract all horizon dates (indented YYYY-MM-DD lines)
465
- const horizonDates = result.match(/^\s+(\d{4}-\d{2}-\d{2}) \w+$/gm);
466
- expect(horizonDates).not.toBeNull();
467
- // All horizon dates must be after today (2026-02-18)
468
- for (const line of horizonDates!) {
469
- const dateStr = line.trim().split(" ")[0];
470
- expect(dateStr > "2026-02-18").toBe(true);
471
- }
472
- });
473
-
474
- test("year-end context: horizon spans into next year for Dec disambiguation", () => {
475
- const result = buildTemporalContext({
476
- nowMs: TUE_DEC_29,
477
- timeZone: "UTC",
478
- horizonDays: 14,
479
- });
480
- // Today is Dec 29 2026 — horizon must include 2027 dates so the model can
481
- // distinguish "January" (Jan 2027) from past January (Jan 2026).
482
- expect(result).toContain("Today: 2026-12-29");
483
- expect(result).toMatch(/2027-01-\d{2} \w+/); // At least one January 2027 date
484
- });
485
-
486
- test("timezone is always present for correct local-month resolution", () => {
487
- const result = buildTemporalContext({
488
- nowMs: WED_FEB_18,
489
- timeZone: "America/New_York",
490
- });
491
- // Timezone must be present so the model resolves months in the user's
492
- // local calendar, not UTC.
493
- expect(result).toMatch(/Timezone: .+/);
494
- expect(result).toContain("America/New_York");
495
- });
496
- });
497
-
498
- // ---------------------------------------------------------------------------
499
- // Trip-planning regression: cross-month weekend resolution
500
- // ---------------------------------------------------------------------------
501
-
502
- describe("trip-planning: cross-month weekend resolution", () => {
503
- test("weekend that spans a month boundary (Feb → Mar)", () => {
504
- const result = buildTemporalContext({ nowMs: FRI_FEB_27, timeZone: "UTC" });
505
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
506
- });
507
-
508
- test("year-boundary weekend (Dec 2026 → Jan 2027)", () => {
509
- const result = buildTemporalContext({ nowMs: TUE_DEC_29, timeZone: "UTC" });
510
- expect(result).toContain("Next weekend: 2027-01-02 – 2027-01-03");
511
- });
512
- });
513
-
514
- // ---------------------------------------------------------------------------
515
- // Trip-planning regression: timezone-shifted weekend anchors
516
- // ---------------------------------------------------------------------------
517
-
518
- describe("trip-planning: timezone-shifted weekend anchors", () => {
519
- test("late Friday UTC is already Saturday in Auckland → skips to next weekend", () => {
520
- // Friday Feb 27 23:00 UTC = Saturday Feb 28 12:00 NZDT
521
- const lateFriUTC = Date.UTC(2026, 1, 27, 23, 0, 0);
522
- const result = buildTemporalContext({
523
- nowMs: lateFriUTC,
524
- timeZone: "Pacific/Auckland",
525
- });
526
- expect(result).toContain("Today: 2026-02-28 (Saturday)");
527
- // "Next weekend" skips current weekend → Mar 7-8.
528
- expect(result).toContain("Next weekend: 2026-03-07 – 2026-03-08");
529
- });
530
-
531
- test("early Saturday UTC is still Friday in US Pacific → next weekend is tomorrow", () => {
532
- // Saturday Feb 28 02:00 UTC = Friday Feb 27 18:00 PST
533
- const earlySatUTC = Date.UTC(2026, 1, 28, 2, 0, 0);
534
- const result = buildTemporalContext({
535
- nowMs: earlySatUTC,
536
- timeZone: "America/Los_Angeles",
537
- });
538
- expect(result).toContain("Today: 2026-02-27 (Friday)");
539
- expect(result).toContain("Next weekend: 2026-02-28 – 2026-03-01");
540
- });
541
- });
542
-
543
226
  // ---------------------------------------------------------------------------
544
227
  // extractUserTimeZoneFromRecall
545
228
  // ---------------------------------------------------------------------------
@@ -551,7 +234,7 @@ describe("extractUserTimeZoneFromRecall", () => {
551
234
  });
552
235
 
553
236
  test("extracts IANA timezone from user_identity section", () => {
554
- const text = `<memory_context>
237
+ const text = `<memory_context __injected>
555
238
 
556
239
  <user_identity>
557
240
  User's timezone is America/New_York
@@ -563,7 +246,7 @@ User works as a software engineer
563
246
  });
564
247
 
565
248
  test("extracts timezone from 'timezone: ...' line in identity", () => {
566
- const text = `<memory_context>
249
+ const text = `<memory_context __injected>
567
250
 
568
251
  <user_identity>
569
252
  - name: Alice
@@ -576,7 +259,7 @@ User works as a software engineer
576
259
  });
577
260
 
578
261
  test("extracts UTC offset timezone", () => {
579
- const text = `<memory_context>
262
+ const text = `<memory_context __injected>
580
263
 
581
264
  <user_identity>
582
265
  User's time zone is UTC+5:30
@@ -585,12 +268,11 @@ User's time zone is UTC+5:30
585
268
  </memory_context>`;
586
269
  const result = extractUserTimeZoneFromRecall(text);
587
270
  expect(result).not.toBeNull();
588
- // UTC+5:30 should canonicalize to +05:30
589
271
  expect(result).toBe("+05:30");
590
272
  });
591
273
 
592
274
  test("falls back to scanning full text when no identity section", () => {
593
- const text = `<memory_context>
275
+ const text = `<memory_context __injected>
594
276
 
595
277
  <relevant_context>
596
278
  <episode source="Mar 5">
@@ -603,7 +285,7 @@ User mentioned their timezone is Asia/Tokyo
603
285
  });
604
286
 
605
287
  test("returns null when no timezone info present", () => {
606
- const text = `<memory_context>
288
+ const text = `<memory_context __injected>
607
289
 
608
290
  <user_identity>
609
291
  User's name is Bob
@@ -615,7 +297,7 @@ User works at Acme Corp
615
297
  });
616
298
 
617
299
  test("prefers identity section over other sections", () => {
618
- const text = `<memory_context>
300
+ const text = `<memory_context __injected>
619
301
 
620
302
  <user_identity>
621
303
  User's timezone is America/Chicago