@vellumai/assistant 0.7.3 → 0.8.1
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.
- package/AGENTS.md +11 -0
- package/ARCHITECTURE.md +29 -28
- package/Dockerfile +6 -4
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +3 -1
- package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
- package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
- package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4126 -959
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-source.test.ts +3 -26
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +3 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +22 -7
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +25 -22
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/injector-chain.test.ts +24 -16
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -1888
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +164 -2
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
- package/src/__tests__/secret-response-routing.test.ts +7 -5
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/server-history-render.test.ts +82 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +42 -16
- package/src/__tests__/skills.test.ts +39 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +3 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/loop.ts +11 -0
- package/src/approvals/guardian-decision-primitive.ts +0 -13
- package/src/approvals/guardian-request-resolvers.ts +19 -102
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/relay-server.ts +42 -1
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +24 -5
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +163 -517
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +182 -345
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +148 -33
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +33 -2
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
- package/src/daemon/conversation-agent-loop.ts +140 -107
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +68 -13
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +92 -26
- package/src/daemon/conversation-tool-setup.ts +33 -19
- package/src/daemon/conversation.ts +49 -10
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +26 -0
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +97 -36
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/host-transfer-proxy.ts +2 -2
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +128 -114
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +62 -14
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +28 -2
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +35 -1
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +42 -56
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +149 -128
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +148 -42
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/ipc/skill-server.ts +99 -42
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +40 -31
- package/src/memory/context-search/sources/memory.ts +9 -2
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +108 -14
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/graph-search.test.ts +6 -5
- package/src/memory/graph/graph-search.ts +3 -4
- package/src/memory/graph/retriever.test.ts +12 -7
- package/src/memory/graph/retriever.ts +4 -5
- package/src/memory/graph/tool-handlers.ts +20 -11
- package/src/memory/graph/tools.ts +48 -9
- package/src/memory/indexer.ts +18 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
- package/src/memory/jobs/embed-concept-page.ts +261 -89
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +60 -7
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -5
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/qdrant-client.ts +3 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +5 -9
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +46 -9
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +768 -33
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +163 -8
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +8 -35
- package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +92 -86
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -115
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +42 -0
- package/src/memory/v2/prompts/consolidation.ts +14 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +307 -133
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +88 -34
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +20 -17
- package/src/memory/v2/sweep-job.ts +127 -102
- package/src/memory/v2/types.ts +16 -5
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +61 -12
- package/src/notifications/decision-engine.ts +46 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/gateway-threshold-reader.ts +116 -8
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +20 -5
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +63 -8
- package/src/proactive-artifact/job.ts +20 -2
- package/src/proactive-artifact/message-copy.ts +18 -1
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/templates/SOUL.md +13 -28
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +304 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/channel-approvals.ts +3 -2
- package/src/runtime/guardian-reply-router.ts +0 -10
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pending-interactions.ts +19 -15
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +7 -21
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/consolidation-routes.ts +8 -9
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +373 -82
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-bash-routes.ts +2 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/filing-routes.ts +2 -3
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-item-routes.test.ts +3 -9
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +105 -404
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/skills/include-graph.ts +35 -13
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/memory/register.test.ts +10 -8
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +28 -5
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +19 -1
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
- package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +28 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -492
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -477
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -3,10 +3,12 @@ import { describe, expect, test } from "bun:test";
|
|
|
3
3
|
import type { ContextWindowConfig } from "../config/types.js";
|
|
4
4
|
import { estimateTextTokens } from "../context/token-estimator.js";
|
|
5
5
|
import {
|
|
6
|
+
appendTailAnchorToSummary,
|
|
6
7
|
clampSummaryAtSectionBoundary,
|
|
7
8
|
CONTEXT_SUMMARY_MARKER,
|
|
8
9
|
ContextWindowManager,
|
|
9
10
|
createContextSummaryMessage,
|
|
11
|
+
extractTailAssistantText,
|
|
10
12
|
getSummaryFromContextMessage,
|
|
11
13
|
stripCompactionOnlyInjections,
|
|
12
14
|
} from "../context/window-manager.js";
|
|
@@ -72,7 +74,7 @@ describe("ContextWindowManager", () => {
|
|
|
72
74
|
expect(result.reason).toBe("below compaction threshold");
|
|
73
75
|
});
|
|
74
76
|
|
|
75
|
-
test("explains forced compaction skip when
|
|
77
|
+
test("explains forced compaction skip when only one user turn exists", async () => {
|
|
76
78
|
const provider = createProvider(() => {
|
|
77
79
|
throw new Error("summarizer should not be called");
|
|
78
80
|
});
|
|
@@ -84,6 +86,10 @@ describe("ContextWindowManager", () => {
|
|
|
84
86
|
targetBudgetRatio: 0.5,
|
|
85
87
|
}),
|
|
86
88
|
});
|
|
89
|
+
// Only one user turn — there is nothing earlier to summarize, so
|
|
90
|
+
// forced compaction must still skip but report a clear reason
|
|
91
|
+
// instead of "conversation already fits within the compaction
|
|
92
|
+
// target". `force=true` is honored everywhere else.
|
|
87
93
|
const history = [message("user", "hello"), message("assistant", "hi")];
|
|
88
94
|
|
|
89
95
|
const result = await manager.maybeCompact(history, undefined, {
|
|
@@ -93,8 +99,151 @@ describe("ContextWindowManager", () => {
|
|
|
93
99
|
expect(result.compacted).toBe(false);
|
|
94
100
|
expect(result.messages).toEqual(history);
|
|
95
101
|
expect(result.reason).toBe(
|
|
102
|
+
"only one user turn — nothing earlier to compact",
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("forced compaction summarizes when adjustForToolPairs would walk boundary to summary", async () => {
|
|
107
|
+
let summaryCalls = 0;
|
|
108
|
+
const provider = createProvider(() => {
|
|
109
|
+
summaryCalls += 1;
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: "## Summary\n- rescue path ran" }],
|
|
112
|
+
model: "mock-model",
|
|
113
|
+
usage: { inputTokens: 100, outputTokens: 25 },
|
|
114
|
+
stopReason: "end_turn",
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
const manager = new ContextWindowManager({
|
|
118
|
+
provider,
|
|
119
|
+
systemPrompt: "system prompt",
|
|
120
|
+
config: makeConfig({
|
|
121
|
+
maxInputTokens: 10_000,
|
|
122
|
+
targetBudgetRatio: 0.5,
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
// Conversation starts with consecutive `assistant(tool_use)` →
|
|
126
|
+
// `user(tool_result + text)` pairs. `collectUserTurnStartIndexes`
|
|
127
|
+
// includes the mixed user messages (not tool_result-only), so the
|
|
128
|
+
// earliest `userTurnStarts` entry is the message containing
|
|
129
|
+
// `tool_result(tool-1)`. Once the projection-optimism clamp
|
|
130
|
+
// decrements the keep boundary to that user turn,
|
|
131
|
+
// `adjustForToolPairs` walks the boundary back through the
|
|
132
|
+
// tool_use/tool_result chain to index 0 — under the old code that
|
|
133
|
+
// routed `/compact` through the "already fits" skip path. With the
|
|
134
|
+
// rescue, summarization runs and orphan `tool_result` blocks are
|
|
135
|
+
// stripped from the kept region.
|
|
136
|
+
const history: Message[] = [
|
|
137
|
+
{
|
|
138
|
+
role: "assistant",
|
|
139
|
+
content: [{ type: "tool_use", id: "tool-1", name: "x", input: {} }],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
role: "user",
|
|
143
|
+
content: [
|
|
144
|
+
{ type: "tool_result", tool_use_id: "tool-1", content: "result1" },
|
|
145
|
+
{ type: "text", text: "u1" },
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
role: "assistant",
|
|
150
|
+
content: [{ type: "tool_use", id: "tool-2", name: "x", input: {} }],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
role: "user",
|
|
154
|
+
content: [
|
|
155
|
+
{ type: "tool_result", tool_use_id: "tool-2", content: "result2" },
|
|
156
|
+
{ type: "text", text: "u2" },
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
message("assistant", "a3"),
|
|
160
|
+
message("user", "u3"),
|
|
161
|
+
message("assistant", "a4"),
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const result = await manager.maybeCompact(history, undefined, {
|
|
165
|
+
force: true,
|
|
166
|
+
precomputedEstimate: 50_000,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(result.compacted).toBe(true);
|
|
170
|
+
expect(summaryCalls).toBe(1);
|
|
171
|
+
expect(result.reason).not.toBe(
|
|
96
172
|
"conversation already fits within the compaction target",
|
|
97
173
|
);
|
|
174
|
+
expect(result.reason).not.toBe(
|
|
175
|
+
"truncated tool results without summarization",
|
|
176
|
+
);
|
|
177
|
+
expect(result.compactedMessages).toBeGreaterThan(0);
|
|
178
|
+
|
|
179
|
+
// The kept region must not contain orphan tool_result blocks whose
|
|
180
|
+
// tool_use lives in the compacted region — the LLM API would reject
|
|
181
|
+
// such messages on the next agent turn.
|
|
182
|
+
const keptToolUseIds = new Set<string>();
|
|
183
|
+
for (const msg of result.messages) {
|
|
184
|
+
if (msg.role !== "assistant") continue;
|
|
185
|
+
for (const block of msg.content) {
|
|
186
|
+
if (
|
|
187
|
+
(block.type === "tool_use" || block.type === "server_tool_use") &&
|
|
188
|
+
"id" in block
|
|
189
|
+
) {
|
|
190
|
+
keptToolUseIds.add((block as { id: string }).id);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
for (const msg of result.messages) {
|
|
195
|
+
if (msg.role !== "user") continue;
|
|
196
|
+
for (const block of msg.content) {
|
|
197
|
+
if (
|
|
198
|
+
(block.type === "tool_result" ||
|
|
199
|
+
block.type === "web_search_tool_result") &&
|
|
200
|
+
"tool_use_id" in block
|
|
201
|
+
) {
|
|
202
|
+
expect(keptToolUseIds.has(block.tool_use_id as string)).toBe(true);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("forced compaction summarizes when compactable count is below MIN guard", async () => {
|
|
209
|
+
let summaryCalls = 0;
|
|
210
|
+
const provider = createProvider(() => {
|
|
211
|
+
summaryCalls += 1;
|
|
212
|
+
return {
|
|
213
|
+
content: [{ type: "text", text: "## Summary\n- min-bypass ran" }],
|
|
214
|
+
model: "mock-model",
|
|
215
|
+
usage: { inputTokens: 100, outputTokens: 25 },
|
|
216
|
+
stopReason: "end_turn",
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
const manager = new ContextWindowManager({
|
|
220
|
+
provider,
|
|
221
|
+
systemPrompt: "system prompt",
|
|
222
|
+
config: makeConfig({
|
|
223
|
+
maxInputTokens: 10_000,
|
|
224
|
+
targetBudgetRatio: 0.5,
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
227
|
+
// Two user turns separated by a single assistant message — the
|
|
228
|
+
// smallest realistic conversation where a forced compaction has
|
|
229
|
+
// anything to summarize. After the projection clamp + rescue, the
|
|
230
|
+
// compactable region is at most one user turn (the first one),
|
|
231
|
+
// which can fall below `MIN_COMPACTABLE_PERSISTED_MESSAGES`. The
|
|
232
|
+
// bypass must let summarization run instead of returning
|
|
233
|
+
// "insufficient compactable persisted messages".
|
|
234
|
+
const history: Message[] = [message("user", "u1"), message("user", "u2")];
|
|
235
|
+
|
|
236
|
+
const result = await manager.maybeCompact(history, undefined, {
|
|
237
|
+
force: true,
|
|
238
|
+
precomputedEstimate: 50_000,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(result.compacted).toBe(true);
|
|
242
|
+
expect(summaryCalls).toBe(1);
|
|
243
|
+
expect(result.reason).not.toBe(
|
|
244
|
+
"insufficient compactable persisted messages",
|
|
245
|
+
);
|
|
246
|
+
expect(result.compactedMessages).toBeGreaterThan(0);
|
|
98
247
|
});
|
|
99
248
|
|
|
100
249
|
test("forced compaction summarizes when projection fits but real usage exceeds target", async () => {
|
|
@@ -2091,3 +2240,242 @@ describe("clampSummaryAtSectionBoundary", () => {
|
|
|
2091
2240
|
expect(clamped.length).toBeLessThanOrEqual(100);
|
|
2092
2241
|
});
|
|
2093
2242
|
});
|
|
2243
|
+
|
|
2244
|
+
describe("extractTailAssistantText", () => {
|
|
2245
|
+
test("returns the most recent assistant text block", () => {
|
|
2246
|
+
const messages: Message[] = [
|
|
2247
|
+
message("user", "u1"),
|
|
2248
|
+
message("assistant", "a1 first"),
|
|
2249
|
+
message("user", "u2"),
|
|
2250
|
+
message("assistant", "a2 last"),
|
|
2251
|
+
];
|
|
2252
|
+
expect(extractTailAssistantText(messages)).toBe("a2 last");
|
|
2253
|
+
});
|
|
2254
|
+
|
|
2255
|
+
test("returns null when no assistant text is present", () => {
|
|
2256
|
+
const messages: Message[] = [message("user", "u1"), message("user", "u2")];
|
|
2257
|
+
expect(extractTailAssistantText(messages)).toBeNull();
|
|
2258
|
+
});
|
|
2259
|
+
|
|
2260
|
+
test("skips assistant messages with only tool_use blocks and finds the prior text", () => {
|
|
2261
|
+
const messages: Message[] = [
|
|
2262
|
+
message("assistant", "a1 narration before tool use"),
|
|
2263
|
+
message("user", "u1"),
|
|
2264
|
+
{
|
|
2265
|
+
role: "assistant",
|
|
2266
|
+
content: [
|
|
2267
|
+
{
|
|
2268
|
+
type: "tool_use",
|
|
2269
|
+
id: "tool-1",
|
|
2270
|
+
name: "bash",
|
|
2271
|
+
input: { command: "ls" },
|
|
2272
|
+
} as ContentBlock,
|
|
2273
|
+
],
|
|
2274
|
+
},
|
|
2275
|
+
];
|
|
2276
|
+
expect(extractTailAssistantText(messages)).toBe(
|
|
2277
|
+
"a1 narration before tool use",
|
|
2278
|
+
);
|
|
2279
|
+
});
|
|
2280
|
+
|
|
2281
|
+
test("clamps long text from the start so the END is preserved", () => {
|
|
2282
|
+
const longText = "early prefix " + "x".repeat(2000) + " FINAL NEXT STEP";
|
|
2283
|
+
const messages: Message[] = [message("assistant", longText)];
|
|
2284
|
+
const result = extractTailAssistantText(messages, 200);
|
|
2285
|
+
expect(result).not.toBeNull();
|
|
2286
|
+
expect(result!.startsWith("[...truncated]")).toBe(true);
|
|
2287
|
+
expect(result!.endsWith("FINAL NEXT STEP")).toBe(true);
|
|
2288
|
+
// Stripped block size ≈ maxChars; "[...truncated] " adds a fixed prefix.
|
|
2289
|
+
expect(result!.length).toBeLessThanOrEqual(200 + "[...truncated] ".length);
|
|
2290
|
+
});
|
|
2291
|
+
|
|
2292
|
+
test("ignores empty/whitespace-only assistant text", () => {
|
|
2293
|
+
const messages: Message[] = [
|
|
2294
|
+
message("assistant", "real content"),
|
|
2295
|
+
message("assistant", " \n "),
|
|
2296
|
+
];
|
|
2297
|
+
expect(extractTailAssistantText(messages)).toBe("real content");
|
|
2298
|
+
});
|
|
2299
|
+
|
|
2300
|
+
test("returns null for an empty messages array", () => {
|
|
2301
|
+
expect(extractTailAssistantText([])).toBeNull();
|
|
2302
|
+
});
|
|
2303
|
+
});
|
|
2304
|
+
|
|
2305
|
+
describe("appendTailAnchorToSummary", () => {
|
|
2306
|
+
test("appends a tag-wrapped block after the summary", () => {
|
|
2307
|
+
const out = appendTailAnchorToSummary(
|
|
2308
|
+
"## Goals\n- item",
|
|
2309
|
+
"Next step: file the SSE followup.",
|
|
2310
|
+
);
|
|
2311
|
+
expect(out).toContain("## Goals\n- item");
|
|
2312
|
+
expect(out).toContain(
|
|
2313
|
+
"<verbatim_tail>\nNext step: file the SSE followup.\n</verbatim_tail>",
|
|
2314
|
+
);
|
|
2315
|
+
expect(out.endsWith("</verbatim_tail>")).toBe(true);
|
|
2316
|
+
});
|
|
2317
|
+
|
|
2318
|
+
test("is idempotent: re-applying with new text replaces the prior tail", () => {
|
|
2319
|
+
const first = appendTailAnchorToSummary("body", "tail-1");
|
|
2320
|
+
const second = appendTailAnchorToSummary(first, "tail-2");
|
|
2321
|
+
expect(second).toContain("body");
|
|
2322
|
+
expect(second).toContain("tail-2");
|
|
2323
|
+
expect(second).not.toContain("tail-1");
|
|
2324
|
+
// Exactly one open-tag occurrence — no stacking.
|
|
2325
|
+
expect(second.match(/<verbatim_tail>/g)?.length).toBe(1);
|
|
2326
|
+
});
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
describe("compaction tail-anchor", () => {
|
|
2330
|
+
test("splices the last assistant text block verbatim into the summary message", async () => {
|
|
2331
|
+
const provider = createProvider(() => ({
|
|
2332
|
+
content: [{ type: "text", text: "## Goals\n- LLM summary" }],
|
|
2333
|
+
model: "mock-model",
|
|
2334
|
+
usage: { inputTokens: 100, outputTokens: 25 },
|
|
2335
|
+
stopReason: "end_turn",
|
|
2336
|
+
}));
|
|
2337
|
+
const manager = new ContextWindowManager({
|
|
2338
|
+
provider,
|
|
2339
|
+
systemPrompt: "system prompt",
|
|
2340
|
+
config: makeConfig({ maxInputTokens: 600 }),
|
|
2341
|
+
});
|
|
2342
|
+
const long = "x".repeat(240);
|
|
2343
|
+
const distinctiveTail =
|
|
2344
|
+
"Pushed 8fe70d63a0 — next step: file the SSE followup as promised.";
|
|
2345
|
+
// Place `distinctiveTail` as the assistant response for u1 so it lands
|
|
2346
|
+
// at the end of the compactable region. With the same 600-token budget
|
|
2347
|
+
// and 6-message shape as the existing 600-token compaction test above,
|
|
2348
|
+
// the binary search settles on keepTurns=2 (kept = [u2, a2, u3, a3];
|
|
2349
|
+
// compactable = [u1, distinctiveTail]) — exercising the real-world
|
|
2350
|
+
// drift scenario where the model's last narration in a long work span
|
|
2351
|
+
// gets summarized away.
|
|
2352
|
+
const history: Message[] = [
|
|
2353
|
+
message("user", `u1 ${long}`),
|
|
2354
|
+
message("assistant", distinctiveTail),
|
|
2355
|
+
message("user", `u2 ${long}`),
|
|
2356
|
+
message("assistant", `a2 ${long}`),
|
|
2357
|
+
message("user", `u3 ${long}`),
|
|
2358
|
+
message("assistant", `a3 ${long}`),
|
|
2359
|
+
];
|
|
2360
|
+
|
|
2361
|
+
const result = await manager.maybeCompact(history);
|
|
2362
|
+
|
|
2363
|
+
expect(result.compacted).toBe(true);
|
|
2364
|
+
const summaryInner = getSummaryFromContextMessage(result.messages[0]);
|
|
2365
|
+
expect(summaryInner).not.toBeNull();
|
|
2366
|
+
// LLM summary still present.
|
|
2367
|
+
expect(summaryInner).toContain("LLM summary");
|
|
2368
|
+
// Verbatim tail spliced in: distinctive text from the LAST assistant
|
|
2369
|
+
// message in the compactable region (here, `distinctiveTail`).
|
|
2370
|
+
expect(summaryInner).toContain("<verbatim_tail>");
|
|
2371
|
+
expect(summaryInner).toContain(distinctiveTail);
|
|
2372
|
+
expect(summaryInner).toContain("</verbatim_tail>");
|
|
2373
|
+
// summaryText reflects what's persisted in messages[0] for consistency
|
|
2374
|
+
// with downstream consumers (DB, context_compacted event).
|
|
2375
|
+
expect(result.summaryText).toContain(distinctiveTail);
|
|
2376
|
+
});
|
|
2377
|
+
|
|
2378
|
+
test("omits the tail-anchor block when no assistant text exists in compactable region", async () => {
|
|
2379
|
+
// Construct a scenario where the compactable region has assistant
|
|
2380
|
+
// messages with ONLY tool_use blocks (no text) plus user turns. The
|
|
2381
|
+
// anchor should be omitted gracefully.
|
|
2382
|
+
const provider = createProvider(() => ({
|
|
2383
|
+
content: [{ type: "text", text: "## Goals\n- summary" }],
|
|
2384
|
+
model: "mock-model",
|
|
2385
|
+
usage: { inputTokens: 100, outputTokens: 25 },
|
|
2386
|
+
stopReason: "end_turn",
|
|
2387
|
+
}));
|
|
2388
|
+
const manager = new ContextWindowManager({
|
|
2389
|
+
provider,
|
|
2390
|
+
systemPrompt: "system prompt",
|
|
2391
|
+
config: makeConfig({ maxInputTokens: 600 }),
|
|
2392
|
+
});
|
|
2393
|
+
const long = "x".repeat(240);
|
|
2394
|
+
const history: Message[] = [
|
|
2395
|
+
message("user", `u1 ${long}`),
|
|
2396
|
+
{
|
|
2397
|
+
role: "assistant",
|
|
2398
|
+
content: [
|
|
2399
|
+
{
|
|
2400
|
+
type: "tool_use",
|
|
2401
|
+
id: "tool-1",
|
|
2402
|
+
name: "bash",
|
|
2403
|
+
input: { command: "ls" },
|
|
2404
|
+
} as ContentBlock,
|
|
2405
|
+
],
|
|
2406
|
+
},
|
|
2407
|
+
{
|
|
2408
|
+
role: "user",
|
|
2409
|
+
content: [
|
|
2410
|
+
{
|
|
2411
|
+
type: "tool_result",
|
|
2412
|
+
tool_use_id: "tool-1",
|
|
2413
|
+
content: "ls output",
|
|
2414
|
+
} as ContentBlock,
|
|
2415
|
+
],
|
|
2416
|
+
},
|
|
2417
|
+
message("user", `u2 ${long}`),
|
|
2418
|
+
message("assistant", `a2 ${long}`),
|
|
2419
|
+
message("user", `u3 ${long}`),
|
|
2420
|
+
message("assistant", `a3 ${long}`),
|
|
2421
|
+
];
|
|
2422
|
+
|
|
2423
|
+
const result = await manager.maybeCompact(history);
|
|
2424
|
+
|
|
2425
|
+
expect(result.compacted).toBe(true);
|
|
2426
|
+
const summaryInner = getSummaryFromContextMessage(result.messages[0]);
|
|
2427
|
+
expect(summaryInner).not.toBeNull();
|
|
2428
|
+
// No tail anchor when the only compactable assistant message has no text.
|
|
2429
|
+
// (a2 / a3 are kept verbatim post-compaction since they're recent enough,
|
|
2430
|
+
// so the compactable-region's only assistant message is the tool_use one.)
|
|
2431
|
+
if (summaryInner!.includes("<verbatim_tail>")) {
|
|
2432
|
+
// If a2 ended up in the compactable region after binary search, the
|
|
2433
|
+
// anchor would surface a2's text — which is fine; the assertion that
|
|
2434
|
+
// matters is that the spliced content (when present) is verbatim
|
|
2435
|
+
// content from the compactable region, not noise. Validate the
|
|
2436
|
+
// ordering: anchor must follow LLM summary text.
|
|
2437
|
+
expect(summaryInner!.indexOf("summary")).toBeLessThan(
|
|
2438
|
+
summaryInner!.indexOf("<verbatim_tail>"),
|
|
2439
|
+
);
|
|
2440
|
+
}
|
|
2441
|
+
});
|
|
2442
|
+
|
|
2443
|
+
test("clamps tail-anchor when the last assistant text is longer than the cap", async () => {
|
|
2444
|
+
const provider = createProvider(() => ({
|
|
2445
|
+
content: [{ type: "text", text: "## Goals\n- summary" }],
|
|
2446
|
+
model: "mock-model",
|
|
2447
|
+
usage: { inputTokens: 100, outputTokens: 25 },
|
|
2448
|
+
stopReason: "end_turn",
|
|
2449
|
+
}));
|
|
2450
|
+
const manager = new ContextWindowManager({
|
|
2451
|
+
provider,
|
|
2452
|
+
systemPrompt: "system prompt",
|
|
2453
|
+
config: makeConfig({ maxInputTokens: 600 }),
|
|
2454
|
+
});
|
|
2455
|
+
const long = "x".repeat(240);
|
|
2456
|
+
const tailEnd = "FINAL DISTINCTIVE END MARKER";
|
|
2457
|
+
// Long enough to trip TAIL_ANCHOR_MAX_CHARS (=1500) clamping.
|
|
2458
|
+
const longTail = "early body " + "y".repeat(2000) + " " + tailEnd;
|
|
2459
|
+
const history: Message[] = [
|
|
2460
|
+
message("user", `u1 ${long}`),
|
|
2461
|
+
message("assistant", longTail),
|
|
2462
|
+
message("user", `u2 ${long}`),
|
|
2463
|
+
message("assistant", `a2 ${long}`),
|
|
2464
|
+
message("user", `u3 ${long}`),
|
|
2465
|
+
message("assistant", `a3 ${long}`),
|
|
2466
|
+
];
|
|
2467
|
+
|
|
2468
|
+
const result = await manager.maybeCompact(history);
|
|
2469
|
+
|
|
2470
|
+
expect(result.compacted).toBe(true);
|
|
2471
|
+
const summaryInner = getSummaryFromContextMessage(result.messages[0]);
|
|
2472
|
+
expect(summaryInner).not.toBeNull();
|
|
2473
|
+
if (summaryInner!.includes("<verbatim_tail>")) {
|
|
2474
|
+
// When clamped, the END is preserved (most recent narration).
|
|
2475
|
+
expect(summaryInner).toContain(tailEnd);
|
|
2476
|
+
// And the early prefix is dropped.
|
|
2477
|
+
expect(summaryInner).toContain("[...truncated]");
|
|
2478
|
+
expect(summaryInner).not.toContain("early body");
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2481
|
+
});
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import type { AgentEvent } from "../agent/loop.js";
|
|
4
|
-
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
5
4
|
import type {
|
|
6
5
|
ContentBlock,
|
|
7
6
|
Message,
|
|
8
7
|
ProviderResponse,
|
|
9
8
|
} from "../providers/types.js";
|
|
10
9
|
|
|
11
|
-
// This test exercises v1 conversation routing. The `memory-v2-enabled` flag
|
|
12
|
-
// (registry default `true`) flips memory routing to v2 — disable it here so
|
|
13
|
-
// the v1 paths under test stay active.
|
|
14
|
-
_setOverridesForTesting({ "memory-v2-enabled": false });
|
|
15
|
-
|
|
16
10
|
mock.module("../util/logger.js", () => ({
|
|
17
11
|
getLogger: () =>
|
|
18
12
|
new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
|
|
@@ -61,6 +55,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
61
55
|
pricingOverrides: [],
|
|
62
56
|
},
|
|
63
57
|
rateLimit: { maxRequestsPerMinute: 0 },
|
|
58
|
+
memory: { v2: { enabled: false } },
|
|
64
59
|
daemon: {
|
|
65
60
|
startupSocketWaitMs: 5000,
|
|
66
61
|
stopTimeoutMs: 5000,
|
|
@@ -76,6 +76,7 @@ const defaultLlmConfig: LLMConfig = {
|
|
|
76
76
|
profiles: {},
|
|
77
77
|
profileOrder: [],
|
|
78
78
|
callSites: {},
|
|
79
|
+
profileSession: { defaultTtlSeconds: 1800, maxTtlSeconds: 43200 },
|
|
79
80
|
pricingOverrides: [],
|
|
80
81
|
};
|
|
81
82
|
|
|
@@ -531,7 +532,7 @@ function makeCtx(
|
|
|
531
532
|
}),
|
|
532
533
|
|
|
533
534
|
graphMemory: {
|
|
534
|
-
onCompacted: () => {},
|
|
535
|
+
onCompacted: async () => {},
|
|
535
536
|
prepareMemory: async () => ({
|
|
536
537
|
runMessages: [],
|
|
537
538
|
injectedTokens: 0,
|
|
@@ -626,7 +626,7 @@ function makeCtx(
|
|
|
626
626
|
}),
|
|
627
627
|
|
|
628
628
|
graphMemory: {
|
|
629
|
-
onCompacted: () => {},
|
|
629
|
+
onCompacted: async () => {},
|
|
630
630
|
prepareMemory: async () => ({
|
|
631
631
|
runMessages: [],
|
|
632
632
|
injectedTokens: 0,
|
|
@@ -3652,11 +3652,11 @@ describe("session-agent-loop", () => {
|
|
|
3652
3652
|
expect(rendered).not.toContain("original root");
|
|
3653
3653
|
});
|
|
3654
3654
|
|
|
3655
|
-
test("applyCompactionResult records Slack timestamp watermark when provided", () => {
|
|
3655
|
+
test("applyCompactionResult records Slack timestamp watermark when provided", async () => {
|
|
3656
3656
|
const ctx = makeCtx();
|
|
3657
3657
|
const events: ServerMessage[] = [];
|
|
3658
3658
|
|
|
3659
|
-
applyCompactionResult(
|
|
3659
|
+
await applyCompactionResult(
|
|
3660
3660
|
ctx,
|
|
3661
3661
|
{
|
|
3662
3662
|
messages: [
|
|
@@ -280,21 +280,13 @@ function seedPendingConfirmation(
|
|
|
280
280
|
conversation: Conversation,
|
|
281
281
|
requestId: string,
|
|
282
282
|
): void {
|
|
283
|
+
// Access private ownedIds so denyAllPending/dispose can find this request.
|
|
284
|
+
// promptResolve/promptReject callbacks are stored in pendingInteractions via
|
|
285
|
+
// registerPendingInteraction, which is called separately in each test.
|
|
283
286
|
const prompter = conversation["prompter"] as unknown as {
|
|
284
|
-
|
|
285
|
-
string,
|
|
286
|
-
{
|
|
287
|
-
resolve: (...args: unknown[]) => void;
|
|
288
|
-
reject: (...args: unknown[]) => void;
|
|
289
|
-
timer: ReturnType<typeof setTimeout>;
|
|
290
|
-
}
|
|
291
|
-
>;
|
|
287
|
+
ownedIds: Set<string>;
|
|
292
288
|
};
|
|
293
|
-
prompter.
|
|
294
|
-
resolve: () => {},
|
|
295
|
-
reject: () => {},
|
|
296
|
-
timer: setTimeout(() => {}, 60_000),
|
|
297
|
-
});
|
|
289
|
+
prompter.ownedIds.add(requestId);
|
|
298
290
|
}
|
|
299
291
|
|
|
300
292
|
// ---------------------------------------------------------------------------
|
|
@@ -9,7 +9,9 @@ mock.module("../util/logger.js", () => ({
|
|
|
9
9
|
import {
|
|
10
10
|
createConversation,
|
|
11
11
|
getConversation,
|
|
12
|
+
getConversationOverrideProfileFromRow,
|
|
12
13
|
setConversationInferenceProfile,
|
|
14
|
+
setConversationInferenceProfileSession,
|
|
13
15
|
} from "../memory/conversation-crud.js";
|
|
14
16
|
import { getDb } from "../memory/db-connection.js";
|
|
15
17
|
import { initializeDb } from "../memory/db-init.js";
|
|
@@ -52,3 +54,101 @@ describe("setConversationInferenceProfile", () => {
|
|
|
52
54
|
expect(updated).toHaveProperty("inferenceProfile", "cost-optimized");
|
|
53
55
|
});
|
|
54
56
|
});
|
|
57
|
+
|
|
58
|
+
describe("getConversationOverrideProfileFromRow — lazy expiry check", () => {
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
const db = getDb();
|
|
61
|
+
db.run(`DELETE FROM messages`);
|
|
62
|
+
db.run(`DELETE FROM conversations`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("returns undefined when inferenceProfileExpiresAt is in the past", () => {
|
|
66
|
+
const conv = createConversation("inference-profile-expired");
|
|
67
|
+
// Set a session-backed profile with an already-expired timestamp.
|
|
68
|
+
setConversationInferenceProfileSession(
|
|
69
|
+
conv.id,
|
|
70
|
+
"balanced",
|
|
71
|
+
"session-uuid-1",
|
|
72
|
+
Date.now() - 1,
|
|
73
|
+
);
|
|
74
|
+
const row = getConversation(conv.id);
|
|
75
|
+
expect(row).not.toBeNull();
|
|
76
|
+
expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("returns the profile when inferenceProfileExpiresAt is in the future", () => {
|
|
80
|
+
const conv = createConversation("inference-profile-active-session");
|
|
81
|
+
setConversationInferenceProfileSession(
|
|
82
|
+
conv.id,
|
|
83
|
+
"balanced",
|
|
84
|
+
"session-uuid-2",
|
|
85
|
+
Date.now() + 60_000,
|
|
86
|
+
);
|
|
87
|
+
const row = getConversation(conv.id);
|
|
88
|
+
expect(row).not.toBeNull();
|
|
89
|
+
expect(getConversationOverrideProfileFromRow(row)).toBe("balanced");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("returns undefined at the exact-expiry boundary (expiresAt === now)", () => {
|
|
93
|
+
// Boundary consistency with the reaper SQL (`expires_at <= now`) and
|
|
94
|
+
// the active-session queries (`expiresAt > now`): the lazy check must
|
|
95
|
+
// treat `expiresAt === now` as expired, not active. Otherwise a
|
|
96
|
+
// just-expired session would be served for one extra turn while the
|
|
97
|
+
// reaper is racing to clear it.
|
|
98
|
+
const conv = createConversation("inference-profile-boundary");
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
setConversationInferenceProfileSession(
|
|
101
|
+
conv.id,
|
|
102
|
+
"balanced",
|
|
103
|
+
"session-uuid-boundary",
|
|
104
|
+
now,
|
|
105
|
+
);
|
|
106
|
+
const row = getConversation(conv.id);
|
|
107
|
+
expect(row).not.toBeNull();
|
|
108
|
+
expect(row?.inferenceProfileExpiresAt).toBe(now);
|
|
109
|
+
// Freeze Date.now to the exact stored expiry so this is deterministic.
|
|
110
|
+
const realNow = Date.now;
|
|
111
|
+
Date.now = () => now;
|
|
112
|
+
try {
|
|
113
|
+
expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
|
|
114
|
+
} finally {
|
|
115
|
+
Date.now = realNow;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("returns the profile when no expiry is set (non-session override)", () => {
|
|
120
|
+
const conv = createConversation("inference-profile-no-expiry");
|
|
121
|
+
setConversationInferenceProfileSession(
|
|
122
|
+
conv.id,
|
|
123
|
+
"quality-optimized",
|
|
124
|
+
null,
|
|
125
|
+
null,
|
|
126
|
+
);
|
|
127
|
+
const row = getConversation(conv.id);
|
|
128
|
+
expect(row).not.toBeNull();
|
|
129
|
+
expect(getConversationOverrideProfileFromRow(row)).toBe(
|
|
130
|
+
"quality-optimized",
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test.each<"background" | "scheduled">(["background", "scheduled"])(
|
|
135
|
+
"returns undefined for %s conversations even when a profile is pinned",
|
|
136
|
+
(conversationType) => {
|
|
137
|
+
const conv = createConversation({
|
|
138
|
+
title: `inference-profile-${conversationType}`,
|
|
139
|
+
conversationType,
|
|
140
|
+
});
|
|
141
|
+
setConversationInferenceProfileSession(
|
|
142
|
+
conv.id,
|
|
143
|
+
"quality-optimized",
|
|
144
|
+
null,
|
|
145
|
+
null,
|
|
146
|
+
);
|
|
147
|
+
const row = getConversation(conv.id);
|
|
148
|
+
expect(row).not.toBeNull();
|
|
149
|
+
expect(row?.conversationType).toBe(conversationType);
|
|
150
|
+
expect(row?.inferenceProfile).toBe("quality-optimized");
|
|
151
|
+
expect(getConversationOverrideProfileFromRow(row)).toBeUndefined();
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
});
|
|
@@ -305,6 +305,44 @@ describe("classifyConversationError", () => {
|
|
|
305
305
|
});
|
|
306
306
|
});
|
|
307
307
|
|
|
308
|
+
describe("image-input dimension errors via ProviderError (400)", () => {
|
|
309
|
+
it("classifies Anthropic 400 with image-dimension overflow as image_dimensions_too_large (non-retryable)", () => {
|
|
310
|
+
const err = new ProviderError(
|
|
311
|
+
'Anthropic API error (400): 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.8.content.3.image.source.base64.data: At least one of the image dimensions exceed max allowed size: 8000 pixels"},"request_id":"req_011CaoaGzPXNs2dxAWegSg9D"}',
|
|
312
|
+
"anthropic",
|
|
313
|
+
400,
|
|
314
|
+
);
|
|
315
|
+
const result = classifyConversationError(err, baseCtx);
|
|
316
|
+
expect(result.code).toBe("IMAGE_TOO_LARGE");
|
|
317
|
+
expect(result.errorCategory).toBe("image_dimensions_too_large");
|
|
318
|
+
expect(result.retryable).toBe(false);
|
|
319
|
+
expect(result.userMessage).toContain("image");
|
|
320
|
+
expect(result.userMessage).toContain("8000");
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("matches the singular 'image dimension exceeds' phrasing as well", () => {
|
|
324
|
+
const err = new ProviderError(
|
|
325
|
+
"image dimension exceeds max allowed size: 8000 pixels",
|
|
326
|
+
"anthropic",
|
|
327
|
+
400,
|
|
328
|
+
);
|
|
329
|
+
const result = classifyConversationError(err, baseCtx);
|
|
330
|
+
expect(result.errorCategory).toBe("image_dimensions_too_large");
|
|
331
|
+
expect(result.retryable).toBe(false);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("does not steal generic 400s that happen to mention 'image'", () => {
|
|
335
|
+
const err = new ProviderError(
|
|
336
|
+
"invalid request: image source is missing",
|
|
337
|
+
"anthropic",
|
|
338
|
+
400,
|
|
339
|
+
);
|
|
340
|
+
const result = classifyConversationError(err, baseCtx);
|
|
341
|
+
expect(result.errorCategory).toBe("provider_api_error");
|
|
342
|
+
expect(result.retryable).toBe(true);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
308
346
|
describe("ordering errors (tool_use/tool_result mismatches)", () => {
|
|
309
347
|
const cases = [
|
|
310
348
|
"tool_result block not immediately after tool_use block",
|