@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
package/src/instrument.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Sentry from "@sentry/node";
|
|
2
2
|
import { APP_VERSION } from "./version.js";
|
|
3
|
+
import { getSentryDsn } from "./config/env.js";
|
|
3
4
|
|
|
4
5
|
/** Patterns that match sensitive data in Sentry event values. */
|
|
5
6
|
const PII_PATTERNS = [
|
|
@@ -20,7 +21,7 @@ function redactString(value: string): string {
|
|
|
20
21
|
function redactObject(obj: unknown): unknown {
|
|
21
22
|
if (typeof obj === "string") return redactString(obj);
|
|
22
23
|
if (Array.isArray(obj)) return obj.map(redactObject);
|
|
23
|
-
if (obj
|
|
24
|
+
if (obj != null && typeof obj === "object") {
|
|
24
25
|
const out: Record<string, unknown> = {};
|
|
25
26
|
for (const [key, val] of Object.entries(obj)) {
|
|
26
27
|
out[key] = redactObject(val);
|
|
@@ -30,10 +31,10 @@ function redactObject(obj: unknown): unknown {
|
|
|
30
31
|
return obj;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
/** Call after dotenv has loaded so
|
|
34
|
+
/** Call after dotenv has loaded so SENTRY_DSN is available. */
|
|
34
35
|
export function initSentry(): void {
|
|
35
36
|
Sentry.init({
|
|
36
|
-
dsn:
|
|
37
|
+
dsn: getSentryDsn(),
|
|
37
38
|
release: `vellum-assistant@${APP_VERSION}`,
|
|
38
39
|
environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
|
|
39
40
|
sendDefaultPii: false,
|
package/src/logfire.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Provider, ProviderResponse, SendMessageOptions, Message, ToolDefinition } from './providers/types.js';
|
|
2
2
|
import { APP_VERSION } from './version.js';
|
|
3
3
|
import { getLogger } from './util/logger.js';
|
|
4
|
+
import { getLogfireToken, isMonitoringEnabled } from './config/env.js';
|
|
4
5
|
|
|
5
6
|
const log = getLogger('logfire');
|
|
6
7
|
|
|
@@ -8,8 +9,8 @@ type LogfireModule = typeof import('@pydantic/logfire-node');
|
|
|
8
9
|
|
|
9
10
|
const LOGFIRE_ENABLED: boolean =
|
|
10
11
|
APP_VERSION === '0.0.0-dev' &&
|
|
11
|
-
!!
|
|
12
|
-
|
|
12
|
+
!!getLogfireToken() &&
|
|
13
|
+
isMonitoringEnabled();
|
|
13
14
|
|
|
14
15
|
let logfireInstance: LogfireModule | null = null;
|
|
15
16
|
|
|
@@ -24,7 +25,7 @@ export async function initLogfire(): Promise<void> {
|
|
|
24
25
|
try {
|
|
25
26
|
const logfire = await import('@pydantic/logfire-node');
|
|
26
27
|
logfire.configure({
|
|
27
|
-
token:
|
|
28
|
+
token: getLogfireToken(),
|
|
28
29
|
serviceName: 'vellum-assistant',
|
|
29
30
|
serviceVersion: APP_VERSION,
|
|
30
31
|
});
|
package/src/memory/admin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getConfig } from '../config/loader.js';
|
|
2
2
|
import { getLogger } from '../util/logger.js';
|
|
3
3
|
import { getMemoryBackendStatus } from './embedding-backend.js';
|
|
4
|
-
import {
|
|
4
|
+
import { rawGet } from './db.js';
|
|
5
5
|
import { enqueueBackfillJob, enqueueRebuildIndexJob } from './indexer.js';
|
|
6
6
|
import {
|
|
7
7
|
enqueueCleanupResolvedConflictsJob,
|
|
@@ -43,28 +43,35 @@ export interface MemoryConflictAndCleanupStats {
|
|
|
43
43
|
cleanup: MemorySystemStatus['cleanup'];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
interface ConflictStatsRow {
|
|
47
|
+
pending_count: number | null;
|
|
48
|
+
resolved_count: number | null;
|
|
49
|
+
oldest_pending_created_at: number | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface CleanupStatsRow {
|
|
53
|
+
resolved_backlog: number | null;
|
|
54
|
+
superseded_backlog: number | null;
|
|
55
|
+
resolved_completed_24h: number | null;
|
|
56
|
+
superseded_completed_24h: number | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
/** Lightweight query for conflict/cleanup metrics only — no table counts or job totals. */
|
|
47
60
|
export function getMemoryConflictAndCleanupStats(): MemoryConflictAndCleanupStats {
|
|
48
|
-
const
|
|
49
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { get: (...args: unknown[]) => unknown } } }).$client;
|
|
50
|
-
const conflictStats = raw.query(`
|
|
61
|
+
const conflictStats = rawGet<ConflictStatsRow>(`
|
|
51
62
|
SELECT
|
|
52
63
|
SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
|
|
53
64
|
SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
|
|
54
65
|
MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
|
|
55
66
|
FROM memory_item_conflicts
|
|
56
|
-
`)
|
|
57
|
-
pending_count: number | null;
|
|
58
|
-
resolved_count: number | null;
|
|
59
|
-
oldest_pending_created_at: number | null;
|
|
60
|
-
} | null;
|
|
67
|
+
`);
|
|
61
68
|
const pending = conflictStats?.pending_count ?? 0;
|
|
62
69
|
const oldestPendingCreatedAt = conflictStats?.oldest_pending_created_at ?? null;
|
|
63
|
-
const oldestPendingAgeMs = oldestPendingCreatedAt
|
|
70
|
+
const oldestPendingAgeMs = oldestPendingCreatedAt == null
|
|
64
71
|
? null
|
|
65
72
|
: Math.max(0, Date.now() - oldestPendingCreatedAt);
|
|
66
73
|
const throughputWindowStartMs = Date.now() - (24 * 60 * 60 * 1000);
|
|
67
|
-
const cleanupStats =
|
|
74
|
+
const cleanupStats = rawGet<CleanupStatsRow>(`
|
|
68
75
|
SELECT
|
|
69
76
|
SUM(CASE
|
|
70
77
|
WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
|
|
@@ -83,12 +90,7 @@ export function getMemoryConflictAndCleanupStats(): MemoryConflictAndCleanupStat
|
|
|
83
90
|
THEN 1 ELSE 0 END
|
|
84
91
|
) AS superseded_completed_24h
|
|
85
92
|
FROM memory_jobs
|
|
86
|
-
|
|
87
|
-
resolved_backlog: number | null;
|
|
88
|
-
superseded_backlog: number | null;
|
|
89
|
-
resolved_completed_24h: number | null;
|
|
90
|
-
superseded_completed_24h: number | null;
|
|
91
|
-
} | null;
|
|
93
|
+
`, throughputWindowStartMs, throughputWindowStartMs);
|
|
92
94
|
return {
|
|
93
95
|
conflicts: {
|
|
94
96
|
pending,
|
|
@@ -107,32 +109,26 @@ export function getMemoryConflictAndCleanupStats(): MemoryConflictAndCleanupStat
|
|
|
107
109
|
export function getMemorySystemStatus(): MemorySystemStatus {
|
|
108
110
|
const config = getConfig();
|
|
109
111
|
const backend = getMemoryBackendStatus(config);
|
|
110
|
-
const db = getDb();
|
|
111
|
-
const raw = (db as unknown as { $client: { query: (q: string) => { get: (...args: unknown[]) => unknown } } }).$client;
|
|
112
112
|
const counts = {
|
|
113
113
|
segments: countTable('memory_segments'),
|
|
114
114
|
items: countTable('memory_items'),
|
|
115
115
|
summaries: countTable('memory_summaries'),
|
|
116
116
|
embeddings: countTable('memory_embeddings'),
|
|
117
117
|
};
|
|
118
|
-
const conflictStats =
|
|
118
|
+
const conflictStats = rawGet<ConflictStatsRow>(`
|
|
119
119
|
SELECT
|
|
120
120
|
SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
|
|
121
121
|
SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
|
|
122
122
|
MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
|
|
123
123
|
FROM memory_item_conflicts
|
|
124
|
-
`)
|
|
125
|
-
pending_count: number | null;
|
|
126
|
-
resolved_count: number | null;
|
|
127
|
-
oldest_pending_created_at: number | null;
|
|
128
|
-
} | null;
|
|
124
|
+
`);
|
|
129
125
|
const pending = conflictStats?.pending_count ?? 0;
|
|
130
126
|
const oldestPendingCreatedAt = conflictStats?.oldest_pending_created_at ?? null;
|
|
131
|
-
const oldestPendingAgeMs = oldestPendingCreatedAt
|
|
127
|
+
const oldestPendingAgeMs = oldestPendingCreatedAt == null
|
|
132
128
|
? null
|
|
133
129
|
: Math.max(0, Date.now() - oldestPendingCreatedAt);
|
|
134
130
|
const throughputWindowStartMs = Date.now() - (24 * 60 * 60 * 1000);
|
|
135
|
-
const cleanupStats =
|
|
131
|
+
const cleanupStats = rawGet<CleanupStatsRow>(`
|
|
136
132
|
SELECT
|
|
137
133
|
SUM(CASE
|
|
138
134
|
WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
|
|
@@ -151,12 +147,7 @@ export function getMemorySystemStatus(): MemorySystemStatus {
|
|
|
151
147
|
THEN 1 ELSE 0 END
|
|
152
148
|
) AS superseded_completed_24h
|
|
153
149
|
FROM memory_jobs
|
|
154
|
-
|
|
155
|
-
resolved_backlog: number | null;
|
|
156
|
-
superseded_backlog: number | null;
|
|
157
|
-
resolved_completed_24h: number | null;
|
|
158
|
-
superseded_completed_24h: number | null;
|
|
159
|
-
} | null;
|
|
150
|
+
`, throughputWindowStartMs, throughputWindowStartMs);
|
|
160
151
|
return {
|
|
161
152
|
enabled: backend.enabled,
|
|
162
153
|
degraded: backend.degraded,
|
|
@@ -179,8 +170,7 @@ export function getMemorySystemStatus(): MemorySystemStatus {
|
|
|
179
170
|
};
|
|
180
171
|
|
|
181
172
|
function countTable(table: string): number {
|
|
182
|
-
|
|
183
|
-
return row?.c ?? 0;
|
|
173
|
+
return rawGet<{ c: number }>(`SELECT COUNT(*) AS c FROM ${table}`)?.c ?? 0;
|
|
184
174
|
}
|
|
185
175
|
}
|
|
186
176
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { eq } from 'drizzle-orm';
|
|
9
9
|
import { v4 as uuid } from 'uuid';
|
|
10
|
-
import { getDb } from './db.js';
|
|
10
|
+
import { getDb, rawRun } from './db.js';
|
|
11
11
|
import { attachments, messageAttachments } from './schema.js';
|
|
12
12
|
|
|
13
13
|
export interface StoredAttachment {
|
|
@@ -322,7 +322,7 @@ export function getAttachmentsForMessage(
|
|
|
322
322
|
|
|
323
323
|
if (links.length === 0) return [];
|
|
324
324
|
|
|
325
|
-
const ids = links.map((l) => l.attachmentId).filter((id): id is string => id
|
|
325
|
+
const ids = links.map((l) => l.attachmentId).filter((id): id is string => id != null);
|
|
326
326
|
return getAttachmentsByIds(ids);
|
|
327
327
|
}
|
|
328
328
|
|
|
@@ -386,12 +386,9 @@ export function getAttachmentById(
|
|
|
386
386
|
*/
|
|
387
387
|
export function deleteOrphanAttachments(candidateIds: string[]): number {
|
|
388
388
|
if (candidateIds.length === 0) return 0;
|
|
389
|
-
const db = getDb();
|
|
390
|
-
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
391
389
|
const placeholders = candidateIds.map(() => '?').join(', ');
|
|
392
|
-
|
|
390
|
+
return rawRun(
|
|
393
391
|
`DELETE FROM attachments WHERE id IN (${placeholders}) AND id NOT IN (SELECT attachment_id FROM message_attachments)`,
|
|
392
|
+
...candidateIds,
|
|
394
393
|
);
|
|
395
|
-
const result = stmt.run(...candidateIds);
|
|
396
|
-
return result.changes;
|
|
397
394
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* and a replay endpoint allows manual recovery of dead-lettered ones.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { eq, and, lte, isNotNull } from 'drizzle-orm';
|
|
14
|
+
import { eq, and, desc, lte, isNotNull } from 'drizzle-orm';
|
|
15
15
|
import { v4 as uuid } from 'uuid';
|
|
16
16
|
import { getDb } from './db.js';
|
|
17
17
|
import { channelInboundEvents, conversations } from './schema.js';
|
|
@@ -229,6 +229,35 @@ export function clearPayload(eventId: string): void {
|
|
|
229
229
|
.run();
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Retrieve the stored raw payload for a given conversation's most recent
|
|
234
|
+
* inbound event. Used by the escalation decide flow to recover the
|
|
235
|
+
* original message content after an approve/deny decision.
|
|
236
|
+
*/
|
|
237
|
+
export function getLatestStoredPayload(conversationId: string): Record<string, unknown> | null {
|
|
238
|
+
const db = getDb();
|
|
239
|
+
const row = db
|
|
240
|
+
.select({
|
|
241
|
+
rawPayload: channelInboundEvents.rawPayload,
|
|
242
|
+
})
|
|
243
|
+
.from(channelInboundEvents)
|
|
244
|
+
.where(
|
|
245
|
+
and(
|
|
246
|
+
eq(channelInboundEvents.conversationId, conversationId),
|
|
247
|
+
isNotNull(channelInboundEvents.rawPayload),
|
|
248
|
+
),
|
|
249
|
+
)
|
|
250
|
+
.orderBy(desc(channelInboundEvents.createdAt))
|
|
251
|
+
.get();
|
|
252
|
+
|
|
253
|
+
if (!row?.rawPayload) return null;
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(row.rawPayload) as Record<string, unknown>;
|
|
256
|
+
} catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
232
261
|
/** Mark an event as successfully processed. */
|
|
233
262
|
export function markProcessed(eventId: string): void {
|
|
234
263
|
const db = getDb();
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* requests track per-run guardian approval decisions.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { and, desc, eq, gt, lte } from 'drizzle-orm';
|
|
11
|
+
import { and, count, desc, eq, gt, lte } from 'drizzle-orm';
|
|
12
12
|
import { v4 as uuid } from 'uuid';
|
|
13
13
|
import { getDb } from './db.js';
|
|
14
14
|
import {
|
|
@@ -142,6 +142,7 @@ export function createBinding(params: {
|
|
|
142
142
|
guardianExternalUserId: string;
|
|
143
143
|
guardianDeliveryChatId: string;
|
|
144
144
|
verifiedVia?: string;
|
|
145
|
+
metadataJson?: string | null;
|
|
145
146
|
}): GuardianBinding {
|
|
146
147
|
const db = getDb();
|
|
147
148
|
const now = Date.now();
|
|
@@ -156,7 +157,7 @@ export function createBinding(params: {
|
|
|
156
157
|
status: 'active' as const,
|
|
157
158
|
verifiedAt: now,
|
|
158
159
|
verifiedVia: params.verifiedVia ?? 'challenge',
|
|
159
|
-
metadataJson: null,
|
|
160
|
+
metadataJson: params.metadataJson ?? null,
|
|
160
161
|
createdAt: now,
|
|
161
162
|
updatedAt: now,
|
|
162
163
|
};
|
|
@@ -256,6 +257,20 @@ export function createChallenge(params: {
|
|
|
256
257
|
return rowToChallenge(row);
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
export function revokePendingChallenges(assistantId: string, channel: string): void {
|
|
261
|
+
const db = getDb();
|
|
262
|
+
db.update(channelGuardianVerificationChallenges)
|
|
263
|
+
.set({ status: 'revoked', updatedAt: Date.now() })
|
|
264
|
+
.where(
|
|
265
|
+
and(
|
|
266
|
+
eq(channelGuardianVerificationChallenges.assistantId, assistantId),
|
|
267
|
+
eq(channelGuardianVerificationChallenges.channel, channel),
|
|
268
|
+
eq(channelGuardianVerificationChallenges.status, 'pending'),
|
|
269
|
+
),
|
|
270
|
+
)
|
|
271
|
+
.run();
|
|
272
|
+
}
|
|
273
|
+
|
|
259
274
|
export function findPendingChallengeByHash(
|
|
260
275
|
assistantId: string,
|
|
261
276
|
channel: string,
|
|
@@ -281,6 +296,33 @@ export function findPendingChallengeByHash(
|
|
|
281
296
|
return row ? rowToChallenge(row) : null;
|
|
282
297
|
}
|
|
283
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Find any pending (non-expired) challenge for a given (assistantId, channel).
|
|
301
|
+
* Used by relay setup to detect whether a voice verification session is active.
|
|
302
|
+
*/
|
|
303
|
+
export function findPendingChallengeForChannel(
|
|
304
|
+
assistantId: string,
|
|
305
|
+
channel: string,
|
|
306
|
+
): VerificationChallenge | null {
|
|
307
|
+
const db = getDb();
|
|
308
|
+
const now = Date.now();
|
|
309
|
+
|
|
310
|
+
const row = db
|
|
311
|
+
.select()
|
|
312
|
+
.from(channelGuardianVerificationChallenges)
|
|
313
|
+
.where(
|
|
314
|
+
and(
|
|
315
|
+
eq(channelGuardianVerificationChallenges.assistantId, assistantId),
|
|
316
|
+
eq(channelGuardianVerificationChallenges.channel, channel),
|
|
317
|
+
eq(channelGuardianVerificationChallenges.status, 'pending'),
|
|
318
|
+
gt(channelGuardianVerificationChallenges.expiresAt, now),
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
.get();
|
|
322
|
+
|
|
323
|
+
return row ? rowToChallenge(row) : null;
|
|
324
|
+
}
|
|
325
|
+
|
|
284
326
|
export function consumeChallenge(
|
|
285
327
|
id: string,
|
|
286
328
|
consumedByExternalUserId: string,
|
|
@@ -538,6 +580,164 @@ export function updateApprovalDecision(
|
|
|
538
580
|
.run();
|
|
539
581
|
}
|
|
540
582
|
|
|
583
|
+
// ---------------------------------------------------------------------------
|
|
584
|
+
// Inbox / Escalation Query Helpers
|
|
585
|
+
// ---------------------------------------------------------------------------
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* List approval requests filtered by assistant, and optionally by channel,
|
|
589
|
+
* conversation, and status. Designed for the inbox UI to show a paginated
|
|
590
|
+
* list of escalations.
|
|
591
|
+
*/
|
|
592
|
+
export function listPendingApprovalRequests(params: {
|
|
593
|
+
assistantId?: string;
|
|
594
|
+
channel?: string;
|
|
595
|
+
conversationId?: string;
|
|
596
|
+
status?: ApprovalRequestStatus;
|
|
597
|
+
limit?: number;
|
|
598
|
+
offset?: number;
|
|
599
|
+
}): GuardianApprovalRequest[] {
|
|
600
|
+
const db = getDb();
|
|
601
|
+
|
|
602
|
+
const conditions = [
|
|
603
|
+
eq(channelGuardianApprovalRequests.assistantId, params.assistantId ?? 'self'),
|
|
604
|
+
];
|
|
605
|
+
if (params.channel) {
|
|
606
|
+
conditions.push(eq(channelGuardianApprovalRequests.channel, params.channel));
|
|
607
|
+
}
|
|
608
|
+
if (params.conversationId) {
|
|
609
|
+
conditions.push(eq(channelGuardianApprovalRequests.conversationId, params.conversationId));
|
|
610
|
+
}
|
|
611
|
+
conditions.push(
|
|
612
|
+
eq(channelGuardianApprovalRequests.status, params.status ?? 'pending'),
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
let query = db
|
|
616
|
+
.select()
|
|
617
|
+
.from(channelGuardianApprovalRequests)
|
|
618
|
+
.where(and(...conditions))
|
|
619
|
+
.orderBy(desc(channelGuardianApprovalRequests.createdAt));
|
|
620
|
+
|
|
621
|
+
if (params.limit !== undefined) {
|
|
622
|
+
query = query.limit(params.limit) as typeof query;
|
|
623
|
+
}
|
|
624
|
+
if (params.offset !== undefined) {
|
|
625
|
+
query = query.offset(params.offset) as typeof query;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return query.all().map(rowToApprovalRequest);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Fetch a single approval request by its primary key.
|
|
633
|
+
*/
|
|
634
|
+
export function getApprovalRequestById(id: string): GuardianApprovalRequest | null {
|
|
635
|
+
const db = getDb();
|
|
636
|
+
|
|
637
|
+
const row = db
|
|
638
|
+
.select()
|
|
639
|
+
.from(channelGuardianApprovalRequests)
|
|
640
|
+
.where(eq(channelGuardianApprovalRequests.id, id))
|
|
641
|
+
.get();
|
|
642
|
+
|
|
643
|
+
return row ? rowToApprovalRequest(row) : null;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Fetch a single approval request by run ID (any status).
|
|
648
|
+
* Useful for checking whether a run has an associated approval request.
|
|
649
|
+
*/
|
|
650
|
+
export function getApprovalRequestByRunId(runId: string): GuardianApprovalRequest | null {
|
|
651
|
+
const db = getDb();
|
|
652
|
+
|
|
653
|
+
const row = db
|
|
654
|
+
.select()
|
|
655
|
+
.from(channelGuardianApprovalRequests)
|
|
656
|
+
.where(eq(channelGuardianApprovalRequests.runId, runId))
|
|
657
|
+
.orderBy(desc(channelGuardianApprovalRequests.createdAt))
|
|
658
|
+
.get();
|
|
659
|
+
|
|
660
|
+
return row ? rowToApprovalRequest(row) : null;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Resolve a pending approval request with a decision.
|
|
665
|
+
*
|
|
666
|
+
* Idempotent: if the request is already resolved with the same decision,
|
|
667
|
+
* the existing record is returned unchanged. Returns null if the request
|
|
668
|
+
* does not exist or was resolved with a *different* decision.
|
|
669
|
+
*/
|
|
670
|
+
export function resolveApprovalRequest(
|
|
671
|
+
id: string,
|
|
672
|
+
decision: 'approved' | 'denied',
|
|
673
|
+
decidedByExternalUserId?: string,
|
|
674
|
+
): GuardianApprovalRequest | null {
|
|
675
|
+
const db = getDb();
|
|
676
|
+
|
|
677
|
+
const existing = db
|
|
678
|
+
.select()
|
|
679
|
+
.from(channelGuardianApprovalRequests)
|
|
680
|
+
.where(eq(channelGuardianApprovalRequests.id, id))
|
|
681
|
+
.get();
|
|
682
|
+
|
|
683
|
+
if (!existing) return null;
|
|
684
|
+
|
|
685
|
+
// Idempotent: already resolved with the same decision
|
|
686
|
+
if (existing.status === decision) {
|
|
687
|
+
return rowToApprovalRequest(existing);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Only resolve if currently pending
|
|
691
|
+
if (existing.status !== 'pending') {
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const now = Date.now();
|
|
696
|
+
|
|
697
|
+
db.update(channelGuardianApprovalRequests)
|
|
698
|
+
.set({
|
|
699
|
+
status: decision,
|
|
700
|
+
decidedByExternalUserId: decidedByExternalUserId ?? null,
|
|
701
|
+
updatedAt: now,
|
|
702
|
+
})
|
|
703
|
+
.where(eq(channelGuardianApprovalRequests.id, id))
|
|
704
|
+
.run();
|
|
705
|
+
|
|
706
|
+
return rowToApprovalRequest({
|
|
707
|
+
...existing,
|
|
708
|
+
status: decision,
|
|
709
|
+
decidedByExternalUserId: decidedByExternalUserId ?? null,
|
|
710
|
+
updatedAt: now,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Count pending approval requests for a given conversation.
|
|
716
|
+
* Used by thread state projection to compute `pending_escalation_count`.
|
|
717
|
+
*/
|
|
718
|
+
export function countPendingByConversation(
|
|
719
|
+
conversationId: string,
|
|
720
|
+
assistantId?: string,
|
|
721
|
+
): number {
|
|
722
|
+
const db = getDb();
|
|
723
|
+
|
|
724
|
+
const conditions = [
|
|
725
|
+
eq(channelGuardianApprovalRequests.conversationId, conversationId),
|
|
726
|
+
eq(channelGuardianApprovalRequests.status, 'pending'),
|
|
727
|
+
];
|
|
728
|
+
if (assistantId) {
|
|
729
|
+
conditions.push(eq(channelGuardianApprovalRequests.assistantId, assistantId));
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
const result = db
|
|
733
|
+
.select({ count: count() })
|
|
734
|
+
.from(channelGuardianApprovalRequests)
|
|
735
|
+
.where(and(...conditions))
|
|
736
|
+
.get();
|
|
737
|
+
|
|
738
|
+
return result?.count ?? 0;
|
|
739
|
+
}
|
|
740
|
+
|
|
541
741
|
// ---------------------------------------------------------------------------
|
|
542
742
|
// Verification Rate Limits
|
|
543
743
|
// ---------------------------------------------------------------------------
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { getConfiguredProvider, createTimeout, extractToolUse, userMessage } from '../providers/provider-send-message.js';
|
|
2
|
+
import type { ModelIntent } from '../providers/types.js';
|
|
3
3
|
import { truncate } from '../util/truncate.js';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const DEFAULT_RESOLVER_MODEL_INTENT: ModelIntent = 'latency-optimized';
|
|
6
6
|
const DEFAULT_RESOLVER_TIMEOUT_MS = 12_000;
|
|
7
7
|
|
|
8
8
|
const DIRECTIONAL_EXISTING_CUES = ['existing', 'old', 'previous', 'first', 'earlier', 'original'];
|
|
@@ -38,6 +38,7 @@ export interface ClarificationResolverInput {
|
|
|
38
38
|
export interface ClarificationResolverOptions {
|
|
39
39
|
apiKey?: string;
|
|
40
40
|
model?: string;
|
|
41
|
+
modelIntent?: ModelIntent;
|
|
41
42
|
timeoutMs?: number;
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -55,21 +56,20 @@ export async function resolveConflictClarification(
|
|
|
55
56
|
const heuristicResult = resolveWithHeuristics(input);
|
|
56
57
|
if (heuristicResult) return heuristicResult;
|
|
57
58
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
if (!apiKey) {
|
|
59
|
+
const provider = getConfiguredProvider();
|
|
60
|
+
if (!provider) {
|
|
61
61
|
return {
|
|
62
62
|
resolution: 'still_unclear',
|
|
63
63
|
strategy: 'no_llm_key',
|
|
64
64
|
resolvedStatement: null,
|
|
65
|
-
explanation: '
|
|
65
|
+
explanation: 'Configured provider unavailable for clarification fallback.',
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
try {
|
|
70
70
|
return await resolveWithLlm(input, {
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
model: options?.model,
|
|
72
|
+
modelIntent: options?.modelIntent ?? DEFAULT_RESOLVER_MODEL_INTENT,
|
|
73
73
|
timeoutMs: options?.timeoutMs ?? DEFAULT_RESOLVER_TIMEOUT_MS,
|
|
74
74
|
});
|
|
75
75
|
} catch (err) {
|
|
@@ -168,9 +168,9 @@ function resolveWithHeuristics(input: ClarificationResolverInput): Clarification
|
|
|
168
168
|
|
|
169
169
|
async function resolveWithLlm(
|
|
170
170
|
input: ClarificationResolverInput,
|
|
171
|
-
options: {
|
|
171
|
+
options: { model?: string; modelIntent: ModelIntent; timeoutMs: number },
|
|
172
172
|
): Promise<ClarificationResolverResult> {
|
|
173
|
-
const
|
|
173
|
+
const provider = getConfiguredProvider()!;
|
|
174
174
|
const userPrompt = [
|
|
175
175
|
'You are resolving a memory clarification response.',
|
|
176
176
|
'',
|
|
@@ -179,22 +179,12 @@ async function resolveWithLlm(
|
|
|
179
179
|
`User clarification: ${input.userMessage}`,
|
|
180
180
|
].join('\n');
|
|
181
181
|
|
|
182
|
-
const
|
|
183
|
-
const timer = setTimeout(() => abortController.abort(), options.timeoutMs);
|
|
182
|
+
const { signal, cleanup } = createTimeout(options.timeoutMs);
|
|
184
183
|
|
|
185
184
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
system: [
|
|
190
|
-
'Classify the user clarification for conflicting memory statements.',
|
|
191
|
-
'Return exactly one resolution:',
|
|
192
|
-
'- keep_existing',
|
|
193
|
-
'- keep_candidate',
|
|
194
|
-
'- merge',
|
|
195
|
-
'- still_unclear',
|
|
196
|
-
].join('\n'),
|
|
197
|
-
tools: [{
|
|
185
|
+
const response = await provider.sendMessage(
|
|
186
|
+
[userMessage(userPrompt)],
|
|
187
|
+
[{
|
|
198
188
|
name: 'resolve_conflict_clarification',
|
|
199
189
|
description: 'Resolve a pending memory contradiction using user clarification.',
|
|
200
190
|
input_schema: {
|
|
@@ -216,13 +206,27 @@ async function resolveWithLlm(
|
|
|
216
206
|
required: ['resolution', 'explanation'],
|
|
217
207
|
},
|
|
218
208
|
}],
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
[
|
|
210
|
+
'Classify the user clarification for conflicting memory statements.',
|
|
211
|
+
'Return exactly one resolution:',
|
|
212
|
+
'- keep_existing',
|
|
213
|
+
'- keep_candidate',
|
|
214
|
+
'- merge',
|
|
215
|
+
'- still_unclear',
|
|
216
|
+
].join('\n'),
|
|
217
|
+
{
|
|
218
|
+
config: {
|
|
219
|
+
...(options.model ? { model: options.model } : { modelIntent: options.modelIntent }),
|
|
220
|
+
max_tokens: 256,
|
|
221
|
+
tool_choice: { type: 'tool' as const, name: 'resolve_conflict_clarification' },
|
|
222
|
+
},
|
|
223
|
+
signal,
|
|
224
|
+
},
|
|
225
|
+
);
|
|
226
|
+
cleanup();
|
|
223
227
|
|
|
224
|
-
const toolBlock = response
|
|
225
|
-
if (!toolBlock
|
|
228
|
+
const toolBlock = extractToolUse(response);
|
|
229
|
+
if (!toolBlock) {
|
|
226
230
|
throw new Error('No tool_use block in clarification resolver response.');
|
|
227
231
|
}
|
|
228
232
|
|
|
@@ -247,8 +251,8 @@ async function resolveWithLlm(
|
|
|
247
251
|
explanation: truncate(normalize(parsed.explanation ?? 'Resolved via LLM fallback.'), 500, ''),
|
|
248
252
|
};
|
|
249
253
|
} catch (err) {
|
|
250
|
-
|
|
251
|
-
if (
|
|
254
|
+
cleanup();
|
|
255
|
+
if (signal.aborted) {
|
|
252
256
|
throw new Error('clarification_resolver_timeout');
|
|
253
257
|
}
|
|
254
258
|
throw err;
|