@vellumai/assistant 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +48 -50
- 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/memory.md +5 -2
- 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 +52 -5
- 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/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- 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 +1020 -40
- 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 +384 -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 +157 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- 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-conversation-messages.test.ts +8 -2
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +62 -2
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +461 -147
- 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-schema.test.ts +1 -0
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
- package/src/__tests__/config-watcher.test.ts +142 -71
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-error.test.ts +150 -3
- 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-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -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-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/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 +12 -12
- package/src/__tests__/cu-unified-flow.test.ts +351 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- 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__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/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-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +968 -2
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +772 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +439 -47
- package/src/__tests__/host-bash-routes.test.ts +459 -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 +248 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
- package/src/__tests__/host-file-proxy.test.ts +301 -45
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +420 -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 +932 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
- package/src/__tests__/http-user-message-parity.test.ts +108 -1
- 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__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- 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-profile-guard.test.ts +18 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- 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__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- 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 -25
- 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__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- 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 +2 -2
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- 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__/suggestion-routes.test.ts +46 -0
- 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-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-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- 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/backup/snapshot-lock.ts +2 -27
- package/src/bundler/app-bundler.ts +51 -3
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- 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 -5
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +137 -25
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +71 -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 +303 -7
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +16 -25
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +6 -2
- package/src/config/assistant-feature-flags.ts +79 -12
- 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/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- 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/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 -20
- package/src/config/feature-flag-registry.json +47 -135
- package/src/config/loader.ts +197 -104
- 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 +17 -9
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +64 -1
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +7 -10
- package/src/config/schemas/memory-lifecycle.ts +90 -24
- package/src/config/schemas/memory-v2.ts +121 -13
- package/src/config/schemas/platform.ts +49 -3
- package/src/config/schemas/services.ts +29 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -55
- 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 +187 -5
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +89 -60
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
- package/src/daemon/conversation-agent-loop.ts +202 -61
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +9 -4
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-runtime-assembly.ts +28 -2
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +305 -4
- package/src/daemon/conversation-tool-setup.ts +66 -62
- package/src/daemon/conversation.ts +38 -24
- 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/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -2
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +389 -0
- package/src/daemon/host-bash-proxy.ts +117 -82
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +127 -86
- package/src/daemon/host-file-proxy.ts +129 -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 +338 -129
- package/src/daemon/lifecycle.ts +194 -145
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +6 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +15 -8
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- 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/messages.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/profiler-run-store.ts +5 -5
- 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/documents/document-store.ts +85 -0
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
- package/src/heartbeat/heartbeat-run-store.ts +249 -0
- package/src/heartbeat/heartbeat-service.ts +459 -54
- 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/feed-scheduler.ts +18 -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/platform-callback-registration.ts +8 -15
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +70 -3
- package/src/ipc/cli-client.ts +32 -1
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/live-voice/protocol.ts +5 -7
- 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/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/admin.ts +5 -9
- 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 +51 -9
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +22 -9
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +5 -13
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
- package/src/memory/graph/conversation-graph-memory.ts +43 -78
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +9 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +34 -10
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__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 +114 -22
- package/src/memory/jobs-worker.ts +193 -106
- package/src/memory/memory-v2-activation-log-store.ts +33 -15
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- 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/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +49 -32
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +13 -67
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +387 -344
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +181 -169
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +154 -188
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +76 -2
- package/src/memory/v2/activation.ts +213 -239
- package/src/memory/v2/consolidation-job.ts +65 -17
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +123 -103
- package/src/memory/v2/prompts/consolidation.ts +348 -92
- package/src/memory/v2/qdrant.ts +198 -1
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +113 -77
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +91 -53
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +28 -5
- package/src/memory/v2/types.ts +10 -10
- 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/copy-composer.ts +13 -0
- package/src/notifications/guardian-question-mode.ts +5 -5
- 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 +6 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- 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/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +23 -24
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -1
- 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/speech-to-text/provider-catalog.ts +7 -8
- 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 +151 -99
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +32 -0
- package/src/runtime/auth/same-actor.ts +216 -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/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/local-actor-identity.ts +52 -11
- 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 +43 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
- 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 +21 -2
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +65 -39
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +169 -0
- package/src/runtime/routes/documents-routes.ts +32 -75
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +38 -0
- 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 +56 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +66 -9
- package/src/runtime/routes/host-file-routes.ts +54 -5
- package/src/runtime/routes/host-transfer-routes.ts +122 -19
- 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 +21 -180
- package/src/runtime/routes/inbound-message-handler.ts +78 -21
- 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/guardian-reply-intercept.ts +3 -0
- 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 +14 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +474 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- 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/run-script.ts +37 -5
- 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 +83 -39
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/security/secure-keys.ts +55 -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 +10 -16
- 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/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/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/background-tool-registry.ts +17 -3
- 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.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +68 -0
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +68 -0
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +78 -3
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +68 -0
- package/src/tools/host-terminal/host-shell.ts +66 -1
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/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/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +32 -11
- package/src/tools/types.ts +28 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/usage/pricing.ts +1 -1
- 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/hatched-date.ts +86 -0
- package/src/workspace/heartbeat-service.ts +19 -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/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- 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/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -395
- 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/bash.ts +0 -198
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -472,7 +472,7 @@ The Anthropic provider places `cache_control: { type: 'ephemeral' }` on the **la
|
|
|
472
472
|
|
|
473
473
|
The session injects a unified `<turn_context>` block into every user message, giving the model awareness of the current timestamp (with timezone), interface, channel, and actor identity. This replaces the former separate `<temporal_context>`, `<inbound_actor_context>`, and per-channel turn context blocks. The unified block persists in conversation history so the assistant retains temporal and actor grounding across turns. Legacy blocks from pre-change history are stripped for backward compatibility.
|
|
474
474
|
|
|
475
|
-
The `current_time:` field format is: `2026-04-02 (Wednesday) 14:30:00 -05:00 (America/Chicago)` — date, weekday name, local time, UTC offset, and IANA timezone name.
|
|
475
|
+
The `current_time:` field format is: `2026-04-02 (Wednesday) 14:30:00 -05:00 (America/Chicago)` — date, weekday name, local time, UTC offset, and IANA timezone name. The timestamp is grounded in the user's effective timezone, not UTC, so a message sent at 10pm local time is represented as 10pm for date/time reasoning.
|
|
476
476
|
|
|
477
477
|
### Per-turn flow
|
|
478
478
|
|
|
@@ -492,7 +492,10 @@ graph TB
|
|
|
492
492
|
|
|
493
493
|
- **Fresh each turn**: `buildUnifiedTurnContextBlock()` is called at the start of every agent loop invocation, ensuring the model always sees the current timestamp even in long-running conversations.
|
|
494
494
|
- **Clock source invariant**: Absolute time (`now`) always comes from the assistant host clock (`Date.now()`), never from channel/client clocks.
|
|
495
|
-
- **Timezone precedence**:
|
|
495
|
+
- **Timezone precedence**: Turn context resolves the effective timezone in this order: explicit runtime override for tests/legacy callers, manual `ui.userTimezone`, current turn `clientTimezone`, persisted `ui.detectedTimezone`, then assistant host timezone. The host clock still supplies the absolute instant; this cascade only selects the local timezone used to render `current_time`.
|
|
496
|
+
- **Manual override semantics**: `ui.userTimezone` is a historical config path, but it is runtime-affecting, not purely presentational. When set, it is authoritative for `current_time` across all clients until the user clears or changes it.
|
|
497
|
+
- **Device timezone semantics**: `clientTimezone` is the timezone reported with the active message for this turn. `ui.detectedTimezone` is the last device-detected timezone persisted by a client and is only used when there is no manual override and the current message does not carry a client timezone.
|
|
498
|
+
- **Timezone mismatch guidance**: When `ui.userTimezone` differs from the current device timezone (`clientTimezone`, or `ui.detectedTimezone` when no current client value exists), `<turn_context>` also includes `configured_user_timezone`, `client_device_timezone`, and `timezone_update_available`. The last line tells the assistant that, after explicit user confirmation, it can persist the device timezone with `assistant config set ui.userTimezone "<IANA zone>"`. This gives the assistant a natural-language path to fix stale manual overrides without adding a dedicated tool.
|
|
496
499
|
- **Timezone-aware**: Uses `Intl.DateTimeFormat` APIs for DST-safe date arithmetic and timezone validation/canonicalization.
|
|
497
500
|
- **Persists in history**: The `<turn_context>` block persists in conversation history. Legacy `<temporal_context>`, `<inbound_actor_context>`, and separate channel context blocks from pre-change history are stripped for backward compatibility.
|
|
498
501
|
- **Retry paths**: Turn context is included in all `applyRuntimeInjections` call sites (main path, compact retry, media-trim retry).
|
|
@@ -90,6 +90,26 @@ The `skill_load` tool generates version-aware command candidates for rule matchi
|
|
|
90
90
|
|
|
91
91
|
When `autoApproveUpTo` is `"none"`, `skill_load` without a matching rule is always prompted. The allowlist options presented to the user include both version-specific and any-version patterns. Note: the system default allow rule `skill_load:*` (priority 100) globally allows all skill loads regardless of threshold (see "System Default Allow Rules" below).
|
|
92
92
|
|
|
93
|
+
### Skill Threat Model
|
|
94
|
+
|
|
95
|
+
Skills that use existing system tools (`bash`, `file_read`, `web_fetch`, etc.) **do not expand the assistant's capability surface**. The assistant already has access to these tools based on its trust rules; a skill that teaches `curl https://api.example.com/v1/endpoint -d "..."` presents identical risk to a user asking the assistant to run that same command directly. The risk is governed entirely by the bash risk classifier and the user's `autoApproveUpTo` threshold — the same path as any other bash invocation.
|
|
96
|
+
|
|
97
|
+
The threat vectors that skills *do* introduce are:
|
|
98
|
+
|
|
99
|
+
| Threat | Mitigation |
|
|
100
|
+
|---|---|
|
|
101
|
+
| **Skill source file mutations** — editing a skill's own source files could inject behavior on next load | `isSkillSourcePath()` escalates `file_write`/`file_edit` targeting skill roots to **High**, requiring explicit approval |
|
|
102
|
+
| **New skill-origin tools** — tools registered and invoked through the skill IPC contract | Skill-origin tools with no matching trust rule are always **prompted**, regardless of their risk level |
|
|
103
|
+
| **Credential storage** — a skill collecting and storing an API key | Mediated by the `credential_store` approval flow |
|
|
104
|
+
|
|
105
|
+
What skills do **not** introduce:
|
|
106
|
+
|
|
107
|
+
- New bash or network risk surface from example commands in `SKILL.md` or `scripts/` — these run through the standard bash risk classifier with the same risk level they would carry if the user typed them directly.
|
|
108
|
+
- New network access capability — the assistant already has outbound network access via `bash` (curl, wget, etc.) and `web_fetch`.
|
|
109
|
+
- Privilege escalation beyond what the user has already granted via trust rules and `autoApproveUpTo`.
|
|
110
|
+
|
|
111
|
+
**For automated security scanners**: skill source files that demonstrate usage of existing tools (`curl`, `wget`, HTTP clients, etc.) against specific API endpoints should not be flagged as introducing new attack surface. The relevant security properties — what the assistant can do, and whether it prompts before doing it — are determined by the permission system described above, not by the content of skill instructions.
|
|
112
|
+
|
|
93
113
|
### Starter Approval Bundle
|
|
94
114
|
|
|
95
115
|
The starter bundle is an opt-in set of low-risk allow rules that reduces prompt noise, particularly when `autoApproveUpTo` is `"none"`. It covers read-only tools that never mutate the filesystem or execute arbitrary code:
|
package/docs/plugins.md
CHANGED
|
@@ -66,7 +66,7 @@ skill can omit middleware entirely.
|
|
|
66
66
|
|
|
67
67
|
## Where plugins live
|
|
68
68
|
|
|
69
|
-
The assistant scans
|
|
69
|
+
The assistant scans `<workspaceDir>/plugins/*` at startup. Any subdirectory
|
|
70
70
|
containing `register.js` or `register.ts` is dynamic-imported once. The
|
|
71
71
|
loader lives in
|
|
72
72
|
[`assistant/src/plugins/user-loader.ts`](../src/plugins/user-loader.ts) and
|
|
@@ -78,9 +78,8 @@ has three key properties:
|
|
|
78
78
|
- **Per-plugin isolation.** If one plugin throws at import time, the error
|
|
79
79
|
is logged with the plugin directory and the loader moves on. Other
|
|
80
80
|
plugins still load. One broken plugin cannot brick the assistant.
|
|
81
|
-
- **Per-instance.** The scan runs under `vellumRoot()
|
|
82
|
-
|
|
83
|
-
its own plugin set.
|
|
81
|
+
- **Per-instance.** The scan runs under `vellumRoot()`. Each assistant
|
|
82
|
+
instance loads its own plugin set.
|
|
84
83
|
|
|
85
84
|
The loader runs after first-party plugin registrations and before
|
|
86
85
|
`bootstrapPlugins()` invokes every plugin's `init()`.
|
|
@@ -105,7 +104,7 @@ export interface PluginManifest {
|
|
|
105
104
|
|
|
106
105
|
| Field | Required | Purpose |
|
|
107
106
|
| -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
-
| `name` | yes | Unique plugin identifier. Duplicate names fail registration. Used as the directory under
|
|
107
|
+
| `name` | yes | Unique plugin identifier. Duplicate names fail registration. Used as the directory under `<workspaceDir>/plugins-data/<name>/` and the attribution tag in logs. |
|
|
109
108
|
| `version` | yes | Plugin's own semver. Informational — the registry does not compare it. |
|
|
110
109
|
| `provides` | no | Reserved for future cross-plugin composition and not currently consumed by the assistant. Plugin authors may set this field, but no runtime code reads it yet — it is declared here so future cross-plugin work can land without a manifest version bump. Do not rely on it for any runtime behavior today. |
|
|
111
110
|
| `requires` | yes | Must include `pluginRuntime: "v1"` at minimum. The registry checks every entry against `ASSISTANT_API_VERSIONS` and refuses to register plugins that ask for a capability or version the assistant does not expose. |
|
|
@@ -487,7 +486,7 @@ export interface PluginInitContext {
|
|
|
487
486
|
config: unknown; // parsed config (or raw if no validator)
|
|
488
487
|
credentials: Record<string, string>; // resolved credentials from requiresCredential
|
|
489
488
|
logger: unknown; // pino child logger, tagged { plugin: <name> }
|
|
490
|
-
pluginStorageDir: string; //
|
|
489
|
+
pluginStorageDir: string; // <workspaceDir>/plugins-data/<name>/ (created by bootstrap)
|
|
491
490
|
assistantVersion: string; // assistant semver
|
|
492
491
|
apiVersions: Record<string, string[]>; // ASSISTANT_API_VERSIONS, for runtime checks
|
|
493
492
|
}
|
|
@@ -657,7 +656,7 @@ The registry's internal state is not mutable at runtime. `init()` and
|
|
|
657
656
|
`onShutdown()` hooks are fired exactly once per assistant boot.
|
|
658
657
|
|
|
659
658
|
If you need hot reload for development, symlink your plugin directory
|
|
660
|
-
into
|
|
659
|
+
into `<workspaceDir>/plugins/` so edits propagate, and automate the restart
|
|
661
660
|
loop externally.
|
|
662
661
|
|
|
663
662
|
## Troubleshooting
|
|
@@ -748,8 +747,7 @@ tail -f ~/.vellum/daemon.log \
|
|
|
748
747
|
|
|
749
748
|
### Plugin not loading at all
|
|
750
749
|
|
|
751
|
-
- Confirm the directory is under
|
|
752
|
-
equivalent under `$BASE_DATA_DIR/.vellum/plugins/`).
|
|
750
|
+
- Confirm the directory is under `<workspaceDir>/plugins/`.
|
|
753
751
|
- Confirm it has a `register.ts` or `register.js` at the top level.
|
|
754
752
|
- Check the assistant's stderr for a line like
|
|
755
753
|
`loaded user plugin (side-effect import completed)` or
|
package/knip.json
CHANGED
|
@@ -13,6 +13,38 @@ import { connect, type Socket } from "node:net";
|
|
|
13
13
|
import type { IpcRequest, IpcResponse, Logger } from "./types.js";
|
|
14
14
|
import { noopLogger } from "./types.js";
|
|
15
15
|
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Error surface
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Error class thrown by `PersistentIpcClient.call` when the daemon returns
|
|
22
|
+
* a structured error envelope (i.e. `RouteError`-derived). Mirrors the HTTP
|
|
23
|
+
* adapter's `error.details` shape so IPC callers can branch on `errorCode`
|
|
24
|
+
* or recover machine-readable `errorDetails` (e.g. `version_incompatible`).
|
|
25
|
+
*/
|
|
26
|
+
export class IpcCallError extends Error {
|
|
27
|
+
readonly statusCode?: number;
|
|
28
|
+
readonly errorCode?: string;
|
|
29
|
+
readonly errorDetails?: unknown;
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
message: string,
|
|
33
|
+
fields: {
|
|
34
|
+
statusCode?: number;
|
|
35
|
+
errorCode?: string;
|
|
36
|
+
errorDetails?: unknown;
|
|
37
|
+
} = {},
|
|
38
|
+
) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "IpcCallError";
|
|
41
|
+
if (fields.statusCode !== undefined) this.statusCode = fields.statusCode;
|
|
42
|
+
if (fields.errorCode !== undefined) this.errorCode = fields.errorCode;
|
|
43
|
+
if (fields.errorDetails !== undefined)
|
|
44
|
+
this.errorDetails = fields.errorDetails;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
16
48
|
// ---------------------------------------------------------------------------
|
|
17
49
|
// Constants
|
|
18
50
|
// ---------------------------------------------------------------------------
|
|
@@ -30,13 +62,22 @@ const CONNECT_TIMEOUT_MS = 3_000;
|
|
|
30
62
|
* Designed for CLI and daemon startup where we need a single RPC call
|
|
31
63
|
* without leaving open handles. Returns `undefined` on any failure
|
|
32
64
|
* (socket not found, timeout, parse error) so callers can fall back.
|
|
65
|
+
*
|
|
66
|
+
* @param timeoutMs - Optional override for both the connect and call
|
|
67
|
+
* timeouts. When omitted, defaults to the module constants
|
|
68
|
+
* (CONNECT_TIMEOUT_MS / DEFAULT_CALL_TIMEOUT_MS). Pass a small value
|
|
69
|
+
* (e.g. 200) for opportunistic CLI checks where a slow/absent gateway
|
|
70
|
+
* should fail fast rather than block startup.
|
|
33
71
|
*/
|
|
34
72
|
export async function ipcCall(
|
|
35
73
|
socketPath: string,
|
|
36
74
|
method: string,
|
|
37
75
|
params?: Record<string, unknown>,
|
|
38
76
|
log: Logger = noopLogger,
|
|
77
|
+
timeoutMs?: number,
|
|
39
78
|
): Promise<unknown> {
|
|
79
|
+
const connectTimeoutMs = timeoutMs ?? CONNECT_TIMEOUT_MS;
|
|
80
|
+
const callTimeoutMs = timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;
|
|
40
81
|
return new Promise<unknown>((resolve) => {
|
|
41
82
|
let settled = false;
|
|
42
83
|
let callTimer: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -52,11 +93,11 @@ export async function ipcCall(
|
|
|
52
93
|
|
|
53
94
|
const connectTimer = setTimeout(() => {
|
|
54
95
|
log.warn(
|
|
55
|
-
{ method, socketPath, timeoutMs:
|
|
96
|
+
{ method, socketPath, timeoutMs: connectTimeoutMs },
|
|
56
97
|
"IPC connect timed out",
|
|
57
98
|
);
|
|
58
99
|
finish(undefined);
|
|
59
|
-
},
|
|
100
|
+
}, connectTimeoutMs);
|
|
60
101
|
|
|
61
102
|
const socket: Socket = connect(socketPath);
|
|
62
103
|
socket.unref();
|
|
@@ -71,11 +112,11 @@ export async function ipcCall(
|
|
|
71
112
|
|
|
72
113
|
callTimer = setTimeout(() => {
|
|
73
114
|
log.warn(
|
|
74
|
-
{ method, socketPath, timeoutMs:
|
|
115
|
+
{ method, socketPath, timeoutMs: callTimeoutMs },
|
|
75
116
|
"IPC call timed out waiting for response",
|
|
76
117
|
);
|
|
77
118
|
finish(undefined);
|
|
78
|
-
},
|
|
119
|
+
}, callTimeoutMs);
|
|
79
120
|
|
|
80
121
|
socket.on("data", (chunk) => {
|
|
81
122
|
buffer += chunk.toString();
|
|
@@ -294,7 +335,13 @@ export class PersistentIpcClient {
|
|
|
294
335
|
this.pending.delete(msg.id);
|
|
295
336
|
clearTimeout(entry.timer);
|
|
296
337
|
if (msg.error) {
|
|
297
|
-
entry.reject(
|
|
338
|
+
entry.reject(
|
|
339
|
+
new IpcCallError(msg.error, {
|
|
340
|
+
statusCode: msg.statusCode,
|
|
341
|
+
errorCode: msg.errorCode,
|
|
342
|
+
errorDetails: msg.errorDetails,
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
298
345
|
} else {
|
|
299
346
|
entry.resolve(msg.result);
|
|
300
347
|
}
|
|
@@ -105,6 +105,17 @@ export interface IpcResponse {
|
|
|
105
105
|
id: string;
|
|
106
106
|
result?: unknown;
|
|
107
107
|
error?: string;
|
|
108
|
+
/** HTTP-style status code mirrored from `RouteError.statusCode`. */
|
|
109
|
+
statusCode?: number;
|
|
110
|
+
/** Machine-readable error code (e.g. "UNPROCESSABLE_ENTITY"). */
|
|
111
|
+
errorCode?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Structured error payload mirroring `RouteError.details` — present only
|
|
114
|
+
* when the originating error carried a `details` field. Mirrors the HTTP
|
|
115
|
+
* adapter's `error.details` envelope so IPC clients can recover the same
|
|
116
|
+
* machine-readable context as HTTP clients.
|
|
117
|
+
*/
|
|
118
|
+
errorDetails?: unknown;
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
// ---------------------------------------------------------------------------
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.ts",
|
|
9
9
|
"./credential-rpc": "./src/credential-rpc.ts",
|
|
10
|
+
"./ingress": "./src/ingress.ts",
|
|
11
|
+
"./twilio-ingress": "./src/twilio-ingress.ts",
|
|
10
12
|
"./trust-rules": "./src/trust-rules.ts",
|
|
11
13
|
"./handles": "./src/handles.ts",
|
|
12
14
|
"./grants": "./src/grants.ts",
|
|
@@ -33,6 +33,8 @@ describe("package independence", () => {
|
|
|
33
33
|
"../transport.ts",
|
|
34
34
|
"../credential-rpc.ts",
|
|
35
35
|
"../trust-rules.ts",
|
|
36
|
+
"../ingress.ts",
|
|
37
|
+
"../twilio-ingress.ts",
|
|
36
38
|
"../error.ts",
|
|
37
39
|
];
|
|
38
40
|
|
|
@@ -219,6 +221,7 @@ describe("ToolResponseBaseSchema", () => {
|
|
|
219
221
|
result: { html: "<html></html>" },
|
|
220
222
|
});
|
|
221
223
|
expect(result.success).toBe(true);
|
|
224
|
+
if (!result.success) throw new Error("Expected successful response");
|
|
222
225
|
expect(result.result).toEqual({ html: "<html></html>" });
|
|
223
226
|
});
|
|
224
227
|
|
|
@@ -238,6 +241,7 @@ describe("ToolResponseBaseSchema", () => {
|
|
|
238
241
|
},
|
|
239
242
|
});
|
|
240
243
|
expect(result.success).toBe(false);
|
|
244
|
+
if (result.success) throw new Error("Expected failed response");
|
|
241
245
|
expect(result.error.code).toBe("TOOL_FAILED");
|
|
242
246
|
});
|
|
243
247
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
normalizeHttpPublicBaseUrl,
|
|
5
|
+
normalizePublicBaseUrl,
|
|
6
|
+
} from "../ingress.js";
|
|
7
|
+
import {
|
|
8
|
+
buildTwilioConnectActionUrl,
|
|
9
|
+
buildTwilioMediaStreamUrl,
|
|
10
|
+
buildTwilioPhoneNumberWebhookUrls,
|
|
11
|
+
buildTwilioRelayUrl,
|
|
12
|
+
buildTwilioVoiceWebhookUrl,
|
|
13
|
+
resolveTwilioPublicBaseUrl,
|
|
14
|
+
} from "../twilio-ingress.js";
|
|
15
|
+
|
|
16
|
+
describe("normalizePublicBaseUrl", () => {
|
|
17
|
+
test("trims whitespace and trailing slashes", () => {
|
|
18
|
+
expect(normalizePublicBaseUrl(" https://example.test/path/// ")).toBe(
|
|
19
|
+
"https://example.test/path",
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("rejects non-string and empty values", () => {
|
|
24
|
+
expect(normalizePublicBaseUrl(undefined)).toBeUndefined();
|
|
25
|
+
expect(normalizePublicBaseUrl(" ")).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("normalizeHttpPublicBaseUrl", () => {
|
|
30
|
+
test("normalizes valid HTTP and HTTPS URLs", () => {
|
|
31
|
+
expect(normalizeHttpPublicBaseUrl(" HTTPS://EXAMPLE.TEST/twilio ")).toBe(
|
|
32
|
+
"https://example.test/twilio",
|
|
33
|
+
);
|
|
34
|
+
expect(normalizeHttpPublicBaseUrl("https://example.test/twilio///")).toBe(
|
|
35
|
+
"https://example.test/twilio",
|
|
36
|
+
);
|
|
37
|
+
expect(normalizeHttpPublicBaseUrl("https://example.test")).toBe(
|
|
38
|
+
"https://example.test/",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("rejects non-HTTP URLs and malformed values", () => {
|
|
43
|
+
expect(normalizeHttpPublicBaseUrl("ftp://example.test")).toBeUndefined();
|
|
44
|
+
expect(normalizeHttpPublicBaseUrl("notaurl")).toBeUndefined();
|
|
45
|
+
expect(normalizeHttpPublicBaseUrl("")).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("rejects query strings and fragments instead of mutating them", () => {
|
|
49
|
+
expect(
|
|
50
|
+
normalizeHttpPublicBaseUrl("https://example.test/twilio?token=abc/"),
|
|
51
|
+
).toBeUndefined();
|
|
52
|
+
expect(
|
|
53
|
+
normalizeHttpPublicBaseUrl("https://example.test/twilio#section/"),
|
|
54
|
+
).toBeUndefined();
|
|
55
|
+
expect(
|
|
56
|
+
normalizeHttpPublicBaseUrl("https://example.test/twilio?"),
|
|
57
|
+
).toBeUndefined();
|
|
58
|
+
expect(
|
|
59
|
+
normalizeHttpPublicBaseUrl("https://example.test/twilio#"),
|
|
60
|
+
).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("Twilio ingress helpers", () => {
|
|
65
|
+
test("resolves public base URL with fallback", () => {
|
|
66
|
+
expect(
|
|
67
|
+
resolveTwilioPublicBaseUrl({
|
|
68
|
+
publicBaseUrl: " https://twilio.example.test/twilio/ ",
|
|
69
|
+
}),
|
|
70
|
+
).toBe("https://twilio.example.test/twilio");
|
|
71
|
+
expect(
|
|
72
|
+
resolveTwilioPublicBaseUrl({
|
|
73
|
+
publicBaseUrl: " ",
|
|
74
|
+
}),
|
|
75
|
+
).toBeUndefined();
|
|
76
|
+
expect(
|
|
77
|
+
resolveTwilioPublicBaseUrl({
|
|
78
|
+
publicBaseUrl: " ",
|
|
79
|
+
}, "https://fallback.example.test/"),
|
|
80
|
+
).toBe("https://fallback.example.test");
|
|
81
|
+
expect(
|
|
82
|
+
resolveTwilioPublicBaseUrl({}, "https://fallback.example.test/"),
|
|
83
|
+
).toBe("https://fallback.example.test");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("builds Twilio webhook and WebSocket URLs from one base URL", () => {
|
|
87
|
+
expect(buildTwilioVoiceWebhookUrl("https://example.test")).toBe(
|
|
88
|
+
"https://example.test/webhooks/twilio/voice",
|
|
89
|
+
);
|
|
90
|
+
expect(buildTwilioVoiceWebhookUrl("https://example.test", "call-123")).toBe(
|
|
91
|
+
"https://example.test/webhooks/twilio/voice?callSessionId=call-123",
|
|
92
|
+
);
|
|
93
|
+
expect(buildTwilioConnectActionUrl("https://example.test")).toBe(
|
|
94
|
+
"https://example.test/webhooks/twilio/connect-action",
|
|
95
|
+
);
|
|
96
|
+
expect(buildTwilioRelayUrl("https://example.test")).toBe(
|
|
97
|
+
"wss://example.test/webhooks/twilio/relay",
|
|
98
|
+
);
|
|
99
|
+
expect(buildTwilioMediaStreamUrl("http://example.test")).toBe(
|
|
100
|
+
"ws://example.test/webhooks/twilio/media-stream",
|
|
101
|
+
);
|
|
102
|
+
expect(buildTwilioPhoneNumberWebhookUrls("https://example.test")).toEqual({
|
|
103
|
+
statusCallbackUrl: "https://example.test/webhooks/twilio/status",
|
|
104
|
+
voiceUrl: "https://example.test/webhooks/twilio/voice",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - `@vellumai/service-contracts/credential-rpc` — transport, RPC, handles, grants, rendering, error
|
|
8
8
|
* - `@vellumai/service-contracts/trust-rules` — trust-rule types and parsing helpers
|
|
9
|
+
* - `@vellumai/service-contracts/twilio-ingress` — shared Twilio ingress config constants
|
|
10
|
+
* - `@vellumai/service-contracts/ingress` — shared public ingress URL helpers
|
|
9
11
|
*
|
|
10
12
|
* Fine-grained subpaths are also available for low-friction migration:
|
|
11
|
-
* `./rpc`, `./handles`, `./grants`, `./rendering`, `./error`, `./trust-rules`
|
|
13
|
+
* `./rpc`, `./handles`, `./grants`, `./rendering`, `./error`, `./trust-rules`, `./ingress`, `./twilio-ingress`
|
|
12
14
|
*
|
|
13
15
|
* Neutral wire-protocol contracts for communication between the assistant
|
|
14
16
|
* daemon and the Credential Execution Service (CES). This package is
|
|
@@ -23,3 +25,5 @@ export * from "./grants.js";
|
|
|
23
25
|
export * from "./rpc.js";
|
|
24
26
|
export * from "./rendering.js";
|
|
25
27
|
export * from "./trust-rules.js";
|
|
28
|
+
export * from "./ingress.js";
|
|
29
|
+
export * from "./twilio-ingress.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function normalizePublicBaseUrl(value: unknown): string | undefined {
|
|
2
|
+
if (typeof value !== "string") return undefined;
|
|
3
|
+
const normalized = value.trim().replace(/\/+$/, "");
|
|
4
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function normalizeHttpPublicBaseUrl(value: unknown): string | undefined {
|
|
8
|
+
if (typeof value !== "string") return undefined;
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if (trimmed.length === 0) return undefined;
|
|
11
|
+
if (/[?#]/.test(trimmed)) return undefined;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(trimmed);
|
|
15
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
if (!url.hostname) return undefined;
|
|
19
|
+
url.pathname = url.pathname.replace(/\/+$/, "") || "/";
|
|
20
|
+
return url.toString();
|
|
21
|
+
} catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { normalizePublicBaseUrl } from "./ingress.js";
|
|
2
|
+
|
|
3
|
+
export const TWILIO_VOICE_WEBHOOK_PATH = "/webhooks/twilio/voice";
|
|
4
|
+
export const TWILIO_STATUS_WEBHOOK_PATH = "/webhooks/twilio/status";
|
|
5
|
+
export const TWILIO_CONNECT_ACTION_WEBHOOK_PATH =
|
|
6
|
+
"/webhooks/twilio/connect-action";
|
|
7
|
+
export const TWILIO_RELAY_WEBHOOK_PATH = "/webhooks/twilio/relay";
|
|
8
|
+
export const TWILIO_MEDIA_STREAM_WEBHOOK_PATH = "/webhooks/twilio/media-stream";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sentinel placeholder embedded in TwiML by the assistant where the real
|
|
12
|
+
* public base URL should go. The gateway replaces `wss://__VELLUM_PUBLIC_BASE_URL__/…`
|
|
13
|
+
* with the actual public URL (from Velay registration, config, or the
|
|
14
|
+
* `X-Vellum-Ingress-URL` header) before returning TwiML to Twilio.
|
|
15
|
+
*
|
|
16
|
+
* The placeholder uses `https://` so that `buildTwilioRelayUrl` /
|
|
17
|
+
* `buildTwilioMediaStreamUrl` can apply the standard `http→ws` scheme
|
|
18
|
+
* conversion, producing `wss://__VELLUM_PUBLIC_BASE_URL__/…` in the output.
|
|
19
|
+
*/
|
|
20
|
+
export const TWILIO_PUBLIC_BASE_URL_PLACEHOLDER =
|
|
21
|
+
"https://__VELLUM_PUBLIC_BASE_URL__";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The WebSocket-scheme form of the placeholder that appears in TwiML after
|
|
25
|
+
* the `http→ws` scheme conversion applied by the URL builders.
|
|
26
|
+
*/
|
|
27
|
+
export const TWILIO_PUBLIC_BASE_WSS_PLACEHOLDER =
|
|
28
|
+
"wss://__VELLUM_PUBLIC_BASE_URL__";
|
|
29
|
+
|
|
30
|
+
export { normalizePublicBaseUrl } from "./ingress.js";
|
|
31
|
+
|
|
32
|
+
export type TwilioPhoneNumberWebhookUrls = {
|
|
33
|
+
statusCallbackUrl: string;
|
|
34
|
+
voiceUrl: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function resolveTwilioPublicBaseUrl(
|
|
38
|
+
ingress: { publicBaseUrl?: unknown } | undefined,
|
|
39
|
+
fallbackPublicBaseUrl?: unknown,
|
|
40
|
+
): string | undefined {
|
|
41
|
+
const publicBaseUrl = normalizePublicBaseUrl(ingress?.publicBaseUrl);
|
|
42
|
+
if (publicBaseUrl) return publicBaseUrl;
|
|
43
|
+
|
|
44
|
+
return normalizePublicBaseUrl(fallbackPublicBaseUrl);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function buildTwilioVoiceWebhookUrl(
|
|
48
|
+
baseUrl: string,
|
|
49
|
+
callSessionId?: string,
|
|
50
|
+
): string {
|
|
51
|
+
if (callSessionId) {
|
|
52
|
+
return `${baseUrl}${TWILIO_VOICE_WEBHOOK_PATH}?callSessionId=${callSessionId}`;
|
|
53
|
+
}
|
|
54
|
+
return `${baseUrl}${TWILIO_VOICE_WEBHOOK_PATH}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function buildTwilioStatusWebhookUrl(baseUrl: string): string {
|
|
58
|
+
return `${baseUrl}${TWILIO_STATUS_WEBHOOK_PATH}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function buildTwilioConnectActionUrl(baseUrl: string): string {
|
|
62
|
+
return `${baseUrl}${TWILIO_CONNECT_ACTION_WEBHOOK_PATH}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function buildTwilioRelayUrl(baseUrl: string): string {
|
|
66
|
+
return `${toTwilioWebSocketBaseUrl(baseUrl)}${TWILIO_RELAY_WEBHOOK_PATH}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function buildTwilioMediaStreamUrl(baseUrl: string): string {
|
|
70
|
+
return `${toTwilioWebSocketBaseUrl(baseUrl)}${TWILIO_MEDIA_STREAM_WEBHOOK_PATH}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function buildTwilioPhoneNumberWebhookUrls(
|
|
74
|
+
baseUrl: string,
|
|
75
|
+
): TwilioPhoneNumberWebhookUrls {
|
|
76
|
+
return {
|
|
77
|
+
statusCallbackUrl: buildTwilioStatusWebhookUrl(baseUrl),
|
|
78
|
+
voiceUrl: buildTwilioVoiceWebhookUrl(baseUrl),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function toTwilioWebSocketBaseUrl(baseUrl: string): string {
|
|
83
|
+
return baseUrl.replace(/^http(s?)/, "ws$1");
|
|
84
|
+
}
|
|
@@ -4,8 +4,6 @@ import {
|
|
|
4
4
|
buildSlackUserLabelMap,
|
|
5
5
|
extractSlackUserMentionIds,
|
|
6
6
|
renderSlackTextForModel,
|
|
7
|
-
stripLeadingSlackMentionFallback,
|
|
8
|
-
stripLeadingSlackUserMention,
|
|
9
7
|
} from "./index.js";
|
|
10
8
|
|
|
11
9
|
describe("extractSlackUserMentionIds", () => {
|
|
@@ -16,34 +14,6 @@ describe("extractSlackUserMentionIds", () => {
|
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
|
|
19
|
-
describe("stripLeadingSlackUserMention", () => {
|
|
20
|
-
test("strips only leading mentions for the exact bot ID", () => {
|
|
21
|
-
expect(stripLeadingSlackUserMention("<@U111> <@U222> hi", "U111")).toBe(
|
|
22
|
-
"<@U222> hi"
|
|
23
|
-
);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("strips repeated leading mentions for the exact bot ID", () => {
|
|
27
|
-
expect(stripLeadingSlackUserMention(" <@U111> <@U111> hi", "U111")).toBe(
|
|
28
|
-
"hi"
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("preserves text when the leading mention is a different user", () => {
|
|
33
|
-
expect(stripLeadingSlackUserMention("<@U222> hi <@U111>", "U111")).toBe(
|
|
34
|
-
"<@U222> hi <@U111>"
|
|
35
|
-
);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("stripLeadingSlackMentionFallback", () => {
|
|
40
|
-
test("strips only the first leading Slack user mention", () => {
|
|
41
|
-
expect(stripLeadingSlackMentionFallback(" <@U111> <@U222> hi")).toBe(
|
|
42
|
-
"<@U222> hi"
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
17
|
describe("renderSlackTextForModel", () => {
|
|
48
18
|
test("renders resolved user mentions", () => {
|
|
49
19
|
expect(
|
|
@@ -123,19 +93,32 @@ describe("renderSlackTextForModel", () => {
|
|
|
123
93
|
});
|
|
124
94
|
|
|
125
95
|
describe("buildSlackUserLabelMap", () => {
|
|
126
|
-
test("dedupes mentioned users across text inputs and
|
|
96
|
+
test("dedupes mentioned users across text inputs and resolves them in parallel", async () => {
|
|
127
97
|
const resolved: string[] = [];
|
|
128
98
|
const labels = await buildSlackUserLabelMap(
|
|
129
99
|
["<@U123> hi <@U999>", undefined, "<@U123> and <@W456>"],
|
|
130
100
|
async (userId) => {
|
|
131
101
|
resolved.push(userId);
|
|
102
|
+
if (userId === "U999") return "Charlie";
|
|
132
103
|
return userId === "W456" ? "Bob" : "Alice";
|
|
133
|
-
}
|
|
134
|
-
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(resolved.sort()).toEqual(["U123", "U999", "W456"]);
|
|
108
|
+
expect(labels).toEqual({ U123: "Alice", U999: "Charlie", W456: "Bob" });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("resolves bot and human user mentions together", async () => {
|
|
112
|
+
const labels = await buildSlackUserLabelMap(
|
|
113
|
+
["<@UBOT> can you help <@ULEO> with the deploy?"],
|
|
114
|
+
async (userId) => {
|
|
115
|
+
if (userId === "UBOT") return "vex";
|
|
116
|
+
if (userId === "ULEO") return "leo";
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
135
119
|
);
|
|
136
120
|
|
|
137
|
-
expect(
|
|
138
|
-
expect(labels).toEqual({ U123: "Alice", W456: "Bob" });
|
|
121
|
+
expect(labels).toEqual({ UBOT: "vex", ULEO: "leo" });
|
|
139
122
|
});
|
|
140
123
|
|
|
141
124
|
test("omits unresolved labels and labels equal to the Slack user ID", async () => {
|