@vellumai/assistant 0.3.5 → 0.3.7
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/README.md +51 -0
- package/eslint.config.mjs +31 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
- package/scripts/ipc/generate-swift.ts +18 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-orchestrator.test.ts +752 -271
- package/src/__tests__/call-pointer-messages.test.ts +148 -0
- package/src/__tests__/call-recovery.test.ts +3 -0
- package/src/__tests__/call-routes-http.test.ts +5 -0
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1260 -85
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +4 -65
- package/src/__tests__/channel-guardian.test.ts +556 -0
- package/src/__tests__/channel-readiness-service.test.ts +74 -7
- package/src/__tests__/checker.test.ts +14 -7
- package/src/__tests__/clarification-resolver.test.ts +44 -24
- package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
- package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
- package/src/__tests__/config-schema.test.ts +12 -7
- package/src/__tests__/context-window-manager.test.ts +30 -2
- package/src/__tests__/contradiction-checker.test.ts +20 -5
- package/src/__tests__/credential-security-invariants.test.ts +6 -2
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/fuzzy-match-property.test.ts +5 -5
- package/src/__tests__/guardian-action-store.test.ts +123 -0
- package/src/__tests__/guardian-action-sweep.test.ts +277 -0
- package/src/__tests__/guardian-dispatch.test.ts +389 -0
- package/src/__tests__/guardian-question-copy.test.ts +47 -0
- package/src/__tests__/handlers-telegram-config.test.ts +4 -2
- package/src/__tests__/handlers-twilio-config.test.ts +126 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +228 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/model-intents.test.ts +96 -0
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
- package/src/__tests__/provider-error-scenarios.test.ts +621 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
- package/src/__tests__/qdrant-manager.test.ts +27 -20
- package/src/__tests__/relay-server.test.ts +779 -40
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
- package/src/__tests__/run-orchestrator.test.ts +20 -4
- package/src/__tests__/runtime-runs-http.test.ts +17 -1
- package/src/__tests__/runtime-runs.test.ts +16 -0
- package/src/__tests__/schedule-store.test.ts +18 -4
- package/src/__tests__/scheduler-recurrence.test.ts +13 -4
- package/src/__tests__/session-abort-tool-results.test.ts +6 -0
- package/src/__tests__/session-agent-loop.test.ts +857 -0
- package/src/__tests__/session-conflict-gate.test.ts +6 -0
- package/src/__tests__/session-pre-run-repair.test.ts +6 -0
- package/src/__tests__/session-profile-injection.test.ts +6 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/session-queue.test.ts +6 -0
- package/src/__tests__/session-runtime-assembly.test.ts +237 -13
- package/src/__tests__/session-slash-known.test.ts +6 -0
- package/src/__tests__/session-slash-queue.test.ts +6 -0
- package/src/__tests__/session-slash-unknown.test.ts +6 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/session-workspace-injection.test.ts +6 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/skills.test.ts +2 -0
- package/src/__tests__/sms-messaging-provider.test.ts +2 -1
- package/src/__tests__/starter-task-flow.test.ts +2 -0
- package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +2 -0
- package/src/__tests__/task-management-tools.test.ts +2 -2
- package/src/__tests__/task-runner.test.ts +14 -4
- package/src/__tests__/terminal-tools.test.ts +25 -19
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
- package/src/__tests__/tool-executor.test.ts +23 -24
- package/src/__tests__/trust-store.test.ts +3 -3
- package/src/__tests__/twilio-rest.test.ts +29 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
- package/src/__tests__/twilio-routes.test.ts +141 -21
- package/src/__tests__/user-reference.test.ts +2 -0
- package/src/__tests__/voice-quality.test.ts +222 -0
- package/src/__tests__/web-search.test.ts +45 -29
- package/src/agent/loop.ts +1 -1
- package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
- package/src/amazon/client.ts +1418 -0
- package/src/amazon/request-extractor.ts +135 -0
- package/src/amazon/session.ts +109 -0
- package/src/autonomy/autonomy-store.ts +5 -5
- package/src/browser-extension-relay/client.ts +124 -0
- package/src/browser-extension-relay/protocol.ts +63 -0
- package/src/browser-extension-relay/server.ts +177 -0
- package/src/bundler/app-bundler.ts +3 -3
- package/src/bundler/bundle-signer.ts +1 -1
- package/src/bundler/signature-verifier.ts +1 -1
- package/src/calls/call-conversation-messages.ts +33 -0
- package/src/calls/call-domain.ts +106 -5
- package/src/calls/call-orchestrator.ts +252 -54
- package/src/calls/call-pointer-messages.ts +53 -0
- package/src/calls/call-recovery.ts +3 -8
- package/src/calls/call-store.ts +69 -87
- package/src/calls/elevenlabs-config.ts +3 -2
- package/src/calls/guardian-action-sweep.ts +105 -0
- package/src/calls/guardian-dispatch.ts +203 -0
- package/src/calls/guardian-question-copy.ts +133 -0
- package/src/calls/relay-server.ts +466 -8
- package/src/calls/speaker-identification.ts +1 -1
- package/src/calls/twilio-config.ts +7 -5
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +40 -15
- package/src/calls/twilio-routes.ts +60 -45
- package/src/calls/types.ts +3 -1
- package/src/channels/types.ts +25 -0
- package/src/cli/amazon.ts +815 -0
- package/src/cli/config-commands.ts +2 -2
- package/src/cli/core-commands.ts +4 -3
- package/src/cli/influencer.ts +244 -0
- package/src/cli/map.ts +89 -6
- package/src/cli.ts +1 -1
- package/src/config/agent-schema.ts +171 -0
- package/src/config/bundled-skills/amazon/SKILL.md +127 -0
- package/src/config/bundled-skills/amazon/icon.svg +13 -0
- package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
- package/src/config/bundled-skills/browser/SKILL.md +1 -0
- package/src/config/bundled-skills/browser/TOOLS.json +17 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
- package/src/config/bundled-skills/doordash/SKILL.md +51 -51
- package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
- package/src/config/bundled-skills/influencer/SKILL.md +144 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
- package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
- package/src/config/bundled-skills/messaging/SKILL.md +12 -2
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
- package/src/config/bundled-skills/twitter/icon.svg +14 -0
- package/src/config/bundled-tool-registry.ts +310 -0
- package/src/config/calls-schema.ts +181 -0
- package/src/config/core-schema.ts +309 -0
- package/src/config/defaults.ts +27 -3
- package/src/config/env-registry.ts +169 -0
- package/src/config/env.ts +175 -0
- package/src/config/loader.ts +6 -6
- package/src/config/memory-schema.ts +528 -0
- package/src/config/sandbox-schema.ts +55 -0
- package/src/config/schema.ts +157 -1138
- package/src/config/skill-state.ts +1 -1
- package/src/config/skills-schema.ts +32 -0
- package/src/config/skills.ts +35 -24
- package/src/config/system-prompt.ts +107 -56
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +1 -0
- package/src/config/user-reference.ts +4 -9
- package/src/config/vellum-skills/catalog.json +0 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
- package/src/context/window-manager.ts +27 -7
- package/src/daemon/approval-generators.ts +186 -0
- package/src/daemon/approved-devices-store.ts +140 -0
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/classifier.ts +35 -32
- package/src/daemon/config-watcher.ts +1 -1
- package/src/daemon/daemon-control.ts +254 -0
- package/src/daemon/handlers/apps.ts +2 -3
- package/src/daemon/handlers/config-channels.ts +158 -0
- package/src/daemon/handlers/config-inbox.ts +540 -0
- package/src/daemon/handlers/config-ingress.ts +231 -0
- package/src/daemon/handlers/config-integrations.ts +258 -0
- package/src/daemon/handlers/config-model.ts +143 -0
- package/src/daemon/handlers/config-parental.ts +163 -0
- package/src/daemon/handlers/config-scheduling.ts +172 -0
- package/src/daemon/handlers/config-slack.ts +92 -0
- package/src/daemon/handlers/config-telegram.ts +301 -0
- package/src/daemon/handlers/config-tools.ts +177 -0
- package/src/daemon/handlers/config-trust.ts +104 -0
- package/src/daemon/handlers/config-twilio.ts +1080 -0
- package/src/daemon/handlers/config.ts +53 -2463
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +4 -6
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/index.ts +9 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +74 -5
- package/src/daemon/handlers/shared.ts +3 -1
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/handlers/twitter-auth.ts +2 -0
- package/src/daemon/handlers/work-items.ts +2 -2
- package/src/daemon/handlers/workspace-files.ts +4 -3
- package/src/daemon/install-cli-launchers.ts +113 -0
- package/src/daemon/ipc-contract/apps.ts +356 -0
- package/src/daemon/ipc-contract/browser.ts +74 -0
- package/src/daemon/ipc-contract/computer-use.ts +151 -0
- package/src/daemon/ipc-contract/diagnostics.ts +56 -0
- package/src/daemon/ipc-contract/documents.ts +74 -0
- package/src/daemon/ipc-contract/inbox.ts +209 -0
- package/src/daemon/ipc-contract/integrations.ts +284 -0
- package/src/daemon/ipc-contract/memory.ts +48 -0
- package/src/daemon/ipc-contract/messages.ts +211 -0
- package/src/daemon/ipc-contract/pairing.ts +45 -0
- package/src/daemon/ipc-contract/parental-control.ts +95 -0
- package/src/daemon/ipc-contract/schedules.ts +97 -0
- package/src/daemon/ipc-contract/sessions.ts +321 -0
- package/src/daemon/ipc-contract/shared.ts +42 -0
- package/src/daemon/ipc-contract/skills.ts +120 -0
- package/src/daemon/ipc-contract/subagents.ts +58 -0
- package/src/daemon/ipc-contract/surfaces.ts +250 -0
- package/src/daemon/ipc-contract/trust.ts +60 -0
- package/src/daemon/ipc-contract/work-items.ts +225 -0
- package/src/daemon/ipc-contract/workspace.ts +113 -0
- package/src/daemon/ipc-contract-inventory.json +62 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +227 -2527
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -379
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +67 -2
- package/src/daemon/server.ts +60 -44
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +113 -275
- package/src/daemon/session-dynamic-profile.ts +1 -1
- package/src/daemon/session-history.ts +1 -1
- package/src/daemon/session-media-retry.ts +1 -1
- package/src/daemon/session-messaging.ts +37 -2
- package/src/daemon/session-notifiers.ts +5 -25
- package/src/daemon/session-process.ts +99 -59
- package/src/daemon/session-queue-manager.ts +98 -4
- package/src/daemon/session-runtime-assembly.ts +149 -15
- package/src/daemon/session-surfaces.ts +26 -4
- package/src/daemon/session-tool-setup.ts +28 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +24 -1
- package/src/daemon/shutdown-handlers.ts +122 -0
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/watch-handler.ts +36 -33
- package/src/doordash/cart-queries.ts +787 -0
- package/src/doordash/client.ts +144 -127
- package/src/doordash/order-queries.ts +85 -0
- package/src/doordash/queries.ts +10 -1308
- package/src/doordash/search-queries.ts +203 -0
- package/src/doordash/session.ts +3 -2
- package/src/doordash/store-queries.ts +246 -0
- package/src/doordash/types.ts +367 -0
- package/src/email/providers/agentmail.ts +2 -1
- package/src/email/providers/index.ts +3 -2
- package/src/email/service.ts +3 -2
- package/src/errors.ts +43 -0
- package/src/home-base/prebuilt/seed.ts +1 -1
- package/src/hooks/cli.ts +6 -5
- package/src/hooks/config.ts +6 -8
- package/src/hooks/discovery.ts +6 -5
- package/src/hooks/manager.ts +4 -3
- package/src/hooks/runner.ts +2 -2
- package/src/hooks/templates.ts +5 -5
- package/src/inbound/public-ingress-urls.ts +3 -1
- package/src/index.ts +4 -2
- package/src/influencer/client.ts +1104 -0
- package/src/instrument.ts +4 -3
- package/src/logfire.ts +4 -3
- package/src/memory/admin.ts +25 -35
- package/src/memory/attachments-store.ts +4 -7
- package/src/memory/channel-delivery-store.ts +30 -1
- package/src/memory/channel-guardian-store.ts +200 -1
- package/src/memory/clarification-resolver.ts +37 -33
- package/src/memory/conflict-store.ts +67 -61
- package/src/memory/contradiction-checker.ts +141 -117
- package/src/memory/conversation-store.ts +335 -51
- package/src/memory/db-connection.ts +27 -4
- package/src/memory/db-init.ts +121 -4
- package/src/memory/db.ts +14 -1
- package/src/memory/embedding-backend.ts +27 -5
- package/src/memory/embedding-ollama.ts +2 -1
- package/src/memory/entity-extractor.ts +38 -35
- package/src/memory/guardian-action-store.ts +430 -0
- package/src/memory/inbox-escalation-projection.ts +59 -0
- package/src/memory/inbox-thread-store.ts +218 -0
- package/src/memory/ingress-invite-store.ts +338 -0
- package/src/memory/ingress-member-store.ts +350 -0
- package/src/memory/items-extractor.ts +91 -97
- package/src/memory/job-handlers/index-maintenance.ts +3 -3
- package/src/memory/job-handlers/media-processing.ts +11 -42
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +6 -9
- package/src/memory/jobs-worker.ts +51 -36
- package/src/memory/migrations/001-job-deferrals.ts +45 -0
- package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
- package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
- package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
- package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
- package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
- package/src/memory/migrations/index.ts +24 -0
- package/src/memory/migrations/registry.ts +79 -0
- package/src/memory/migrations/validate-migration-state.ts +69 -0
- package/src/memory/qdrant-manager.ts +49 -8
- package/src/memory/query-builder.ts +1 -1
- package/src/memory/raw-query.ts +119 -0
- package/src/memory/recall-cache.ts +4 -1
- package/src/memory/retriever.ts +163 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +130 -7
- package/src/memory/search/entity.ts +10 -19
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +21 -22
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/shared-app-links-store.ts +4 -5
- package/src/memory/validation.ts +19 -0
- package/src/messaging/draft-store.ts +5 -6
- package/src/messaging/providers/sms/adapter.ts +3 -6
- package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
- package/src/messaging/providers/whatsapp/adapter.ts +136 -0
- package/src/messaging/providers/whatsapp/client.ts +67 -0
- package/src/messaging/style-analyzer.ts +5 -4
- package/src/messaging/thread-summarizer.ts +61 -69
- package/src/messaging/triage-engine.ts +62 -71
- package/src/migrations/config-merge.ts +53 -0
- package/src/migrations/data-layout.ts +68 -0
- package/src/migrations/data-merge.ts +33 -0
- package/src/migrations/hooks-merge.ts +90 -0
- package/src/migrations/index.ts +6 -0
- package/src/migrations/log.ts +23 -0
- package/src/migrations/skills-merge.ts +33 -0
- package/src/migrations/workspace-layout.ts +79 -0
- package/src/permissions/checker.ts +126 -11
- package/src/permissions/prompter.ts +14 -0
- package/src/permissions/shell-identity.ts +31 -1
- package/src/permissions/trust-store.ts +21 -1
- package/src/providers/anthropic/client.ts +4 -4
- package/src/providers/failover.ts +2 -2
- package/src/providers/model-intents.ts +70 -0
- package/src/providers/ollama/client.ts +2 -1
- package/src/providers/provider-send-message.ts +176 -0
- package/src/providers/registry.ts +71 -30
- package/src/providers/retry.ts +35 -1
- package/src/providers/types.ts +12 -1
- package/src/runtime/approval-conversation-turn.ts +97 -0
- package/src/runtime/approval-message-composer.ts +115 -5
- package/src/runtime/assistant-event-hub.ts +3 -1
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +0 -21
- package/src/runtime/channel-guardian-service.ts +48 -7
- package/src/runtime/channel-readiness-service.ts +160 -34
- package/src/runtime/channel-readiness-types.ts +10 -4
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +289 -745
- package/src/runtime/http-types.ts +56 -3
- package/src/runtime/middleware/auth.ts +116 -0
- package/src/runtime/middleware/error-handler.ts +33 -0
- package/src/runtime/middleware/twilio-validation.ts +127 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/call-routes.ts +49 -6
- package/src/runtime/routes/channel-delivery-routes.ts +170 -0
- package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
- package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
- package/src/runtime/routes/channel-route-shared.ts +144 -0
- package/src/runtime/routes/channel-routes.ts +32 -1634
- package/src/runtime/routes/conversation-routes.ts +50 -7
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +126 -0
- package/src/runtime/routes/pairing-routes.ts +144 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +52 -34
- package/src/schedule/schedule-store.ts +36 -32
- package/src/schedule/scheduler.ts +3 -3
- package/src/security/encrypted-store.ts +5 -7
- package/src/security/oauth2.ts +45 -15
- package/src/security/parental-control-store.ts +183 -0
- package/src/security/secret-allowlist.ts +4 -3
- package/src/security/secret-scanner.ts +5 -5
- package/src/security/secure-keys.ts +1 -1
- package/src/security/token-manager.ts +3 -2
- package/src/services/vercel-deploy.ts +6 -2
- package/src/skills/tool-manifest.ts +3 -3
- package/src/skills/vellum-catalog-remote.ts +75 -16
- package/src/slack/slack-webhook.ts +2 -1
- package/src/swarm/orchestrator.ts +92 -1
- package/src/swarm/router-planner.ts +6 -9
- package/src/swarm/worker-prompts.ts +9 -12
- package/src/tasks/task-compiler.ts +19 -28
- package/src/tasks/task-runner.ts +1 -1
- package/src/tools/assets/search.ts +15 -14
- package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
- package/src/tools/browser/auto-navigate.ts +1 -0
- package/src/tools/browser/browser-execution.ts +13 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -0
- package/src/tools/credentials/broker.ts +11 -2
- package/src/tools/credentials/metadata-store.ts +18 -14
- package/src/tools/credentials/post-connect-hooks.ts +61 -0
- package/src/tools/credentials/vault.ts +49 -23
- package/src/tools/executor.ts +80 -18
- package/src/tools/host-terminal/cli-discover.ts +1 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
- package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
- package/src/tools/network/script-proxy/server.ts +1 -1
- package/src/tools/network/script-proxy/session-manager.ts +6 -5
- package/src/tools/network/web-fetch.ts +18 -2
- package/src/tools/network/web-search.ts +7 -3
- package/src/tools/reminder/reminder-store.ts +14 -15
- package/src/tools/schedule/create.ts +1 -0
- package/src/tools/schedule/list.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
- package/src/tools/skills/skill-script-runner.ts +24 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/tasks/work-item-enqueue.ts +2 -2
- package/src/tools/terminal/evaluate-typescript.ts +21 -12
- package/src/tools/terminal/parser.ts +50 -0
- package/src/tools/watcher/delete.ts +6 -0
- package/src/tools/weather/service.ts +1 -1
- package/src/twitter/client.ts +190 -24
- package/src/twitter/session.ts +4 -3
- package/src/util/clipboard.ts +1 -1
- package/src/util/errors.ts +65 -8
- package/src/util/fs.ts +40 -0
- package/src/util/json.ts +10 -0
- package/src/util/log-redact.ts +189 -0
- package/src/util/logger.ts +25 -18
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +72 -365
- package/src/util/pricing.ts +1 -1
- package/src/util/promise-guard.ts +1 -1
- package/src/util/retry.ts +19 -0
- package/src/util/row-mapper.ts +79 -0
- package/src/util/silently.ts +21 -0
- package/src/watcher/engine.ts +5 -1
- package/src/watcher/provider-types.ts +20 -0
- package/src/watcher/providers/github.ts +156 -0
- package/src/watcher/providers/gmail.ts +1 -0
- package/src/watcher/providers/google-calendar.ts +1 -0
- package/src/watcher/providers/linear.ts +460 -0
- package/src/watcher/providers/slack.ts +1 -0
- package/src/work-items/work-item-runner.ts +1 -1
- package/src/workspace/git-service.ts +1 -1
- package/src/workspace/provider-commit-message-generator.ts +51 -22
- package/src/__tests__/call-bridge.test.ts +0 -517
- package/src/__tests__/session-process-bridge.test.ts +0 -244
- package/src/calls/call-bridge.ts +0 -168
- package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
- package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
- package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
- package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
- package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
- package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
- package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
- package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
- package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
- package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
package/src/calls/twilio-rest.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { getSecureKey } from '../security/secure-keys.js';
|
|
10
|
+
import { ProviderError, ConfigError } from '../util/errors.js';
|
|
10
11
|
|
|
11
12
|
export interface TwilioCredentials {
|
|
12
13
|
accountSid: string;
|
|
@@ -18,7 +19,7 @@ export function getTwilioCredentials(): TwilioCredentials {
|
|
|
18
19
|
const accountSid = getSecureKey('credential:twilio:account_sid');
|
|
19
20
|
const authToken = getSecureKey('credential:twilio:auth_token');
|
|
20
21
|
if (!accountSid || !authToken) {
|
|
21
|
-
throw new
|
|
22
|
+
throw new ConfigError(
|
|
22
23
|
'Twilio credentials not configured. Set credential:twilio:account_sid and credential:twilio:auth_token via the credential_store tool.',
|
|
23
24
|
);
|
|
24
25
|
}
|
|
@@ -58,7 +59,7 @@ export async function listIncomingPhoneNumbers(
|
|
|
58
59
|
|
|
59
60
|
if (!res.ok) {
|
|
60
61
|
const text = await res.text();
|
|
61
|
-
throw new
|
|
62
|
+
throw new ProviderError(`Twilio API error ${res.status}: ${text}`, 'twilio', res.status);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
const data = (await res.json()) as {
|
|
@@ -102,7 +103,7 @@ export async function searchAvailableNumbers(
|
|
|
102
103
|
|
|
103
104
|
if (!res.ok) {
|
|
104
105
|
const text = await res.text();
|
|
105
|
-
throw new
|
|
106
|
+
throw new ProviderError(`Twilio API error ${res.status}: ${text}`, 'twilio', res.status);
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
const data = (await res.json()) as {
|
|
@@ -139,7 +140,7 @@ export async function provisionPhoneNumber(
|
|
|
139
140
|
|
|
140
141
|
if (!res.ok) {
|
|
141
142
|
const text = await res.text();
|
|
142
|
-
throw new
|
|
143
|
+
throw new ProviderError(`Twilio API error ${res.status}: ${text}`, 'twilio', res.status);
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
const data = (await res.json()) as {
|
|
@@ -171,7 +172,7 @@ export async function fetchMessageStatus(
|
|
|
171
172
|
|
|
172
173
|
if (!res.ok) {
|
|
173
174
|
const text = await res.text();
|
|
174
|
-
throw new
|
|
175
|
+
throw new ProviderError(`Twilio API error ${res.status}: ${text}`, 'twilio', res.status);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
const data = (await res.json()) as {
|
|
@@ -217,7 +218,7 @@ export async function updatePhoneNumberWebhooks(
|
|
|
217
218
|
|
|
218
219
|
if (!listRes.ok) {
|
|
219
220
|
const text = await listRes.text();
|
|
220
|
-
throw new
|
|
221
|
+
throw new ProviderError(`Twilio API error ${listRes.status} looking up phone number: ${text}`, 'twilio', listRes.status);
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
const listData = (await listRes.json()) as {
|
|
@@ -226,7 +227,7 @@ export async function updatePhoneNumberWebhooks(
|
|
|
226
227
|
|
|
227
228
|
const match = listData.incoming_phone_numbers.find((n) => n.phone_number === phoneNumber);
|
|
228
229
|
if (!match) {
|
|
229
|
-
throw new
|
|
230
|
+
throw new ProviderError(`Phone number ${phoneNumber} not found on Twilio account ${accountSid}`, 'twilio');
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
// Update the phone number's webhook configuration
|
|
@@ -253,7 +254,7 @@ export async function updatePhoneNumberWebhooks(
|
|
|
253
254
|
|
|
254
255
|
if (!updateRes.ok) {
|
|
255
256
|
const text = await updateRes.text();
|
|
256
|
-
throw new
|
|
257
|
+
throw new ProviderError(`Twilio API error ${updateRes.status} updating webhooks: ${text}`, 'twilio', updateRes.status);
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
|
|
@@ -310,7 +311,7 @@ export async function getTollFreeVerificationStatus(
|
|
|
310
311
|
|
|
311
312
|
if (!res.ok) {
|
|
312
313
|
const text = await res.text();
|
|
313
|
-
throw new
|
|
314
|
+
throw new ProviderError(`Twilio Toll-Free Verification API error ${res.status}: ${text}`, 'twilio', res.status);
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
const data = (await res.json()) as { verifications?: Array<Record<string, unknown>> };
|
|
@@ -320,6 +321,30 @@ export async function getTollFreeVerificationStatus(
|
|
|
320
321
|
return parseTollFreeVerification(verifications[0]);
|
|
321
322
|
}
|
|
322
323
|
|
|
324
|
+
/** Fetch a specific toll-free verification by SID. */
|
|
325
|
+
export async function getTollFreeVerificationBySid(
|
|
326
|
+
accountSid: string,
|
|
327
|
+
authToken: string,
|
|
328
|
+
verificationSid: string,
|
|
329
|
+
): Promise<TollFreeVerification | null> {
|
|
330
|
+
const res = await fetch(`${TOLLFREE_VERIFICATION_BASE}/${encodeURIComponent(verificationSid)}`, {
|
|
331
|
+
method: 'GET',
|
|
332
|
+
headers: { Authorization: twilioAuthHeader(accountSid, authToken) },
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
if (res.status === 404) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!res.ok) {
|
|
340
|
+
const text = await res.text();
|
|
341
|
+
throw new ProviderError(`Twilio Toll-Free Verification fetch error ${res.status}: ${text}`, 'twilio', res.status);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const data = (await res.json()) as Record<string, unknown>;
|
|
345
|
+
return parseTollFreeVerification(data);
|
|
346
|
+
}
|
|
347
|
+
|
|
323
348
|
export interface TollFreeVerificationSubmitParams {
|
|
324
349
|
tollfreePhoneNumberSid: string;
|
|
325
350
|
businessName: string;
|
|
@@ -373,7 +398,7 @@ export async function submitTollFreeVerification(
|
|
|
373
398
|
|
|
374
399
|
if (!res.ok) {
|
|
375
400
|
const text = await res.text();
|
|
376
|
-
throw new
|
|
401
|
+
throw new ProviderError(`Twilio Toll-Free Verification submit error ${res.status}: ${text}`, 'twilio', res.status);
|
|
377
402
|
}
|
|
378
403
|
|
|
379
404
|
const data = (await res.json()) as Record<string, unknown>;
|
|
@@ -419,7 +444,7 @@ export async function updateTollFreeVerification(
|
|
|
419
444
|
|
|
420
445
|
if (!res.ok) {
|
|
421
446
|
const text = await res.text();
|
|
422
|
-
throw new
|
|
447
|
+
throw new ProviderError(`Twilio Toll-Free Verification update error ${res.status}: ${text}`, 'twilio', res.status);
|
|
423
448
|
}
|
|
424
449
|
|
|
425
450
|
const data = (await res.json()) as Record<string, unknown>;
|
|
@@ -439,7 +464,7 @@ export async function deleteTollFreeVerification(
|
|
|
439
464
|
|
|
440
465
|
if (!res.ok) {
|
|
441
466
|
const text = await res.text();
|
|
442
|
-
throw new
|
|
467
|
+
throw new ProviderError(`Twilio Toll-Free Verification delete error ${res.status}: ${text}`, 'twilio', res.status);
|
|
443
468
|
}
|
|
444
469
|
}
|
|
445
470
|
|
|
@@ -462,7 +487,7 @@ export async function getPhoneNumberSid(
|
|
|
462
487
|
|
|
463
488
|
if (!res.ok) {
|
|
464
489
|
const text = await res.text();
|
|
465
|
-
throw new
|
|
490
|
+
throw new ProviderError(`Twilio API error ${res.status} looking up phone number SID: ${text}`, 'twilio', res.status);
|
|
466
491
|
}
|
|
467
492
|
|
|
468
493
|
const data = (await res.json()) as {
|
|
@@ -484,7 +509,7 @@ export async function releasePhoneNumber(
|
|
|
484
509
|
): Promise<void> {
|
|
485
510
|
const sid = await getPhoneNumberSid(accountSid, authToken, phoneNumber);
|
|
486
511
|
if (!sid) {
|
|
487
|
-
throw new
|
|
512
|
+
throw new ProviderError(`Phone number ${phoneNumber} not found on Twilio account ${accountSid}`, 'twilio');
|
|
488
513
|
}
|
|
489
514
|
|
|
490
515
|
const res = await fetch(
|
|
@@ -497,6 +522,6 @@ export async function releasePhoneNumber(
|
|
|
497
522
|
|
|
498
523
|
if (!res.ok) {
|
|
499
524
|
const text = await res.text();
|
|
500
|
-
throw new
|
|
525
|
+
throw new ProviderError(`Twilio API error ${res.status} releasing phone number: ${text}`, 'twilio', res.status);
|
|
501
526
|
}
|
|
502
527
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { getLogger } from '../util/logger.js';
|
|
10
|
+
import { getCallWelcomeGreeting } from '../config/env.js';
|
|
10
11
|
import {
|
|
11
12
|
getCallSession,
|
|
12
13
|
getCallSessionByCallSid,
|
|
@@ -25,14 +26,12 @@ import { getTwilioConfig } from './twilio-config.js';
|
|
|
25
26
|
import { loadConfig } from '../config/loader.js';
|
|
26
27
|
import { getTwilioRelayUrl } from '../inbound/public-ingress-urls.js';
|
|
27
28
|
import { fireCallCompletionNotifier } from './call-state.js';
|
|
29
|
+
import { persistCallCompletionMessage } from './call-conversation-messages.js';
|
|
28
30
|
import { resolveVoiceQualityProfile, isVoiceProfileValid } from './voice-quality.js';
|
|
31
|
+
import { createInboundVoiceSession } from './call-domain.js';
|
|
29
32
|
|
|
30
33
|
const log = getLogger('twilio-routes');
|
|
31
34
|
|
|
32
|
-
const CONTEXT_BLOCK_SPLIT_REGEX = /\n\s*\nContext:\s*/i;
|
|
33
|
-
const MAX_TASK_SUMMARY_CHARS = 120;
|
|
34
|
-
const DEFAULT_WELCOME_GREETING = 'Hello, this is an assistant calling. Is now a good time to talk?';
|
|
35
|
-
|
|
36
35
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
37
36
|
|
|
38
37
|
function escapeXml(str: string): string {
|
|
@@ -47,15 +46,18 @@ function escapeXml(str: string): string {
|
|
|
47
46
|
export function generateTwiML(
|
|
48
47
|
callSessionId: string,
|
|
49
48
|
relayUrl: string,
|
|
50
|
-
welcomeGreeting: string,
|
|
49
|
+
welcomeGreeting: string | null,
|
|
51
50
|
profile: { language: string; transcriptionProvider: string; ttsProvider: string; voice: string },
|
|
52
51
|
): string {
|
|
52
|
+
const greetingAttr = welcomeGreeting && welcomeGreeting.trim().length > 0
|
|
53
|
+
? `\n welcomeGreeting="${escapeXml(welcomeGreeting.trim())}"`
|
|
54
|
+
: '';
|
|
53
55
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
54
56
|
<Response>
|
|
55
57
|
<Connect>
|
|
56
58
|
<ConversationRelay
|
|
57
59
|
url="${escapeXml(relayUrl)}?callSessionId=${escapeXml(callSessionId)}"
|
|
58
|
-
|
|
60
|
+
${greetingAttr}
|
|
59
61
|
voice="${escapeXml(profile.voice)}"
|
|
60
62
|
language="${escapeXml(profile.language)}"
|
|
61
63
|
transcriptionProvider="${escapeXml(profile.transcriptionProvider)}"
|
|
@@ -67,38 +69,14 @@ export function generateTwiML(
|
|
|
67
69
|
</Response>`;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
function summarizeTaskForGreeting(task: string | null): string | null {
|
|
71
|
-
if (!task) return null;
|
|
72
|
-
const primaryTask = task.split(CONTEXT_BLOCK_SPLIT_REGEX)[0]?.trim() ?? '';
|
|
73
|
-
if (!primaryTask) return null;
|
|
74
|
-
|
|
75
|
-
const compact = primaryTask.replace(/\s+/g, ' ').trim().replace(/[.!?]+$/, '');
|
|
76
|
-
if (!compact) return null;
|
|
77
|
-
if (compact.length <= MAX_TASK_SUMMARY_CHARS) return compact;
|
|
78
|
-
return `${compact.slice(0, MAX_TASK_SUMMARY_CHARS - 3).trimEnd()}...`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function formatTaskAsCallPurpose(taskSummary: string): string {
|
|
82
|
-
const lower = taskSummary.toLowerCase();
|
|
83
|
-
if (
|
|
84
|
-
lower.startsWith('about ') ||
|
|
85
|
-
lower.startsWith('to ') ||
|
|
86
|
-
lower.startsWith('for ') ||
|
|
87
|
-
lower.startsWith('regarding ')
|
|
88
|
-
) {
|
|
89
|
-
return taskSummary;
|
|
90
|
-
}
|
|
91
|
-
return `about ${taskSummary}`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
72
|
export function buildWelcomeGreeting(task: string | null, configuredGreeting?: string): string {
|
|
73
|
+
void task;
|
|
95
74
|
const override = configuredGreeting?.trim();
|
|
96
75
|
if (override) return override;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return `Hello, I am calling ${formatTaskAsCallPurpose(taskSummary)}. Is now a good time to talk?`;
|
|
76
|
+
// The contextual first opener now comes from the call orchestrator's
|
|
77
|
+
// initial LLM turn. Keep Twilio's relay-level greeting empty by default
|
|
78
|
+
// so we don't speak a deterministic static line first.
|
|
79
|
+
return '';
|
|
102
80
|
}
|
|
103
81
|
|
|
104
82
|
/**
|
|
@@ -144,16 +122,43 @@ function mapTwilioStatus(twilioStatus: string): CallStatus | null {
|
|
|
144
122
|
/**
|
|
145
123
|
* Receives the initial voice webhook when Twilio connects the call.
|
|
146
124
|
* Returns TwiML XML that tells Twilio to open a ConversationRelay WebSocket.
|
|
125
|
+
*
|
|
126
|
+
* Supports two modes:
|
|
127
|
+
* - **Outbound** (callSessionId present in query): uses the existing session
|
|
128
|
+
* - **Inbound** (callSessionId absent): creates or reuses a session keyed
|
|
129
|
+
* by the Twilio CallSid. The optional `forwardedAssistantId` is resolved
|
|
130
|
+
* by the gateway from the "To" phone number.
|
|
147
131
|
*/
|
|
148
|
-
export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
132
|
+
export async function handleVoiceWebhook(req: Request, forwardedAssistantId?: string): Promise<Response> {
|
|
149
133
|
const url = new URL(req.url);
|
|
150
134
|
const callSessionId = url.searchParams.get('callSessionId');
|
|
151
135
|
|
|
136
|
+
// Parse the Twilio POST body to capture CallSid and caller metadata.
|
|
137
|
+
const formBody = new URLSearchParams(await req.text());
|
|
138
|
+
const callSid = formBody.get('CallSid');
|
|
139
|
+
const callerFrom = formBody.get('From') ?? '';
|
|
140
|
+
const callerTo = formBody.get('To') ?? '';
|
|
141
|
+
|
|
142
|
+
// ── Inbound mode: no callSessionId in query ─────────────────────
|
|
152
143
|
if (!callSessionId) {
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
if (!callSid) {
|
|
145
|
+
log.warn('Inbound voice webhook called without CallSid');
|
|
146
|
+
return new Response('Missing CallSid', { status: 400 });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
log.info({ callSid, from: callerFrom, to: callerTo, assistantId: forwardedAssistantId }, 'Inbound voice webhook — creating/reusing session');
|
|
150
|
+
|
|
151
|
+
const { session } = createInboundVoiceSession({
|
|
152
|
+
callSid,
|
|
153
|
+
fromNumber: callerFrom,
|
|
154
|
+
toNumber: callerTo,
|
|
155
|
+
assistantId: forwardedAssistantId,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return buildVoiceWebhookTwiml(session.id, session.assistantId ?? undefined, session.task);
|
|
155
159
|
}
|
|
156
160
|
|
|
161
|
+
// ── Outbound mode: callSessionId is present ─────────────────────
|
|
157
162
|
const session = getCallSession(callSessionId);
|
|
158
163
|
if (!session) {
|
|
159
164
|
log.warn({ callSessionId }, 'Voice webhook: call session not found');
|
|
@@ -165,16 +170,25 @@ export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
|
165
170
|
return new Response('Call session is no longer active', { status: 410 });
|
|
166
171
|
}
|
|
167
172
|
|
|
168
|
-
//
|
|
169
|
-
// callbacks (keyed by CallSid) can locate this session even if the
|
|
170
|
-
// WebSocket relay hasn't been set up yet.
|
|
171
|
-
const formBody = new URLSearchParams(await req.text());
|
|
172
|
-
const callSid = formBody.get('CallSid');
|
|
173
|
+
// Capture CallSid immediately so status callbacks can locate this session
|
|
173
174
|
if (callSid && callSid !== session.providerCallSid) {
|
|
174
175
|
updateCallSession(callSessionId, { providerCallSid: callSid });
|
|
175
176
|
log.info({ callSessionId, callSid }, 'Stored CallSid from voice webhook');
|
|
176
177
|
}
|
|
177
178
|
|
|
179
|
+
return buildVoiceWebhookTwiml(callSessionId, session.assistantId ?? undefined, session.task);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Shared TwiML generation for both inbound and outbound voice webhooks.
|
|
184
|
+
* Resolves voice quality profile, relay URL, and welcome greeting,
|
|
185
|
+
* then returns a Response with the generated TwiML.
|
|
186
|
+
*/
|
|
187
|
+
function buildVoiceWebhookTwiml(
|
|
188
|
+
callSessionId: string,
|
|
189
|
+
assistantId: string | undefined,
|
|
190
|
+
task: string | null,
|
|
191
|
+
): Response {
|
|
178
192
|
let profile = resolveVoiceQualityProfile(loadConfig());
|
|
179
193
|
|
|
180
194
|
log.info({ callSessionId, mode: profile.mode, ttsProvider: profile.ttsProvider, voice: profile.voice }, 'Voice quality profile resolved');
|
|
@@ -213,7 +227,7 @@ export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
|
213
227
|
});
|
|
214
228
|
}
|
|
215
229
|
|
|
216
|
-
const twilioConfig = getTwilioConfig();
|
|
230
|
+
const twilioConfig = getTwilioConfig(assistantId);
|
|
217
231
|
let relayUrl: string;
|
|
218
232
|
try {
|
|
219
233
|
relayUrl = getTwilioRelayUrl(loadConfig());
|
|
@@ -221,7 +235,7 @@ export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
|
221
235
|
// Fallback to legacy resolution when ingress is not configured
|
|
222
236
|
relayUrl = resolveRelayUrl(twilioConfig.wssBaseUrl, twilioConfig.webhookBaseUrl);
|
|
223
237
|
}
|
|
224
|
-
const welcomeGreeting = buildWelcomeGreeting(
|
|
238
|
+
const welcomeGreeting = buildWelcomeGreeting(task, getCallWelcomeGreeting());
|
|
225
239
|
|
|
226
240
|
const twiml = generateTwiML(callSessionId, relayUrl, welcomeGreeting, profile);
|
|
227
241
|
|
|
@@ -308,6 +322,7 @@ export async function handleStatusCallback(req: Request): Promise<Response> {
|
|
|
308
322
|
expirePendingQuestions(session.id);
|
|
309
323
|
|
|
310
324
|
if (!wasTerminal) {
|
|
325
|
+
persistCallCompletionMessage(session.conversationId, session.id);
|
|
311
326
|
fireCallCompletionNotifier(session.conversationId, session.id);
|
|
312
327
|
}
|
|
313
328
|
}
|
package/src/calls/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type CallStatus = 'initiated' | 'ringing' | 'in_progress' | 'waiting_on_user' | 'completed' | 'failed' | 'cancelled';
|
|
2
|
-
export type CallEventType = 'call_started' | 'call_connected' | 'caller_spoke' | 'assistant_spoke' | 'user_question_asked' | 'user_answered' | 'user_instruction_relayed' | 'call_ended' | 'call_failed';
|
|
2
|
+
export type CallEventType = 'call_started' | 'call_connected' | 'caller_spoke' | 'assistant_spoke' | 'user_question_asked' | 'user_answered' | 'user_instruction_relayed' | 'call_ended' | 'call_failed' | 'callee_verification_started' | 'callee_verification_succeeded' | 'callee_verification_failed' | 'guardian_voice_verification_started' | 'guardian_voice_verification_succeeded' | 'guardian_voice_verification_failed';
|
|
3
3
|
export type PendingQuestionStatus = 'pending' | 'answered' | 'expired' | 'cancelled';
|
|
4
4
|
|
|
5
5
|
export interface CallSession {
|
|
@@ -13,6 +13,8 @@ export interface CallSession {
|
|
|
13
13
|
status: CallStatus;
|
|
14
14
|
callerIdentityMode: string | null;
|
|
15
15
|
callerIdentitySource: string | null;
|
|
16
|
+
assistantId: string | null;
|
|
17
|
+
initiatedFromConversationId?: string | null;
|
|
16
18
|
startedAt: number | null;
|
|
17
19
|
endedAt: number | null;
|
|
18
20
|
lastError: string | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const CHANNEL_IDS = [
|
|
2
|
+
'telegram', 'sms', 'voice', 'macos', 'ios', 'whatsapp', 'slack', 'email',
|
|
3
|
+
] as const;
|
|
4
|
+
|
|
5
|
+
export type ChannelId = (typeof CHANNEL_IDS)[number];
|
|
6
|
+
|
|
7
|
+
export function isChannelId(value: unknown): value is ChannelId {
|
|
8
|
+
return typeof value === 'string' && (CHANNEL_IDS as readonly string[]).includes(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseChannelId(value: unknown): ChannelId | null {
|
|
12
|
+
return isChannelId(value) ? value : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function assertChannelId(value: unknown, field: string): ChannelId {
|
|
16
|
+
if (!isChannelId(value)) {
|
|
17
|
+
throw new Error(`Invalid channel ID for ${field}: ${String(value)}. Valid values: ${CHANNEL_IDS.join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TurnChannelContext {
|
|
23
|
+
userMessageChannel: ChannelId;
|
|
24
|
+
assistantMessageChannel: ChannelId;
|
|
25
|
+
}
|