@vellumai/assistant 0.3.4 → 0.3.6
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/Dockerfile +2 -0
- package/README.md +88 -2
- 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 +31 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
- package/src/__tests__/approval-message-composer.test.ts +253 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-domain.test.ts +12 -2
- package/src/__tests__/call-orchestrator.test.ts +799 -249
- 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 +32 -2
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1277 -98
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +36 -50
- package/src/__tests__/channel-guardian.test.ts +630 -22
- package/src/__tests__/channel-readiness-service.test.ts +324 -0
- 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 +14 -8
- 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 +7 -2
- package/src/__tests__/daemon-lifecycle.test.ts +13 -12
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dictation-mode-detection.test.ts +63 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/entity-search.test.ts +615 -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 +533 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +291 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/messaging-send-tool.test.ts +65 -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 +6 -0
- package/src/__tests__/run-orchestrator.test.ts +42 -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 +321 -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 +126 -0
- 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 +167 -11
- package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
- 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 +46 -30
- package/src/__tests__/work-item-output.test.ts +110 -0
- 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 +114 -10
- package/src/calls/call-orchestrator.ts +268 -59
- 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 +22 -14
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +308 -7
- package/src/calls/twilio-routes.ts +65 -12
- 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/knowledge-graph/SKILL.md +15 -0
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
- package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
- 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 +259 -0
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
- package/src/config/bundled-skills/messaging/SKILL.md +33 -8
- 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/messaging/tools/messaging-send.ts +5 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
- package/src/config/bundled-skills/twitter/SKILL.md +19 -3
- 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 +28 -3
- package/src/config/env-registry.ts +162 -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 +158 -1133
- 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 +131 -56
- package/src/config/templates/IDENTITY.md +2 -2
- 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 +6 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
- package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
- 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 +217 -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 -1689
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +180 -0
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/identity.ts +14 -23
- package/src/daemon/handlers/index.ts +11 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +56 -5
- package/src/daemon/handlers/shared.ts +6 -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 +17 -9
- 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 +315 -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 +70 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +229 -2426
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -377
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +68 -3
- package/src/daemon/server.ts +66 -46
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +117 -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 +96 -4
- package/src/daemon/session-runtime-assembly.ts +199 -10
- package/src/daemon/session-surfaces.ts +19 -4
- package/src/daemon/session-tool-setup.ts +30 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +35 -2
- 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 +6 -4
- 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 +202 -2
- 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 +265 -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 +69 -0
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +8 -10
- package/src/memory/jobs-worker.ts +55 -36
- package/src/memory/media-store.ts +759 -0
- 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 +10 -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 +165 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +228 -7
- package/src/memory/search/entity.ts +205 -31
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +27 -23
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/search/types.ts +24 -0
- 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/provider-types.ts +2 -0
- package/src/messaging/providers/sms/adapter.ts +201 -0
- package/src/messaging/providers/sms/client.ts +93 -0
- package/src/messaging/providers/sms/types.ts +7 -0
- 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 +133 -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 +253 -0
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +11 -24
- package/src/runtime/channel-guardian-service.ts +88 -21
- package/src/runtime/channel-readiness-service.ts +418 -0
- package/src/runtime/channel-readiness-types.ts +35 -0
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +275 -717
- package/src/runtime/http-types.ts +59 -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 +51 -7
- 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 -1588
- 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 +143 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +86 -35
- 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/materialize.ts +2 -2
- 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 +10 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -0
- package/src/tools/calls/call-start.ts +1 -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/execution-target.ts +11 -1
- package/src/tools/executor.ts +68 -9
- 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 +8 -4
- 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/types.ts +2 -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/router.ts +1 -1
- 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 +19 -17
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +105 -363
- 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/vellum-skills/google-oauth-setup/SKILL.md +0 -199
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMS messaging provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Enables proactive outbound SMS messaging via the gateway's /deliver/sms
|
|
5
|
+
* endpoint. Similar to the Telegram provider, SMS delivery is proxied through
|
|
6
|
+
* the gateway which owns the Twilio credentials and handles the Messages API.
|
|
7
|
+
*
|
|
8
|
+
* Twilio credentials (account_sid, auth_token) and a configured phone number
|
|
9
|
+
* are required for connectivity. The phone number is resolved from the config
|
|
10
|
+
* (sms.phoneNumber), env var (TWILIO_PHONE_NUMBER), or secure key fallback.
|
|
11
|
+
*
|
|
12
|
+
* The `token` parameter in MessagingProvider methods is unused for SMS
|
|
13
|
+
* because delivery is authenticated via the gateway's bearer token, not
|
|
14
|
+
* a per-user OAuth token.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { MessagingProvider } from '../../provider.js';
|
|
18
|
+
import type {
|
|
19
|
+
Conversation,
|
|
20
|
+
Message,
|
|
21
|
+
SearchResult,
|
|
22
|
+
SendResult,
|
|
23
|
+
ConnectionInfo,
|
|
24
|
+
ListOptions,
|
|
25
|
+
HistoryOptions,
|
|
26
|
+
SearchOptions,
|
|
27
|
+
SendOptions,
|
|
28
|
+
} from '../../provider-types.js';
|
|
29
|
+
import { getSecureKey } from '../../../security/secure-keys.js';
|
|
30
|
+
import { readHttpToken } from '../../../util/platform.js';
|
|
31
|
+
import { loadConfig } from '../../../config/loader.js';
|
|
32
|
+
import { getGatewayInternalBaseUrl, getTwilioPhoneNumberEnv } from '../../../config/env.js';
|
|
33
|
+
import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
|
|
34
|
+
import * as externalConversationStore from '../../../memory/external-conversation-store.js';
|
|
35
|
+
import * as sms from './client.js';
|
|
36
|
+
|
|
37
|
+
/** Resolve the gateway base URL, preferring GATEWAY_INTERNAL_BASE_URL if set. */
|
|
38
|
+
function getGatewayUrl(): string {
|
|
39
|
+
return getGatewayInternalBaseUrl();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Read the runtime HTTP bearer token used to authenticate with the gateway. */
|
|
43
|
+
function getBearerToken(): string {
|
|
44
|
+
const token = readHttpToken();
|
|
45
|
+
if (!token) {
|
|
46
|
+
throw new Error('No runtime HTTP bearer token available — is the daemon running?');
|
|
47
|
+
}
|
|
48
|
+
return token;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Check whether Twilio credentials are stored. */
|
|
52
|
+
function hasTwilioCredentials(): boolean {
|
|
53
|
+
return (
|
|
54
|
+
!!getSecureKey('credential:twilio:account_sid') &&
|
|
55
|
+
!!getSecureKey('credential:twilio:auth_token')
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the configured SMS phone number.
|
|
61
|
+
* Priority: assistant-scoped phone number > TWILIO_PHONE_NUMBER env > config sms.phoneNumber > secure key fallback.
|
|
62
|
+
*/
|
|
63
|
+
function getPhoneNumber(assistantId?: string): string | undefined {
|
|
64
|
+
// Check assistant-scoped phone number first
|
|
65
|
+
if (assistantId) {
|
|
66
|
+
try {
|
|
67
|
+
const config = loadConfig();
|
|
68
|
+
const assistantPhone = config.sms?.assistantPhoneNumbers?.[assistantId];
|
|
69
|
+
if (assistantPhone) return assistantPhone;
|
|
70
|
+
} catch {
|
|
71
|
+
// Config may not be available yet during early startup
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fromEnv = getTwilioPhoneNumberEnv();
|
|
76
|
+
if (fromEnv) return fromEnv;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const config = loadConfig();
|
|
80
|
+
if (config.sms?.phoneNumber) return config.sms.phoneNumber;
|
|
81
|
+
} catch {
|
|
82
|
+
// Config may not be available yet during early startup
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return getSecureKey('credential:twilio:phone_number') || undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function hasAnyAssistantPhoneNumber(): boolean {
|
|
89
|
+
try {
|
|
90
|
+
const config = loadConfig();
|
|
91
|
+
return Object.keys(config.sms?.assistantPhoneNumbers ?? {}).length > 0;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const smsMessagingProvider: MessagingProvider = {
|
|
98
|
+
id: 'sms',
|
|
99
|
+
displayName: 'SMS',
|
|
100
|
+
credentialService: 'twilio',
|
|
101
|
+
capabilities: new Set(['send']),
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* SMS is connected when Twilio credentials are stored AND a phone number
|
|
105
|
+
* is configured. Without a phone number the gateway cannot determine
|
|
106
|
+
* the `from` for outbound messages.
|
|
107
|
+
*/
|
|
108
|
+
isConnected(): boolean {
|
|
109
|
+
return hasTwilioCredentials() && (!!getPhoneNumber() || hasAnyAssistantPhoneNumber());
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
async testConnection(_token: string): Promise<ConnectionInfo> {
|
|
113
|
+
if (!hasTwilioCredentials()) {
|
|
114
|
+
return {
|
|
115
|
+
connected: false,
|
|
116
|
+
user: 'unknown',
|
|
117
|
+
platform: 'sms',
|
|
118
|
+
metadata: { error: 'No Twilio credentials found. Run the twilio-setup skill.' },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const phoneNumber = getPhoneNumber();
|
|
123
|
+
if (!phoneNumber && !hasAnyAssistantPhoneNumber()) {
|
|
124
|
+
return {
|
|
125
|
+
connected: false,
|
|
126
|
+
user: 'unknown',
|
|
127
|
+
platform: 'sms',
|
|
128
|
+
metadata: { error: 'No phone number configured. Run the twilio-setup skill to assign a number.' },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const accountSid = getSecureKey('credential:twilio:account_sid')!;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
connected: true,
|
|
136
|
+
user: phoneNumber ?? 'assistant-scoped numbers configured',
|
|
137
|
+
platform: 'sms',
|
|
138
|
+
metadata: {
|
|
139
|
+
accountSid: accountSid.slice(0, 6) + '...',
|
|
140
|
+
...(phoneNumber ? { phoneNumber } : {}),
|
|
141
|
+
hasAssistantScopedPhoneNumbers: hasAnyAssistantPhoneNumber(),
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
async sendMessage(_token: string, conversationId: string, text: string, options?: SendOptions): Promise<SendResult> {
|
|
147
|
+
const gatewayUrl = getGatewayUrl();
|
|
148
|
+
const bearerToken = getBearerToken();
|
|
149
|
+
const assistantId = options?.assistantId;
|
|
150
|
+
|
|
151
|
+
const sendResult = await sms.sendMessage(gatewayUrl, bearerToken, conversationId, text, assistantId);
|
|
152
|
+
|
|
153
|
+
// Upsert external conversation binding so the conversation key mapping
|
|
154
|
+
// exists for the next inbound SMS from this number.
|
|
155
|
+
try {
|
|
156
|
+
const sourceChannel = 'sms';
|
|
157
|
+
const conversationKey = assistantId && assistantId !== 'self'
|
|
158
|
+
? `asst:${assistantId}:${sourceChannel}:${conversationId}`
|
|
159
|
+
: `${sourceChannel}:${conversationId}`;
|
|
160
|
+
const { conversationId: internalId } = getOrCreateConversation(conversationKey);
|
|
161
|
+
// external_conversation_bindings is assistant-agnostic (unique by
|
|
162
|
+
// sourceChannel + externalChatId). Restrict proactive writes to self so
|
|
163
|
+
// multi-assistant sends cannot clobber each other's binding metadata.
|
|
164
|
+
if (!assistantId || assistantId === 'self') {
|
|
165
|
+
externalConversationStore.upsertOutboundBinding({
|
|
166
|
+
conversationId: internalId,
|
|
167
|
+
sourceChannel,
|
|
168
|
+
externalChatId: conversationId,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
// Best-effort — don't fail the send if binding upsert fails
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Use the Twilio message SID as the send result ID when available,
|
|
176
|
+
// falling back to a timestamp-based ID for older gateway versions.
|
|
177
|
+
const id = sendResult.messageSid || `sms-${Date.now()}`;
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
id,
|
|
181
|
+
timestamp: Date.now(),
|
|
182
|
+
conversationId,
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// SMS does not support listing conversations. The assistant can only
|
|
187
|
+
// send to known phone numbers (conversation IDs).
|
|
188
|
+
async listConversations(_token: string, _options?: ListOptions): Promise<Conversation[]> {
|
|
189
|
+
return [];
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
// SMS does not provide message history retrieval via the gateway.
|
|
193
|
+
async getHistory(_token: string, _conversationId: string, _options?: HistoryOptions): Promise<Message[]> {
|
|
194
|
+
return [];
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// SMS does not support message search.
|
|
198
|
+
async search(_token: string, _query: string, _options?: SearchOptions): Promise<SearchResult> {
|
|
199
|
+
return { total: 0, messages: [], hasMore: false };
|
|
200
|
+
},
|
|
201
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level SMS operations.
|
|
3
|
+
*
|
|
4
|
+
* Outbound message delivery routes through the gateway's /deliver/sms
|
|
5
|
+
* endpoint, which handles Twilio credential management and the Messages API.
|
|
6
|
+
* The gateway resolves the `from` number using the optional assistantId or
|
|
7
|
+
* its default Twilio phone number configuration.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const DELIVERY_TIMEOUT_MS = 30_000;
|
|
11
|
+
|
|
12
|
+
export class SmsApiError extends Error {
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly status: number,
|
|
15
|
+
message: string,
|
|
16
|
+
) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'SmsApiError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Payload accepted by the gateway's /deliver/sms endpoint. */
|
|
23
|
+
interface DeliverPayload {
|
|
24
|
+
to: string;
|
|
25
|
+
text: string;
|
|
26
|
+
assistantId?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Result returned by sendMessage with Twilio acceptance details. */
|
|
30
|
+
export interface SmsSendResult {
|
|
31
|
+
messageSid?: string;
|
|
32
|
+
status?: string;
|
|
33
|
+
errorCode?: string | null;
|
|
34
|
+
errorMessage?: string | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Send an SMS message via the gateway's /deliver/sms endpoint.
|
|
39
|
+
*
|
|
40
|
+
* Returns Twilio acceptance details propagated from the gateway.
|
|
41
|
+
* "Accepted" means Twilio received it for delivery -- it has NOT yet
|
|
42
|
+
* been confirmed as delivered to the handset.
|
|
43
|
+
*/
|
|
44
|
+
export async function sendMessage(
|
|
45
|
+
gatewayUrl: string,
|
|
46
|
+
bearerToken: string,
|
|
47
|
+
to: string,
|
|
48
|
+
text: string,
|
|
49
|
+
assistantId?: string,
|
|
50
|
+
): Promise<SmsSendResult> {
|
|
51
|
+
const payload: DeliverPayload = { to, text };
|
|
52
|
+
if (assistantId) {
|
|
53
|
+
payload.assistantId = assistantId;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const url = `${gatewayUrl}/deliver/sms`;
|
|
57
|
+
const resp = await fetch(url, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(payload),
|
|
64
|
+
signal: AbortSignal.timeout(DELIVERY_TIMEOUT_MS),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!resp.ok) {
|
|
68
|
+
const body = await resp.text().catch(() => '<unreadable>');
|
|
69
|
+
throw new SmsApiError(
|
|
70
|
+
resp.status,
|
|
71
|
+
`Gateway /deliver/sms failed (${resp.status}): ${body}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const data = (await resp.json()) as {
|
|
77
|
+
ok?: boolean;
|
|
78
|
+
messageSid?: string;
|
|
79
|
+
status?: string;
|
|
80
|
+
errorCode?: string | null;
|
|
81
|
+
errorMessage?: string | null;
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
messageSid: data.messageSid,
|
|
85
|
+
status: data.status,
|
|
86
|
+
errorCode: data.errorCode,
|
|
87
|
+
errorMessage: data.errorMessage,
|
|
88
|
+
};
|
|
89
|
+
} catch {
|
|
90
|
+
// Older gateway versions may not return JSON with Twilio details
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -25,17 +25,14 @@ import type {
|
|
|
25
25
|
} from '../../provider-types.js';
|
|
26
26
|
import { getSecureKey } from '../../../security/secure-keys.js';
|
|
27
27
|
import { readHttpToken } from '../../../util/platform.js';
|
|
28
|
+
import { getGatewayInternalBaseUrl } from '../../../config/env.js';
|
|
28
29
|
import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
|
|
29
30
|
import * as externalConversationStore from '../../../memory/external-conversation-store.js';
|
|
30
31
|
import * as telegram from './client.js';
|
|
31
32
|
|
|
32
33
|
/** Resolve the gateway base URL, preferring GATEWAY_INTERNAL_BASE_URL if set. */
|
|
33
34
|
function getGatewayUrl(): string {
|
|
34
|
-
|
|
35
|
-
return process.env.GATEWAY_INTERNAL_BASE_URL.replace(/\/+$/, "");
|
|
36
|
-
}
|
|
37
|
-
const port = Number(process.env.GATEWAY_PORT) || 7830;
|
|
38
|
-
return `http://127.0.0.1:${port}`;
|
|
35
|
+
return getGatewayInternalBaseUrl();
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
/** Read the runtime HTTP bearer token used to authenticate with the gateway. */
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsApp Business messaging provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Enables proactive outbound WhatsApp messaging via the gateway's /deliver/whatsapp
|
|
5
|
+
* endpoint. Delivery is proxied through the gateway which owns the Meta Cloud API
|
|
6
|
+
* credentials (phone_number_id + access_token).
|
|
7
|
+
*
|
|
8
|
+
* The `token` parameter in MessagingProvider methods is unused for WhatsApp
|
|
9
|
+
* because delivery is authenticated via the gateway's bearer token, not
|
|
10
|
+
* a per-user OAuth token.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { MessagingProvider } from '../../provider.js';
|
|
14
|
+
import type {
|
|
15
|
+
Conversation,
|
|
16
|
+
Message,
|
|
17
|
+
SearchResult,
|
|
18
|
+
SendResult,
|
|
19
|
+
ConnectionInfo,
|
|
20
|
+
ListOptions,
|
|
21
|
+
HistoryOptions,
|
|
22
|
+
SearchOptions,
|
|
23
|
+
SendOptions,
|
|
24
|
+
} from '../../provider-types.js';
|
|
25
|
+
import { getSecureKey } from '../../../security/secure-keys.js';
|
|
26
|
+
import { readHttpToken } from '../../../util/platform.js';
|
|
27
|
+
import { getGatewayInternalBaseUrl } from '../../../config/env.js';
|
|
28
|
+
import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
|
|
29
|
+
import * as externalConversationStore from '../../../memory/external-conversation-store.js';
|
|
30
|
+
import * as whatsapp from './client.js';
|
|
31
|
+
|
|
32
|
+
/** Resolve the gateway base URL. */
|
|
33
|
+
function getGatewayUrl(): string {
|
|
34
|
+
return getGatewayInternalBaseUrl();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Read the runtime HTTP bearer token used to authenticate with the gateway. */
|
|
38
|
+
function getBearerToken(): string {
|
|
39
|
+
const token = readHttpToken();
|
|
40
|
+
if (!token) {
|
|
41
|
+
throw new Error('No runtime HTTP bearer token available — is the daemon running?');
|
|
42
|
+
}
|
|
43
|
+
return token;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Check whether WhatsApp credentials are stored. */
|
|
47
|
+
function hasWhatsAppCredentials(): boolean {
|
|
48
|
+
return (
|
|
49
|
+
!!getSecureKey('credential:whatsapp:phone_number_id') &&
|
|
50
|
+
!!getSecureKey('credential:whatsapp:access_token')
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const whatsappMessagingProvider: MessagingProvider = {
|
|
55
|
+
id: 'whatsapp',
|
|
56
|
+
displayName: 'WhatsApp',
|
|
57
|
+
credentialService: 'whatsapp',
|
|
58
|
+
capabilities: new Set(['send']),
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* WhatsApp is connected when Meta Cloud API credentials are stored.
|
|
62
|
+
*/
|
|
63
|
+
isConnected(): boolean {
|
|
64
|
+
return hasWhatsAppCredentials();
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
async testConnection(_token: string): Promise<ConnectionInfo> {
|
|
68
|
+
if (!hasWhatsAppCredentials()) {
|
|
69
|
+
return {
|
|
70
|
+
connected: false,
|
|
71
|
+
user: 'unknown',
|
|
72
|
+
platform: 'whatsapp',
|
|
73
|
+
metadata: { error: 'No WhatsApp credentials found. Configure WHATSAPP_PHONE_NUMBER_ID and WHATSAPP_ACCESS_TOKEN.' },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const phoneNumberId = getSecureKey('credential:whatsapp:phone_number_id')!;
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
connected: true,
|
|
81
|
+
user: phoneNumberId,
|
|
82
|
+
platform: 'whatsapp',
|
|
83
|
+
metadata: {
|
|
84
|
+
phoneNumberId: phoneNumberId.slice(0, 6) + '...',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
async sendMessage(_token: string, conversationId: string, text: string, options?: SendOptions): Promise<SendResult> {
|
|
90
|
+
const gatewayUrl = getGatewayUrl();
|
|
91
|
+
const bearerToken = getBearerToken();
|
|
92
|
+
const assistantId = options?.assistantId;
|
|
93
|
+
|
|
94
|
+
await whatsapp.sendMessage(gatewayUrl, bearerToken, conversationId, text, assistantId);
|
|
95
|
+
|
|
96
|
+
// Upsert external conversation binding so the conversation key mapping
|
|
97
|
+
// exists for the next inbound WhatsApp message from this number.
|
|
98
|
+
try {
|
|
99
|
+
const sourceChannel = 'whatsapp';
|
|
100
|
+
const conversationKey = assistantId && assistantId !== 'self'
|
|
101
|
+
? `asst:${assistantId}:${sourceChannel}:${conversationId}`
|
|
102
|
+
: `${sourceChannel}:${conversationId}`;
|
|
103
|
+
const { conversationId: internalId } = getOrCreateConversation(conversationKey);
|
|
104
|
+
if (!assistantId || assistantId === 'self') {
|
|
105
|
+
externalConversationStore.upsertOutboundBinding({
|
|
106
|
+
conversationId: internalId,
|
|
107
|
+
sourceChannel,
|
|
108
|
+
externalChatId: conversationId,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// Best-effort — don't fail the send if binding upsert fails
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
id: `whatsapp-${Date.now()}`,
|
|
117
|
+
timestamp: Date.now(),
|
|
118
|
+
conversationId,
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// WhatsApp does not support listing conversations via this provider.
|
|
123
|
+
async listConversations(_token: string, _options?: ListOptions): Promise<Conversation[]> {
|
|
124
|
+
return [];
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// WhatsApp does not provide message history retrieval via the gateway.
|
|
128
|
+
async getHistory(_token: string, _conversationId: string, _options?: HistoryOptions): Promise<Message[]> {
|
|
129
|
+
return [];
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// WhatsApp does not support message search.
|
|
133
|
+
async search(_token: string, _query: string, _options?: SearchOptions): Promise<SearchResult> {
|
|
134
|
+
return { total: 0, messages: [], hasMore: false };
|
|
135
|
+
},
|
|
136
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level WhatsApp operations.
|
|
3
|
+
*
|
|
4
|
+
* Outbound message delivery routes through the gateway's /deliver/whatsapp
|
|
5
|
+
* endpoint, which handles WhatsApp credential management and the Meta Cloud API.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DELIVERY_TIMEOUT_MS = 30_000;
|
|
9
|
+
|
|
10
|
+
export class WhatsAppApiError extends Error {
|
|
11
|
+
constructor(
|
|
12
|
+
public readonly status: number,
|
|
13
|
+
message: string,
|
|
14
|
+
) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'WhatsAppApiError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Payload accepted by the gateway's /deliver/whatsapp endpoint. */
|
|
21
|
+
interface DeliverPayload {
|
|
22
|
+
to: string;
|
|
23
|
+
text: string;
|
|
24
|
+
assistantId?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Result returned by sendMessage. */
|
|
28
|
+
export interface WhatsAppSendResult {
|
|
29
|
+
ok: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Send a WhatsApp message via the gateway's /deliver/whatsapp endpoint.
|
|
34
|
+
*/
|
|
35
|
+
export async function sendMessage(
|
|
36
|
+
gatewayUrl: string,
|
|
37
|
+
bearerToken: string,
|
|
38
|
+
to: string,
|
|
39
|
+
text: string,
|
|
40
|
+
assistantId?: string,
|
|
41
|
+
): Promise<WhatsAppSendResult> {
|
|
42
|
+
const payload: DeliverPayload = { to, text };
|
|
43
|
+
if (assistantId) {
|
|
44
|
+
payload.assistantId = assistantId;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const url = `${gatewayUrl}/deliver/whatsapp`;
|
|
48
|
+
const resp = await fetch(url, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify(payload),
|
|
55
|
+
signal: AbortSignal.timeout(DELIVERY_TIMEOUT_MS),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!resp.ok) {
|
|
59
|
+
const body = await resp.text().catch(() => '<unreadable>');
|
|
60
|
+
throw new WhatsAppApiError(
|
|
61
|
+
resp.status,
|
|
62
|
+
`Gateway /deliver/whatsapp failed (${resp.status}): ${body}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { ok: true };
|
|
67
|
+
}
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
import type { Message as ProviderMessage } from './provider-types.js';
|
|
10
10
|
import type { Message, ToolDefinition } from '../providers/types.js';
|
|
11
11
|
import { truncate } from '../util/truncate.js';
|
|
12
|
-
import {
|
|
13
|
-
import { getConfig } from '../config/loader.js';
|
|
12
|
+
import { getConfiguredProvider } from '../providers/provider-send-message.js';
|
|
14
13
|
|
|
15
14
|
export interface StylePattern {
|
|
16
15
|
aspect: string;
|
|
@@ -118,8 +117,10 @@ export async function extractStylePatterns(
|
|
|
118
117
|
|
|
119
118
|
const corpus = corpusEntries.map((e, i) => `--- Message ${i + 1} ---\n${e}`).join('\n\n');
|
|
120
119
|
|
|
121
|
-
const
|
|
122
|
-
|
|
120
|
+
const provider = getConfiguredProvider();
|
|
121
|
+
if (!provider) {
|
|
122
|
+
return { stylePatterns: [], contactObservations: [] };
|
|
123
|
+
}
|
|
123
124
|
const promptMessages: Message[] = [{
|
|
124
125
|
role: 'user',
|
|
125
126
|
content: [{ type: 'text', text: `Analyze these ${corpusEntries.length} sent messages for writing style patterns:\n\n${corpus}` }],
|