@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
|
@@ -7,8 +7,18 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
10
|
+
import {
|
|
11
|
+
enforceSameActorOrThrow,
|
|
12
|
+
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
13
|
+
} from "../auth/same-actor.js";
|
|
14
|
+
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
10
15
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
11
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
BadRequestError,
|
|
18
|
+
ConflictError,
|
|
19
|
+
ForbiddenError,
|
|
20
|
+
NotFoundError,
|
|
21
|
+
} from "./errors.js";
|
|
12
22
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
13
23
|
|
|
14
24
|
// ---------------------------------------------------------------------------
|
|
@@ -44,16 +54,33 @@ function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
|
44
54
|
|
|
45
55
|
// Validate submitting client matches the targeted client (if any).
|
|
46
56
|
if (peeked.targetClientId != null) {
|
|
47
|
-
const
|
|
48
|
-
const submittingClientId =
|
|
57
|
+
const headerMap = (headers as Record<string, string | undefined>) ?? {};
|
|
58
|
+
const submittingClientId =
|
|
59
|
+
headerMap["x-vellum-client-id"]?.trim() || undefined;
|
|
49
60
|
if (!submittingClientId) {
|
|
50
|
-
throw new BadRequestError(
|
|
61
|
+
throw new BadRequestError(
|
|
62
|
+
"x-vellum-client-id header is missing for a targeted host file request.",
|
|
63
|
+
);
|
|
51
64
|
}
|
|
52
65
|
if (submittingClientId !== peeked.targetClientId) {
|
|
53
66
|
throw new ForbiddenError(
|
|
54
67
|
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
55
68
|
);
|
|
56
69
|
}
|
|
70
|
+
|
|
71
|
+
// Defense-in-depth: also require the submitting actor's principal id to
|
|
72
|
+
// match the actor that opened the target client's SSE stream. This blocks
|
|
73
|
+
// cross-user submissions even if a different user somehow obtains the
|
|
74
|
+
// target client id.
|
|
75
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
76
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
77
|
+
);
|
|
78
|
+
enforceSameActorOrThrow({
|
|
79
|
+
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
80
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
81
|
+
targetClientId: peeked.targetClientId,
|
|
82
|
+
op: "host_file",
|
|
83
|
+
});
|
|
57
84
|
}
|
|
58
85
|
|
|
59
86
|
HostFileProxy.instance.resolve(requestId, {
|
|
@@ -102,8 +129,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
102
129
|
"x-vellum-client-id header is missing for a targeted host file request.",
|
|
103
130
|
},
|
|
104
131
|
"403": {
|
|
105
|
-
description:
|
|
106
|
-
"Submitting client does not match the targeted client for this request.",
|
|
132
|
+
description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
107
133
|
},
|
|
108
134
|
"404": {
|
|
109
135
|
description: "No pending interaction found for the given requestId.",
|
|
@@ -8,8 +8,18 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
|
|
11
|
+
import {
|
|
12
|
+
enforceSameActorOrThrow,
|
|
13
|
+
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
14
|
+
} from "../auth/same-actor.js";
|
|
15
|
+
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
11
16
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
12
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
BadRequestError,
|
|
19
|
+
ConflictError,
|
|
20
|
+
ForbiddenError,
|
|
21
|
+
NotFoundError,
|
|
22
|
+
} from "./errors.js";
|
|
13
23
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
14
24
|
|
|
15
25
|
/**
|
|
@@ -44,9 +54,31 @@ function handleTransferContentGet({
|
|
|
44
54
|
|
|
45
55
|
const targetClientId = match.proxy.getTargetClientIdForTransfer(transferId);
|
|
46
56
|
if (targetClientId != null) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
const headerMap = headers as Record<string, string | undefined>;
|
|
58
|
+
const submittingClientId =
|
|
59
|
+
headerMap["x-vellum-client-id"]?.trim() || undefined;
|
|
60
|
+
if (!submittingClientId)
|
|
61
|
+
throw new BadRequestError(
|
|
62
|
+
"x-vellum-client-id header required for targeted transfer",
|
|
63
|
+
);
|
|
64
|
+
if (submittingClientId !== targetClientId)
|
|
65
|
+
throw new ForbiddenError(
|
|
66
|
+
`Client "${submittingClientId}" is not the owner of this transfer`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Defense-in-depth: the submitting actor's principal must match the
|
|
70
|
+
// actor that opened the target client's SSE stream. Compare against
|
|
71
|
+
// the value persisted at registration time so a brief reconnect does
|
|
72
|
+
// not 403 a legitimate fetch.
|
|
73
|
+
enforceSameActorOrThrow({
|
|
74
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
75
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
76
|
+
),
|
|
77
|
+
targetActorPrincipalId:
|
|
78
|
+
match.proxy.getTargetActorPrincipalIdForTransfer(transferId),
|
|
79
|
+
targetClientId,
|
|
80
|
+
op: "host_transfer",
|
|
81
|
+
});
|
|
50
82
|
}
|
|
51
83
|
|
|
52
84
|
const content = match.proxy.getTransferContent(transferId);
|
|
@@ -105,9 +137,27 @@ async function handleTransferContentPut({
|
|
|
105
137
|
|
|
106
138
|
const targetClientId = match.proxy.getTargetClientIdForTransfer(transferId);
|
|
107
139
|
if (targetClientId != null) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
140
|
+
const headerMap = headers as Record<string, string | undefined>;
|
|
141
|
+
const submittingClientId =
|
|
142
|
+
headerMap["x-vellum-client-id"]?.trim() || undefined;
|
|
143
|
+
if (!submittingClientId)
|
|
144
|
+
throw new BadRequestError(
|
|
145
|
+
"x-vellum-client-id header required for targeted transfer",
|
|
146
|
+
);
|
|
147
|
+
if (submittingClientId !== targetClientId)
|
|
148
|
+
throw new ForbiddenError(
|
|
149
|
+
`Client "${submittingClientId}" is not the owner of this transfer`,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
enforceSameActorOrThrow({
|
|
153
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
154
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
155
|
+
),
|
|
156
|
+
targetActorPrincipalId:
|
|
157
|
+
match.proxy.getTargetActorPrincipalIdForTransfer(transferId),
|
|
158
|
+
targetClientId,
|
|
159
|
+
op: "host_transfer",
|
|
160
|
+
});
|
|
111
161
|
}
|
|
112
162
|
|
|
113
163
|
const data = rawBody ? Buffer.from(rawBody) : Buffer.alloc(0);
|
|
@@ -158,10 +208,26 @@ function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
|
158
208
|
}
|
|
159
209
|
|
|
160
210
|
if (peeked.targetClientId != null) {
|
|
161
|
-
const
|
|
211
|
+
const headerMap = (headers as Record<string, string | undefined>) ?? {};
|
|
212
|
+
const rawClientId = headerMap["x-vellum-client-id"];
|
|
162
213
|
const submittingClientId = rawClientId?.trim() || undefined;
|
|
163
|
-
if (!submittingClientId)
|
|
164
|
-
|
|
214
|
+
if (!submittingClientId)
|
|
215
|
+
throw new BadRequestError(
|
|
216
|
+
"x-vellum-client-id header is missing for a targeted host transfer request.",
|
|
217
|
+
);
|
|
218
|
+
if (submittingClientId !== peeked.targetClientId)
|
|
219
|
+
throw new ForbiddenError(
|
|
220
|
+
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}").`,
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
enforceSameActorOrThrow({
|
|
224
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
225
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
226
|
+
),
|
|
227
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
228
|
+
targetClientId: peeked.targetClientId,
|
|
229
|
+
op: "host_transfer",
|
|
230
|
+
});
|
|
165
231
|
}
|
|
166
232
|
|
|
167
233
|
HostTransferProxy.instance.resolveTransferResult(requestId, {
|
|
@@ -195,8 +261,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
195
261
|
"x-vellum-client-id header is missing for a targeted transfer.",
|
|
196
262
|
},
|
|
197
263
|
"403": {
|
|
198
|
-
description:
|
|
199
|
-
"Submitting client does not match the targeted client for this transfer.",
|
|
264
|
+
description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
200
265
|
},
|
|
201
266
|
},
|
|
202
267
|
handler: handleTransferContentGet,
|
|
@@ -217,8 +282,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
217
282
|
"x-vellum-client-id header is missing for a targeted transfer.",
|
|
218
283
|
},
|
|
219
284
|
"403": {
|
|
220
|
-
description:
|
|
221
|
-
"Submitting client does not match the targeted client for this transfer.",
|
|
285
|
+
description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
222
286
|
},
|
|
223
287
|
},
|
|
224
288
|
handler: handleTransferContentPut,
|
|
@@ -247,8 +311,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
247
311
|
"x-vellum-client-id header is missing for a targeted host transfer request.",
|
|
248
312
|
},
|
|
249
313
|
"403": {
|
|
250
|
-
description:
|
|
251
|
-
"Submitting client does not match the targeted client for this transfer.",
|
|
314
|
+
description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
252
315
|
},
|
|
253
316
|
},
|
|
254
317
|
handler: handleTransferResult,
|
|
@@ -2,24 +2,20 @@
|
|
|
2
2
|
* Identity and health endpoint handlers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { existsSync, readFileSync, statfsSync } from "node:fs";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
6
|
import { availableParallelism, cpus, totalmem } from "node:os";
|
|
8
7
|
|
|
9
8
|
import { z } from "zod";
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
getCpuLimit,
|
|
13
|
-
getIsPlatform,
|
|
14
|
-
getMinikubeStorageSize,
|
|
15
|
-
} from "../../config/env-registry.js";
|
|
10
|
+
import { getCpuLimit, getIsPlatform } from "../../config/env-registry.js";
|
|
16
11
|
import { parseIdentityFields } from "../../daemon/handlers/identity.js";
|
|
17
12
|
import { getProfilerRuntimeStatus } from "../../daemon/profiler-run-store.js";
|
|
18
13
|
import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
|
|
19
14
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "../../util/
|
|
15
|
+
getDiskUsageInfo,
|
|
16
|
+
parseK8sMemoryBytes,
|
|
17
|
+
} from "../../util/disk-usage.js";
|
|
18
|
+
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
23
19
|
import { APP_VERSION } from "../../version.js";
|
|
24
20
|
import { resolveHatchedAtReadOnly } from "../../workspace/hatched-date.js";
|
|
25
21
|
import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
|
|
@@ -28,138 +24,11 @@ import { NotFoundError } from "./errors.js";
|
|
|
28
24
|
import { getCachedIntro } from "./identity-intro-cache.js";
|
|
29
25
|
import type { RouteDefinition } from "./types.js";
|
|
30
26
|
|
|
31
|
-
interface DiskSpaceInfo {
|
|
32
|
-
path: string;
|
|
33
|
-
totalMb: number;
|
|
34
|
-
usedMb: number;
|
|
35
|
-
freeMb: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Measure the on-disk usage of one or more directory paths using `du -sb`.
|
|
40
|
-
* Returns the sum of all paths in bytes, or null on failure.
|
|
41
|
-
*/
|
|
42
|
-
function getDirectorySizeBytes(paths: string[]): number | null {
|
|
43
|
-
try {
|
|
44
|
-
const existing = paths.filter((p) => existsSync(p));
|
|
45
|
-
if (existing.length === 0) return null;
|
|
46
|
-
const result = spawnSync("du", ["-sb", ...existing], {
|
|
47
|
-
encoding: "utf-8",
|
|
48
|
-
timeout: 30_000,
|
|
49
|
-
});
|
|
50
|
-
if (result.status !== 0) return null;
|
|
51
|
-
let total = 0;
|
|
52
|
-
for (const line of result.stdout.trim().split("\n")) {
|
|
53
|
-
const size = parseInt(line.split("\t")[0], 10);
|
|
54
|
-
if (!isNaN(size) && size > 0) total += size;
|
|
55
|
-
}
|
|
56
|
-
return total > 0 ? total : null;
|
|
57
|
-
} catch {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const DU_CACHE_TTL_MS = 60_000;
|
|
63
|
-
let duCacheValue: number | null = null;
|
|
64
|
-
let duCacheTime = 0;
|
|
65
|
-
let duCachePaths: string | null = null;
|
|
66
|
-
|
|
67
|
-
function getCachedDirectorySizeBytes(paths: string[]): number | null {
|
|
68
|
-
const key = paths.join("\0");
|
|
69
|
-
const now = Date.now();
|
|
70
|
-
if (duCachePaths === key && now - duCacheTime < DU_CACHE_TTL_MS) {
|
|
71
|
-
return duCacheValue;
|
|
72
|
-
}
|
|
73
|
-
duCacheValue = getDirectorySizeBytes(paths);
|
|
74
|
-
duCacheTime = now;
|
|
75
|
-
duCachePaths = key;
|
|
76
|
-
return duCacheValue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function getDiskSpaceInfo(): DiskSpaceInfo | null {
|
|
80
|
-
try {
|
|
81
|
-
const wsDir = getWorkspaceDir();
|
|
82
|
-
const diskPath = existsSync(wsDir) ? wsDir : "/";
|
|
83
|
-
const stats = statfsSync(diskPath);
|
|
84
|
-
const fsTotalBytes = stats.bsize * stats.blocks;
|
|
85
|
-
const fsFreeBytes = stats.bsize * stats.bavail;
|
|
86
|
-
const bytesToMb = (b: number) =>
|
|
87
|
-
Math.round((b / (1024 * 1024)) * 100) / 100;
|
|
88
|
-
|
|
89
|
-
// Minikube mode: the platform passes the PVC storage size so we can
|
|
90
|
-
// report accurate capacity. On hostPath-backed PVCs statfsSync reports
|
|
91
|
-
// the host's entire filesystem rather than the PVC. Detect this by
|
|
92
|
-
// comparing filesystem size against PVC size — if the filesystem is
|
|
93
|
-
// larger, measure actual directory usage with `du` instead.
|
|
94
|
-
const storageSizeRaw = getMinikubeStorageSize();
|
|
95
|
-
if (storageSizeRaw) {
|
|
96
|
-
const pvcTotalBytes = parseK8sMemoryBytes(storageSizeRaw);
|
|
97
|
-
if (pvcTotalBytes !== null && fsTotalBytes > pvcTotalBytes * 1.1) {
|
|
98
|
-
const volumePaths = [diskPath];
|
|
99
|
-
if (diskPath !== "/data" && existsSync("/data")) {
|
|
100
|
-
volumePaths.push("/data");
|
|
101
|
-
}
|
|
102
|
-
const usedBytes = getCachedDirectorySizeBytes(volumePaths);
|
|
103
|
-
if (usedBytes !== null) {
|
|
104
|
-
return {
|
|
105
|
-
path: diskPath,
|
|
106
|
-
totalMb: bytesToMb(pvcTotalBytes),
|
|
107
|
-
usedMb: bytesToMb(usedBytes),
|
|
108
|
-
freeMb: bytesToMb(Math.max(0, pvcTotalBytes - usedBytes)),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
path: diskPath,
|
|
116
|
-
totalMb: bytesToMb(fsTotalBytes),
|
|
117
|
-
usedMb: bytesToMb(fsTotalBytes - fsFreeBytes),
|
|
118
|
-
freeMb: bytesToMb(fsFreeBytes),
|
|
119
|
-
};
|
|
120
|
-
} catch {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
27
|
interface MemoryInfo {
|
|
126
28
|
currentMb: number;
|
|
127
29
|
maxMb: number;
|
|
128
30
|
}
|
|
129
31
|
|
|
130
|
-
/**
|
|
131
|
-
* Parse a Kubernetes-style memory string (e.g. "3Gi", "512Mi", "1G") into bytes.
|
|
132
|
-
* Returns null if the value is not a recognized format.
|
|
133
|
-
*/
|
|
134
|
-
function parseK8sMemoryBytes(value: string): number | null {
|
|
135
|
-
const match = value
|
|
136
|
-
.trim()
|
|
137
|
-
.match(/^(\d+(?:\.\d+)?)\s*(Ki|Mi|Gi|Ti|Pi|Ei|k|M|G|T|P|E|m)?$/);
|
|
138
|
-
if (!match) return null;
|
|
139
|
-
const num = parseFloat(match[1]);
|
|
140
|
-
const unit = match[2] ?? "";
|
|
141
|
-
const multipliers: Record<string, number> = {
|
|
142
|
-
"": 1,
|
|
143
|
-
m: 1e-3,
|
|
144
|
-
k: 1e3,
|
|
145
|
-
M: 1e6,
|
|
146
|
-
G: 1e9,
|
|
147
|
-
T: 1e12,
|
|
148
|
-
P: 1e15,
|
|
149
|
-
E: 1e18,
|
|
150
|
-
Ki: 1024,
|
|
151
|
-
Mi: 1024 ** 2,
|
|
152
|
-
Gi: 1024 ** 3,
|
|
153
|
-
Ti: 1024 ** 4,
|
|
154
|
-
Pi: 1024 ** 5,
|
|
155
|
-
Ei: 1024 ** 6,
|
|
156
|
-
};
|
|
157
|
-
const mult = multipliers[unit];
|
|
158
|
-
if (mult === undefined) return null;
|
|
159
|
-
const bytes = Math.round(num * mult);
|
|
160
|
-
return bytes > 0 ? bytes : null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
32
|
/**
|
|
164
33
|
* Read the memory limit from the VELLUM_MEMORY_LIMIT env var (K8s resource format),
|
|
165
34
|
* then fall back to cgroups, then to os.totalmem().
|
|
@@ -458,7 +327,7 @@ function getDetailedHealth() {
|
|
|
458
327
|
status: "healthy",
|
|
459
328
|
timestamp: new Date().toISOString(),
|
|
460
329
|
version: APP_VERSION,
|
|
461
|
-
disk:
|
|
330
|
+
disk: getDiskUsageInfo(),
|
|
462
331
|
memory: getMemoryInfo(),
|
|
463
332
|
cpu: getCpuInfo(),
|
|
464
333
|
migrations: {
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
createApprovalConversationGenerator,
|
|
16
16
|
createApprovalCopyGenerator,
|
|
17
17
|
} from "../../daemon/approval-generators.js";
|
|
18
|
+
import { getDiskPressureStatus } from "../../daemon/disk-pressure-guard.js";
|
|
19
|
+
import { classifyDiskPressureTurnPolicy } from "../../daemon/disk-pressure-policy.js";
|
|
18
20
|
import { processMessage } from "../../daemon/process-message.js";
|
|
19
21
|
import type { TrustContext } from "../../daemon/trust-context.js";
|
|
20
22
|
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
@@ -35,6 +37,7 @@ import {
|
|
|
35
37
|
getPendingVerificationReply,
|
|
36
38
|
} from "../../memory/delivery-channels.js";
|
|
37
39
|
import {
|
|
40
|
+
clearPayload,
|
|
38
41
|
findMessageBySourceId,
|
|
39
42
|
linkMessage,
|
|
40
43
|
recordInbound,
|
|
@@ -75,6 +78,8 @@ import { tryTranscribeAudioAttachments } from "./inbound-stages/transcribe-audio
|
|
|
75
78
|
import type { RouteHandlerArgs } from "./types.js";
|
|
76
79
|
|
|
77
80
|
const log = getLogger("runtime-http");
|
|
81
|
+
const DISK_PRESSURE_REMOTE_BLOCK_REPLY =
|
|
82
|
+
"Storage is critically low, so remote messages are ignored until the guardian frees enough space. Please try again later.";
|
|
78
83
|
|
|
79
84
|
// Delete-lookup retry configuration. Delete webhooks can race ahead of
|
|
80
85
|
// the inbound handler's `linkMessage` call when the original message's
|
|
@@ -524,6 +529,78 @@ export async function handleChannelInbound({
|
|
|
524
529
|
});
|
|
525
530
|
}
|
|
526
531
|
|
|
532
|
+
// ── Actor role resolution ──
|
|
533
|
+
// Uses shared channel-agnostic resolution so all ingress paths classify
|
|
534
|
+
// guardian vs non-guardian actors the same way.
|
|
535
|
+
const trustCtx: TrustContext = resolveTrustContext({
|
|
536
|
+
assistantId: canonicalAssistantId,
|
|
537
|
+
sourceChannel,
|
|
538
|
+
conversationExternalId,
|
|
539
|
+
actorExternalId: rawSenderId,
|
|
540
|
+
actorUsername: body.actorUsername,
|
|
541
|
+
actorDisplayName: body.actorDisplayName,
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const diskPressureDecision = classifyDiskPressureTurnPolicy(
|
|
545
|
+
getDiskPressureStatus(),
|
|
546
|
+
{
|
|
547
|
+
sourceChannel,
|
|
548
|
+
sourceInterface,
|
|
549
|
+
trustContext: {
|
|
550
|
+
sourceChannel: trustCtx.sourceChannel,
|
|
551
|
+
trustClass: trustCtx.trustClass,
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
);
|
|
555
|
+
if (diskPressureDecision.action === "block") {
|
|
556
|
+
if (!result.duplicate) {
|
|
557
|
+
clearPayload(result.eventId);
|
|
558
|
+
markProcessed(result.eventId);
|
|
559
|
+
}
|
|
560
|
+
log.info(
|
|
561
|
+
{
|
|
562
|
+
conversationId: result.conversationId,
|
|
563
|
+
eventId: result.eventId,
|
|
564
|
+
duplicate: result.duplicate,
|
|
565
|
+
reason: diskPressureDecision.reason,
|
|
566
|
+
trustClass: trustCtx.trustClass,
|
|
567
|
+
},
|
|
568
|
+
"Channel inbound blocked during disk pressure cleanup mode",
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
if (replyCallbackUrl && !result.duplicate) {
|
|
572
|
+
const replyPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
573
|
+
chatId: conversationExternalId,
|
|
574
|
+
text: DISK_PRESSURE_REMOTE_BLOCK_REPLY,
|
|
575
|
+
assistantId: canonicalAssistantId,
|
|
576
|
+
};
|
|
577
|
+
if (sourceChannel === "slack" && (canonicalSenderId ?? rawSenderId)) {
|
|
578
|
+
replyPayload.ephemeral = true;
|
|
579
|
+
replyPayload.user = (canonicalSenderId ?? rawSenderId)!;
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
await deliverChannelReply(replyCallbackUrl, replyPayload);
|
|
583
|
+
} catch (err) {
|
|
584
|
+
log.warn(
|
|
585
|
+
{
|
|
586
|
+
err,
|
|
587
|
+
conversationId: result.conversationId,
|
|
588
|
+
eventId: result.eventId,
|
|
589
|
+
},
|
|
590
|
+
"Failed to deliver disk pressure block reply",
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
accepted: true,
|
|
597
|
+
duplicate: result.duplicate,
|
|
598
|
+
eventId: result.eventId,
|
|
599
|
+
diskPressure: "blocked",
|
|
600
|
+
reason: diskPressureDecision.reason,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
527
604
|
// ── Slack reaction handling ──
|
|
528
605
|
// Reactions arrive as regular `SlackInboundEvent`s with `callbackData`
|
|
529
606
|
// prefixed `reaction:` (added) or `reaction_removed:` (removed).
|
|
@@ -735,18 +812,6 @@ export async function handleChannelInbound({
|
|
|
735
812
|
// which handles request code matching, callback parsing, and NL classification
|
|
736
813
|
// against canonical_guardian_requests.
|
|
737
814
|
|
|
738
|
-
// ── Actor role resolution ──
|
|
739
|
-
// Uses shared channel-agnostic resolution so all ingress paths classify
|
|
740
|
-
// guardian vs non-guardian actors the same way.
|
|
741
|
-
const trustCtx: TrustContext = resolveTrustContext({
|
|
742
|
-
assistantId: canonicalAssistantId,
|
|
743
|
-
sourceChannel,
|
|
744
|
-
conversationExternalId,
|
|
745
|
-
actorExternalId: rawSenderId,
|
|
746
|
-
actorUsername: body.actorUsername,
|
|
747
|
-
actorDisplayName: body.actorDisplayName,
|
|
748
|
-
});
|
|
749
|
-
|
|
750
815
|
// ── Canonical guardian reply router ──
|
|
751
816
|
const guardianReplyResult = await handleGuardianReplyIntercept({
|
|
752
817
|
isDuplicate: result.duplicate,
|
|
@@ -37,9 +37,11 @@ import { ROUTES as CONVERSATION_QUERY_ROUTES } from "./conversation-query-routes
|
|
|
37
37
|
import { ROUTES as CONVERSATION_MESSAGE_ROUTES } from "./conversation-routes.js";
|
|
38
38
|
import { ROUTES as CONVERSATION_STARTER_ROUTES } from "./conversation-starter-routes.js";
|
|
39
39
|
import { ROUTES as CREDENTIAL_PROMPT_ROUTES } from "./credential-prompt-routes.js";
|
|
40
|
+
import { ROUTES as DEBUG_BASH_ROUTES } from "./debug-bash-routes.js";
|
|
40
41
|
import { ROUTES as DEBUG_ROUTES } from "./debug-routes.js";
|
|
41
42
|
import { ROUTES as DEFER_ROUTES } from "./defer-routes.js";
|
|
42
43
|
import { ROUTES as DIAGNOSTICS_ROUTES } from "./diagnostics-routes.js";
|
|
44
|
+
import { ROUTES as DISK_PRESSURE_ROUTES } from "./disk-pressure-routes.js";
|
|
43
45
|
import { ROUTES as DOCUMENT_ROUTES } from "./documents-routes.js";
|
|
44
46
|
import { ROUTES as EVENTS_ROUTES } from "./events-routes.js";
|
|
45
47
|
import { ROUTES as FILING_ROUTES } from "./filing-routes.js";
|
|
@@ -74,6 +76,7 @@ import { ROUTES as MIGRATION_ROLLBACK_ROUTES } from "./migration-rollback-routes
|
|
|
74
76
|
import { ROUTES as MIGRATION_ROUTES } from "./migration-routes.js";
|
|
75
77
|
import { ROUTES as NOTIFICATION_ROUTES } from "./notification-routes.js";
|
|
76
78
|
import { ROUTES as OAUTH_APPS_ROUTES } from "./oauth-apps.js";
|
|
79
|
+
import { ROUTES as OAUTH_CONNECT_ROUTES } from "./oauth-connect-routes.js";
|
|
77
80
|
import { ROUTES as OAUTH_PROVIDERS_ROUTES } from "./oauth-providers.js";
|
|
78
81
|
import { ROUTES as PLAYGROUND_ROUTES } from "./playground/index.js";
|
|
79
82
|
import { ROUTES as PROFILER_ROUTES } from "./profiler-routes.js";
|
|
@@ -137,8 +140,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
137
140
|
...DEFER_ROUTES,
|
|
138
141
|
...CONVERSATION_QUERY_ROUTES,
|
|
139
142
|
...CONVERSATION_STARTER_ROUTES,
|
|
143
|
+
...DEBUG_BASH_ROUTES,
|
|
140
144
|
...DEBUG_ROUTES,
|
|
141
145
|
...DIAGNOSTICS_ROUTES,
|
|
146
|
+
...DISK_PRESSURE_ROUTES,
|
|
142
147
|
...DOCUMENT_ROUTES,
|
|
143
148
|
...EVENTS_ROUTES,
|
|
144
149
|
...FILING_ROUTES,
|
|
@@ -159,6 +164,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
159
164
|
...INTERFACE_ROUTES,
|
|
160
165
|
...INTERNAL_OAUTH_ROUTES,
|
|
161
166
|
...MCP_AUTH_ROUTES,
|
|
167
|
+
...OAUTH_CONNECT_ROUTES,
|
|
162
168
|
...INTERNAL_TWILIO_ROUTES,
|
|
163
169
|
...LOG_EXPORT_ROUTES,
|
|
164
170
|
...LLM_CALL_SITES_ROUTES,
|