@vellumai/assistant 0.7.2 → 0.8.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.
- package/ARCHITECTURE.md +45 -29
- package/Dockerfile +1 -0
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- package/docs/architecture/memory.md +5 -2
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- 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/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +470 -25
- package/package.json +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +48 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +58 -28
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +284 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +6 -33
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +12 -7
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +457 -8
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-process-callsite.test.ts +38 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +74 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +476 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +61 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +2 -20
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -26
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +36 -16
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +154 -67
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/notification-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/oauth-cli.test.ts +121 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +60 -5
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- 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__/server-history-render.test.ts +82 -0
- package/src/__tests__/skill-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-tool.test.ts +44 -16
- package/src/__tests__/skills.test.ts +39 -0
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/voice-session-bridge.test.ts +3 -0
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +120 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +78 -0
- package/src/agent/loop.ts +11 -0
- package/src/approvals/guardian-request-resolvers.ts +3 -32
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +7 -1
- package/src/calls/voice-session-bridge.ts +1 -1
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +11 -10
- package/src/cli/commands/oauth/__tests__/connect.test.ts +401 -219
- package/src/cli/commands/oauth/connect.ts +124 -40
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +199 -27
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +76 -12
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +32 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +38 -0
- package/src/daemon/conversation-agent-loop.ts +183 -43
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +22 -10
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +211 -29
- package/src/daemon/conversation-tool-setup.ts +66 -19
- package/src/daemon/conversation.ts +18 -23
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +26 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +47 -22
- package/src/daemon/host-browser-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +50 -4
- package/src/daemon/host-file-proxy.ts +44 -8
- package/src/daemon/host-transfer-proxy.ts +97 -6
- package/src/daemon/lifecycle.ts +167 -101
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +66 -15
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +22 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +119 -0
- package/src/filing/filing-service.ts +29 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +149 -38
- package/src/ipc/gateway-client.ts +37 -3
- package/src/ipc/skill-server.ts +99 -42
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +34 -51
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +1 -16
- package/src/memory/context-search/sources/memory.ts +2 -3
- package/src/memory/context-search/sources/pkb.ts +2 -3
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +136 -82
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/conversation-graph-memory.ts +72 -61
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +11 -67
- package/src/memory/graph/graph-search.ts +4 -24
- package/src/memory/graph/retriever.test.ts +12 -1
- package/src/memory/graph/retriever.ts +10 -15
- package/src/memory/graph/tool-handlers.ts +3 -4
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/indexer.ts +53 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +116 -0
- package/src/memory/jobs/embed-concept-page.ts +223 -87
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +85 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +7 -0
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/qdrant-client.ts +3 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +10 -72
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +346 -255
- package/src/memory/v2/__tests__/consolidation-job.test.ts +61 -40
- package/src/memory/v2/__tests__/injection.test.ts +297 -190
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +326 -9
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +113 -196
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +77 -14
- package/src/memory/v2/__tests__/sweep-job.test.ts +19 -33
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +69 -20
- package/src/memory/v2/injection.ts +75 -68
- package/src/memory/v2/page-store.ts +39 -0
- package/src/memory/v2/prompts/consolidation.ts +41 -1
- package/src/memory/v2/qdrant.ts +306 -46
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +77 -110
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +26 -8
- package/src/memory/v2/sweep-job.ts +5 -6
- package/src/memory/v2/types.ts +17 -10
- package/src/notifications/copy-composer.ts +47 -0
- package/src/notifications/decision-engine.ts +46 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/permissions/gateway-threshold-reader.ts +116 -8
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- package/src/plugins/defaults/injectors.ts +36 -4
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +914 -0
- package/src/proactive-artifact/job.ts +366 -0
- package/src/proactive-artifact/message-copy.ts +58 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -28
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +15 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-approvals.ts +3 -2
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +27 -15
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
- package/src/runtime/routes/approval-routes.ts +7 -3
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/consolidation-routes.ts +8 -9
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +44 -1
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +165 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/filing-routes.ts +2 -3
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +37 -17
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +136 -17
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/include-graph.ts +35 -13
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +14 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/permission-checker.ts +15 -0
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +43 -3
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +14 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +28 -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/registry.ts +14 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
|
@@ -73,7 +73,10 @@ import type { ConversationGraphMemory } from "../memory/graph/conversation-graph
|
|
|
73
73
|
import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
|
|
74
74
|
import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
|
|
75
75
|
import type { QdrantSparseVector } from "../memory/qdrant-client.js";
|
|
76
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
readMemoryV2StaticContent,
|
|
78
|
+
shouldLoadMemoryV2Static,
|
|
79
|
+
} from "../memory/v2/static-context.js";
|
|
77
80
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
78
81
|
import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
|
|
79
82
|
import { defaultHistoryRepairTerminal } from "../plugins/defaults/history-repair.js";
|
|
@@ -106,6 +109,11 @@ import type {
|
|
|
106
109
|
TurnContext as PluginTurnContext,
|
|
107
110
|
} from "../plugins/types.js";
|
|
108
111
|
import { PluginExecutionError, PluginTimeoutError } from "../plugins/types.js";
|
|
112
|
+
import {
|
|
113
|
+
hasProactiveArtifactCompleted,
|
|
114
|
+
runProactiveArtifactJob,
|
|
115
|
+
tryClaimProactiveArtifactTrigger,
|
|
116
|
+
} from "../proactive-artifact/index.js";
|
|
109
117
|
import type {
|
|
110
118
|
ContentBlock,
|
|
111
119
|
Message,
|
|
@@ -113,6 +121,7 @@ import type {
|
|
|
113
121
|
} from "../providers/types.js";
|
|
114
122
|
import type { Provider } from "../providers/types.js";
|
|
115
123
|
import { resolveActorTrust } from "../runtime/actor-trust-resolver.js";
|
|
124
|
+
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
116
125
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
117
126
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
118
127
|
import { getSubagentManager } from "../subagent/index.js";
|
|
@@ -175,7 +184,12 @@ import type { SkillProjectionCache } from "./conversation-skill-tools.js";
|
|
|
175
184
|
import { markSurfaceCompleted } from "./conversation-surfaces.js";
|
|
176
185
|
import { resolveTrustClass } from "./conversation-tool-setup.js";
|
|
177
186
|
import { recordUsage } from "./conversation-usage.js";
|
|
178
|
-
import {
|
|
187
|
+
import {
|
|
188
|
+
formatTurnTimestamp,
|
|
189
|
+
resolveTurnTimezoneContext,
|
|
190
|
+
} from "./date-context.js";
|
|
191
|
+
import { getDiskPressureStatus } from "./disk-pressure-guard.js";
|
|
192
|
+
import { classifyDiskPressureTurnPolicy } from "./disk-pressure-policy.js";
|
|
179
193
|
import { deepRepairHistory } from "./history-repair.js";
|
|
180
194
|
import type {
|
|
181
195
|
DynamicPageSurfaceData,
|
|
@@ -192,6 +206,8 @@ import type { TrustContext } from "./trust-context.js";
|
|
|
192
206
|
import { stripHistoricalWebSearchResults } from "./web-search-history.js";
|
|
193
207
|
|
|
194
208
|
const log = getLogger("conversation-agent-loop");
|
|
209
|
+
const DISK_PRESSURE_ERROR_CODE = "DISK_SPACE_CRITICAL" as const;
|
|
210
|
+
const DISK_PRESSURE_ERROR_CATEGORY = "disk_pressure";
|
|
195
211
|
|
|
196
212
|
/** Title-cased friendly labels for tool names, used in confirmation chips. */
|
|
197
213
|
const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
@@ -211,6 +227,10 @@ type GitServiceInitializer = {
|
|
|
211
227
|
ensureInitialized(): Promise<void>;
|
|
212
228
|
};
|
|
213
229
|
|
|
230
|
+
function formatDiskPressureBlockedMessage(): string {
|
|
231
|
+
return "Storage is critically low, so background processes are paused and remote messages are ignored until the guardian frees enough space. Remote senders should try again later.";
|
|
232
|
+
}
|
|
233
|
+
|
|
214
234
|
// ── Compaction circuit-breaker pipeline helpers ─────────────────────
|
|
215
235
|
//
|
|
216
236
|
// The circuit-breaker behavior (3 consecutive summary-LLM failures trips a
|
|
@@ -438,7 +458,6 @@ export interface AgentLoopConversationContext {
|
|
|
438
458
|
/** Timestamp (ms since epoch) until which the circuit breaker is open. */
|
|
439
459
|
compactionCircuitOpenUntil: number | null;
|
|
440
460
|
|
|
441
|
-
readonly memoryPolicy: { scopeId: string; includeDefaultFallback: boolean };
|
|
442
461
|
readonly graphMemory: ConversationGraphMemory;
|
|
443
462
|
|
|
444
463
|
currentActiveSurfaceId?: string;
|
|
@@ -495,9 +514,11 @@ export interface AgentLoopConversationContext {
|
|
|
495
514
|
voiceCallControlPrompt?: string;
|
|
496
515
|
transportHints?: string[];
|
|
497
516
|
slackRuntimeContextNotice?: string;
|
|
517
|
+
clientTimezone?: string;
|
|
498
518
|
|
|
499
519
|
readonly coreToolNames: Set<string>;
|
|
500
520
|
allowedToolNames?: Set<string>;
|
|
521
|
+
diskPressureCleanupModeActive?: boolean;
|
|
501
522
|
toolsDisabledDepth: number;
|
|
502
523
|
preactivatedSkillIds?: string[];
|
|
503
524
|
readonly skillProjectionState: Map<string, string>;
|
|
@@ -707,19 +728,39 @@ export async function runAgentLoopImpl(
|
|
|
707
728
|
};
|
|
708
729
|
})();
|
|
709
730
|
|
|
731
|
+
const isInteractiveResolved =
|
|
732
|
+
options?.isInteractive ?? (!ctx.hasNoClient && !ctx.headlessLock);
|
|
733
|
+
const diskPressureDecision = classifyDiskPressureTurnPolicy(
|
|
734
|
+
getDiskPressureStatus(),
|
|
735
|
+
{
|
|
736
|
+
conversationType: turnStartConversation?.conversationType ?? null,
|
|
737
|
+
conversationSource: turnStartConversation?.source ?? null,
|
|
738
|
+
callSite: turnCallSite,
|
|
739
|
+
isInteractive: isInteractiveResolved,
|
|
740
|
+
sourceChannel:
|
|
741
|
+
ctx.trustContext?.sourceChannel ??
|
|
742
|
+
capturedTurnChannelContext.userMessageChannel,
|
|
743
|
+
sourceInterface:
|
|
744
|
+
ctx.channelCapabilities?.clientOS ??
|
|
745
|
+
capturedTurnInterfaceContext.userMessageInterface,
|
|
746
|
+
trustContext: ctx.trustContext
|
|
747
|
+
? {
|
|
748
|
+
sourceChannel: ctx.trustContext.sourceChannel,
|
|
749
|
+
trustClass: ctx.trustContext.trustClass,
|
|
750
|
+
}
|
|
751
|
+
: null,
|
|
752
|
+
},
|
|
753
|
+
);
|
|
754
|
+
const diskPressureContext =
|
|
755
|
+
diskPressureDecision.action === "allow-cleanup-mode"
|
|
756
|
+
? { cleanupModeActive: true }
|
|
757
|
+
: null;
|
|
758
|
+
ctx.diskPressureCleanupModeActive =
|
|
759
|
+
diskPressureDecision.action === "allow-cleanup-mode";
|
|
760
|
+
|
|
710
761
|
ctx.lastAssistantAttachments = [];
|
|
711
762
|
ctx.lastAttachmentWarnings = [];
|
|
712
763
|
|
|
713
|
-
// Ensure workspace git repo is initialized before any tools run.
|
|
714
|
-
try {
|
|
715
|
-
const getWorkspaceGitServiceFn =
|
|
716
|
-
ctx.getWorkspaceGitService ?? getWorkspaceGitService;
|
|
717
|
-
const gitService = getWorkspaceGitServiceFn(ctx.workingDir);
|
|
718
|
-
await gitService.ensureInitialized();
|
|
719
|
-
} catch (err) {
|
|
720
|
-
rlog.warn({ err }, "Failed to initialize workspace git repo (non-fatal)");
|
|
721
|
-
}
|
|
722
|
-
|
|
723
764
|
ctx.profiler.startRequest();
|
|
724
765
|
let turnStarted = false;
|
|
725
766
|
|
|
@@ -736,6 +777,52 @@ export async function runAgentLoopImpl(
|
|
|
736
777
|
});
|
|
737
778
|
|
|
738
779
|
try {
|
|
780
|
+
if (diskPressureDecision.action === "block") {
|
|
781
|
+
const message = formatDiskPressureBlockedMessage();
|
|
782
|
+
rlog.warn(
|
|
783
|
+
{ reason: diskPressureDecision.reason },
|
|
784
|
+
"Blocked turn during disk pressure cleanup mode",
|
|
785
|
+
);
|
|
786
|
+
ctx.emitActivityState("idle", "error_terminal", "global", reqId);
|
|
787
|
+
ctx.traceEmitter.emit("request_error", message, {
|
|
788
|
+
requestId: reqId,
|
|
789
|
+
status: "error",
|
|
790
|
+
attributes: {
|
|
791
|
+
errorCategory: DISK_PRESSURE_ERROR_CATEGORY,
|
|
792
|
+
errorCode: DISK_PRESSURE_ERROR_CODE,
|
|
793
|
+
diskPressureReason: diskPressureDecision.reason,
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
onEvent({
|
|
797
|
+
type: "error",
|
|
798
|
+
conversationId: ctx.conversationId,
|
|
799
|
+
requestId: reqId,
|
|
800
|
+
code: DISK_PRESSURE_ERROR_CODE,
|
|
801
|
+
message,
|
|
802
|
+
category: DISK_PRESSURE_ERROR_CATEGORY,
|
|
803
|
+
errorCategory: DISK_PRESSURE_ERROR_CATEGORY,
|
|
804
|
+
});
|
|
805
|
+
onEvent({
|
|
806
|
+
type: "conversation_error",
|
|
807
|
+
conversationId: ctx.conversationId,
|
|
808
|
+
code: DISK_PRESSURE_ERROR_CODE,
|
|
809
|
+
userMessage: message,
|
|
810
|
+
retryable: true,
|
|
811
|
+
errorCategory: DISK_PRESSURE_ERROR_CATEGORY,
|
|
812
|
+
});
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Ensure workspace git repo is initialized before any tools run.
|
|
817
|
+
try {
|
|
818
|
+
const getWorkspaceGitServiceFn =
|
|
819
|
+
ctx.getWorkspaceGitService ?? getWorkspaceGitService;
|
|
820
|
+
const gitService = getWorkspaceGitServiceFn(ctx.workingDir);
|
|
821
|
+
await gitService.ensureInitialized();
|
|
822
|
+
} catch (err) {
|
|
823
|
+
rlog.warn({ err }, "Failed to initialize workspace git repo (non-fatal)");
|
|
824
|
+
}
|
|
825
|
+
|
|
739
826
|
// Auto-complete stale interactive surfaces from previous turns.
|
|
740
827
|
// Only dismiss when the user sends a new message (not a surface action
|
|
741
828
|
// response), so internal turns (subagent notifications, lifecycle
|
|
@@ -899,7 +986,7 @@ export async function runAgentLoopImpl(
|
|
|
899
986
|
compactableStartIndex: 1,
|
|
900
987
|
};
|
|
901
988
|
};
|
|
902
|
-
const applySuccessfulCompaction = (
|
|
989
|
+
const applySuccessfulCompaction = async (
|
|
903
990
|
result: Awaited<ReturnType<typeof ctx.contextWindowManager.maybeCompact>>,
|
|
904
991
|
compactedBasis?: Message[],
|
|
905
992
|
) => {
|
|
@@ -913,7 +1000,7 @@ export async function runAgentLoopImpl(
|
|
|
913
1000
|
provenanceContext,
|
|
914
1001
|
result.compactedMessages,
|
|
915
1002
|
);
|
|
916
|
-
applyCompactionResult(ctx, result, onEvent, reqId, {
|
|
1003
|
+
await applyCompactionResult(ctx, result, onEvent, reqId, {
|
|
917
1004
|
slackContextCompactionWatermarkTs: slackWatermarkTs,
|
|
918
1005
|
});
|
|
919
1006
|
currentSlackContextSummary = result.summaryText;
|
|
@@ -1000,7 +1087,10 @@ export async function runAgentLoopImpl(
|
|
|
1000
1087
|
await trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent);
|
|
1001
1088
|
}
|
|
1002
1089
|
if (compacted?.compacted) {
|
|
1003
|
-
applySuccessfulCompaction(
|
|
1090
|
+
await applySuccessfulCompaction(
|
|
1091
|
+
compacted,
|
|
1092
|
+
messagesForStartOfTurnCompaction,
|
|
1093
|
+
);
|
|
1004
1094
|
shouldInjectWorkspace = true;
|
|
1005
1095
|
if (compacted.compactedPersistedMessages > 0) {
|
|
1006
1096
|
compactedThisTurn = true;
|
|
@@ -1238,14 +1328,16 @@ export async function runAgentLoopImpl(
|
|
|
1238
1328
|
|
|
1239
1329
|
// Compute fresh turn timestamp for date grounding.
|
|
1240
1330
|
// Absolute "now" is always anchored to assistant host clock, while local
|
|
1241
|
-
// date semantics prefer configured user timezone, then
|
|
1331
|
+
// date semantics prefer configured user timezone, then device timezones.
|
|
1242
1332
|
const hostTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1333
|
+
const timezoneContext = resolveTurnTimezoneContext({
|
|
1334
|
+
configuredUserTimeZone: config.ui.userTimezone ?? null,
|
|
1335
|
+
clientTimezone: ctx.clientTimezone ?? null,
|
|
1336
|
+
detectedTimezone: config.ui.detectedTimezone ?? null,
|
|
1246
1337
|
hostTimeZone,
|
|
1247
|
-
|
|
1248
|
-
|
|
1338
|
+
});
|
|
1339
|
+
const timestamp = formatTurnTimestamp({
|
|
1340
|
+
timeZone: timezoneContext.effectiveTimezone,
|
|
1249
1341
|
});
|
|
1250
1342
|
|
|
1251
1343
|
// Resolve the inbound actor context for the unified <turn_context> block.
|
|
@@ -1299,23 +1391,26 @@ export async function runAgentLoopImpl(
|
|
|
1299
1391
|
}
|
|
1300
1392
|
}
|
|
1301
1393
|
|
|
1394
|
+
const baseTurnContext = {
|
|
1395
|
+
timestamp,
|
|
1396
|
+
interfaceName,
|
|
1397
|
+
channelName,
|
|
1398
|
+
configuredUserTimezone: timezoneContext.configuredUserTimezone,
|
|
1399
|
+
clientTimezone: timezoneContext.clientTimezone,
|
|
1400
|
+
detectedTimezone: timezoneContext.detectedTimezone,
|
|
1401
|
+
timeSinceLastMessage,
|
|
1402
|
+
};
|
|
1302
1403
|
const unifiedTurnContextStr = buildUnifiedTurnContextBlock(
|
|
1303
1404
|
isGuardian
|
|
1304
|
-
?
|
|
1405
|
+
? baseTurnContext
|
|
1305
1406
|
: {
|
|
1306
|
-
|
|
1307
|
-
interfaceName,
|
|
1308
|
-
channelName,
|
|
1407
|
+
...baseTurnContext,
|
|
1309
1408
|
actorContext: resolvedInboundActorContext,
|
|
1310
|
-
timeSinceLastMessage,
|
|
1311
1409
|
},
|
|
1312
1410
|
);
|
|
1313
1411
|
|
|
1314
1412
|
// The `remember` tool handles scratchpad-style memory writes directly to the graph.
|
|
1315
1413
|
|
|
1316
|
-
const isInteractiveResolved =
|
|
1317
|
-
options?.isInteractive ?? (!ctx.hasNoClient && !ctx.headlessLock);
|
|
1318
|
-
|
|
1319
1414
|
// Inject NOW.md and PKB content only on the first turn (or after
|
|
1320
1415
|
// compaction re-strips them). Old injections persist in history and
|
|
1321
1416
|
// are never stripped on normal turns — this preserves the cached prefix.
|
|
@@ -1330,10 +1425,16 @@ export async function runAgentLoopImpl(
|
|
|
1330
1425
|
const pkbActive = currentPkbContent !== null;
|
|
1331
1426
|
|
|
1332
1427
|
// V2 static memory block (essentials/threads/recent/buffer). Same
|
|
1333
|
-
// first-turn / post-compaction cadence as PKB
|
|
1334
|
-
//
|
|
1335
|
-
//
|
|
1336
|
-
|
|
1428
|
+
// first-turn / post-compaction cadence as PKB. `shouldLoadMemoryV2Static`
|
|
1429
|
+
// also blocks remote-channel non-guardian actors from inducing the
|
|
1430
|
+
// model to recite private memory; `readMemoryV2StaticContent` self-gates
|
|
1431
|
+
// on the v2 flag + config and returns null when v2 is off, so the file
|
|
1432
|
+
// reads are skipped on non-injection turns.
|
|
1433
|
+
const currentMemoryV2Static = shouldLoadMemoryV2Static({
|
|
1434
|
+
shouldInjectNowAndPkb,
|
|
1435
|
+
sourceChannel: ctx.trustContext?.sourceChannel,
|
|
1436
|
+
isTrustedActor,
|
|
1437
|
+
})
|
|
1337
1438
|
? readMemoryV2StaticContent()
|
|
1338
1439
|
: null;
|
|
1339
1440
|
const memoryV2Static = currentMemoryV2Static;
|
|
@@ -1349,8 +1450,8 @@ export async function runAgentLoopImpl(
|
|
|
1349
1450
|
// `getInContextPkbPaths` re-reads `conversation.messages` on each call,
|
|
1350
1451
|
// so post-compaction re-injects see the updated history.
|
|
1351
1452
|
const pkbConversation = pkbActive ? ctx : undefined;
|
|
1352
|
-
// PKB points live under a single workspace sentinel scope
|
|
1353
|
-
//
|
|
1453
|
+
// PKB points live under a single workspace sentinel scope.
|
|
1454
|
+
// See `PKB_WORKSPACE_SCOPE` for why.
|
|
1354
1455
|
const pkbScopeId = pkbActive ? PKB_WORKSPACE_SCOPE : undefined;
|
|
1355
1456
|
|
|
1356
1457
|
// Subagent status injection — gives the parent LLM visibility into active/completed children.
|
|
@@ -1417,6 +1518,7 @@ export async function runAgentLoopImpl(
|
|
|
1417
1518
|
|
|
1418
1519
|
// Shared injection options — reused whenever we need to re-inject after reduction.
|
|
1419
1520
|
const injectionOpts = {
|
|
1521
|
+
diskPressureContext,
|
|
1420
1522
|
activeSurface,
|
|
1421
1523
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1422
1524
|
? ctx.workspaceTopLevelContext
|
|
@@ -1691,7 +1793,7 @@ export async function runAgentLoopImpl(
|
|
|
1691
1793
|
await trackCompactionOutcome(ctx, result.summaryFailed, onEvent);
|
|
1692
1794
|
}
|
|
1693
1795
|
if (result.compacted) {
|
|
1694
|
-
applySuccessfulCompaction(result, compactedBasis);
|
|
1796
|
+
await applySuccessfulCompaction(result, compactedBasis);
|
|
1695
1797
|
shouldInjectWorkspace = true;
|
|
1696
1798
|
}
|
|
1697
1799
|
},
|
|
@@ -2020,7 +2122,7 @@ export async function runAgentLoopImpl(
|
|
|
2020
2122
|
);
|
|
2021
2123
|
}
|
|
2022
2124
|
if (midLoopCompact.compacted) {
|
|
2023
|
-
applySuccessfulCompaction(midLoopCompact, rawHistory);
|
|
2125
|
+
await applySuccessfulCompaction(midLoopCompact, rawHistory);
|
|
2024
2126
|
reducerCompacted = true;
|
|
2025
2127
|
shouldInjectWorkspace = true;
|
|
2026
2128
|
}
|
|
@@ -2272,7 +2374,7 @@ export async function runAgentLoopImpl(
|
|
|
2272
2374
|
}
|
|
2273
2375
|
|
|
2274
2376
|
if (step.compactionResult?.compacted) {
|
|
2275
|
-
applySuccessfulCompaction(
|
|
2377
|
+
await applySuccessfulCompaction(
|
|
2276
2378
|
step.compactionResult,
|
|
2277
2379
|
convergenceCompactionBasis,
|
|
2278
2380
|
);
|
|
@@ -2438,7 +2540,7 @@ export async function runAgentLoopImpl(
|
|
|
2438
2540
|
);
|
|
2439
2541
|
}
|
|
2440
2542
|
if (emergencyCompact?.compacted) {
|
|
2441
|
-
applySuccessfulCompaction(emergencyCompact, ctx.messages);
|
|
2543
|
+
await applySuccessfulCompaction(emergencyCompact, ctx.messages);
|
|
2442
2544
|
reducerCompacted = true;
|
|
2443
2545
|
shouldInjectWorkspace = true;
|
|
2444
2546
|
}
|
|
@@ -2874,6 +2976,42 @@ export async function runAgentLoopImpl(
|
|
|
2874
2976
|
"Failed to build home-feed event for background conversation",
|
|
2875
2977
|
);
|
|
2876
2978
|
}
|
|
2979
|
+
|
|
2980
|
+
// Proactive artifact: fire once when the processed turn was the 4th user message.
|
|
2981
|
+
// Only trigger for real user-authored turns (not subagent/system messages).
|
|
2982
|
+
{
|
|
2983
|
+
const paConv = getConversation(ctx.conversationId);
|
|
2984
|
+
if (
|
|
2985
|
+
paConv &&
|
|
2986
|
+
paConv.conversationType === "standard" &&
|
|
2987
|
+
options?.isUserMessage
|
|
2988
|
+
) {
|
|
2989
|
+
void (async () => {
|
|
2990
|
+
try {
|
|
2991
|
+
if (hasProactiveArtifactCompleted()) return;
|
|
2992
|
+
const userMsg = getMessageById(
|
|
2993
|
+
userMessageId,
|
|
2994
|
+
ctx.conversationId,
|
|
2995
|
+
);
|
|
2996
|
+
if (!userMsg) return;
|
|
2997
|
+
if (!tryClaimProactiveArtifactTrigger(userMsg.createdAt))
|
|
2998
|
+
return;
|
|
2999
|
+
await runProactiveArtifactJob({
|
|
3000
|
+
conversationId: ctx.conversationId,
|
|
3001
|
+
userMessageCutoff: userMsg.createdAt,
|
|
3002
|
+
assistantMessageId: state.lastAssistantMessageId,
|
|
3003
|
+
suppressAppBuild: state.appBuildToolUsedThisRun,
|
|
3004
|
+
broadcastMessage,
|
|
3005
|
+
});
|
|
3006
|
+
} catch (err) {
|
|
3007
|
+
log.warn(
|
|
3008
|
+
{ err, conversationId: ctx.conversationId },
|
|
3009
|
+
"Proactive artifact trigger failed",
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
})();
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
2877
3015
|
}
|
|
2878
3016
|
}
|
|
2879
3017
|
|
|
@@ -2937,6 +3075,7 @@ export async function runAgentLoopImpl(
|
|
|
2937
3075
|
conversationId: ctx.conversationId,
|
|
2938
3076
|
code: classified.code,
|
|
2939
3077
|
message: classified.userMessage,
|
|
3078
|
+
errorCategory: classified.errorCategory,
|
|
2940
3079
|
});
|
|
2941
3080
|
onEvent(buildConversationErrorMessage(ctx.conversationId, classified));
|
|
2942
3081
|
}
|
|
@@ -2988,6 +3127,7 @@ export async function runAgentLoopImpl(
|
|
|
2988
3127
|
ctx.currentRequestId = undefined;
|
|
2989
3128
|
ctx.currentActiveSurfaceId = undefined;
|
|
2990
3129
|
ctx.allowedToolNames = undefined;
|
|
3130
|
+
ctx.diskPressureCleanupModeActive = false;
|
|
2991
3131
|
ctx.preactivatedSkillIds = undefined;
|
|
2992
3132
|
ctx.currentTurnOverrideProfile = undefined;
|
|
2993
3133
|
ctx.slackRuntimeContextNotice = undefined;
|
|
@@ -3086,7 +3226,7 @@ export interface CompactionApplyContext {
|
|
|
3086
3226
|
* truth for the UI indicator after compaction. Emitting both caused a
|
|
3087
3227
|
* redundant SwiftUI invalidation on every compaction.
|
|
3088
3228
|
*/
|
|
3089
|
-
export function applyCompactionResult(
|
|
3229
|
+
export async function applyCompactionResult(
|
|
3090
3230
|
ctx: CompactionApplyContext,
|
|
3091
3231
|
result: {
|
|
3092
3232
|
messages: Message[];
|
|
@@ -3112,12 +3252,12 @@ export function applyCompactionResult(
|
|
|
3112
3252
|
options: {
|
|
3113
3253
|
slackContextCompactionWatermarkTs?: string | null;
|
|
3114
3254
|
} = {},
|
|
3115
|
-
): void {
|
|
3255
|
+
): Promise<void> {
|
|
3116
3256
|
ctx.messages = result.messages;
|
|
3117
3257
|
ctx.contextCompactedMessageCount += result.compactedPersistedMessages;
|
|
3118
3258
|
const compactedAt = Date.now();
|
|
3119
3259
|
ctx.contextCompactedAt = compactedAt;
|
|
3120
|
-
ctx.graphMemory.onCompacted(result.compactedPersistedMessages);
|
|
3260
|
+
await ctx.graphMemory.onCompacted(result.compactedPersistedMessages);
|
|
3121
3261
|
updateConversationContextWindow(
|
|
3122
3262
|
ctx.conversationId,
|
|
3123
3263
|
result.summaryText,
|
|
@@ -36,6 +36,23 @@ const NETWORK_PATTERNS = [
|
|
|
36
36
|
// Rate limit patterns (HTTP 429 or explicit rate limit messages)
|
|
37
37
|
const RATE_LIMIT_PATTERNS = [/429/, /rate.?limit/i, /too many requests/i];
|
|
38
38
|
|
|
39
|
+
// Managed usage-limit responses are generated by Vellum, even though they can
|
|
40
|
+
// travel through provider SDKs and get wrapped as ProviderError.
|
|
41
|
+
const MANAGED_USAGE_LIMIT_PATTERNS = [
|
|
42
|
+
/"code"\s*:\s*"daily_quota_exceeded"/i,
|
|
43
|
+
/"code"\s*:\s*"rate_limit_exceeded"/i,
|
|
44
|
+
/system credential proxy rate limit/i,
|
|
45
|
+
/you've reached your usage limit for today/i,
|
|
46
|
+
/current plan allows/i,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const PROVIDER_BILLING_PATTERNS = [
|
|
50
|
+
/credit balance is too low/i,
|
|
51
|
+
/insufficient.*credits?/i,
|
|
52
|
+
/requires more credits/i,
|
|
53
|
+
/can only afford/i,
|
|
54
|
+
];
|
|
55
|
+
|
|
39
56
|
// Overloaded patterns — provider is capacity-constrained (distinct from rate limiting)
|
|
40
57
|
const OVERLOADED_PATTERNS = [/overloaded/i];
|
|
41
58
|
|
|
@@ -259,15 +276,21 @@ function classifyCore(
|
|
|
259
276
|
};
|
|
260
277
|
}
|
|
261
278
|
if (error.statusCode === 402) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
retryable: false,
|
|
267
|
-
errorCategory: "credits_exhausted",
|
|
268
|
-
};
|
|
279
|
+
if (isManagedBalanceError(error)) {
|
|
280
|
+
return managedBalanceClassification();
|
|
281
|
+
}
|
|
282
|
+
return providerBillingClassification();
|
|
269
283
|
}
|
|
270
284
|
if (error.statusCode === 429) {
|
|
285
|
+
if (isManagedUsageLimitError(error, message)) {
|
|
286
|
+
return {
|
|
287
|
+
code: "MANAGED_USAGE_LIMIT",
|
|
288
|
+
userMessage:
|
|
289
|
+
"Vellum managed inference is rate limited. This is a Vellum-side usage limit, not an AI provider outage.",
|
|
290
|
+
retryable: true,
|
|
291
|
+
errorCategory: "managed_usage_limit",
|
|
292
|
+
};
|
|
293
|
+
}
|
|
271
294
|
return {
|
|
272
295
|
code: "PROVIDER_RATE_LIMIT",
|
|
273
296
|
userMessage:
|
|
@@ -331,13 +354,8 @@ function classifyCore(
|
|
|
331
354
|
errorCategory: "tool_ordering",
|
|
332
355
|
};
|
|
333
356
|
}
|
|
334
|
-
if (
|
|
335
|
-
return
|
|
336
|
-
code: "PROVIDER_BILLING",
|
|
337
|
-
userMessage: "Your API key has insufficient credits.",
|
|
338
|
-
retryable: false,
|
|
339
|
-
errorCategory: "provider_billing",
|
|
340
|
-
};
|
|
357
|
+
if (isProviderBillingError(message)) {
|
|
358
|
+
return providerBillingClassification();
|
|
341
359
|
}
|
|
342
360
|
if (
|
|
343
361
|
/invalid.*api.?key|invalid.*x-api-key|authentication.?error|invalid.authentication/i.test(
|
|
@@ -362,7 +380,7 @@ function classifyCore(
|
|
|
362
380
|
}
|
|
363
381
|
|
|
364
382
|
// Regex fallback for non-ProviderError or ProviderError without statusCode
|
|
365
|
-
return classifyByMessage(message);
|
|
383
|
+
return classifyByMessage(error, message);
|
|
366
384
|
}
|
|
367
385
|
|
|
368
386
|
/** Check whether an error message indicates a context-too-large failure. */
|
|
@@ -394,7 +412,52 @@ function isStreamingError(message: string): boolean {
|
|
|
394
412
|
return STREAMING_ERROR_PATTERNS.some((p) => p.test(message));
|
|
395
413
|
}
|
|
396
414
|
|
|
415
|
+
function isManagedUsageLimitError(error: unknown, message: string): boolean {
|
|
416
|
+
if (
|
|
417
|
+
error instanceof ProviderError &&
|
|
418
|
+
getProviderRoutingSource(error.provider) === "managed-proxy"
|
|
419
|
+
) {
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
return MANAGED_USAGE_LIMIT_PATTERNS.some((p) => p.test(message));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function isManagedBalanceError(error: ProviderError): boolean {
|
|
426
|
+
return getProviderRoutingSource(error.provider) === "managed-proxy";
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function isProviderBillingError(message: string): boolean {
|
|
430
|
+
return PROVIDER_BILLING_PATTERNS.some((p) => p.test(message));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function managedBalanceClassification(): Omit<
|
|
434
|
+
ClassifiedConversationError,
|
|
435
|
+
"debugDetails"
|
|
436
|
+
> {
|
|
437
|
+
return {
|
|
438
|
+
code: "PROVIDER_BILLING",
|
|
439
|
+
userMessage:
|
|
440
|
+
"You've run out of credits. Add funds to continue using the assistant.",
|
|
441
|
+
retryable: false,
|
|
442
|
+
errorCategory: "credits_exhausted",
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function providerBillingClassification(): Omit<
|
|
447
|
+
ClassifiedConversationError,
|
|
448
|
+
"debugDetails"
|
|
449
|
+
> {
|
|
450
|
+
return {
|
|
451
|
+
code: "PROVIDER_BILLING",
|
|
452
|
+
userMessage:
|
|
453
|
+
"Your API provider account or key needs credits. Add funds with the provider or update the key in Settings.",
|
|
454
|
+
retryable: false,
|
|
455
|
+
errorCategory: "provider_billing",
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
397
459
|
function classifyByMessage(
|
|
460
|
+
error: unknown,
|
|
398
461
|
message: string,
|
|
399
462
|
): Omit<ClassifiedConversationError, "debugDetails"> {
|
|
400
463
|
// Check context-too-large before other patterns
|
|
@@ -411,6 +474,15 @@ function classifyByMessage(
|
|
|
411
474
|
// Check rate limit first (before network, since 429 could match both)
|
|
412
475
|
for (const pattern of RATE_LIMIT_PATTERNS) {
|
|
413
476
|
if (pattern.test(message)) {
|
|
477
|
+
if (isManagedUsageLimitError(error, message)) {
|
|
478
|
+
return {
|
|
479
|
+
code: "MANAGED_USAGE_LIMIT",
|
|
480
|
+
userMessage:
|
|
481
|
+
"Vellum managed inference is rate limited. This is a Vellum-side usage limit, not an AI provider outage.",
|
|
482
|
+
retryable: true,
|
|
483
|
+
errorCategory: "managed_usage_limit",
|
|
484
|
+
};
|
|
485
|
+
}
|
|
414
486
|
return {
|
|
415
487
|
code: "PROVIDER_RATE_LIMIT",
|
|
416
488
|
userMessage:
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* can delegate without exposing its full surface.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { getConfig } from "../config/loader.js";
|
|
7
8
|
import { createContextSummaryMessage } from "../context/window-manager.js";
|
|
8
9
|
import type { EventBus } from "../events/bus.js";
|
|
9
10
|
import type { AssistantDomainEvents } from "../events/domain-events.js";
|
|
@@ -153,8 +154,6 @@ export interface DisposeContext extends AbortContext {
|
|
|
153
154
|
trustContext?: { trustClass: TrustClass };
|
|
154
155
|
/** Active memory node IDs snapshotted from the conversation's InContextTracker before disposal. */
|
|
155
156
|
activeContextNodeIds?: string[];
|
|
156
|
-
/** Memory scope for extraction — defaults to "default" if omitted. */
|
|
157
|
-
memoryScopeId?: string;
|
|
158
157
|
abort(): void;
|
|
159
158
|
}
|
|
160
159
|
|
|
@@ -375,16 +374,29 @@ export function disposeConversation(ctx: DisposeContext): void {
|
|
|
375
374
|
// Best-effort — don't block conversation disposal
|
|
376
375
|
}
|
|
377
376
|
if (!isAutoAnalysis) {
|
|
377
|
+
// Suppress v1 graph extraction when memory v2 is active — v2 reads
|
|
378
|
+
// from buffer.md and concept pages, so the v1 graph would be stale
|
|
379
|
+
// data nobody consumes. Mirrors the gate applied in `indexer.ts`
|
|
380
|
+
// for the per-message indexing path. Fail open to v1 if config
|
|
381
|
+
// can't load, since the worker handler also short-circuits.
|
|
382
|
+
let v2Enabled = false;
|
|
378
383
|
try {
|
|
379
|
-
|
|
380
|
-
conversationId: ctx.conversationId,
|
|
381
|
-
scopeId: ctx.memoryScopeId ?? "default",
|
|
382
|
-
...(ctx.activeContextNodeIds?.length
|
|
383
|
-
? { activeContextNodeIds: ctx.activeContextNodeIds }
|
|
384
|
-
: {}),
|
|
385
|
-
});
|
|
384
|
+
v2Enabled = getConfig().memory.v2.enabled;
|
|
386
385
|
} catch {
|
|
387
|
-
// Best-effort —
|
|
386
|
+
// Best-effort — fall through to legacy v1 enqueue
|
|
387
|
+
}
|
|
388
|
+
if (!v2Enabled) {
|
|
389
|
+
try {
|
|
390
|
+
enqueueMemoryJob("graph_extract", {
|
|
391
|
+
conversationId: ctx.conversationId,
|
|
392
|
+
scopeId: "default",
|
|
393
|
+
...(ctx.activeContextNodeIds?.length
|
|
394
|
+
? { activeContextNodeIds: ctx.activeContextNodeIds }
|
|
395
|
+
: {}),
|
|
396
|
+
});
|
|
397
|
+
} catch {
|
|
398
|
+
// Best-effort — don't block conversation disposal
|
|
399
|
+
}
|
|
388
400
|
}
|
|
389
401
|
}
|
|
390
402
|
|
|
@@ -182,6 +182,8 @@ export interface ProcessConversationContext {
|
|
|
182
182
|
forceCompact(): Promise<ContextWindowResult>;
|
|
183
183
|
/** Set transport-derived hints for the conversation. */
|
|
184
184
|
setTransportHints(hints: string[] | undefined): void;
|
|
185
|
+
/** IANA timezone reported by the active client for the current turn. */
|
|
186
|
+
clientTimezone?: string;
|
|
185
187
|
/**
|
|
186
188
|
* Apply client-reported host env (home dir, username) from transport
|
|
187
189
|
* metadata, gating on `supportsHostProxy` so non-host-proxy interfaces
|
|
@@ -189,6 +191,10 @@ export interface ProcessConversationContext {
|
|
|
189
191
|
* `DaemonServer.applyTransportMetadata` and the queue-drain path below.
|
|
190
192
|
*/
|
|
191
193
|
applyHostEnvFromTransport(transport: ConversationTransportMetadata): void;
|
|
194
|
+
/** Apply the per-turn client timezone reported by transport metadata. */
|
|
195
|
+
applyClientTimezoneFromTransport(
|
|
196
|
+
transport: ConversationTransportMetadata,
|
|
197
|
+
): void;
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
function resolveQueuedTurnContext(
|
|
@@ -423,6 +429,7 @@ async function drainSingleMessage(
|
|
|
423
429
|
// setter used by DaemonServer.applyTransportMetadata so create/reuse
|
|
424
430
|
// and queue-drain stay in sync without duplicating the gate logic.
|
|
425
431
|
conversation.applyHostEnvFromTransport(next.transport);
|
|
432
|
+
conversation.applyClientTimezoneFromTransport(next.transport);
|
|
426
433
|
}
|
|
427
434
|
|
|
428
435
|
// Re-preactivate host-proxy skills for interactive desktop turns. The
|
|
@@ -865,6 +872,7 @@ async function drainBatch(
|
|
|
865
872
|
if (head.transport) {
|
|
866
873
|
conversation.setTransportHints(buildTransportHints(head.transport));
|
|
867
874
|
conversation.applyHostEnvFromTransport(head.transport);
|
|
875
|
+
conversation.applyClientTimezoneFromTransport(head.transport);
|
|
868
876
|
}
|
|
869
877
|
|
|
870
878
|
// Re-preactivate host-proxy skills for interactive desktop turns.
|