@vellumai/assistant 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- 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 +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- 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 +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -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__/config-loader-backfill.test.ts +379 -0
- 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 +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -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-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- 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 +3 -4
- 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 +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- 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__/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 +15 -4
- 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__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- 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-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- 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 +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- 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/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 +27 -3
- package/src/config/loader.ts +127 -8
- 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 +75 -11
- 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-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 +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- 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 +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- 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 +0 -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 +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- 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 +14 -4
- 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 +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -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 +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- 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 +52 -22
- 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 +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- 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 +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -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-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -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 +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- 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 +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -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/plugins/defaults/injectors.ts +35 -2
- 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 +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -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/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 +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- 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/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -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/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/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- 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/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/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 +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- 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 +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -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
package/ARCHITECTURE.md
CHANGED
|
@@ -21,6 +21,20 @@ This document owns assistant-runtime architecture details. The repo-level archit
|
|
|
21
21
|
- Voice calls mirror the same prompt contract: `CallController` receives guardian context on setup and refreshes it immediately after successful voice challenge verification, so the first post-verification turn is grounded as `actor_role: guardian`.
|
|
22
22
|
- Voice-specific behavior (DTMF/speech verification flow, relay state machine) remains voice-local; only actor-role resolution is shared.
|
|
23
23
|
|
|
24
|
+
### Safe Storage Limits
|
|
25
|
+
|
|
26
|
+
Safe storage limits are gated by the assistant feature flag `safe-storage-limits`, default off. When the flag is off, the disk pressure guard reports a disabled status and no runtime path blocks work, injects cleanup guidance, or changes tool access.
|
|
27
|
+
|
|
28
|
+
**Disk pressure state:** `src/daemon/disk-pressure-guard.ts` samples workspace storage usage every 60 seconds through `src/util/disk-usage.ts`. At or above the 95% critical threshold it creates an in-memory lock with `lockId`, usage snapshot, `acknowledged`, `overrideActive`, `effectivelyLocked`, and the blocked capabilities `agent-turns`, `background-work`, and `remote-ingress`. The lock clears when usage drops below the threshold or the process restarts. `acknowledgeDiskPressureLock()` only lets the guardian enter cleanup mode; `overrideDiskPressureLock()` requires the exact phrase `I understand the risks` and disables the effective lock while usage remains critical.
|
|
29
|
+
|
|
30
|
+
**Runtime API and events:** `src/runtime/routes/disk-pressure-routes.ts` exposes `GET /v1/disk-pressure/status`, `POST /v1/disk-pressure/acknowledge`, and `POST /v1/disk-pressure/override`. Route auth policies require normal runtime protection, and `disk_pressure_status_changed` events are emitted when the status changes so clients can update live.
|
|
31
|
+
|
|
32
|
+
**Turn policy:** `src/daemon/disk-pressure-policy.ts` classifies turns before the main agent loop. Local guardian/owner turns are allowed in cleanup mode; trusted contacts, non-guardian actors, unknown remote senders, background conversations, direct wakes, and non-main LLM call sites are blocked while `effectivelyLocked` is true. Blocked turns emit terminal conversation errors rather than reaching the provider.
|
|
33
|
+
|
|
34
|
+
**Background work:** Heartbeats, scheduled tasks, filing work, retry sweeps, and background tool completions call `src/daemon/disk-pressure-background-gate.ts` before starting work. While effectively locked they skip the wake or job and log throttled disk-pressure fields.
|
|
35
|
+
|
|
36
|
+
**Prompt and tools:** Cleanup-mode turns carry `diskPressureContext` through runtime assembly and receive the `<disk_pressure_warning>` injector in `src/plugins/defaults/injectors.ts`. The instruction tells the assistant to warn first, focus only on freeing storage, inspect before deleting, ask for deletion approval, and explain that background processes and trusted-contact messages are blocked. Tool setup marks the turn as cleanup mode; `src/tools/tool-approval-handler.ts` rejects non-cleanup-safe tools, and foreground shell inspection remains available while background `bash` and `host_bash` modes are rejected. When a new lock is created, active background terminal tools are cancelled with reason `disk_pressure`.
|
|
37
|
+
|
|
24
38
|
### Single-Header JWT Auth Model
|
|
25
39
|
|
|
26
40
|
All HTTP API requests use a single `Authorization: Bearer <jwt>` header for authentication. The JWT carries identity, permissions, and policy versioning in a unified token.
|
|
@@ -966,6 +980,7 @@ The daemon emits two distinct error message types via SSE:
|
|
|
966
980
|
| -------------------------------- | ----------------------------------------------------------------------- | --------- |
|
|
967
981
|
| `PROVIDER_NETWORK` | Unable to reach the LLM provider (connection refused, timeout, DNS) | Yes |
|
|
968
982
|
| `PROVIDER_RATE_LIMIT` | LLM provider rate-limited the request (HTTP 429) | Yes |
|
|
983
|
+
| `MANAGED_USAGE_LIMIT` | Vellum managed inference usage limit or quota was exceeded (HTTP 429) | Yes |
|
|
969
984
|
| `PROVIDER_API` | Provider returned a server error (5xx) or retryable 4xx | Yes |
|
|
970
985
|
| `PROVIDER_BILLING` | Invalid/expired API key or insufficient credits (HTTP 401, billing 4xx) | No |
|
|
971
986
|
| `CONTEXT_TOO_LARGE` | Request exceeds the model's context window (HTTP 413, token limit) | No |
|
|
@@ -980,7 +995,7 @@ The daemon classifies errors via `classifyConversationError()` in `conversation-
|
|
|
980
995
|
|
|
981
996
|
Classification uses a two-tier strategy:
|
|
982
997
|
|
|
983
|
-
1. **Structured provider errors**: If the error is a `ProviderError` with a `statusCode`, the status code determines the category deterministically — `413` maps to `CONTEXT_TOO_LARGE` (not retryable), `401` maps to `PROVIDER_BILLING` (not retryable, invalid/expired key), `429` maps to `PROVIDER_RATE_LIMIT` (retryable), `5xx` to `PROVIDER_API` (retryable), other `4xx` to `PROVIDER_API` (retryable) unless a message pattern matches a more specific non-retryable category (context-too-large, billing/auth).
|
|
998
|
+
1. **Structured provider errors**: If the error is a `ProviderError` with a `statusCode`, the status code determines the category deterministically — `413` maps to `CONTEXT_TOO_LARGE` (not retryable), `401` maps to `PROVIDER_BILLING` (not retryable, invalid/expired key), `429` maps to `MANAGED_USAGE_LIMIT` when the provider is routed through the managed proxy or the payload matches a Vellum managed quota/limit response, otherwise `PROVIDER_RATE_LIMIT` (retryable), `5xx` to `PROVIDER_API` (retryable), other `4xx` to `PROVIDER_API` (retryable) unless a message pattern matches a more specific non-retryable category (context-too-large, billing/auth).
|
|
984
999
|
2. **Regex fallback**: For non-provider errors or `ProviderError` without a status code, regex pattern matching against the error message detects network failures, rate limits, and API errors. Phase-specific overrides handle regeneration contexts.
|
|
985
1000
|
|
|
986
1001
|
Debug details are capped at 4,000 characters to prevent oversized payloads.
|
|
@@ -472,7 +472,7 @@ The Anthropic provider places `cache_control: { type: 'ephemeral' }` on the **la
|
|
|
472
472
|
|
|
473
473
|
The session injects a unified `<turn_context>` block into every user message, giving the model awareness of the current timestamp (with timezone), interface, channel, and actor identity. This replaces the former separate `<temporal_context>`, `<inbound_actor_context>`, and per-channel turn context blocks. The unified block persists in conversation history so the assistant retains temporal and actor grounding across turns. Legacy blocks from pre-change history are stripped for backward compatibility.
|
|
474
474
|
|
|
475
|
-
The `current_time:` field format is: `2026-04-02 (Wednesday) 14:30:00 -05:00 (America/Chicago)` — date, weekday name, local time, UTC offset, and IANA timezone name.
|
|
475
|
+
The `current_time:` field format is: `2026-04-02 (Wednesday) 14:30:00 -05:00 (America/Chicago)` — date, weekday name, local time, UTC offset, and IANA timezone name. The timestamp is grounded in the user's effective timezone, not UTC, so a message sent at 10pm local time is represented as 10pm for date/time reasoning.
|
|
476
476
|
|
|
477
477
|
### Per-turn flow
|
|
478
478
|
|
|
@@ -492,7 +492,10 @@ graph TB
|
|
|
492
492
|
|
|
493
493
|
- **Fresh each turn**: `buildUnifiedTurnContextBlock()` is called at the start of every agent loop invocation, ensuring the model always sees the current timestamp even in long-running conversations.
|
|
494
494
|
- **Clock source invariant**: Absolute time (`now`) always comes from the assistant host clock (`Date.now()`), never from channel/client clocks.
|
|
495
|
-
- **Timezone precedence**:
|
|
495
|
+
- **Timezone precedence**: Turn context resolves the effective timezone in this order: explicit runtime override for tests/legacy callers, manual `ui.userTimezone`, current turn `clientTimezone`, persisted `ui.detectedTimezone`, then assistant host timezone. The host clock still supplies the absolute instant; this cascade only selects the local timezone used to render `current_time`.
|
|
496
|
+
- **Manual override semantics**: `ui.userTimezone` is a historical config path, but it is runtime-affecting, not purely presentational. When set, it is authoritative for `current_time` across all clients until the user clears or changes it.
|
|
497
|
+
- **Device timezone semantics**: `clientTimezone` is the timezone reported with the active message for this turn. `ui.detectedTimezone` is the last device-detected timezone persisted by a client and is only used when there is no manual override and the current message does not carry a client timezone.
|
|
498
|
+
- **Timezone mismatch guidance**: When `ui.userTimezone` differs from the current device timezone (`clientTimezone`, or `ui.detectedTimezone` when no current client value exists), `<turn_context>` also includes `configured_user_timezone`, `client_device_timezone`, and `timezone_update_available`. The last line tells the assistant that, after explicit user confirmation, it can persist the device timezone with `assistant config set ui.userTimezone "<IANA zone>"`. This gives the assistant a natural-language path to fix stale manual overrides without adding a dedicated tool.
|
|
496
499
|
- **Timezone-aware**: Uses `Intl.DateTimeFormat` APIs for DST-safe date arithmetic and timezone validation/canonicalization.
|
|
497
500
|
- **Persists in history**: The `<turn_context>` block persists in conversation history. Legacy `<temporal_context>`, `<inbound_actor_context>`, and separate channel context blocks from pre-change history are stripped for backward compatibility.
|
|
498
501
|
- **Retry paths**: Turn context is included in all `applyRuntimeInjections` call sites (main path, compact retry, media-trim retry).
|
|
@@ -62,13 +62,22 @@ const CONNECT_TIMEOUT_MS = 3_000;
|
|
|
62
62
|
* Designed for CLI and daemon startup where we need a single RPC call
|
|
63
63
|
* without leaving open handles. Returns `undefined` on any failure
|
|
64
64
|
* (socket not found, timeout, parse error) so callers can fall back.
|
|
65
|
+
*
|
|
66
|
+
* @param timeoutMs - Optional override for both the connect and call
|
|
67
|
+
* timeouts. When omitted, defaults to the module constants
|
|
68
|
+
* (CONNECT_TIMEOUT_MS / DEFAULT_CALL_TIMEOUT_MS). Pass a small value
|
|
69
|
+
* (e.g. 200) for opportunistic CLI checks where a slow/absent gateway
|
|
70
|
+
* should fail fast rather than block startup.
|
|
65
71
|
*/
|
|
66
72
|
export async function ipcCall(
|
|
67
73
|
socketPath: string,
|
|
68
74
|
method: string,
|
|
69
75
|
params?: Record<string, unknown>,
|
|
70
76
|
log: Logger = noopLogger,
|
|
77
|
+
timeoutMs?: number,
|
|
71
78
|
): Promise<unknown> {
|
|
79
|
+
const connectTimeoutMs = timeoutMs ?? CONNECT_TIMEOUT_MS;
|
|
80
|
+
const callTimeoutMs = timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;
|
|
72
81
|
return new Promise<unknown>((resolve) => {
|
|
73
82
|
let settled = false;
|
|
74
83
|
let callTimer: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -84,11 +93,11 @@ export async function ipcCall(
|
|
|
84
93
|
|
|
85
94
|
const connectTimer = setTimeout(() => {
|
|
86
95
|
log.warn(
|
|
87
|
-
{ method, socketPath, timeoutMs:
|
|
96
|
+
{ method, socketPath, timeoutMs: connectTimeoutMs },
|
|
88
97
|
"IPC connect timed out",
|
|
89
98
|
);
|
|
90
99
|
finish(undefined);
|
|
91
|
-
},
|
|
100
|
+
}, connectTimeoutMs);
|
|
92
101
|
|
|
93
102
|
const socket: Socket = connect(socketPath);
|
|
94
103
|
socket.unref();
|
|
@@ -103,11 +112,11 @@ export async function ipcCall(
|
|
|
103
112
|
|
|
104
113
|
callTimer = setTimeout(() => {
|
|
105
114
|
log.warn(
|
|
106
|
-
{ method, socketPath, timeoutMs:
|
|
115
|
+
{ method, socketPath, timeoutMs: callTimeoutMs },
|
|
107
116
|
"IPC call timed out waiting for response",
|
|
108
117
|
);
|
|
109
118
|
finish(undefined);
|
|
110
|
-
},
|
|
119
|
+
}, callTimeoutMs);
|
|
111
120
|
|
|
112
121
|
socket.on("data", (chunk) => {
|
|
113
122
|
buffer += chunk.toString();
|
|
@@ -84,12 +84,3 @@ export function formatSseFrame(event: AssistantEvent): string {
|
|
|
84
84
|
export function formatSseHeartbeat(): string {
|
|
85
85
|
return ": heartbeat\n\n";
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Format a keep-alive as both an SSE comment (for proxy keepalive) and a
|
|
90
|
-
* data-bearing event (so fetch-based SSE clients that cannot observe comment
|
|
91
|
-
* lines can still detect heartbeats for disconnect watchdogs).
|
|
92
|
-
*/
|
|
93
|
-
export function formatSseHeartbeatWithData(): string {
|
|
94
|
-
return `${formatSseHeartbeat()}event: assistant_event\ndata: ${JSON.stringify({ type: "heartbeat" })}\n\n`;
|
|
95
|
-
}
|
|
@@ -4,8 +4,6 @@ import {
|
|
|
4
4
|
buildSlackUserLabelMap,
|
|
5
5
|
extractSlackUserMentionIds,
|
|
6
6
|
renderSlackTextForModel,
|
|
7
|
-
stripLeadingSlackMentionFallback,
|
|
8
|
-
stripLeadingSlackUserMention,
|
|
9
7
|
} from "./index.js";
|
|
10
8
|
|
|
11
9
|
describe("extractSlackUserMentionIds", () => {
|
|
@@ -16,34 +14,6 @@ describe("extractSlackUserMentionIds", () => {
|
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
|
|
19
|
-
describe("stripLeadingSlackUserMention", () => {
|
|
20
|
-
test("strips only leading mentions for the exact bot ID", () => {
|
|
21
|
-
expect(stripLeadingSlackUserMention("<@U111> <@U222> hi", "U111")).toBe(
|
|
22
|
-
"<@U222> hi"
|
|
23
|
-
);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("strips repeated leading mentions for the exact bot ID", () => {
|
|
27
|
-
expect(stripLeadingSlackUserMention(" <@U111> <@U111> hi", "U111")).toBe(
|
|
28
|
-
"hi"
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("preserves text when the leading mention is a different user", () => {
|
|
33
|
-
expect(stripLeadingSlackUserMention("<@U222> hi <@U111>", "U111")).toBe(
|
|
34
|
-
"<@U222> hi <@U111>"
|
|
35
|
-
);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("stripLeadingSlackMentionFallback", () => {
|
|
40
|
-
test("strips only the first leading Slack user mention", () => {
|
|
41
|
-
expect(stripLeadingSlackMentionFallback(" <@U111> <@U222> hi")).toBe(
|
|
42
|
-
"<@U222> hi"
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
17
|
describe("renderSlackTextForModel", () => {
|
|
48
18
|
test("renders resolved user mentions", () => {
|
|
49
19
|
expect(
|
|
@@ -123,19 +93,32 @@ describe("renderSlackTextForModel", () => {
|
|
|
123
93
|
});
|
|
124
94
|
|
|
125
95
|
describe("buildSlackUserLabelMap", () => {
|
|
126
|
-
test("dedupes mentioned users across text inputs and
|
|
96
|
+
test("dedupes mentioned users across text inputs and resolves them in parallel", async () => {
|
|
127
97
|
const resolved: string[] = [];
|
|
128
98
|
const labels = await buildSlackUserLabelMap(
|
|
129
99
|
["<@U123> hi <@U999>", undefined, "<@U123> and <@W456>"],
|
|
130
100
|
async (userId) => {
|
|
131
101
|
resolved.push(userId);
|
|
102
|
+
if (userId === "U999") return "Charlie";
|
|
132
103
|
return userId === "W456" ? "Bob" : "Alice";
|
|
133
|
-
}
|
|
134
|
-
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(resolved.sort()).toEqual(["U123", "U999", "W456"]);
|
|
108
|
+
expect(labels).toEqual({ U123: "Alice", U999: "Charlie", W456: "Bob" });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("resolves bot and human user mentions together", async () => {
|
|
112
|
+
const labels = await buildSlackUserLabelMap(
|
|
113
|
+
["<@UBOT> can you help <@ULEO> with the deploy?"],
|
|
114
|
+
async (userId) => {
|
|
115
|
+
if (userId === "UBOT") return "vex";
|
|
116
|
+
if (userId === "ULEO") return "leo";
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
135
119
|
);
|
|
136
120
|
|
|
137
|
-
expect(
|
|
138
|
-
expect(labels).toEqual({ U123: "Alice", W456: "Bob" });
|
|
121
|
+
expect(labels).toEqual({ UBOT: "vex", ULEO: "leo" });
|
|
139
122
|
});
|
|
140
123
|
|
|
141
124
|
test("omits unresolved labels and labels equal to the Slack user ID", async () => {
|
|
@@ -5,12 +5,7 @@ export interface RenderSlackTextOptions {
|
|
|
5
5
|
channelFallbackLabel?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export interface BuildSlackUserLabelMapOptions {
|
|
9
|
-
ignoredUserIds?: Iterable<string | undefined>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
8
|
const SLACK_USER_MENTION_RE = /<@([UW][A-Z0-9]+)>/g;
|
|
13
|
-
const LEADING_SLACK_USER_MENTION_RE = /^\s*<@[UW][A-Z0-9]+>\s*/;
|
|
14
9
|
|
|
15
10
|
export function extractSlackUserMentionIds(text: string): string[] {
|
|
16
11
|
const seen = new Set<string>();
|
|
@@ -27,30 +22,6 @@ export function extractSlackUserMentionIds(text: string): string[] {
|
|
|
27
22
|
return ids;
|
|
28
23
|
}
|
|
29
24
|
|
|
30
|
-
export function stripLeadingSlackUserMention(
|
|
31
|
-
text: string,
|
|
32
|
-
userId: string
|
|
33
|
-
): string {
|
|
34
|
-
if (!isSlackUserId(userId)) {
|
|
35
|
-
return text;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const mention = `<@${userId}>`;
|
|
39
|
-
let stripped = text;
|
|
40
|
-
|
|
41
|
-
while (true) {
|
|
42
|
-
const next = stripLeadingExactToken(stripped, mention);
|
|
43
|
-
if (next === stripped) {
|
|
44
|
-
return stripped;
|
|
45
|
-
}
|
|
46
|
-
stripped = next;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function stripLeadingSlackMentionFallback(text: string): string {
|
|
51
|
-
return text.replace(LEADING_SLACK_USER_MENTION_RE, "");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
25
|
export function renderSlackTextForModel(
|
|
55
26
|
text: string,
|
|
56
27
|
options: RenderSlackTextOptions = {}
|
|
@@ -78,21 +49,15 @@ export function renderSlackTextForModel(
|
|
|
78
49
|
|
|
79
50
|
export async function buildSlackUserLabelMap(
|
|
80
51
|
texts: Iterable<string | undefined>,
|
|
81
|
-
resolveLabel: (userId: string) => Promise<string | undefined | null
|
|
82
|
-
options: BuildSlackUserLabelMapOptions = {}
|
|
52
|
+
resolveLabel: (userId: string) => Promise<string | undefined | null>
|
|
83
53
|
): Promise<Record<string, string>> {
|
|
84
|
-
const ignored = new Set(
|
|
85
|
-
[...(options.ignoredUserIds ?? [])].filter(
|
|
86
|
-
(id): id is string => typeof id === "string" && id.length > 0
|
|
87
|
-
)
|
|
88
|
-
);
|
|
89
54
|
const ids: string[] = [];
|
|
90
55
|
const seen = new Set<string>();
|
|
91
56
|
|
|
92
57
|
for (const text of texts) {
|
|
93
58
|
if (!text) continue;
|
|
94
59
|
for (const id of extractSlackUserMentionIds(text)) {
|
|
95
|
-
if (
|
|
60
|
+
if (seen.has(id)) continue;
|
|
96
61
|
seen.add(id);
|
|
97
62
|
ids.push(id);
|
|
98
63
|
}
|
|
@@ -215,17 +180,6 @@ function sanitizeOptionalLabel(label: string | undefined): string | undefined {
|
|
|
215
180
|
.trim();
|
|
216
181
|
}
|
|
217
182
|
|
|
218
|
-
function stripLeadingExactToken(text: string, token: string): string {
|
|
219
|
-
const leadingWhitespaceLength = text.length - text.trimStart().length;
|
|
220
|
-
const afterWhitespace = text.slice(leadingWhitespaceLength);
|
|
221
|
-
|
|
222
|
-
if (!afterWhitespace.startsWith(token)) {
|
|
223
|
-
return text;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return afterWhitespace.slice(token.length).trimStart();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
183
|
function isSlackUserId(value: string): boolean {
|
|
230
184
|
return /^[UW][A-Z0-9]+$/.test(value);
|
|
231
185
|
}
|