@vellumai/assistant 0.4.48 → 0.4.50
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/ARCHITECTURE.md +26 -35
- package/README.md +5 -26
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/architecture/memory.md +180 -119
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +2 -2
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +249 -2
- package/src/__tests__/approval-cascade.test.ts +796 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +4 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +13 -20
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +284 -49
- package/src/__tests__/credential-vault.test.ts +150 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +791 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-redemption-service.test.ts +65 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +14 -46
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +941 -15
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +870 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -3
- package/src/__tests__/relay-server.test.ts +46 -1
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secure-keys.test.ts +7 -2
- package/src/__tests__/send-endpoint-busy.test.ts +24 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +7 -13
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-invite-redemption.test.ts +32 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +286 -0
- package/src/agent/loop.ts +104 -131
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +133 -6
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +52 -18
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +3 -8
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/types.ts +3 -1
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/doctor.ts +4 -3
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +284 -0
- package/src/cli/commands/oauth/connections.ts +633 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +256 -0
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +177 -339
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +6 -11
- package/src/cli/reference.ts +1 -3
- package/src/cli.ts +4 -10
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
- package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +4 -13
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/skills.ts +21 -2
- package/src/config/types.ts +0 -4
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +53 -11
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/config-watcher.ts +61 -3
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +27 -36
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +430 -0
- package/src/daemon/lifecycle.ts +67 -71
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +1 -129
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +4 -0
- package/src/daemon/message-types/sessions.ts +4 -0
- package/src/daemon/server.ts +25 -21
- package/src/daemon/session-agent-loop-handlers.ts +40 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +43 -28
- package/src/daemon/session-tool-setup.ts +9 -10
- package/src/daemon/session.ts +150 -17
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/instrument.ts +61 -1
- package/src/logfire.ts +16 -5
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/conversation-queries.ts +22 -3
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +62 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +67 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +133 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +582 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +167 -0
- package/src/oauth/token-persistence.ts +81 -77
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +1 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +36 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +46 -42
- package/src/providers/anthropic/client.ts +59 -20
- package/src/providers/retry.ts +1 -27
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -6
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +10 -8
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +19 -1
- package/src/runtime/invite-service.ts +25 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +81 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/runtime/routes/workspace-routes.ts +2 -1
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +22 -10
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +25 -3
- package/src/security/token-manager.ts +137 -64
- package/src/skills/catalog-install.ts +414 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +36 -11
- package/src/tools/computer-use/registry.ts +5 -6
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +92 -167
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/registry.ts +2 -7
- package/src/tools/schedule/create.ts +8 -1
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +85 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/routes/mcp-routes.ts +0 -20
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host computer-use proxy.
|
|
3
|
+
*
|
|
4
|
+
* Proxies computer-use actions to the desktop client when running as a
|
|
5
|
+
* managed assistant, following the same request/resolve pattern as
|
|
6
|
+
* HostBashProxy. Also owns CU-specific state tracking (step counting,
|
|
7
|
+
* loop detection, observation formatting) for the unified agent loop.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { v4 as uuid } from "uuid";
|
|
11
|
+
|
|
12
|
+
import { escapeAxTreeContent } from "../agent/loop.js";
|
|
13
|
+
import type { ContentBlock } from "../providers/types.js";
|
|
14
|
+
import type { ToolExecutionResult } from "../tools/types.js";
|
|
15
|
+
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
16
|
+
import { getLogger } from "../util/logger.js";
|
|
17
|
+
import type { ServerMessage } from "./message-protocol.js";
|
|
18
|
+
|
|
19
|
+
const log = getLogger("host-cu-proxy");
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Constants
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
const REQUEST_TIMEOUT_SEC = 60;
|
|
26
|
+
const MAX_STEPS = 50;
|
|
27
|
+
const MAX_HISTORY_ENTRIES = 10;
|
|
28
|
+
const LOOP_DETECTION_WINDOW = 3;
|
|
29
|
+
const CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD = 2;
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Types
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
export interface CuObservationResult {
|
|
36
|
+
axTree?: string;
|
|
37
|
+
axDiff?: string;
|
|
38
|
+
secondaryWindows?: string;
|
|
39
|
+
screenshot?: string; // base64 JPEG
|
|
40
|
+
screenshotWidthPx?: number;
|
|
41
|
+
screenshotHeightPx?: number;
|
|
42
|
+
screenWidthPt?: number;
|
|
43
|
+
screenHeightPt?: number;
|
|
44
|
+
executionResult?: string;
|
|
45
|
+
executionError?: string;
|
|
46
|
+
userGuidance?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ActionRecord {
|
|
50
|
+
step: number;
|
|
51
|
+
toolName: string;
|
|
52
|
+
input: Record<string, unknown>;
|
|
53
|
+
reasoning?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface PendingRequest {
|
|
57
|
+
resolve: (result: ToolExecutionResult) => void;
|
|
58
|
+
reject: (err: Error) => void;
|
|
59
|
+
timer: ReturnType<typeof setTimeout>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// HostCuProxy
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
export class HostCuProxy {
|
|
67
|
+
private pending = new Map<string, PendingRequest>();
|
|
68
|
+
private sendToClient: (msg: ServerMessage) => void;
|
|
69
|
+
private onInternalResolve?: (requestId: string) => void;
|
|
70
|
+
private clientConnected = false;
|
|
71
|
+
|
|
72
|
+
// CU state tracking (per-conversation)
|
|
73
|
+
private _stepCount = 0;
|
|
74
|
+
private _maxSteps: number;
|
|
75
|
+
private _previousAXTree: string | undefined;
|
|
76
|
+
private _consecutiveUnchangedSteps = 0;
|
|
77
|
+
private _actionHistory: ActionRecord[] = [];
|
|
78
|
+
|
|
79
|
+
constructor(
|
|
80
|
+
sendToClient: (msg: ServerMessage) => void,
|
|
81
|
+
onInternalResolve?: (requestId: string) => void,
|
|
82
|
+
maxSteps = MAX_STEPS,
|
|
83
|
+
) {
|
|
84
|
+
this.sendToClient = sendToClient;
|
|
85
|
+
this.onInternalResolve = onInternalResolve;
|
|
86
|
+
this._maxSteps = maxSteps;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// CU state accessors (for testing / external inspection)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
get stepCount(): number {
|
|
94
|
+
return this._stepCount;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get maxSteps(): number {
|
|
98
|
+
return this._maxSteps;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get previousAXTree(): string | undefined {
|
|
102
|
+
return this._previousAXTree;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get consecutiveUnchangedSteps(): number {
|
|
106
|
+
return this._consecutiveUnchangedSteps;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get actionHistory(): readonly ActionRecord[] {
|
|
110
|
+
return this._actionHistory;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Sender management
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
updateSender(
|
|
118
|
+
sendToClient: (msg: ServerMessage) => void,
|
|
119
|
+
clientConnected: boolean,
|
|
120
|
+
): void {
|
|
121
|
+
this.sendToClient = sendToClient;
|
|
122
|
+
this.clientConnected = clientConnected;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Request / resolve lifecycle
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
request(
|
|
130
|
+
toolName: string,
|
|
131
|
+
input: Record<string, unknown>,
|
|
132
|
+
sessionId: string,
|
|
133
|
+
stepNumber: number,
|
|
134
|
+
reasoning?: string,
|
|
135
|
+
signal?: AbortSignal,
|
|
136
|
+
): Promise<ToolExecutionResult> {
|
|
137
|
+
if (signal?.aborted) {
|
|
138
|
+
return Promise.resolve({
|
|
139
|
+
content: "Aborted",
|
|
140
|
+
isError: true,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Enforce step limit before sending to client
|
|
145
|
+
if (this._stepCount > this._maxSteps) {
|
|
146
|
+
return Promise.resolve({
|
|
147
|
+
content: `Step limit (${this._maxSteps}) exceeded. Call computer_use_done to finish.`,
|
|
148
|
+
isError: true,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const requestId = uuid();
|
|
153
|
+
|
|
154
|
+
return new Promise<ToolExecutionResult>((resolve, reject) => {
|
|
155
|
+
const timer = setTimeout(() => {
|
|
156
|
+
this.pending.delete(requestId);
|
|
157
|
+
this.onInternalResolve?.(requestId);
|
|
158
|
+
log.warn({ requestId, toolName }, "Host CU proxy request timed out");
|
|
159
|
+
resolve({
|
|
160
|
+
content: "Host CU proxy timed out waiting for client response",
|
|
161
|
+
isError: true,
|
|
162
|
+
});
|
|
163
|
+
}, REQUEST_TIMEOUT_SEC * 1000);
|
|
164
|
+
|
|
165
|
+
this.pending.set(requestId, { resolve, reject, timer });
|
|
166
|
+
|
|
167
|
+
if (signal) {
|
|
168
|
+
const onAbort = () => {
|
|
169
|
+
if (this.pending.has(requestId)) {
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
this.pending.delete(requestId);
|
|
172
|
+
this.onInternalResolve?.(requestId);
|
|
173
|
+
resolve({ content: "Aborted", isError: true });
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.sendToClient({
|
|
180
|
+
type: "host_cu_request",
|
|
181
|
+
requestId,
|
|
182
|
+
sessionId,
|
|
183
|
+
toolName,
|
|
184
|
+
input,
|
|
185
|
+
stepNumber,
|
|
186
|
+
reasoning,
|
|
187
|
+
} as ServerMessage);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
resolve(requestId: string, observation: CuObservationResult): void {
|
|
192
|
+
const entry = this.pending.get(requestId);
|
|
193
|
+
if (!entry) {
|
|
194
|
+
log.warn({ requestId }, "No pending host CU request for response");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
clearTimeout(entry.timer);
|
|
198
|
+
this.pending.delete(requestId);
|
|
199
|
+
|
|
200
|
+
// Capture pre-update state so formatObservation sees the correct previous AX tree
|
|
201
|
+
const prevAXTree = this._previousAXTree;
|
|
202
|
+
|
|
203
|
+
// Update CU state from observation
|
|
204
|
+
this.updateStateFromObservation(observation);
|
|
205
|
+
|
|
206
|
+
const result = this.formatObservation(observation, prevAXTree);
|
|
207
|
+
entry.resolve(result);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
hasPendingRequest(requestId: string): boolean {
|
|
211
|
+
return this.pending.has(requestId);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
isAvailable(): boolean {
|
|
215
|
+
return this.clientConnected;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// CU state management
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Increment step count and record an action. Call this before sending
|
|
224
|
+
* each non-terminal tool request.
|
|
225
|
+
*/
|
|
226
|
+
recordAction(
|
|
227
|
+
toolName: string,
|
|
228
|
+
input: Record<string, unknown>,
|
|
229
|
+
reasoning?: string,
|
|
230
|
+
): void {
|
|
231
|
+
this._stepCount++;
|
|
232
|
+
this._actionHistory.push({
|
|
233
|
+
step: this._stepCount,
|
|
234
|
+
toolName,
|
|
235
|
+
input,
|
|
236
|
+
reasoning,
|
|
237
|
+
});
|
|
238
|
+
// Keep history bounded
|
|
239
|
+
if (this._actionHistory.length > MAX_HISTORY_ENTRIES) {
|
|
240
|
+
this._actionHistory = this._actionHistory.slice(-MAX_HISTORY_ENTRIES);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Reset all CU state. Called on terminal tools (computer_use_done, etc.). */
|
|
245
|
+
reset(): void {
|
|
246
|
+
this._stepCount = 0;
|
|
247
|
+
this._previousAXTree = undefined;
|
|
248
|
+
this._consecutiveUnchangedSteps = 0;
|
|
249
|
+
this._actionHistory = [];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Observation formatting
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Formats a CU observation into a ToolExecutionResult with text content
|
|
258
|
+
* (AX tree wrapped in markers, diff, warnings) and optional screenshot
|
|
259
|
+
* as an image content block.
|
|
260
|
+
*/
|
|
261
|
+
formatObservation(
|
|
262
|
+
obs: CuObservationResult,
|
|
263
|
+
previousAXTree?: string,
|
|
264
|
+
): ToolExecutionResult {
|
|
265
|
+
const prevTree = previousAXTree;
|
|
266
|
+
const parts: string[] = [];
|
|
267
|
+
|
|
268
|
+
// Surface user guidance prominently so the model sees it first
|
|
269
|
+
if (obs.userGuidance) {
|
|
270
|
+
parts.push(`USER GUIDANCE: ${obs.userGuidance}`);
|
|
271
|
+
parts.push("");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (obs.executionResult) {
|
|
275
|
+
parts.push(obs.executionResult);
|
|
276
|
+
parts.push("");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// AX tree diff / unchanged warning
|
|
280
|
+
if (obs.axDiff) {
|
|
281
|
+
parts.push(obs.axDiff);
|
|
282
|
+
parts.push("");
|
|
283
|
+
} else if (prevTree != null && obs.axTree != null) {
|
|
284
|
+
// Skip unchanged warning after wait actions — they intentionally yield no immediate change
|
|
285
|
+
const lastAction =
|
|
286
|
+
this._actionHistory.length > 0
|
|
287
|
+
? this._actionHistory[this._actionHistory.length - 1]
|
|
288
|
+
: undefined;
|
|
289
|
+
const isWaitAction = lastAction?.toolName === "computer_use_wait";
|
|
290
|
+
|
|
291
|
+
if (!isWaitAction) {
|
|
292
|
+
// No diff means the screen didn't change
|
|
293
|
+
if (
|
|
294
|
+
this._consecutiveUnchangedSteps >=
|
|
295
|
+
CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD
|
|
296
|
+
) {
|
|
297
|
+
parts.push(
|
|
298
|
+
`WARNING: ${this._consecutiveUnchangedSteps} consecutive actions had NO VISIBLE EFFECT on the UI. You MUST try a completely different approach.`,
|
|
299
|
+
);
|
|
300
|
+
} else {
|
|
301
|
+
parts.push(
|
|
302
|
+
"Your last action had NO VISIBLE EFFECT on the UI. Try something different.",
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
parts.push("");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Loop detection: identical actions repeated
|
|
310
|
+
if (this._actionHistory.length >= LOOP_DETECTION_WINDOW) {
|
|
311
|
+
const recent = this._actionHistory.slice(-LOOP_DETECTION_WINDOW);
|
|
312
|
+
const allIdentical = recent.every(
|
|
313
|
+
(r) =>
|
|
314
|
+
r.toolName === recent[0].toolName &&
|
|
315
|
+
JSON.stringify(r.input) === JSON.stringify(recent[0].input),
|
|
316
|
+
);
|
|
317
|
+
if (allIdentical) {
|
|
318
|
+
parts.push(
|
|
319
|
+
`WARNING: You've repeated the same action (${recent[0].toolName}) ${LOOP_DETECTION_WINDOW} times. Try something different.`,
|
|
320
|
+
);
|
|
321
|
+
parts.push("");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Current screen state wrapped in markers for history compaction
|
|
326
|
+
if (obs.axTree) {
|
|
327
|
+
parts.push("<ax-tree>");
|
|
328
|
+
parts.push("CURRENT SCREEN STATE:");
|
|
329
|
+
parts.push(escapeAxTreeContent(obs.axTree));
|
|
330
|
+
parts.push("</ax-tree>");
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Secondary windows for cross-app awareness
|
|
334
|
+
if (obs.secondaryWindows) {
|
|
335
|
+
parts.push("");
|
|
336
|
+
parts.push(obs.secondaryWindows);
|
|
337
|
+
parts.push("");
|
|
338
|
+
parts.push(
|
|
339
|
+
"Note: The element [ID]s above are from other windows — you can reference them for context but can only interact with the focused window's elements.",
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Screenshot metadata
|
|
344
|
+
const screenshotMeta = this.formatScreenshotMetadata(obs);
|
|
345
|
+
if (screenshotMeta.length > 0) {
|
|
346
|
+
parts.push("");
|
|
347
|
+
parts.push(...screenshotMeta);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const content = parts.join("\n").trim() || "Action executed";
|
|
351
|
+
|
|
352
|
+
// Build content blocks for screenshot
|
|
353
|
+
const contentBlocks: ContentBlock[] = [];
|
|
354
|
+
if (obs.screenshot) {
|
|
355
|
+
contentBlocks.push({
|
|
356
|
+
type: "image",
|
|
357
|
+
source: {
|
|
358
|
+
type: "base64",
|
|
359
|
+
media_type: "image/jpeg",
|
|
360
|
+
data: obs.screenshot,
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const isError = obs.executionError != null;
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
content: isError
|
|
369
|
+
? `Action failed: ${obs.executionError}\n\n${content}`
|
|
370
|
+
: content,
|
|
371
|
+
isError,
|
|
372
|
+
...(contentBlocks.length > 0 ? { contentBlocks } : {}),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
// Dispose
|
|
378
|
+
// ---------------------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
dispose(): void {
|
|
381
|
+
for (const [requestId, entry] of this.pending) {
|
|
382
|
+
clearTimeout(entry.timer);
|
|
383
|
+
this.onInternalResolve?.(requestId);
|
|
384
|
+
entry.reject(
|
|
385
|
+
new AssistantError("Host CU proxy disposed", ErrorCode.INTERNAL_ERROR),
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
this.pending.clear();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ---------------------------------------------------------------------------
|
|
392
|
+
// Private helpers
|
|
393
|
+
// ---------------------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
/** Update consecutive-unchanged tracking from an incoming observation. */
|
|
396
|
+
private updateStateFromObservation(obs: CuObservationResult): void {
|
|
397
|
+
if (this._stepCount > 0) {
|
|
398
|
+
if (
|
|
399
|
+
obs.axDiff == null &&
|
|
400
|
+
this._previousAXTree != null &&
|
|
401
|
+
obs.axTree != null
|
|
402
|
+
) {
|
|
403
|
+
this._consecutiveUnchangedSteps++;
|
|
404
|
+
} else if (obs.axDiff != null) {
|
|
405
|
+
this._consecutiveUnchangedSteps = 0;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (obs.axTree != null) {
|
|
410
|
+
this._previousAXTree = obs.axTree;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private formatScreenshotMetadata(obs: CuObservationResult): string[] {
|
|
415
|
+
if (!obs.screenshot) return [];
|
|
416
|
+
|
|
417
|
+
const lines: string[] = [];
|
|
418
|
+
if (obs.screenshotWidthPx != null && obs.screenshotHeightPx != null) {
|
|
419
|
+
lines.push(
|
|
420
|
+
`Screenshot metadata: ${obs.screenshotWidthPx}x${obs.screenshotHeightPx} px`,
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
if (obs.screenWidthPt != null && obs.screenHeightPt != null) {
|
|
424
|
+
lines.push(
|
|
425
|
+
`Screen metadata: ${obs.screenWidthPt}x${obs.screenHeightPt} pt`,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
return lines;
|
|
429
|
+
}
|
|
430
|
+
}
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getQdrantUrlEnv,
|
|
16
16
|
getRuntimeHttpHost,
|
|
17
17
|
getRuntimeHttpPort,
|
|
18
|
+
setIngressPublicBaseUrl,
|
|
18
19
|
validateEnv,
|
|
19
20
|
} from "../config/env.js";
|
|
20
21
|
import { loadConfig } from "../config/loader.js";
|
|
@@ -22,16 +23,21 @@ import { HeartbeatService } from "../heartbeat/heartbeat-service.js";
|
|
|
22
23
|
import { getHookManager } from "../hooks/manager.js";
|
|
23
24
|
import { installTemplates } from "../hooks/templates.js";
|
|
24
25
|
import { closeSentry, initSentry } from "../instrument.js";
|
|
25
|
-
import { initLogfire } from "../logfire.js";
|
|
26
|
+
import { disableLogfire, initLogfire } from "../logfire.js";
|
|
26
27
|
import { getMcpServerManager } from "../mcp/manager.js";
|
|
27
28
|
import * as attachmentsStore from "../memory/attachments-store.js";
|
|
29
|
+
import { expireAllPendingCanonicalRequests } from "../memory/canonical-guardian-store.js";
|
|
28
30
|
import {
|
|
29
31
|
deleteMessageById,
|
|
30
32
|
getConversationThreadType,
|
|
31
33
|
getMessages,
|
|
32
34
|
} from "../memory/conversation-crud.js";
|
|
33
35
|
import { initializeDb } from "../memory/db.js";
|
|
34
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
selectEmbeddingBackend,
|
|
38
|
+
SPARSE_EMBEDDING_VERSION,
|
|
39
|
+
} from "../memory/embedding-backend.js";
|
|
40
|
+
import { enqueueMemoryJob } from "../memory/jobs-store.js";
|
|
35
41
|
import { startMemoryJobsWorker } from "../memory/jobs-worker.js";
|
|
36
42
|
import { initQdrantClient } from "../memory/qdrant-client.js";
|
|
37
43
|
import { QdrantManager } from "../memory/qdrant-manager.js";
|
|
@@ -40,6 +46,8 @@ import {
|
|
|
40
46
|
emitNotificationSignal,
|
|
41
47
|
registerBroadcastFn,
|
|
42
48
|
} from "../notifications/emit-signal.js";
|
|
49
|
+
import { backfillManualTokenConnections } from "../oauth/manual-token-connection.js";
|
|
50
|
+
import { seedOAuthProviders } from "../oauth/seed-providers.js";
|
|
43
51
|
import { ensurePromptFiles } from "../prompts/system-prompt.js";
|
|
44
52
|
import { syncUpdateBulletinOnStartup } from "../prompts/update-bulletin.js";
|
|
45
53
|
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
@@ -54,8 +62,6 @@ import {
|
|
|
54
62
|
import { ensureVellumGuardianBinding } from "../runtime/guardian-vellum-migration.js";
|
|
55
63
|
import { RuntimeHttpServer } from "../runtime/http-server.js";
|
|
56
64
|
import { startScheduler } from "../schedule/scheduler.js";
|
|
57
|
-
import { migrateKeys } from "../security/credential-key.js";
|
|
58
|
-
import { watchSessions } from "../tools/watch/watch-state.js";
|
|
59
65
|
import { getLogger, initLogger } from "../util/logger.js";
|
|
60
66
|
import {
|
|
61
67
|
ensureDataDir,
|
|
@@ -95,10 +101,6 @@ import {
|
|
|
95
101
|
registerMessagingProviders,
|
|
96
102
|
registerWatcherProviders,
|
|
97
103
|
} from "./providers-setup.js";
|
|
98
|
-
import {
|
|
99
|
-
handleRideShotgunStart,
|
|
100
|
-
handleRideShotgunStop,
|
|
101
|
-
} from "./ride-shotgun-handler.js";
|
|
102
104
|
import { seedInterfaceFiles } from "./seed-files.js";
|
|
103
105
|
import { DaemonServer } from "./server.js";
|
|
104
106
|
import { initSlashPairingContext } from "./session-slash.js";
|
|
@@ -137,11 +139,6 @@ export async function runDaemon(): Promise<void> {
|
|
|
137
139
|
|
|
138
140
|
ensureDataDir();
|
|
139
141
|
|
|
140
|
-
// Migrate legacy colon-delimited credential keys to the new
|
|
141
|
-
// slash-delimited format. Must run after ensureDataDir() so the
|
|
142
|
-
// secure key store is available, and before any credential reads.
|
|
143
|
-
migrateKeys();
|
|
144
|
-
|
|
145
142
|
// Load (or generate + persist) the auth signing key so tokens survive
|
|
146
143
|
// daemon restarts. Must happen after ensureDataDir() creates the
|
|
147
144
|
// protected directory.
|
|
@@ -165,8 +162,26 @@ export async function runDaemon(): Promise<void> {
|
|
|
165
162
|
);
|
|
166
163
|
}
|
|
167
164
|
initializeDb();
|
|
165
|
+
// Seed well-known OAuth provider configurations (insert-if-not-exists)
|
|
166
|
+
seedOAuthProviders();
|
|
167
|
+
// Backfill oauth_connection rows for manual-token providers (Telegram,
|
|
168
|
+
// Slack channel) that already have keychain credentials from before the
|
|
169
|
+
// oauth_connection migration. Safe to call on every startup.
|
|
170
|
+
await backfillManualTokenConnections();
|
|
168
171
|
log.info("Daemon startup: DB initialized");
|
|
169
172
|
|
|
173
|
+
// Expire any pending canonical guardian requests left over from before
|
|
174
|
+
// this process started. Their in-memory pending-interaction session
|
|
175
|
+
// references are gone, so they can never be completed. The agent loop
|
|
176
|
+
// will re-request tool approvals on the next turn.
|
|
177
|
+
const expiredCount = expireAllPendingCanonicalRequests();
|
|
178
|
+
if (expiredCount > 0) {
|
|
179
|
+
log.info(
|
|
180
|
+
{ event: "startup_expired_stale_requests", expiredCount },
|
|
181
|
+
`Expired ${expiredCount} stale pending canonical request(s) from previous process`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
170
185
|
// Ensure a vellum guardian binding exists and mint the CLI edge token
|
|
171
186
|
// as an actor token bound to the guardian principal.
|
|
172
187
|
let guardianPrincipalId: string | undefined;
|
|
@@ -242,6 +257,19 @@ export async function runDaemon(): Promise<void> {
|
|
|
242
257
|
log.info("Daemon startup: loading config");
|
|
243
258
|
const config = loadConfig();
|
|
244
259
|
|
|
260
|
+
// Seed module-level ingress state from the workspace config so that
|
|
261
|
+
// getIngressPublicBaseUrl() returns the correct value immediately after
|
|
262
|
+
// startup (before any handleIngressConfig("set") call). Without this,
|
|
263
|
+
// code paths that read the module-level state directly (e.g. session-slash
|
|
264
|
+
// pairing info) would see undefined until an explicit set.
|
|
265
|
+
if (config.ingress.enabled && config.ingress.publicBaseUrl) {
|
|
266
|
+
setIngressPublicBaseUrl(config.ingress.publicBaseUrl);
|
|
267
|
+
log.info(
|
|
268
|
+
{ url: config.ingress.publicBaseUrl },
|
|
269
|
+
"Daemon startup: seeded ingress URL from workspace config",
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
245
273
|
if (config.logFile.dir) {
|
|
246
274
|
initLogger({
|
|
247
275
|
dir: config.logFile.dir,
|
|
@@ -259,6 +287,18 @@ export async function runDaemon(): Promise<void> {
|
|
|
259
287
|
await closeSentry();
|
|
260
288
|
}
|
|
261
289
|
|
|
290
|
+
// If Logfire observability is not explicitly enabled, disable it so
|
|
291
|
+
// wrapWithLogfire() calls during provider setup become no-ops. Logfire
|
|
292
|
+
// is initialized eagerly (before config loads) for the same reason as
|
|
293
|
+
// Sentry — but the feature flag gates whether it actually traces.
|
|
294
|
+
const logfireEnabled = isAssistantFeatureFlagEnabled(
|
|
295
|
+
"feature_flags.logfire.enabled",
|
|
296
|
+
config,
|
|
297
|
+
);
|
|
298
|
+
if (!logfireEnabled) {
|
|
299
|
+
disableLogfire();
|
|
300
|
+
}
|
|
301
|
+
|
|
262
302
|
await initializeProvidersAndTools(config);
|
|
263
303
|
|
|
264
304
|
// Start the DaemonServer (session manager) before Qdrant so HTTP
|
|
@@ -282,9 +322,9 @@ export async function runDaemon(): Promise<void> {
|
|
|
282
322
|
await qdrantManager.start();
|
|
283
323
|
const embeddingSelection = selectEmbeddingBackend(config);
|
|
284
324
|
const embeddingModel = embeddingSelection.backend
|
|
285
|
-
? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}`
|
|
325
|
+
? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
|
|
286
326
|
: undefined;
|
|
287
|
-
initQdrantClient({
|
|
327
|
+
const qdrantClient = initQdrantClient({
|
|
288
328
|
url: qdrantUrl,
|
|
289
329
|
collection: config.memory.qdrant.collection,
|
|
290
330
|
vectorSize: config.memory.qdrant.vectorSize,
|
|
@@ -292,6 +332,17 @@ export async function runDaemon(): Promise<void> {
|
|
|
292
332
|
quantization: config.memory.qdrant.quantization,
|
|
293
333
|
embeddingModel,
|
|
294
334
|
});
|
|
335
|
+
|
|
336
|
+
// Eagerly ensure the collection exists so we detect migrations
|
|
337
|
+
// (unnamed→named vectors, dimension/model changes) at startup.
|
|
338
|
+
// If a destructive migration occurred, enqueue a rebuild_index job
|
|
339
|
+
// to re-embed all memory items from the SQLite cache.
|
|
340
|
+
const { migrated } = await qdrantClient.ensureCollection();
|
|
341
|
+
if (migrated) {
|
|
342
|
+
enqueueMemoryJob("rebuild_index", {});
|
|
343
|
+
log.info("Qdrant collection was migrated — enqueued rebuild_index job");
|
|
344
|
+
}
|
|
345
|
+
|
|
295
346
|
log.info("Qdrant vector store initialized");
|
|
296
347
|
} catch (err) {
|
|
297
348
|
log.warn(
|
|
@@ -501,64 +552,9 @@ export async function runDaemon(): Promise<void> {
|
|
|
501
552
|
);
|
|
502
553
|
},
|
|
503
554
|
},
|
|
504
|
-
|
|
555
|
+
getWatchDeps: () => {
|
|
505
556
|
const ctx = server.getHandlerContext();
|
|
506
557
|
return {
|
|
507
|
-
cuSessions: ctx.cuSessions,
|
|
508
|
-
sharedRequestTimestamps: ctx.sharedRequestTimestamps,
|
|
509
|
-
cuObservationParseSequence: ctx.cuObservationParseSequence,
|
|
510
|
-
handleRideShotgunStart: async (params) => {
|
|
511
|
-
// The handler generates its own watchId/sessionId and
|
|
512
|
-
// sends them via ctx.send as a watch_started message.
|
|
513
|
-
// We intercept send to capture the IDs before they broadcast.
|
|
514
|
-
let capturedWatchId = "";
|
|
515
|
-
let capturedSessionId = "";
|
|
516
|
-
const interceptCtx = {
|
|
517
|
-
...ctx,
|
|
518
|
-
send: (msg: ServerMessage) => {
|
|
519
|
-
if (
|
|
520
|
-
"type" in msg &&
|
|
521
|
-
msg.type === "watch_started" &&
|
|
522
|
-
"watchId" in msg &&
|
|
523
|
-
"sessionId" in msg
|
|
524
|
-
) {
|
|
525
|
-
capturedWatchId = (msg as { watchId: string }).watchId;
|
|
526
|
-
capturedSessionId = (msg as { sessionId: string }).sessionId;
|
|
527
|
-
}
|
|
528
|
-
ctx.send(msg);
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
await handleRideShotgunStart(
|
|
532
|
-
{
|
|
533
|
-
type: "ride_shotgun_start",
|
|
534
|
-
durationSeconds: params.durationSeconds,
|
|
535
|
-
intervalSeconds: params.intervalSeconds,
|
|
536
|
-
mode: params.mode,
|
|
537
|
-
targetDomain: params.targetDomain,
|
|
538
|
-
navigateDomain: params.navigateDomain,
|
|
539
|
-
autoNavigate: params.autoNavigate,
|
|
540
|
-
},
|
|
541
|
-
interceptCtx,
|
|
542
|
-
);
|
|
543
|
-
return { watchId: capturedWatchId, sessionId: capturedSessionId };
|
|
544
|
-
},
|
|
545
|
-
handleRideShotgunStop: async (watchId) => {
|
|
546
|
-
await handleRideShotgunStop(
|
|
547
|
-
{ type: "ride_shotgun_stop", watchId },
|
|
548
|
-
ctx,
|
|
549
|
-
);
|
|
550
|
-
},
|
|
551
|
-
getRideShotgunStatus: (watchId) => {
|
|
552
|
-
const session = watchSessions.get(watchId);
|
|
553
|
-
if (!session) return undefined;
|
|
554
|
-
return {
|
|
555
|
-
status: session.status,
|
|
556
|
-
sessionId: session.sessionId,
|
|
557
|
-
recordingId: session.recordingId,
|
|
558
|
-
savedRecordingPath: session.savedRecordingPath,
|
|
559
|
-
bootstrapFailureReason: session.bootstrapFailureReason,
|
|
560
|
-
};
|
|
561
|
-
},
|
|
562
558
|
handleWatchObservation: async (params) => {
|
|
563
559
|
await handleWatchObservation(
|
|
564
560
|
{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared MCP reload business logic.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Called by the ConfigWatcher when config.json changes or a reload signal
|
|
5
|
+
* file is detected, so the daemon automatically reconnects MCP servers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { getConfig, invalidateConfigCache } from "../config/loader.js";
|
|
@@ -21,6 +21,7 @@ export * from "./message-types/diagnostics.js";
|
|
|
21
21
|
export * from "./message-types/documents.js";
|
|
22
22
|
export * from "./message-types/guardian-actions.js";
|
|
23
23
|
export * from "./message-types/host-bash.js";
|
|
24
|
+
export * from "./message-types/host-cu.js";
|
|
24
25
|
export * from "./message-types/host-file.js";
|
|
25
26
|
export * from "./message-types/inbox.js";
|
|
26
27
|
export * from "./message-types/integrations.js";
|
|
@@ -69,6 +70,7 @@ import type {
|
|
|
69
70
|
_GuardianActionsServerMessages,
|
|
70
71
|
} from "./message-types/guardian-actions.js";
|
|
71
72
|
import type { _HostBashServerMessages } from "./message-types/host-bash.js";
|
|
73
|
+
import type { _HostCuServerMessages } from "./message-types/host-cu.js";
|
|
72
74
|
import type { _HostFileServerMessages } from "./message-types/host-file.js";
|
|
73
75
|
import type {
|
|
74
76
|
_InboxClientMessages,
|
|
@@ -180,6 +182,7 @@ export type ServerMessage =
|
|
|
180
182
|
| _DocumentsServerMessages
|
|
181
183
|
| _GuardianActionsServerMessages
|
|
182
184
|
| _HostBashServerMessages
|
|
185
|
+
| _HostCuServerMessages
|
|
183
186
|
| _HostFileServerMessages
|
|
184
187
|
| _MemoryServerMessages
|
|
185
188
|
| _WorkspaceServerMessages
|