@vellumai/assistant 0.7.1 → 0.7.2
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 +32 -49
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +565 -12
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +374 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/bundler/app-bundler.ts +51 -3
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +63 -38
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +5 -5
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the gateway_logs_tail IPC route handler.
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Happy path: all params → correct URL with querystring
|
|
6
|
+
* - All params absent → URL with no querystring
|
|
7
|
+
* - Only n provided → querystring has only n
|
|
8
|
+
* - Gateway returns 500 with error body → Error thrown with error message
|
|
9
|
+
* - level: "INVALID" → ZodError (no gateway call)
|
|
10
|
+
* - n: 0 → ZodError (min 1 violation)
|
|
11
|
+
* - n: 1001 → ZodError (max 1000 violation)
|
|
12
|
+
* - module: "" → accepted (empty string passes zod string validation)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
16
|
+
|
|
17
|
+
import { ZodError } from "zod";
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Mocks — must be defined before importing the module under test
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
mock.module("../../../util/logger.js", () => ({
|
|
24
|
+
getLogger: () =>
|
|
25
|
+
new Proxy({} as Record<string, unknown>, {
|
|
26
|
+
get: () => () => {},
|
|
27
|
+
}),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
mock.module("../../../config/env.js", () => ({
|
|
31
|
+
getGatewayInternalBaseUrl: () => "http://localhost:9999",
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Import the module under test AFTER mocks are set up
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
import { ROUTES } from "../gateway-log-routes.js";
|
|
39
|
+
|
|
40
|
+
const gatewayLogsTailRoute = ROUTES.find(
|
|
41
|
+
(r) => r.operationId === "gateway_logs_tail",
|
|
42
|
+
)!;
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Helpers
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
function makeFetchMock(
|
|
49
|
+
status: number,
|
|
50
|
+
body: unknown,
|
|
51
|
+
): ReturnType<typeof mock> {
|
|
52
|
+
return mock(async () => ({
|
|
53
|
+
ok: status >= 200 && status < 300,
|
|
54
|
+
status,
|
|
55
|
+
json: async () => body,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Tests
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
describe("gateway_logs_tail route", () => {
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
// Reset global fetch to avoid cross-test contamination
|
|
66
|
+
globalThis.fetch = undefined as unknown as typeof fetch;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("route is registered with correct operationId, method, and endpoint", () => {
|
|
70
|
+
expect(gatewayLogsTailRoute).toBeDefined();
|
|
71
|
+
expect(gatewayLogsTailRoute.operationId).toBe("gateway_logs_tail");
|
|
72
|
+
expect(gatewayLogsTailRoute.method).toBe("GET");
|
|
73
|
+
expect(gatewayLogsTailRoute.endpoint).toBe("gateway/logs/tail");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("happy path — all params provided via body", () => {
|
|
77
|
+
test("calls gateway with correct URL including all query params", async () => {
|
|
78
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
79
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
80
|
+
|
|
81
|
+
await gatewayLogsTailRoute.handler({
|
|
82
|
+
body: { n: 5, level: "warn", module: "mcp" },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
86
|
+
const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
|
|
87
|
+
expect(calledUrl).toBe(
|
|
88
|
+
"http://localhost:9999/v1/logs/tail?n=5&level=warn&module=mcp",
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("returns the parsed response body", async () => {
|
|
93
|
+
const responseBody = { entries: [{ msg: "hello", level: 40 }] };
|
|
94
|
+
globalThis.fetch = makeFetchMock(200, responseBody) as unknown as typeof fetch;
|
|
95
|
+
|
|
96
|
+
const result = await gatewayLogsTailRoute.handler({
|
|
97
|
+
body: { n: 5, level: "warn", module: "mcp" },
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(result).toEqual(responseBody);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe("all params absent", () => {
|
|
105
|
+
test("calls gateway URL with no querystring when body is empty", async () => {
|
|
106
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
107
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
108
|
+
|
|
109
|
+
await gatewayLogsTailRoute.handler({ body: {} });
|
|
110
|
+
|
|
111
|
+
const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
|
|
112
|
+
expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("calls gateway URL with no querystring when no args provided", async () => {
|
|
116
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
117
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
118
|
+
|
|
119
|
+
await gatewayLogsTailRoute.handler({});
|
|
120
|
+
|
|
121
|
+
const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
|
|
122
|
+
expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe("only n provided", () => {
|
|
127
|
+
test("querystring contains only n — no spurious level or module keys", async () => {
|
|
128
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
129
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
130
|
+
|
|
131
|
+
await gatewayLogsTailRoute.handler({ body: { n: 5 } });
|
|
132
|
+
|
|
133
|
+
const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
|
|
134
|
+
expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail?n=5");
|
|
135
|
+
expect(calledUrl).not.toContain("level");
|
|
136
|
+
expect(calledUrl).not.toContain("module");
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("gateway error handling", () => {
|
|
141
|
+
test("gateway 500 with { error: 'disk error' } throws Error with that message", async () => {
|
|
142
|
+
globalThis.fetch = makeFetchMock(500, {
|
|
143
|
+
error: "disk error",
|
|
144
|
+
}) as unknown as typeof fetch;
|
|
145
|
+
|
|
146
|
+
await expect(
|
|
147
|
+
gatewayLogsTailRoute.handler({ body: {} }),
|
|
148
|
+
).rejects.toThrow("disk error");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("gateway 500 with non-string error falls back to generic message", async () => {
|
|
152
|
+
globalThis.fetch = makeFetchMock(500, {
|
|
153
|
+
error: { nested: true },
|
|
154
|
+
}) as unknown as typeof fetch;
|
|
155
|
+
|
|
156
|
+
await expect(
|
|
157
|
+
gatewayLogsTailRoute.handler({ body: {} }),
|
|
158
|
+
).rejects.toThrow("Gateway request failed (500)");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("gateway 500 with unparseable JSON falls back to generic message", async () => {
|
|
162
|
+
globalThis.fetch = mock(async () => ({
|
|
163
|
+
ok: false,
|
|
164
|
+
status: 500,
|
|
165
|
+
json: async () => {
|
|
166
|
+
throw new SyntaxError("Unexpected token");
|
|
167
|
+
},
|
|
168
|
+
})) as unknown as typeof fetch;
|
|
169
|
+
|
|
170
|
+
await expect(
|
|
171
|
+
gatewayLogsTailRoute.handler({ body: {} }),
|
|
172
|
+
).rejects.toThrow("Gateway request failed (500)");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("zod validation", () => {
|
|
177
|
+
test("level: 'INVALID' is rejected with ZodError before calling gateway", async () => {
|
|
178
|
+
const mockFetch = makeFetchMock(200, {});
|
|
179
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
180
|
+
|
|
181
|
+
await expect(
|
|
182
|
+
gatewayLogsTailRoute.handler({
|
|
183
|
+
body: { level: "INVALID" },
|
|
184
|
+
}),
|
|
185
|
+
).rejects.toBeInstanceOf(ZodError);
|
|
186
|
+
|
|
187
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("n: 0 is rejected with ZodError (min 1 violation)", async () => {
|
|
191
|
+
const mockFetch = makeFetchMock(200, {});
|
|
192
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
193
|
+
|
|
194
|
+
await expect(
|
|
195
|
+
gatewayLogsTailRoute.handler({ body: { n: 0 } }),
|
|
196
|
+
).rejects.toBeInstanceOf(ZodError);
|
|
197
|
+
|
|
198
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("n: 1001 is rejected with ZodError (max 1000 violation)", async () => {
|
|
202
|
+
const mockFetch = makeFetchMock(200, {});
|
|
203
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
204
|
+
|
|
205
|
+
await expect(
|
|
206
|
+
gatewayLogsTailRoute.handler({ body: { n: 1001 } }),
|
|
207
|
+
).rejects.toBeInstanceOf(ZodError);
|
|
208
|
+
|
|
209
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("module: '' is accepted (empty string passes zod string validation)", async () => {
|
|
213
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
214
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
215
|
+
|
|
216
|
+
await expect(
|
|
217
|
+
gatewayLogsTailRoute.handler({ body: { module: "" } }),
|
|
218
|
+
).resolves.toBeDefined();
|
|
219
|
+
|
|
220
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("queryParams source (HTTP GET path)", () => {
|
|
225
|
+
test("uses queryParams when provided (HTTP GET path) — string params", async () => {
|
|
226
|
+
const mockFetch = makeFetchMock(200, { entries: [] });
|
|
227
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
228
|
+
|
|
229
|
+
// When queryParams has values, those take precedence over body.
|
|
230
|
+
// Only string-valued params (level, module) are valid from the HTTP layer;
|
|
231
|
+
// n is numeric and must come via IPC body.
|
|
232
|
+
await gatewayLogsTailRoute.handler({
|
|
233
|
+
queryParams: { level: "info", module: "cors" },
|
|
234
|
+
body: {},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
|
|
238
|
+
expect(calledUrl).toContain("level=info");
|
|
239
|
+
expect(calledUrl).toContain("module=cors");
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asserts `setHeartbeatConfig` persists only user-set heartbeat fields to
|
|
3
|
+
* `config.json` and surfaces the resolved (post-default) values via the
|
|
4
|
+
* response payload.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import { invalidateConfigCache } from "../../../config/loader.js";
|
|
13
|
+
import { ROUTES } from "../heartbeat-routes.js";
|
|
14
|
+
import type { RouteDefinition } from "../types.js";
|
|
15
|
+
|
|
16
|
+
// ─── Module mocks ──────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
// Stub the heartbeat service so the response-path's getInstance() returns
|
|
19
|
+
// undefined (no scheduler running in tests).
|
|
20
|
+
mock.module("../../../heartbeat/heartbeat-service.js", () => ({
|
|
21
|
+
HeartbeatService: {
|
|
22
|
+
getInstance: () => undefined,
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
// ─── Setup ─────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
let workspaceDir: string;
|
|
29
|
+
let origWorkspaceDir: string | undefined;
|
|
30
|
+
let configPath: string;
|
|
31
|
+
|
|
32
|
+
function findHandler(operationId: string): RouteDefinition["handler"] {
|
|
33
|
+
const route = ROUTES.find((r) => r.operationId === operationId);
|
|
34
|
+
if (!route) throw new Error(`Route ${operationId} not found`);
|
|
35
|
+
return route.handler;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readConfig(): Record<string, unknown> {
|
|
39
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
workspaceDir = mkdtempSync(join(tmpdir(), "vellum-hbr-"));
|
|
44
|
+
origWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR;
|
|
45
|
+
process.env.VELLUM_WORKSPACE_DIR = workspaceDir;
|
|
46
|
+
configPath = join(workspaceDir, "config.json");
|
|
47
|
+
invalidateConfigCache();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
if (origWorkspaceDir === undefined) {
|
|
52
|
+
delete process.env.VELLUM_WORKSPACE_DIR;
|
|
53
|
+
} else {
|
|
54
|
+
process.env.VELLUM_WORKSPACE_DIR = origWorkspaceDir;
|
|
55
|
+
}
|
|
56
|
+
invalidateConfigCache();
|
|
57
|
+
try {
|
|
58
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
59
|
+
} catch {
|
|
60
|
+
// best-effort cleanup
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ─── Tests ─────────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
describe("setHeartbeatConfig handler", () => {
|
|
67
|
+
test("persists only user-set fields when starting from a config with no heartbeat block", async () => {
|
|
68
|
+
writeFileSync(
|
|
69
|
+
configPath,
|
|
70
|
+
JSON.stringify({ provider: "anthropic" }, null, 2) + "\n",
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const handler = findHandler("updateHeartbeatConfig");
|
|
74
|
+
const result = (await handler({ body: { enabled: true } })) as {
|
|
75
|
+
enabled: boolean;
|
|
76
|
+
intervalMs: number;
|
|
77
|
+
activeHoursStart: number | null;
|
|
78
|
+
activeHoursEnd: number | null;
|
|
79
|
+
success: boolean;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// On-disk: only user-set heartbeat fields, no schema defaults baked in.
|
|
83
|
+
const onDisk = readConfig();
|
|
84
|
+
expect(onDisk).toEqual({
|
|
85
|
+
provider: "anthropic",
|
|
86
|
+
heartbeat: { enabled: true },
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Response: schema-default intervalMs surfaces, proving cache
|
|
90
|
+
// invalidation + getConfig() read picked up the new on-disk state.
|
|
91
|
+
expect(result.success).toBe(true);
|
|
92
|
+
expect(result.enabled).toBe(true);
|
|
93
|
+
expect(result.intervalMs).toBe(6 * 3_600_000);
|
|
94
|
+
expect(result.activeHoursStart).toBe(8);
|
|
95
|
+
expect(result.activeHoursEnd).toBe(22);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("merges patch into existing heartbeat block instead of overwriting", async () => {
|
|
99
|
+
writeFileSync(
|
|
100
|
+
configPath,
|
|
101
|
+
JSON.stringify({ heartbeat: { intervalMs: 60000 } }, null, 2) + "\n",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const handler = findHandler("updateHeartbeatConfig");
|
|
105
|
+
await handler({ body: { enabled: true } });
|
|
106
|
+
|
|
107
|
+
const onDisk = readConfig();
|
|
108
|
+
expect(onDisk).toEqual({
|
|
109
|
+
heartbeat: { intervalMs: 60000, enabled: true },
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types extracted from guardian-approval-interception.ts to break the
|
|
3
|
+
* interception ↔ guardian-text-engine-strategy cycle.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ApprovalInterceptionResult {
|
|
7
|
+
handled: boolean;
|
|
8
|
+
type?:
|
|
9
|
+
| "decision_applied"
|
|
10
|
+
| "assistant_turn"
|
|
11
|
+
| "guardian_decision_applied"
|
|
12
|
+
| "stale_ignored";
|
|
13
|
+
}
|
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
ApprovalConversationGenerator,
|
|
18
18
|
ApprovalCopyGenerator,
|
|
19
19
|
} from "../../http-types.js";
|
|
20
|
-
import type { ApprovalInterceptionResult } from "../
|
|
20
|
+
import type { ApprovalInterceptionResult } from "../approval-interception-types.js";
|
|
21
21
|
import { deliverStaleApprovalReply } from "../guardian-approval-reply-helpers.js";
|
|
22
22
|
|
|
23
23
|
const log = getLogger("runtime-http");
|
|
@@ -26,17 +26,11 @@ import { dirname, sep } from "node:path";
|
|
|
26
26
|
|
|
27
27
|
import { z } from "zod";
|
|
28
28
|
|
|
29
|
-
import { readBackupKey } from "../../backup/backup-key.js";
|
|
30
|
-
import {
|
|
31
|
-
type BackupRunResult,
|
|
32
|
-
createSnapshotNow,
|
|
33
|
-
} from "../../backup/backup-worker.js";
|
|
34
29
|
import {
|
|
35
30
|
listSnapshotsInDir,
|
|
36
31
|
type SnapshotEntry,
|
|
37
32
|
} from "../../backup/list-snapshots.js";
|
|
38
33
|
import {
|
|
39
|
-
getBackupKeyPath,
|
|
40
34
|
getLocalBackupsDir,
|
|
41
35
|
resolveOffsiteDestinations,
|
|
42
36
|
} from "../../backup/paths.js";
|
|
@@ -47,7 +41,7 @@ import { getMemoryCheckpoint } from "../../memory/checkpoints.js";
|
|
|
47
41
|
import { getLogger } from "../../util/logger.js";
|
|
48
42
|
import { getWorkspaceDir, getWorkspaceHooksDir } from "../../util/platform.js";
|
|
49
43
|
import { DefaultPathResolver } from "../migrations/vbundle-import-analyzer.js";
|
|
50
|
-
import { BadRequestError,
|
|
44
|
+
import { BadRequestError, RouteError } from "./errors.js";
|
|
51
45
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
52
46
|
|
|
53
47
|
const log = getLogger("backup-routes");
|
|
@@ -115,23 +109,16 @@ async function validateSnapshotPath(rawPath: unknown): Promise<string> {
|
|
|
115
109
|
}
|
|
116
110
|
|
|
117
111
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* encrypted bundle is supplied but no key file exists.
|
|
112
|
+
* Reject encrypted snapshots — decryption has moved to the gateway (ATL-397).
|
|
113
|
+
* The assistant daemon no longer has access to the backup key.
|
|
121
114
|
*/
|
|
122
|
-
|
|
123
|
-
snapshotPath
|
|
124
|
-
): Promise<Buffer | null> {
|
|
125
|
-
if (!snapshotPath.endsWith(".vbundle.enc")) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
const key = await readBackupKey(getBackupKeyPath());
|
|
129
|
-
if (key == null) {
|
|
115
|
+
function rejectIfEncrypted(snapshotPath: string): void {
|
|
116
|
+
if (snapshotPath.endsWith(".vbundle.enc")) {
|
|
130
117
|
throw new BadRequestError(
|
|
131
|
-
"Encrypted snapshot
|
|
118
|
+
"Encrypted snapshot restore/verify must go through the gateway, " +
|
|
119
|
+
"which owns the backup key. Use the gateway's backup endpoints instead.",
|
|
132
120
|
);
|
|
133
121
|
}
|
|
134
|
-
return key;
|
|
135
122
|
}
|
|
136
123
|
|
|
137
124
|
// ---------------------------------------------------------------------------
|
|
@@ -189,24 +176,17 @@ export async function handleBackupList(): Promise<BackupListResponse> {
|
|
|
189
176
|
return { local, offsite, offsiteEnabled, nextRunAt };
|
|
190
177
|
}
|
|
191
178
|
|
|
192
|
-
export async function handleBackupCreate(): Promise<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
198
|
-
if (message.startsWith("snapshot in progress")) {
|
|
199
|
-
throw new ConflictError("A snapshot is already in progress");
|
|
200
|
-
}
|
|
201
|
-
log.error({ err }, "Manual backup snapshot failed");
|
|
202
|
-
throw new RouteError(message, "INTERNAL_ERROR", 500);
|
|
203
|
-
}
|
|
179
|
+
export async function handleBackupCreate(): Promise<never> {
|
|
180
|
+
throw new BadRequestError(
|
|
181
|
+
"Backup snapshot creation has moved to the gateway. " +
|
|
182
|
+
"Use the gateway's POST /v1/backups/create endpoint instead.",
|
|
183
|
+
);
|
|
204
184
|
}
|
|
205
185
|
|
|
206
186
|
export async function handleBackupRestore({ body }: RouteHandlerArgs) {
|
|
207
187
|
const path = body?.path;
|
|
208
188
|
const snapshotPath = await validateSnapshotPath(path);
|
|
209
|
-
|
|
189
|
+
rejectIfEncrypted(snapshotPath);
|
|
210
190
|
|
|
211
191
|
try {
|
|
212
192
|
const pathResolver = new DefaultPathResolver(
|
|
@@ -215,7 +195,6 @@ export async function handleBackupRestore({ body }: RouteHandlerArgs) {
|
|
|
215
195
|
);
|
|
216
196
|
|
|
217
197
|
const result = await restoreFromSnapshot(snapshotPath, {
|
|
218
|
-
key: key ?? undefined,
|
|
219
198
|
pathResolver,
|
|
220
199
|
workspaceDir: getWorkspaceDir(),
|
|
221
200
|
});
|
|
@@ -239,12 +218,10 @@ export async function handleBackupRestore({ body }: RouteHandlerArgs) {
|
|
|
239
218
|
export async function handleBackupVerify({ body }: RouteHandlerArgs) {
|
|
240
219
|
const path = body?.path;
|
|
241
220
|
const snapshotPath = await validateSnapshotPath(path);
|
|
242
|
-
|
|
221
|
+
rejectIfEncrypted(snapshotPath);
|
|
243
222
|
|
|
244
223
|
try {
|
|
245
|
-
return await verifySnapshot(snapshotPath
|
|
246
|
-
key: key ?? undefined,
|
|
247
|
-
});
|
|
224
|
+
return await verifySnapshot(snapshotPath);
|
|
248
225
|
} catch (err) {
|
|
249
226
|
log.error({ err, snapshotPath }, "Snapshot verification failed");
|
|
250
227
|
throw new RouteError(
|
|
@@ -18,6 +18,8 @@ import { z } from "zod";
|
|
|
18
18
|
|
|
19
19
|
import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
|
|
20
20
|
import { getOrCreateConversation } from "../../daemon/conversation-store.js";
|
|
21
|
+
import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
|
|
22
|
+
import { parseIdentityFields } from "../../daemon/handlers/identity.js";
|
|
21
23
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
22
24
|
import { resolvePersonaContext } from "../../prompts/persona-resolver.js";
|
|
23
25
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -35,33 +37,6 @@ const IDENTITY_INTRO_KEY = "identity-intro";
|
|
|
35
37
|
/** Conversation key used by the client for empty-state greeting generation. */
|
|
36
38
|
const GREETING_KEY = "greeting";
|
|
37
39
|
|
|
38
|
-
/**
|
|
39
|
-
* Parse the `## Identity Intro` section from SOUL.md.
|
|
40
|
-
* Returns the first non-empty line under that heading, or null.
|
|
41
|
-
*/
|
|
42
|
-
function readSoulIdentityIntro(): string | null {
|
|
43
|
-
try {
|
|
44
|
-
const soulPath = getWorkspacePromptPath("SOUL.md");
|
|
45
|
-
if (!existsSync(soulPath)) return null;
|
|
46
|
-
const content = readFileSync(soulPath, "utf-8");
|
|
47
|
-
|
|
48
|
-
let inSection = false;
|
|
49
|
-
for (const line of content.split("\n")) {
|
|
50
|
-
const trimmed = line.trim();
|
|
51
|
-
if (/^#+\s/.test(trimmed)) {
|
|
52
|
-
inSection = trimmed.toLowerCase().includes("identity intro");
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (inSection && trimmed.length > 0) {
|
|
56
|
-
return trimmed;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
// Fall through — no SOUL.md intro available
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
40
|
// ---------------------------------------------------------------------------
|
|
66
41
|
// SSE helpers
|
|
67
42
|
// ---------------------------------------------------------------------------
|
|
@@ -94,14 +69,17 @@ async function handleBtw({
|
|
|
94
69
|
|
|
95
70
|
// ----- Identity intro fast-path -----
|
|
96
71
|
if (conversationKey === IDENTITY_INTRO_KEY) {
|
|
97
|
-
|
|
98
|
-
const
|
|
72
|
+
let fastText: string | undefined;
|
|
73
|
+
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
74
|
+
if (existsSync(identityPath)) {
|
|
75
|
+
const fields = parseIdentityFields(readFileSync(identityPath, "utf-8"));
|
|
76
|
+
if (fields.name) {
|
|
77
|
+
fastText = `Hi, I'm ${fields.name}!`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
fastText ??= getCachedIntro()?.text;
|
|
99
81
|
if (fastText) {
|
|
100
|
-
log.debug(
|
|
101
|
-
soulIntro
|
|
102
|
-
? "Returning SOUL.md identity intro"
|
|
103
|
-
: "Returning cached identity intro",
|
|
104
|
-
);
|
|
82
|
+
log.debug("Returning identity intro fast-path");
|
|
105
83
|
return new ReadableStream({
|
|
106
84
|
start(controller) {
|
|
107
85
|
controller.enqueue(sseEvent("btw_text_delta", { text: fastText }));
|
|
@@ -129,9 +107,7 @@ async function handleBtw({
|
|
|
129
107
|
try {
|
|
130
108
|
conversation = await getOrCreateConversation(conversationId);
|
|
131
109
|
} catch {
|
|
132
|
-
throw new ServiceUnavailableError(
|
|
133
|
-
"Message processing is not available",
|
|
134
|
-
);
|
|
110
|
+
throw new ServiceUnavailableError("Message processing is not available");
|
|
135
111
|
}
|
|
136
112
|
|
|
137
113
|
return new ReadableStream({
|
|
@@ -145,6 +121,7 @@ async function handleBtw({
|
|
|
145
121
|
const result = await runBtwSidechain({
|
|
146
122
|
content: effectiveContent,
|
|
147
123
|
conversation,
|
|
124
|
+
tools: buildToolDefinitions(),
|
|
148
125
|
signal: abortSignal,
|
|
149
126
|
userPersona,
|
|
150
127
|
channelPersona,
|