@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,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "SMS Setup"
|
|
3
|
+
description: "Set up and troubleshoot SMS messaging with guided Twilio configuration, compliance, and verification"
|
|
4
|
+
user-invocable: true
|
|
5
|
+
metadata: {"vellum": {"emoji": "\ud83d\udce8"}}
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are helping your user set up SMS messaging. This skill orchestrates Twilio setup, SMS-specific compliance, and end-to-end testing through a conversational flow.
|
|
9
|
+
|
|
10
|
+
## Step 1: Check Channel Readiness
|
|
11
|
+
|
|
12
|
+
First, check the current SMS channel readiness state by sending the `channel_readiness` IPC message:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"type": "channel_readiness",
|
|
17
|
+
"action": "get",
|
|
18
|
+
"channel": "sms"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Inspect the `channel_readiness_response`. The response contains `snapshots` with each channel's readiness state.
|
|
23
|
+
|
|
24
|
+
- If the SMS channel shows `ready: true` and all `localChecks` pass, skip to Step 3.
|
|
25
|
+
- If any local checks fail, proceed to Step 2 to fix the baseline.
|
|
26
|
+
|
|
27
|
+
## Step 2: Establish Baseline (Twilio Setup)
|
|
28
|
+
|
|
29
|
+
If SMS baseline is not ready (missing credentials, phone number, or ingress), load the `twilio-setup` skill to walk the user through the basics:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
skill_load skill=twilio-setup
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Tell the user: *"SMS needs Twilio configured first. I've loaded the Twilio setup guide — let's walk through it."*
|
|
36
|
+
|
|
37
|
+
After twilio-setup completes, re-check readiness:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"type": "channel_readiness",
|
|
42
|
+
"action": "refresh",
|
|
43
|
+
"channel": "sms"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If baseline is still not ready, report the specific failures and ask the user to address them before continuing.
|
|
48
|
+
|
|
49
|
+
## Step 3: Remote Compliance Check
|
|
50
|
+
|
|
51
|
+
Once baseline is ready, run a full readiness check including remote (Twilio API) checks:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"type": "channel_readiness",
|
|
56
|
+
"action": "refresh",
|
|
57
|
+
"channel": "sms",
|
|
58
|
+
"includeRemote": true
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Examine the remote check results:
|
|
63
|
+
- If all remote checks pass, proceed to Step 4.
|
|
64
|
+
- If compliance issues are found (e.g., toll-free verification needed), guide the user through the compliance flow.
|
|
65
|
+
|
|
66
|
+
### Toll-Free Verification Submission
|
|
67
|
+
|
|
68
|
+
When the remote check returns `toll_free_verification` as a failing check, the assistant must submit verification directly to the Twilio API. The daemon does not yet have an IPC action for this, so use the Twilio REST API directly.
|
|
69
|
+
|
|
70
|
+
**Prerequisites:** The assistant needs the Account SID and Auth Token. These are stored in daemon secure storage and can be accessed by importing `getSecureKey` from the daemon's `security/secure-keys` module:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { getSecureKey } from "./src/security/secure-keys.js";
|
|
74
|
+
const accountSid = getSecureKey("credential:twilio:account_sid");
|
|
75
|
+
const authToken = getSecureKey("credential:twilio:auth_token");
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Step 3a: Look up the phone number SID.** The toll-free verification API requires the phone number's SID (format `PNxxxx`), not the E.164 number itself:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
GET https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json?PhoneNumber={E.164 number}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Extract the `sid` field from the matching number in `incoming_phone_numbers`.
|
|
85
|
+
|
|
86
|
+
**Step 3b: Check for existing verifications.** Before submitting, check if a verification already exists:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
GET https://messaging.twilio.com/v1/Tollfree/Verifications
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If a verification already exists for this number, report its status to the user and skip submission.
|
|
93
|
+
|
|
94
|
+
**Step 3c: Check Trust Hub profile assignments.** Twilio auto-attaches toll-free numbers to their assigned Trust Hub Customer Profile. The verification API rejects submissions when the number is attached to a Primary Customer Profile (PCP). It requires either no profile, a Starter profile, or a Secondary Customer Profile (SCP).
|
|
95
|
+
|
|
96
|
+
Check if the number is assigned to a profile:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
GET https://trusthub.twilio.com/v1/CustomerProfiles?PageSize=50
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For each profile, check `ChannelEndpointAssignments`:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
GET https://trusthub.twilio.com/v1/CustomerProfiles/{ProfileSid}/ChannelEndpointAssignments?PageSize=50
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If the number is assigned to a Primary profile:
|
|
109
|
+
1. **Tell the user** the number is linked to a Primary Customer Profile, which blocks toll-free verification.
|
|
110
|
+
2. **Offer two options:**
|
|
111
|
+
- **Option A:** Remove the number from the Primary profile (DELETE the ChannelEndpointAssignment), then resubmit. Warn that this may affect other services tied to that profile.
|
|
112
|
+
- **Option B:** Wait for the Starter profile to be approved (if one exists and is `in-review`), then link the number to that profile instead.
|
|
113
|
+
3. **Do not silently retry.** The same error will recur until the profile assignment is resolved.
|
|
114
|
+
|
|
115
|
+
**Step 3d: Collect user information.** Collect the following from the user (assume individual/sole proprietor by default):
|
|
116
|
+
|
|
117
|
+
| Field | API Parameter | Notes |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| Name | `BusinessName` | Can be personal name |
|
|
120
|
+
| Business type | `BusinessType` | Use `SOLE_PROPRIETOR` for individuals. Valid values: `PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `SOLE_PROPRIETOR`, `NON_PROFIT`, `GOVERNMENT` |
|
|
121
|
+
| Website | `BusinessWebsite` | LinkedIn or personal site is fine |
|
|
122
|
+
| Street address | `BusinessStreetAddress` | |
|
|
123
|
+
| City | `BusinessCity` | |
|
|
124
|
+
| State | `BusinessStateProvinceRegion` | |
|
|
125
|
+
| Zip | `BusinessPostalCode` | |
|
|
126
|
+
| Country | `BusinessCountry` | Two-letter ISO code, e.g. `US` |
|
|
127
|
+
| Notification email | `NotificationEmail` | Where Twilio sends status updates |
|
|
128
|
+
| Contact phone | `BusinessContactPhone` | E.164 format |
|
|
129
|
+
| Contact first name | `BusinessContactFirstName` | |
|
|
130
|
+
| Contact last name | `BusinessContactLastName` | |
|
|
131
|
+
| Contact email | `BusinessContactEmail` | |
|
|
132
|
+
| Use case category | `UseCaseCategories` | e.g. `ACCOUNT_NOTIFICATIONS` |
|
|
133
|
+
| Use case summary | `UseCaseSummary` | Plain English description |
|
|
134
|
+
| Message volume | `MessageVolume` | Estimated monthly messages, e.g. `100` |
|
|
135
|
+
| Sample message | `ProductionMessageSample` | A realistic example message |
|
|
136
|
+
| Opt-in type | `OptInType` | `VERBAL`, `WEB_FORM`, `PAPER_FORM`, `VIA_TEXT`, `MOBILE_QR_CODE` |
|
|
137
|
+
| Opt-in image URL | `OptInImageUrls` | URL showing opt-in mechanism (can be website URL) |
|
|
138
|
+
|
|
139
|
+
Do NOT ask for EIN, business registration number, or business registration authority. Explain that Twilio labels some fields as "business" fields even for individual submitters.
|
|
140
|
+
|
|
141
|
+
**Step 3e: Submit verification:**
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
POST https://messaging.twilio.com/v1/Tollfree/Verifications
|
|
145
|
+
Content-Type: application/x-www-form-urlencoded
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
With all fields as form-encoded parameters, including `TollfreePhoneNumberSid` (the PN SID from Step 3a).
|
|
149
|
+
|
|
150
|
+
**Common errors:**
|
|
151
|
+
- `"BusinessType must be one of [...]"` — Use exact enum values listed above
|
|
152
|
+
- `"Customer profiles submitted with verifications must be either ISV Starters or Secondary Customer Profiles"` — The number is linked to a Primary profile. See Step 3c above.
|
|
153
|
+
- `400` or `20001` errors — Check the `message` field for specifics and report to user
|
|
154
|
+
|
|
155
|
+
**On success:** Tell the user the verification has been submitted and is now `PENDING_REVIEW`. Twilio typically reviews within 1-5 business days. They'll receive status updates at the notification email provided.
|
|
156
|
+
|
|
157
|
+
**On failure:** Report the exact error message and guide the user through resolution.
|
|
158
|
+
|
|
159
|
+
## Step 4: Test Send
|
|
160
|
+
|
|
161
|
+
Run a test SMS to verify end-to-end delivery:
|
|
162
|
+
|
|
163
|
+
Tell the user: *"Let's send a test SMS to verify everything works. What phone number should I send the test to?"*
|
|
164
|
+
|
|
165
|
+
**Important:** If toll-free verification is pending (not yet approved), inform the user that test messages may be silently dropped by carriers even though Twilio accepts them. Offer to attempt the test anyway, but set expectations.
|
|
166
|
+
|
|
167
|
+
**Trial account limitation:** On Twilio trial accounts, SMS can only be sent to verified phone numbers. If the send fails with a "not verified" error, tell the user to verify the recipient number in the Twilio Console under Verified Caller IDs, or upgrade their account.
|
|
168
|
+
|
|
169
|
+
After the user provides a number, send a test message using the messaging tools:
|
|
170
|
+
- Use `messaging_send` with `platform: "sms"`, `conversation_id: "<phone number>"`, and a test message like "Test SMS from your Vellum assistant."
|
|
171
|
+
- Report the result honestly:
|
|
172
|
+
- If the send succeeds: *"The message was accepted by Twilio. Note: 'accepted' means Twilio received it for delivery, not that it reached the handset yet. Delivery can take a few seconds to a few minutes. If verification is still pending, carriers may silently drop the message."*
|
|
173
|
+
- If the send fails: report the error and suggest troubleshooting steps
|
|
174
|
+
|
|
175
|
+
## Step 5: Final Status Report
|
|
176
|
+
|
|
177
|
+
After completing (or skipping) the test, present a clear summary:
|
|
178
|
+
|
|
179
|
+
**If everything passed:**
|
|
180
|
+
*"SMS is ready! Here's your setup status:"*
|
|
181
|
+
- Twilio credentials: configured
|
|
182
|
+
- Phone number: {number}
|
|
183
|
+
- Ingress: configured
|
|
184
|
+
- Compliance: {status}
|
|
185
|
+
- Test send: {result}
|
|
186
|
+
|
|
187
|
+
**If there are blockers:**
|
|
188
|
+
*"SMS setup is partially complete. Here's what still needs attention:"*
|
|
189
|
+
- List each blocker with the specific next action
|
|
190
|
+
|
|
191
|
+
## Troubleshooting
|
|
192
|
+
|
|
193
|
+
If the user returns to this skill after initial setup:
|
|
194
|
+
1. Always start with Step 1 (readiness check) to assess current state
|
|
195
|
+
2. Skip steps that are already complete
|
|
196
|
+
3. Focus on the specific issue the user is experiencing
|
|
197
|
+
|
|
198
|
+
Common issues:
|
|
199
|
+
- **"Messages not delivering"** — Check compliance status (toll-free verification), verify the number isn't flagged
|
|
200
|
+
- **"Twilio error on send"** — Check credentials, phone number assignment, and ingress
|
|
201
|
+
- **"Trial account limitations"** — Explain that trial accounts can only send to verified numbers
|
|
202
|
+
- **"Customer profiles must be ISV Starters or Secondary"** — The toll-free number is linked to a Primary Customer Profile in Trust Hub. Must be unlinked or reassigned before verification can be submitted.
|
|
203
|
+
|
|
204
|
+
## Accessing the Twilio API
|
|
205
|
+
|
|
206
|
+
The skill references IPC messages (`channel_readiness`, `twilio_config`) that are sent via Unix socket to the daemon. The assistant does not have an HTTP endpoint for IPC. Use the following pattern to send IPC messages:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
cd "$(git rev-parse --show-toplevel)/assistant" && bun -e '
|
|
210
|
+
import { sendOneMessage } from "./src/cli/ipc-client.js";
|
|
211
|
+
const res = await sendOneMessage({ type: "twilio_config", action: "get" });
|
|
212
|
+
console.log(JSON.stringify(res, null, 2));
|
|
213
|
+
'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For direct Twilio REST API calls (e.g., toll-free verification submission), use the same `bun -e` pattern with `getSecureKey` from `./src/security/secure-keys.js` to retrieve credentials, then use `fetch()`.
|
|
@@ -18,6 +18,27 @@ This skill manages the full Twilio lifecycle:
|
|
|
18
18
|
|
|
19
19
|
All operations go through the `twilio_config` IPC handler on the daemon, which validates inputs, stores credentials securely, and manages phone number state.
|
|
20
20
|
|
|
21
|
+
### Multi-Assistant Setups
|
|
22
|
+
|
|
23
|
+
In a multi-assistant environment (multiple assistants sharing the same daemon), some `twilio_config` actions are **assistant-scoped** while others are **global** (shared across all assistants):
|
|
24
|
+
|
|
25
|
+
**Global actions** (ignore `assistantId` — credentials are shared across all assistants):
|
|
26
|
+
- `set_credentials` — Stores Account SID and Auth Token in global secure storage (`credential:twilio:*` keys). All assistants share the same Twilio account credentials.
|
|
27
|
+
- `clear_credentials` — Removes the globally stored Account SID and Auth Token. This affects all assistants.
|
|
28
|
+
|
|
29
|
+
**Assistant-scoped actions** (use `assistantId` to scope phone number configuration per assistant):
|
|
30
|
+
- `get` — Returns the phone number assigned to the specified assistant (falls back to the legacy global number if no per-assistant mapping exists).
|
|
31
|
+
- `assign_number` — Assigns a phone number to a specific assistant via the per-assistant mapping.
|
|
32
|
+
- `provision_number` — Provisions a new number and assigns it to the specified assistant.
|
|
33
|
+
- `list_numbers` — Lists all phone numbers on the shared Twilio account (uses global credentials).
|
|
34
|
+
|
|
35
|
+
Include `assistantId` in assistant-scoped actions whenever:
|
|
36
|
+
- Multiple assistants share the same Twilio account but use different phone numbers
|
|
37
|
+
- You want to ensure configuration changes only affect a specific assistant
|
|
38
|
+
- The user has explicitly selected or referenced a particular assistant
|
|
39
|
+
|
|
40
|
+
All IPC examples below include the optional `assistantId` field in assistant-scoped actions. Omit it in single-assistant setups. For global actions (`set_credentials`, `clear_credentials`), the `assistantId` field is accepted but ignored.
|
|
41
|
+
|
|
21
42
|
## Step 1: Check Current Configuration
|
|
22
43
|
|
|
23
44
|
First, check whether Twilio is already configured by sending the `twilio_config` IPC message with `action: "get"`:
|
|
@@ -25,7 +46,8 @@ First, check whether Twilio is already configured by sending the `twilio_config`
|
|
|
25
46
|
```json
|
|
26
47
|
{
|
|
27
48
|
"type": "twilio_config",
|
|
28
|
-
"action": "get"
|
|
49
|
+
"action": "get",
|
|
50
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
29
51
|
}
|
|
30
52
|
```
|
|
31
53
|
|
|
@@ -62,6 +84,8 @@ After both credentials are collected, retrieve them from secure storage and pass
|
|
|
62
84
|
|
|
63
85
|
Both `accountSid` and `authToken` are required — the daemon validates the credentials against the Twilio API before storing them. If credentials are invalid, the daemon returns an error. Tell the user and ask them to re-enter via the secure prompt.
|
|
64
86
|
|
|
87
|
+
**Note:** `set_credentials` is a global operation — credentials are stored once and shared across all assistants. The `assistantId` field is accepted but ignored.
|
|
88
|
+
|
|
65
89
|
## Step 3: Get a Phone Number
|
|
66
90
|
|
|
67
91
|
The assistant needs a phone number to make calls and send SMS. There are two paths:
|
|
@@ -75,7 +99,8 @@ If the user wants to buy a new number through Twilio, send:
|
|
|
75
99
|
"type": "twilio_config",
|
|
76
100
|
"action": "provision_number",
|
|
77
101
|
"areaCode": "415",
|
|
78
|
-
"country": "US"
|
|
102
|
+
"country": "US",
|
|
103
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
79
104
|
}
|
|
80
105
|
```
|
|
81
106
|
|
|
@@ -100,7 +125,8 @@ If the user already has a Twilio phone number, first list available numbers:
|
|
|
100
125
|
```json
|
|
101
126
|
{
|
|
102
127
|
"type": "twilio_config",
|
|
103
|
-
"action": "list_numbers"
|
|
128
|
+
"action": "list_numbers",
|
|
129
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
104
130
|
}
|
|
105
131
|
```
|
|
106
132
|
|
|
@@ -112,7 +138,8 @@ Then assign the chosen number:
|
|
|
112
138
|
{
|
|
113
139
|
"type": "twilio_config",
|
|
114
140
|
"action": "assign_number",
|
|
115
|
-
"phoneNumber": "+14155551234"
|
|
141
|
+
"phoneNumber": "+14155551234",
|
|
142
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
116
143
|
}
|
|
117
144
|
```
|
|
118
145
|
|
|
@@ -132,7 +159,8 @@ Then assign it through the IPC:
|
|
|
132
159
|
{
|
|
133
160
|
"type": "twilio_config",
|
|
134
161
|
"action": "assign_number",
|
|
135
|
-
"phoneNumber": "+14155551234"
|
|
162
|
+
"phoneNumber": "+14155551234",
|
|
163
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
136
164
|
}
|
|
137
165
|
```
|
|
138
166
|
|
|
@@ -181,7 +209,8 @@ Now link the user's phone number as the trusted SMS guardian for this assistant.
|
|
|
181
209
|
{
|
|
182
210
|
"type": "guardian_verification",
|
|
183
211
|
"action": "create_challenge",
|
|
184
|
-
"channel": "sms"
|
|
212
|
+
"channel": "sms",
|
|
213
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
185
214
|
}
|
|
186
215
|
```
|
|
187
216
|
|
|
@@ -195,7 +224,8 @@ Now link the user's phone number as the trusted SMS guardian for this assistant.
|
|
|
195
224
|
{
|
|
196
225
|
"type": "guardian_verification",
|
|
197
226
|
"action": "status",
|
|
198
|
-
"channel": "sms"
|
|
227
|
+
"channel": "sms",
|
|
228
|
+
"assistantId": "<optional — omit for single-assistant setups>"
|
|
199
229
|
}
|
|
200
230
|
```
|
|
201
231
|
|
|
@@ -232,7 +262,9 @@ If the user wants to disconnect Twilio, send:
|
|
|
232
262
|
}
|
|
233
263
|
```
|
|
234
264
|
|
|
235
|
-
This removes the stored Account SID and Auth Token.
|
|
265
|
+
This removes the stored Account SID and Auth Token. Phone number assignments are preserved. Voice calls and SMS will stop working until credentials are reconfigured.
|
|
266
|
+
|
|
267
|
+
**Note:** `clear_credentials` is a global operation — it removes credentials for all assistants, not just the current one. The `assistantId` field is accepted but ignored. In multi-assistant setups, warn the user that clearing credentials will affect all assistants sharing this Twilio account.
|
|
236
268
|
|
|
237
269
|
## Troubleshooting
|
|
238
270
|
|
|
@@ -112,7 +112,7 @@ export class ContextWindowManager {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const summaryOffset = existingSummary
|
|
115
|
+
const summaryOffset = existingSummary != null ? 1 : 0;
|
|
116
116
|
const userTurnStarts = collectUserTurnStartIndexes(messages);
|
|
117
117
|
if (userTurnStarts.length === 0) {
|
|
118
118
|
return {
|
|
@@ -186,14 +186,34 @@ export class ContextWindowManager {
|
|
|
186
186
|
const projectedGainTokens = Math.max(0, previousEstimatedInputTokens - projectedInputTokens);
|
|
187
187
|
const severePressure = previousEstimatedInputTokens >= Math.floor(this.config.maxInputTokens * SEVERE_PRESSURE_RATIO);
|
|
188
188
|
const lastCompactedAt = options?.lastCompactedAt;
|
|
189
|
-
const withinCooldown = typeof lastCompactedAt === 'number'
|
|
190
|
-
&& Date.now() - lastCompactedAt < COMPACTION_COOLDOWN_MS;
|
|
191
189
|
|
|
190
|
+
// Adaptive cooldown: conversations growing quickly (high projected gain) compact
|
|
191
|
+
// sooner. Scale the cooldown inversely with the growth-rate multiplier, capped at
|
|
192
|
+
// 1/4 of the base cooldown so we never check more than 4× as frequently.
|
|
193
|
+
const growthRateMultiplier = Math.max(1, projectedGainTokens / MIN_GAIN_TOKENS_DURING_COOLDOWN);
|
|
194
|
+
const adaptiveCooldownMs = Math.max(
|
|
195
|
+
COMPACTION_COOLDOWN_MS / 4,
|
|
196
|
+
COMPACTION_COOLDOWN_MS / growthRateMultiplier,
|
|
197
|
+
);
|
|
198
|
+
const withinCooldown = typeof lastCompactedAt === 'number'
|
|
199
|
+
&& Date.now() - lastCompactedAt < adaptiveCooldownMs;
|
|
200
|
+
|
|
201
|
+
// The adaptive cooldown is already tuned to be shorter for fast-growing
|
|
202
|
+
// conversations (high projectedGainTokens → smaller adaptiveCooldownMs).
|
|
203
|
+
// Removing the redundant MIN_GAIN_TOKENS_DURING_COOLDOWN guard here lets
|
|
204
|
+
// that shorter cooldown actually gate compaction: high-growth conversations
|
|
205
|
+
// break out of the cooldown sooner and compact more frequently.
|
|
206
|
+
// force=true bypasses the cooldown so context-too-large recovery can always
|
|
207
|
+
// attempt a compaction even within the cooldown window.
|
|
192
208
|
if (
|
|
193
209
|
withinCooldown
|
|
194
|
-
&& projectedGainTokens < MIN_GAIN_TOKENS_DURING_COOLDOWN
|
|
195
210
|
&& !severePressure
|
|
211
|
+
&& !options?.force
|
|
196
212
|
) {
|
|
213
|
+
log.debug(
|
|
214
|
+
{ projectedGainTokens, adaptiveCooldownMs, growthRateMultiplier, msSinceCompaction: typeof lastCompactedAt === 'number' ? Date.now() - lastCompactedAt : null },
|
|
215
|
+
'Compaction cooldown active',
|
|
216
|
+
);
|
|
197
217
|
return {
|
|
198
218
|
messages,
|
|
199
219
|
compacted: false,
|
|
@@ -208,7 +228,7 @@ export class ContextWindowManager {
|
|
|
208
228
|
summaryOutputTokens: 0,
|
|
209
229
|
summaryModel: '',
|
|
210
230
|
summaryText: existingSummary ?? '',
|
|
211
|
-
reason: 'compaction cooldown active
|
|
231
|
+
reason: 'compaction cooldown active',
|
|
212
232
|
};
|
|
213
233
|
}
|
|
214
234
|
|
|
@@ -355,7 +375,7 @@ function collectUserTurnStartIndexes(messages: Message[]): number[] {
|
|
|
355
375
|
for (let i = 0; i < messages.length; i++) {
|
|
356
376
|
const message = messages[i];
|
|
357
377
|
if (message.role !== 'user') continue;
|
|
358
|
-
if (getSummaryFromContextMessage(message) !==
|
|
378
|
+
if (getSummaryFromContextMessage(message) !== undefined) continue;
|
|
359
379
|
if (isToolResultOnly(message)) continue;
|
|
360
380
|
starts.push(i);
|
|
361
381
|
}
|
|
@@ -370,7 +390,7 @@ function collectUserTurnStartIndexes(messages: Message[]): number[] {
|
|
|
370
390
|
*/
|
|
371
391
|
function countPersistedMessages(messages: Message[]): number {
|
|
372
392
|
return messages.filter((message) => {
|
|
373
|
-
return getSummaryFromContextMessage(message) ===
|
|
393
|
+
return getSummaryFromContextMessage(message) === undefined;
|
|
374
394
|
}).length;
|
|
375
395
|
}
|
|
376
396
|
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { ApprovalCopyGenerator, ApprovalConversationGenerator, ApprovalConversationResult, ApprovalConversationDisposition } from '../runtime/http-types.js';
|
|
2
|
+
import {
|
|
3
|
+
buildGenerationPrompt,
|
|
4
|
+
includesRequiredKeywords,
|
|
5
|
+
getFallbackMessage,
|
|
6
|
+
APPROVAL_COPY_TIMEOUT_MS,
|
|
7
|
+
APPROVAL_COPY_MAX_TOKENS,
|
|
8
|
+
APPROVAL_COPY_SYSTEM_PROMPT,
|
|
9
|
+
} from '../runtime/approval-message-composer.js';
|
|
10
|
+
import { loadConfig } from '../config/loader.js';
|
|
11
|
+
import { getFailoverProvider, listProviders } from '../providers/registry.js';
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Approval conversation generator constants
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
const APPROVAL_CONVERSATION_TIMEOUT_MS = 8_000;
|
|
18
|
+
const APPROVAL_CONVERSATION_MAX_TOKENS = 300;
|
|
19
|
+
|
|
20
|
+
const APPROVAL_CONVERSATION_SYSTEM_PROMPT =
|
|
21
|
+
'You are an assistant helping a user manage a pending tool approval request. '
|
|
22
|
+
+ 'Analyze the user\'s message to determine if they are making a decision '
|
|
23
|
+
+ '(approve, reject, or cancel) or just asking a question / making conversation. '
|
|
24
|
+
+ 'When uncertain, default to keep_pending — never approve or reject without clear intent. '
|
|
25
|
+
+ 'For guardians: explain what tool is requesting approval and from whom. '
|
|
26
|
+
+ 'Always provide a natural, helpful reply along with your decision.';
|
|
27
|
+
|
|
28
|
+
const APPROVAL_CONVERSATION_TOOL_NAME = 'approval_decision';
|
|
29
|
+
|
|
30
|
+
const APPROVAL_CONVERSATION_TOOL_SCHEMA = {
|
|
31
|
+
name: APPROVAL_CONVERSATION_TOOL_NAME,
|
|
32
|
+
description:
|
|
33
|
+
'Record the disposition of the approval conversation turn. '
|
|
34
|
+
+ 'Call this tool with the determined disposition and a natural reply to the user.',
|
|
35
|
+
input_schema: {
|
|
36
|
+
type: 'object' as const,
|
|
37
|
+
properties: {
|
|
38
|
+
disposition: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
enum: ['keep_pending', 'approve_once', 'approve_always', 'reject'],
|
|
41
|
+
description:
|
|
42
|
+
'The decision: keep_pending if the user is asking questions or unclear, '
|
|
43
|
+
+ 'approve_once to approve this single request, approve_always to approve '
|
|
44
|
+
+ 'this tool permanently, reject to deny the request.',
|
|
45
|
+
},
|
|
46
|
+
replyText: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'A natural language reply to send back to the user.',
|
|
49
|
+
},
|
|
50
|
+
targetRunId: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description:
|
|
53
|
+
'The run ID of the specific pending approval being acted on. '
|
|
54
|
+
+ 'Required when there are multiple pending approvals and the disposition is decision-bearing.',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['disposition', 'replyText'],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const VALID_DISPOSITIONS: ReadonlySet<string> = new Set([
|
|
62
|
+
'keep_pending',
|
|
63
|
+
'approve_once',
|
|
64
|
+
'approve_always',
|
|
65
|
+
'reject',
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create the daemon-owned approval copy generator that resolves providers
|
|
70
|
+
* and calls `provider.sendMessage` to generate approval copy text.
|
|
71
|
+
* This keeps all provider awareness in the daemon lifecycle, away from
|
|
72
|
+
* the runtime composer.
|
|
73
|
+
*/
|
|
74
|
+
export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
|
|
75
|
+
return async (context, options = {}) => {
|
|
76
|
+
const config = loadConfig();
|
|
77
|
+
let provider;
|
|
78
|
+
try {
|
|
79
|
+
provider = getFailoverProvider(config.provider, config.providerOrder);
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const fallbackText = options.fallbackText?.trim() || getFallbackMessage(context);
|
|
85
|
+
const requiredKeywords = options.requiredKeywords?.map((kw) => kw.trim()).filter((kw) => kw.length > 0);
|
|
86
|
+
const prompt = buildGenerationPrompt(context, fallbackText, requiredKeywords);
|
|
87
|
+
|
|
88
|
+
const response = await provider.sendMessage(
|
|
89
|
+
[{ role: 'user', content: [{ type: 'text', text: prompt }] }],
|
|
90
|
+
[],
|
|
91
|
+
APPROVAL_COPY_SYSTEM_PROMPT,
|
|
92
|
+
{
|
|
93
|
+
config: {
|
|
94
|
+
max_tokens: options.maxTokens ?? APPROVAL_COPY_MAX_TOKENS,
|
|
95
|
+
},
|
|
96
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? APPROVAL_COPY_TIMEOUT_MS),
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const block = response.content.find((entry) => entry.type === 'text');
|
|
101
|
+
const text = block && 'text' in block ? block.text.trim() : '';
|
|
102
|
+
if (!text) return null;
|
|
103
|
+
const cleaned = text
|
|
104
|
+
.replace(/^["'`]+/, '')
|
|
105
|
+
.replace(/["'`]+$/, '')
|
|
106
|
+
.trim();
|
|
107
|
+
if (!cleaned) return null;
|
|
108
|
+
if (!includesRequiredKeywords(cleaned, requiredKeywords)) return null;
|
|
109
|
+
return cleaned;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create the daemon-owned approval conversation generator that resolves
|
|
115
|
+
* providers and uses tool_use / function calling for structured output.
|
|
116
|
+
* Follows the same provider-aware pattern as createApprovalCopyGenerator().
|
|
117
|
+
*/
|
|
118
|
+
export function createApprovalConversationGenerator(): ApprovalConversationGenerator {
|
|
119
|
+
return async (context) => {
|
|
120
|
+
const config = loadConfig();
|
|
121
|
+
if (!listProviders().includes(config.provider)) {
|
|
122
|
+
throw new Error('No provider available for approval conversation');
|
|
123
|
+
}
|
|
124
|
+
const provider = getFailoverProvider(config.provider, config.providerOrder);
|
|
125
|
+
|
|
126
|
+
const pendingDescription = context.pendingApprovals
|
|
127
|
+
.map((p) => `- Run ${p.runId}: tool "${p.toolName}"`)
|
|
128
|
+
.join('\n');
|
|
129
|
+
|
|
130
|
+
const userPrompt = [
|
|
131
|
+
`Role: ${context.role}`,
|
|
132
|
+
`Tool requesting approval: "${context.toolName}"`,
|
|
133
|
+
`Allowed actions: ${context.allowedActions.join(', ')}`,
|
|
134
|
+
`Pending approvals:\n${pendingDescription}`,
|
|
135
|
+
`\nUser message: ${context.userMessage}`,
|
|
136
|
+
].join('\n');
|
|
137
|
+
|
|
138
|
+
const response = await provider.sendMessage(
|
|
139
|
+
[{ role: 'user', content: [{ type: 'text', text: userPrompt }] }],
|
|
140
|
+
[APPROVAL_CONVERSATION_TOOL_SCHEMA],
|
|
141
|
+
APPROVAL_CONVERSATION_SYSTEM_PROMPT,
|
|
142
|
+
{
|
|
143
|
+
config: {
|
|
144
|
+
max_tokens: APPROVAL_CONVERSATION_MAX_TOKENS,
|
|
145
|
+
},
|
|
146
|
+
signal: AbortSignal.timeout(APPROVAL_CONVERSATION_TIMEOUT_MS),
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Extract the tool_use block from the response
|
|
151
|
+
const toolUseBlock = response.content.find(
|
|
152
|
+
(block) => block.type === 'tool_use' && block.name === APPROVAL_CONVERSATION_TOOL_NAME,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (!toolUseBlock || toolUseBlock.type !== 'tool_use') {
|
|
156
|
+
throw new Error('Provider did not return a tool_use block for approval decision');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const input = toolUseBlock.input as Record<string, unknown>;
|
|
160
|
+
|
|
161
|
+
// Strict validation of the structured output
|
|
162
|
+
const disposition = input.disposition;
|
|
163
|
+
if (typeof disposition !== 'string' || !VALID_DISPOSITIONS.has(disposition)) {
|
|
164
|
+
throw new Error(`Invalid disposition: ${String(disposition)}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const replyText = input.replyText;
|
|
168
|
+
if (typeof replyText !== 'string' || replyText.trim().length === 0) {
|
|
169
|
+
throw new Error('Missing or empty replyText in tool_use response');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const targetRunId = input.targetRunId;
|
|
173
|
+
if (targetRunId !== undefined && typeof targetRunId !== 'string') {
|
|
174
|
+
throw new Error('Invalid targetRunId in tool_use response');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const result: ApprovalConversationResult = {
|
|
178
|
+
disposition: disposition as ApprovalConversationDisposition,
|
|
179
|
+
replyText: replyText.trim(),
|
|
180
|
+
};
|
|
181
|
+
if (typeof targetRunId === 'string' && targetRunId.length > 0) {
|
|
182
|
+
result.targetRunId = targetRunId;
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
};
|
|
186
|
+
}
|