@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,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory pairing request store with TTL.
|
|
3
|
+
*
|
|
4
|
+
* Each pairing request lives for at most TTL_MS (5 minutes) before
|
|
5
|
+
* being swept as expired. Status transitions:
|
|
6
|
+
* registered → pending → approved | denied | expired
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
10
|
+
import { getLogger } from '../util/logger.js';
|
|
11
|
+
|
|
12
|
+
const log = getLogger('pairing-store');
|
|
13
|
+
|
|
14
|
+
const TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
15
|
+
const SWEEP_INTERVAL_MS = 30_000; // 30 seconds
|
|
16
|
+
|
|
17
|
+
export type PairingStatus = 'registered' | 'pending' | 'approved' | 'denied' | 'expired';
|
|
18
|
+
|
|
19
|
+
export interface PairingRequest {
|
|
20
|
+
pairingRequestId: string;
|
|
21
|
+
hashedPairingSecret: string;
|
|
22
|
+
hashedDeviceId?: string;
|
|
23
|
+
deviceName?: string;
|
|
24
|
+
status: PairingStatus;
|
|
25
|
+
gatewayUrl: string;
|
|
26
|
+
localLanUrl: string | null;
|
|
27
|
+
bearerToken?: string;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hashValue(value: string): string {
|
|
32
|
+
return createHash('sha256').update(value).digest('hex');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function timingSafeCompare(a: string, b: string): boolean {
|
|
36
|
+
const bufA = Buffer.from(a);
|
|
37
|
+
const bufB = Buffer.from(b);
|
|
38
|
+
if (bufA.length !== bufB.length) return false;
|
|
39
|
+
return timingSafeEqual(bufA, bufB);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class PairingStore {
|
|
43
|
+
private requests = new Map<string, PairingRequest>();
|
|
44
|
+
private sweepTimer: ReturnType<typeof setInterval> | null = null;
|
|
45
|
+
|
|
46
|
+
start(): void {
|
|
47
|
+
this.sweepTimer = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
stop(): void {
|
|
51
|
+
if (this.sweepTimer) {
|
|
52
|
+
clearInterval(this.sweepTimer);
|
|
53
|
+
this.sweepTimer = null;
|
|
54
|
+
}
|
|
55
|
+
this.requests.clear();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Pre-register a pairing request (called when QR is displayed).
|
|
60
|
+
* Idempotent: if the same ID exists and secret matches, overwrite.
|
|
61
|
+
* Returns false with 'conflict' if ID exists but secret doesn't match.
|
|
62
|
+
*/
|
|
63
|
+
register(params: {
|
|
64
|
+
pairingRequestId: string;
|
|
65
|
+
pairingSecret: string;
|
|
66
|
+
gatewayUrl: string;
|
|
67
|
+
localLanUrl?: string | null;
|
|
68
|
+
}): { ok: true } | { ok: false; reason: 'conflict' } {
|
|
69
|
+
const hashedSecret = hashValue(params.pairingSecret);
|
|
70
|
+
const existing = this.requests.get(params.pairingRequestId);
|
|
71
|
+
|
|
72
|
+
if (existing) {
|
|
73
|
+
if (!timingSafeCompare(existing.hashedPairingSecret, hashedSecret)) {
|
|
74
|
+
return { ok: false, reason: 'conflict' };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.requests.set(params.pairingRequestId, {
|
|
79
|
+
pairingRequestId: params.pairingRequestId,
|
|
80
|
+
hashedPairingSecret: hashedSecret,
|
|
81
|
+
status: 'registered',
|
|
82
|
+
gatewayUrl: params.gatewayUrl,
|
|
83
|
+
localLanUrl: params.localLanUrl ?? null,
|
|
84
|
+
createdAt: Date.now(),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
log.info({ pairingRequestId: params.pairingRequestId }, 'Pairing request registered');
|
|
88
|
+
return { ok: true };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* iOS initiates a pairing request. Validates the secret and transitions
|
|
93
|
+
* the entry to "pending" (or "approved" if auto-approved).
|
|
94
|
+
*/
|
|
95
|
+
beginRequest(params: {
|
|
96
|
+
pairingRequestId: string;
|
|
97
|
+
pairingSecret: string;
|
|
98
|
+
deviceId: string;
|
|
99
|
+
deviceName: string;
|
|
100
|
+
}): { ok: true; entry: PairingRequest } | { ok: false; reason: 'not_found' | 'invalid_secret' | 'expired' } {
|
|
101
|
+
const entry = this.requests.get(params.pairingRequestId);
|
|
102
|
+
if (!entry) {
|
|
103
|
+
return { ok: false, reason: 'not_found' };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (entry.status === 'expired' || entry.status === 'denied') {
|
|
107
|
+
return { ok: false, reason: 'expired' };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const hashedSecret = hashValue(params.pairingSecret);
|
|
111
|
+
if (!timingSafeCompare(entry.hashedPairingSecret, hashedSecret)) {
|
|
112
|
+
return { ok: false, reason: 'invalid_secret' };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
entry.hashedDeviceId = hashValue(params.deviceId);
|
|
116
|
+
entry.deviceName = params.deviceName;
|
|
117
|
+
if (entry.status === 'registered') {
|
|
118
|
+
entry.status = 'pending';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { ok: true, entry };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Approve a pairing request. Sets the bearer token for iOS to retrieve.
|
|
126
|
+
*/
|
|
127
|
+
approve(pairingRequestId: string, bearerToken: string): PairingRequest | null {
|
|
128
|
+
const entry = this.requests.get(pairingRequestId);
|
|
129
|
+
if (!entry) return null;
|
|
130
|
+
entry.status = 'approved';
|
|
131
|
+
entry.bearerToken = bearerToken;
|
|
132
|
+
return entry;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Deny a pairing request.
|
|
137
|
+
*/
|
|
138
|
+
deny(pairingRequestId: string): PairingRequest | null {
|
|
139
|
+
const entry = this.requests.get(pairingRequestId);
|
|
140
|
+
if (!entry) return null;
|
|
141
|
+
entry.status = 'denied';
|
|
142
|
+
return entry;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get a pairing request by ID.
|
|
147
|
+
*/
|
|
148
|
+
get(pairingRequestId: string): PairingRequest | null {
|
|
149
|
+
return this.requests.get(pairingRequestId) ?? null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Validate the secret for a status poll request (timing-safe).
|
|
154
|
+
*/
|
|
155
|
+
validateSecret(pairingRequestId: string, secret: string): boolean {
|
|
156
|
+
const entry = this.requests.get(pairingRequestId);
|
|
157
|
+
if (!entry) return false;
|
|
158
|
+
const hashedSecret = hashValue(secret);
|
|
159
|
+
return timingSafeCompare(entry.hashedPairingSecret, hashedSecret);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private sweep(): void {
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
for (const [id, entry] of this.requests) {
|
|
165
|
+
if (now - entry.createdAt > TTL_MS) {
|
|
166
|
+
if (entry.status !== 'approved') {
|
|
167
|
+
entry.status = 'expired';
|
|
168
|
+
}
|
|
169
|
+
// Remove entries older than 2x TTL regardless of status
|
|
170
|
+
if (now - entry.createdAt > TTL_MS * 2) {
|
|
171
|
+
this.requests.delete(id);
|
|
172
|
+
log.debug({ pairingRequestId: id }, 'Pairing request swept');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { initializeProviders } from '../providers/registry.js';
|
|
2
|
+
import { initializeTools } from '../tools/registry.js';
|
|
3
|
+
import { registerWatcherProvider } from '../watcher/provider-registry.js';
|
|
4
|
+
import { gmailProvider } from '../watcher/providers/gmail.js';
|
|
5
|
+
import { googleCalendarProvider } from '../watcher/providers/google-calendar.js';
|
|
6
|
+
import { slackProvider as slackWatcherProvider } from '../watcher/providers/slack.js';
|
|
7
|
+
import { githubProvider } from '../watcher/providers/github.js';
|
|
8
|
+
import { linearProvider } from '../watcher/providers/linear.js';
|
|
9
|
+
import { registerMessagingProvider } from '../messaging/registry.js';
|
|
10
|
+
import { slackProvider as slackMessagingProvider } from '../messaging/providers/slack/adapter.js';
|
|
11
|
+
import { gmailMessagingProvider } from '../messaging/providers/gmail/adapter.js';
|
|
12
|
+
import { telegramBotMessagingProvider } from '../messaging/providers/telegram-bot/adapter.js';
|
|
13
|
+
import { smsMessagingProvider } from '../messaging/providers/sms/adapter.js';
|
|
14
|
+
import { whatsappMessagingProvider } from '../messaging/providers/whatsapp/adapter.js';
|
|
15
|
+
import { initWatcherEngine } from '../watcher/engine.js';
|
|
16
|
+
import type { AssistantConfig } from '../config/types.js';
|
|
17
|
+
import { getLogger } from '../util/logger.js';
|
|
18
|
+
|
|
19
|
+
const log = getLogger('lifecycle');
|
|
20
|
+
|
|
21
|
+
export async function initializeProvidersAndTools(config: AssistantConfig): Promise<void> {
|
|
22
|
+
log.info('Daemon startup: initializing providers and tools');
|
|
23
|
+
initializeProviders(config);
|
|
24
|
+
await initializeTools();
|
|
25
|
+
log.info('Daemon startup: providers and tools initialized');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function registerWatcherProviders(): void {
|
|
29
|
+
registerWatcherProvider(gmailProvider);
|
|
30
|
+
registerWatcherProvider(googleCalendarProvider);
|
|
31
|
+
registerWatcherProvider(slackWatcherProvider);
|
|
32
|
+
registerWatcherProvider(githubProvider);
|
|
33
|
+
registerWatcherProvider(linearProvider);
|
|
34
|
+
initWatcherEngine();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function registerMessagingProviders(): void {
|
|
38
|
+
registerMessagingProvider(slackMessagingProvider);
|
|
39
|
+
registerMessagingProvider(gmailMessagingProvider);
|
|
40
|
+
registerMessagingProvider(telegramBotMessagingProvider);
|
|
41
|
+
registerMessagingProvider(smsMessagingProvider);
|
|
42
|
+
registerMessagingProvider(whatsappMessagingProvider);
|
|
43
|
+
}
|
|
@@ -23,6 +23,9 @@ const log = getLogger('ride-shotgun-handler');
|
|
|
23
23
|
/** Active network recorders keyed by watchId. */
|
|
24
24
|
const activeRecorders = new Map<string, NetworkRecorder>();
|
|
25
25
|
|
|
26
|
+
/** Active progress interval timers keyed by watchId, cleared on session completion. */
|
|
27
|
+
const activeProgressIntervals = new Map<string, NodeJS.Timeout>();
|
|
28
|
+
|
|
26
29
|
/** Return domain-specific URL patterns that indicate a successful login. */
|
|
27
30
|
function getLoginSignals(targetDomain?: string): string[] {
|
|
28
31
|
if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
|
|
@@ -52,6 +55,13 @@ async function completeSession(session: WatchSession): Promise<void> {
|
|
|
52
55
|
session.timeoutHandle = undefined;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
// Clear progress interval timer if one was registered for this session
|
|
59
|
+
const progressTimer = activeProgressIntervals.get(session.watchId);
|
|
60
|
+
if (progressTimer) {
|
|
61
|
+
clearInterval(progressTimer);
|
|
62
|
+
activeProgressIntervals.delete(session.watchId);
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
const { watchId, sessionId } = session;
|
|
56
66
|
log.info(
|
|
57
67
|
{ watchId, sessionId, observationCount: session.observations.length },
|
|
@@ -135,9 +145,62 @@ export async function handleRideShotgunStart(
|
|
|
135
145
|
activeRecorders.set(watchId, recorder);
|
|
136
146
|
log.info({ watchId, targetDomain, attempt }, 'Network recording started for learn session');
|
|
137
147
|
|
|
148
|
+
// Send periodic progress updates with network entry counts and idle detection
|
|
149
|
+
let lastNetworkEntryCount = 0;
|
|
150
|
+
let lastActivityTimestamp = Date.now();
|
|
151
|
+
let idleHintSent = false;
|
|
152
|
+
|
|
153
|
+
const progressInterval: NodeJS.Timeout = setInterval(() => {
|
|
154
|
+
if (session.status !== 'active') {
|
|
155
|
+
clearInterval(progressInterval);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const currentCount = recorder.entryCount;
|
|
160
|
+
|
|
161
|
+
// Track activity: reset idle timer when count changes
|
|
162
|
+
if (currentCount !== lastNetworkEntryCount) {
|
|
163
|
+
lastNetworkEntryCount = currentCount;
|
|
164
|
+
lastActivityTimestamp = Date.now();
|
|
165
|
+
// If we previously sent an idle hint, clear it now that activity resumed
|
|
166
|
+
if (idleHintSent) {
|
|
167
|
+
idleHintSent = false;
|
|
168
|
+
log.info({ watchId, currentCount }, 'Activity resumed — clearing idleHint');
|
|
169
|
+
ctx.send(socket, {
|
|
170
|
+
type: 'ride_shotgun_progress',
|
|
171
|
+
watchId,
|
|
172
|
+
message: `Recording network traffic...`,
|
|
173
|
+
networkEntryCount: currentCount,
|
|
174
|
+
statusMessage: 'Recording network traffic...',
|
|
175
|
+
idleHint: false,
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Idle detection: if some initial activity happened and no new entries for 15s, hint once
|
|
182
|
+
const idleMs = Date.now() - lastActivityTimestamp;
|
|
183
|
+
let idleHint: boolean | undefined;
|
|
184
|
+
if (!idleHintSent && currentCount > 0 && idleMs >= 15_000) {
|
|
185
|
+
idleHint = true;
|
|
186
|
+
idleHintSent = true;
|
|
187
|
+
log.info({ watchId, currentCount, idleMs }, 'Idle detected — sending idleHint');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
ctx.send(socket, {
|
|
191
|
+
type: 'ride_shotgun_progress',
|
|
192
|
+
watchId,
|
|
193
|
+
message: `Recording network traffic...`,
|
|
194
|
+
networkEntryCount: currentCount,
|
|
195
|
+
statusMessage: 'Recording network traffic...',
|
|
196
|
+
...(idleHint !== undefined ? { idleHint } : {}),
|
|
197
|
+
});
|
|
198
|
+
}, 5000);
|
|
199
|
+
activeProgressIntervals.set(watchId, progressInterval);
|
|
200
|
+
|
|
138
201
|
// For x.com, auto-navigate Chrome through key pages to capture the full API surface.
|
|
139
202
|
// Skip login detection — auto-navigation will complete the session when done.
|
|
140
|
-
if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
|
|
203
|
+
if ((targetDomain === 'x.com' || targetDomain === 'twitter.com') && msg.autoNavigate !== false) {
|
|
141
204
|
// Don't set onLoginDetected — it would kill the session after the first
|
|
142
205
|
// GraphQL call (5s grace), before auto-navigation finishes.
|
|
143
206
|
const abortSignal = { aborted: false };
|
|
@@ -177,7 +240,7 @@ export async function handleRideShotgunStart(
|
|
|
177
240
|
type: 'ride_shotgun_progress',
|
|
178
241
|
watchId,
|
|
179
242
|
message: `[${progress.pageNumber || '?'}] ${shortUrl}`,
|
|
180
|
-
}
|
|
243
|
+
});
|
|
181
244
|
}
|
|
182
245
|
}).then(visited => {
|
|
183
246
|
clearInterval(checkInterval);
|
|
@@ -192,8 +255,10 @@ export async function handleRideShotgunStart(
|
|
|
192
255
|
completeSession(session);
|
|
193
256
|
}
|
|
194
257
|
});
|
|
258
|
+
} else if (msg.autoNavigate === false && targetDomain) {
|
|
259
|
+
// Manual mode: just record network traffic until timeout or early stop — no login detection shortcut.
|
|
195
260
|
} else {
|
|
196
|
-
// No targetDomain: use login detection
|
|
261
|
+
// No targetDomain or targetDomain without explicit autoNavigate=false: use login detection
|
|
197
262
|
recorder.onLoginDetected = () => {
|
|
198
263
|
log.info({ watchId }, 'Login detected — auto-stopping learn session');
|
|
199
264
|
completeSession(session);
|
package/src/daemon/server.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { IngressBlockedError } from '../util/errors.js';
|
|
|
15
15
|
import * as conversationStore from '../memory/conversation-store.js';
|
|
16
16
|
import * as attachmentsStore from '../memory/attachments-store.js';
|
|
17
17
|
import { Session, DEFAULT_MEMORY_POLICY, type SessionMemoryPolicy } from './session.js';
|
|
18
|
+
import { parseChannelId, type ChannelId } from '../channels/types.js';
|
|
18
19
|
import { resolveChannelCapabilities } from './session-runtime-assembly.js';
|
|
19
20
|
import { ComputerUseSession } from './computer-use-session.js';
|
|
20
21
|
import {
|
|
@@ -31,7 +32,6 @@ import { ensureBlobDir, sweepStaleBlobs } from './ipc-blob-store.js';
|
|
|
31
32
|
import { bootstrapHomeBaseAppLink } from '../home-base/bootstrap.js';
|
|
32
33
|
import { SessionEvictor } from './session-evictor.js';
|
|
33
34
|
import { getSubagentManager } from '../subagent/index.js';
|
|
34
|
-
import { tryRouteCallMessage } from '../calls/call-bridge.js';
|
|
35
35
|
import { resolveSlash } from './session-slash.js';
|
|
36
36
|
import { createUserMessage, createAssistantMessage } from '../agent/message-types.js';
|
|
37
37
|
import { registerDaemonCallbacks } from '../work-items/work-item-runner.js';
|
|
@@ -53,6 +53,24 @@ function readPackageVersion(): string | undefined {
|
|
|
53
53
|
|
|
54
54
|
const daemonVersion = readPackageVersion();
|
|
55
55
|
|
|
56
|
+
function resolveTurnChannel(sourceChannel?: string, transportChannelId?: string): ChannelId {
|
|
57
|
+
if (sourceChannel != null) {
|
|
58
|
+
const parsed = parseChannelId(sourceChannel);
|
|
59
|
+
if (!parsed) {
|
|
60
|
+
throw new Error(`Invalid sourceChannel: ${sourceChannel}`);
|
|
61
|
+
}
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
if (transportChannelId != null) {
|
|
65
|
+
const parsed = parseChannelId(transportChannelId);
|
|
66
|
+
if (!parsed) {
|
|
67
|
+
throw new Error(`Invalid transport.channelId: ${transportChannelId}`);
|
|
68
|
+
}
|
|
69
|
+
return parsed;
|
|
70
|
+
}
|
|
71
|
+
return 'macos';
|
|
72
|
+
}
|
|
73
|
+
|
|
56
74
|
export class DaemonServer {
|
|
57
75
|
private server: net.Server | null = null;
|
|
58
76
|
private tcpServer: tls.Server | null = null;
|
|
@@ -358,7 +376,7 @@ export class DaemonServer {
|
|
|
358
376
|
const parseDurationMs = Number(process.hrtime.bigint() - parseStartNs) / 1_000_000;
|
|
359
377
|
for (const entry of parsed) {
|
|
360
378
|
const msg = entry.msg;
|
|
361
|
-
if (typeof msg === 'object' && msg
|
|
379
|
+
if (typeof msg === 'object' && msg != null && (msg as { type?: unknown }).type === 'cu_observation') {
|
|
362
380
|
const maybeSessionId = (msg as { sessionId?: unknown }).sessionId;
|
|
363
381
|
const sessionId = typeof maybeSessionId === 'string' ? maybeSessionId : 'unknown';
|
|
364
382
|
const previousSequence = this.cuObservationParseSequence.get(sessionId) ?? 0;
|
|
@@ -488,6 +506,20 @@ export class DaemonServer {
|
|
|
488
506
|
}
|
|
489
507
|
}
|
|
490
508
|
|
|
509
|
+
get lastConfigFingerprint(): string {
|
|
510
|
+
return this.configWatcher.lastFingerprint;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
set lastConfigFingerprint(value: string) {
|
|
514
|
+
this.configWatcher.lastFingerprint = value;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
refreshConfigFromSources(): boolean {
|
|
518
|
+
const changed = this.configWatcher.refreshConfigFromSources();
|
|
519
|
+
if (changed) this.evictSessionsForReload();
|
|
520
|
+
return changed;
|
|
521
|
+
}
|
|
522
|
+
|
|
491
523
|
private async sendInitialSession(socket: net.Socket): Promise<void> {
|
|
492
524
|
const conversation = conversationStore.getLatestConversation();
|
|
493
525
|
if (!conversation) {
|
|
@@ -666,7 +698,15 @@ export class DaemonServer {
|
|
|
666
698
|
throw new Error('Session is already processing a message');
|
|
667
699
|
}
|
|
668
700
|
|
|
701
|
+
session.setAssistantId(options?.assistantId ?? 'self');
|
|
702
|
+
session.setGuardianContext(options?.guardianContext ?? null);
|
|
669
703
|
session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
|
|
704
|
+
session.setCommandIntent(options?.commandIntent ?? null);
|
|
705
|
+
const resolvedChannel = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
|
|
706
|
+
session.setTurnChannelContext({
|
|
707
|
+
userMessageChannel: resolvedChannel,
|
|
708
|
+
assistantMessageChannel: resolvedChannel,
|
|
709
|
+
});
|
|
670
710
|
|
|
671
711
|
const attachments = attachmentIds
|
|
672
712
|
? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
@@ -680,21 +720,6 @@ export class DaemonServer {
|
|
|
680
720
|
const requestId = crypto.randomUUID();
|
|
681
721
|
const messageId = session.persistUserMessage(content, attachments, requestId);
|
|
682
722
|
|
|
683
|
-
let bridgeHandled = false;
|
|
684
|
-
try {
|
|
685
|
-
const bridgeResult = await tryRouteCallMessage(conversationId, content, messageId);
|
|
686
|
-
bridgeHandled = bridgeResult.handled;
|
|
687
|
-
} catch (err) {
|
|
688
|
-
log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (bridgeHandled) {
|
|
692
|
-
resetSessionProcessingState(session);
|
|
693
|
-
session.drainQueue('loop_complete');
|
|
694
|
-
log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
|
|
695
|
-
return { messageId };
|
|
696
|
-
}
|
|
697
|
-
|
|
698
723
|
session.runAgentLoop(content, messageId, () => {}).catch((err) => {
|
|
699
724
|
log.error({ err, conversationId }, 'Background agent loop failed');
|
|
700
725
|
});
|
|
@@ -720,7 +745,15 @@ export class DaemonServer {
|
|
|
720
745
|
throw new Error('Session is already processing a message');
|
|
721
746
|
}
|
|
722
747
|
|
|
748
|
+
session.setAssistantId(options?.assistantId ?? 'self');
|
|
749
|
+
session.setGuardianContext(options?.guardianContext ?? null);
|
|
723
750
|
session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
|
|
751
|
+
session.setCommandIntent(options?.commandIntent ?? null);
|
|
752
|
+
const resolvedChannel2 = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
|
|
753
|
+
session.setTurnChannelContext({
|
|
754
|
+
userMessageChannel: resolvedChannel2,
|
|
755
|
+
assistantMessageChannel: resolvedChannel2,
|
|
756
|
+
});
|
|
724
757
|
|
|
725
758
|
const attachments = attachmentIds
|
|
726
759
|
? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
@@ -734,19 +767,33 @@ export class DaemonServer {
|
|
|
734
767
|
const slashResult = resolveSlash(content);
|
|
735
768
|
|
|
736
769
|
if (slashResult.kind === 'unknown') {
|
|
770
|
+
const serverTurnCtx = session.getTurnChannelContext();
|
|
771
|
+
const serverChannelMeta = serverTurnCtx
|
|
772
|
+
? { userMessageChannel: serverTurnCtx.userMessageChannel, assistantMessageChannel: serverTurnCtx.assistantMessageChannel }
|
|
773
|
+
: undefined;
|
|
737
774
|
const userMsg = createUserMessage(content, attachments);
|
|
738
775
|
const persisted = conversationStore.addMessage(
|
|
739
776
|
conversationId,
|
|
740
777
|
'user',
|
|
741
778
|
JSON.stringify(userMsg.content),
|
|
779
|
+
serverChannelMeta,
|
|
742
780
|
);
|
|
743
781
|
session.getMessages().push(userMsg);
|
|
744
782
|
|
|
783
|
+
if (serverTurnCtx) {
|
|
784
|
+
try {
|
|
785
|
+
conversationStore.setConversationOriginChannelIfUnset(conversationId, serverTurnCtx.userMessageChannel);
|
|
786
|
+
} catch (err) {
|
|
787
|
+
log.warn({ err, conversationId }, 'Failed to set origin channel (best-effort)');
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
745
791
|
const assistantMsg = createAssistantMessage(slashResult.message);
|
|
746
792
|
conversationStore.addMessage(
|
|
747
793
|
conversationId,
|
|
748
794
|
'assistant',
|
|
749
795
|
JSON.stringify(assistantMsg.content),
|
|
796
|
+
serverChannelMeta,
|
|
750
797
|
);
|
|
751
798
|
session.getMessages().push(assistantMsg);
|
|
752
799
|
return { messageId: persisted.id };
|
|
@@ -767,22 +814,6 @@ export class DaemonServer {
|
|
|
767
814
|
throw err;
|
|
768
815
|
}
|
|
769
816
|
|
|
770
|
-
let bridgeHandled = false;
|
|
771
|
-
try {
|
|
772
|
-
const bridgeResult = await tryRouteCallMessage(conversationId, resolvedContent, messageId);
|
|
773
|
-
bridgeHandled = bridgeResult.handled;
|
|
774
|
-
} catch (err) {
|
|
775
|
-
log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
if (bridgeHandled) {
|
|
779
|
-
(session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
|
|
780
|
-
resetSessionProcessingState(session);
|
|
781
|
-
session.drainQueue('loop_complete');
|
|
782
|
-
log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
|
|
783
|
-
return { messageId };
|
|
784
|
-
}
|
|
785
|
-
|
|
786
817
|
await session.runAgentLoop(resolvedContent, messageId, () => {});
|
|
787
818
|
|
|
788
819
|
return { messageId };
|
|
@@ -790,8 +821,8 @@ export class DaemonServer {
|
|
|
790
821
|
|
|
791
822
|
createRunOrchestrator(): RunOrchestrator {
|
|
792
823
|
return new RunOrchestrator({
|
|
793
|
-
getOrCreateSession: (conversationId) =>
|
|
794
|
-
this.getOrCreateSession(conversationId),
|
|
824
|
+
getOrCreateSession: (conversationId, transport) =>
|
|
825
|
+
this.getOrCreateSession(conversationId, undefined, true, transport ? { transport } : undefined),
|
|
795
826
|
resolveAttachments: (attachmentIds) =>
|
|
796
827
|
attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
|
|
797
828
|
id: a.id,
|
|
@@ -805,14 +836,3 @@ export class DaemonServer {
|
|
|
805
836
|
}
|
|
806
837
|
|
|
807
838
|
}
|
|
808
|
-
|
|
809
|
-
function resetSessionProcessingState(session: Session): void {
|
|
810
|
-
const s = session as unknown as {
|
|
811
|
-
processing: boolean;
|
|
812
|
-
abortController: AbortController | null;
|
|
813
|
-
currentRequestId: string | undefined;
|
|
814
|
-
};
|
|
815
|
-
s.processing = false;
|
|
816
|
-
s.abortController = null;
|
|
817
|
-
s.currentRequestId = undefined;
|
|
818
|
-
}
|