@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
package/src/instrument.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { arch, platform, release } from "node:os";
|
|
1
|
+
import { arch, hostname, platform, release } from "node:os";
|
|
2
2
|
|
|
3
3
|
import * as Sentry from "@sentry/node";
|
|
4
4
|
|
|
@@ -47,12 +47,14 @@ export function initSentry(): void {
|
|
|
47
47
|
dist: COMMIT_SHA,
|
|
48
48
|
environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
|
|
49
49
|
sendDefaultPii: false,
|
|
50
|
+
serverName: hostname(),
|
|
50
51
|
initialScope: {
|
|
51
52
|
tags: {
|
|
52
53
|
commit: COMMIT_SHA,
|
|
53
54
|
os_platform: platform(),
|
|
54
55
|
os_release: release(),
|
|
55
56
|
os_arch: arch(),
|
|
57
|
+
server_name: hostname(),
|
|
56
58
|
runtime: "bun",
|
|
57
59
|
runtime_version:
|
|
58
60
|
typeof Bun !== "undefined" ? Bun.version : process.version,
|
|
@@ -90,3 +92,61 @@ export function initSentry(): void {
|
|
|
90
92
|
export async function closeSentry(): Promise<void> {
|
|
91
93
|
await Sentry.close();
|
|
92
94
|
}
|
|
95
|
+
|
|
96
|
+
// ── Dynamic session-scoped Sentry tags ──────────────────────────────
|
|
97
|
+
//
|
|
98
|
+
// These tags change per conversation turn and are set on the current
|
|
99
|
+
// Sentry scope before the agent loop runs. Any `Sentry.captureException`
|
|
100
|
+
// call within that async execution chain (e.g. inside agent/loop.ts)
|
|
101
|
+
// will inherit these tags, enabling filtering by conversation, session,
|
|
102
|
+
// user, or assistant in the Sentry dashboard.
|
|
103
|
+
|
|
104
|
+
/** Tag keys set by {@link setSentrySessionContext}. */
|
|
105
|
+
const SESSION_TAG_KEYS = [
|
|
106
|
+
"assistant_id",
|
|
107
|
+
"conversation_id",
|
|
108
|
+
"session_id",
|
|
109
|
+
"message_count",
|
|
110
|
+
"user_identifier",
|
|
111
|
+
] as const;
|
|
112
|
+
|
|
113
|
+
export interface SentrySessionContext {
|
|
114
|
+
/** Internal assistant ID (daemon uses 'self'). */
|
|
115
|
+
assistantId: string;
|
|
116
|
+
/** Conversation/session identifier. */
|
|
117
|
+
conversationId: string;
|
|
118
|
+
/** Number of messages in the conversation at time of the turn. */
|
|
119
|
+
messageCount: number;
|
|
120
|
+
/** Stable per-user identifier (guardian principal ID or similar). */
|
|
121
|
+
userIdentifier?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Set session-scoped tags on the current Sentry scope.
|
|
126
|
+
*
|
|
127
|
+
* Call at the start of each agent loop turn so that any exceptions
|
|
128
|
+
* captured within the turn include conversation/session context.
|
|
129
|
+
*/
|
|
130
|
+
export function setSentrySessionContext(ctx: SentrySessionContext): void {
|
|
131
|
+
Sentry.setTag("assistant_id", ctx.assistantId);
|
|
132
|
+
Sentry.setTag("conversation_id", ctx.conversationId);
|
|
133
|
+
// session_id mirrors conversation_id — in this codebase they are the
|
|
134
|
+
// same value, but downstream Sentry users may search by either name.
|
|
135
|
+
Sentry.setTag("session_id", ctx.conversationId);
|
|
136
|
+
Sentry.setTag("message_count", String(ctx.messageCount));
|
|
137
|
+
if (ctx.userIdentifier) {
|
|
138
|
+
Sentry.setTag("user_identifier", ctx.userIdentifier);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Clear session-scoped tags from the current Sentry scope.
|
|
144
|
+
*
|
|
145
|
+
* Call in the finally block after the agent loop completes so tags
|
|
146
|
+
* from one conversation do not leak into unrelated error captures.
|
|
147
|
+
*/
|
|
148
|
+
export function clearSentrySessionContext(): void {
|
|
149
|
+
for (const key of SESSION_TAG_KEYS) {
|
|
150
|
+
Sentry.setTag(key, undefined);
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/logfire.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getLogfireToken
|
|
1
|
+
import { getLogfireToken } from "./config/env.js";
|
|
2
2
|
import type {
|
|
3
3
|
Message,
|
|
4
4
|
Provider,
|
|
@@ -13,7 +13,7 @@ const log = getLogger("logfire");
|
|
|
13
13
|
|
|
14
14
|
type LogfireModule = typeof import("@pydantic/logfire-node");
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
let logfireEnabled: boolean = !!getLogfireToken();
|
|
17
17
|
|
|
18
18
|
let logfireInstance: LogfireModule | null = null;
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ let logfireInstance: LogfireModule | null = null;
|
|
|
23
23
|
* Non-fatal on failure (logs warning and continues).
|
|
24
24
|
*/
|
|
25
25
|
export async function initLogfire(): Promise<void> {
|
|
26
|
-
if (!
|
|
26
|
+
if (!logfireEnabled) return;
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
29
|
const logfire = await import("@pydantic/logfire-node");
|
|
@@ -42,12 +42,23 @@ export async function initLogfire(): Promise<void> {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Disable Logfire after early initialization. Called when the user has opted
|
|
47
|
+
* out via the feature flag. Nulls out the instance so future wrapWithLogfire
|
|
48
|
+
* calls become no-ops.
|
|
49
|
+
*/
|
|
50
|
+
export function disableLogfire(): void {
|
|
51
|
+
logfireEnabled = false;
|
|
52
|
+
logfireInstance = null;
|
|
53
|
+
log.info("Logfire disabled by feature flag");
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
/**
|
|
46
57
|
* Wraps a provider with Logfire tracing spans.
|
|
47
|
-
* When
|
|
58
|
+
* When logfireEnabled is false, returns the provider as-is (no wrapper allocated).
|
|
48
59
|
*/
|
|
49
60
|
export function wrapWithLogfire(provider: Provider): Provider {
|
|
50
|
-
if (!
|
|
61
|
+
if (!logfireEnabled) return provider;
|
|
51
62
|
return new LogfireProvider(provider);
|
|
52
63
|
}
|
|
53
64
|
|
package/src/memory/admin.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
2
|
import { getLogger } from "../util/logger.js";
|
|
3
|
-
import {
|
|
4
|
-
listPendingConflictDetails,
|
|
5
|
-
resolveConflict,
|
|
6
|
-
} from "./conflict-store.js";
|
|
7
3
|
import { rawGet } from "./db.js";
|
|
8
4
|
import { getMemoryBackendStatus } from "./embedding-backend.js";
|
|
9
5
|
import { enqueueBackfillJob, enqueueRebuildIndexJob } from "./indexer.js";
|
|
10
6
|
import {
|
|
11
|
-
enqueueCleanupResolvedConflictsJob,
|
|
12
7
|
enqueueCleanupStaleSupersededItemsJob,
|
|
13
8
|
getMemoryJobCounts,
|
|
14
9
|
} from "./jobs-store.js";
|
|
@@ -28,94 +23,18 @@ export interface MemorySystemStatus {
|
|
|
28
23
|
summaries: number;
|
|
29
24
|
embeddings: number;
|
|
30
25
|
};
|
|
31
|
-
conflicts: {
|
|
32
|
-
pending: number;
|
|
33
|
-
resolved: number;
|
|
34
|
-
oldestPendingAgeMs: number | null;
|
|
35
|
-
};
|
|
36
26
|
cleanup: {
|
|
37
|
-
resolvedBacklog: number;
|
|
38
27
|
supersededBacklog: number;
|
|
39
|
-
resolvedCompleted24h: number;
|
|
40
28
|
supersededCompleted24h: number;
|
|
41
29
|
};
|
|
42
30
|
jobs: Record<string, number>;
|
|
43
31
|
}
|
|
44
32
|
|
|
45
|
-
export interface MemoryConflictAndCleanupStats {
|
|
46
|
-
conflicts: MemorySystemStatus["conflicts"];
|
|
47
|
-
cleanup: MemorySystemStatus["cleanup"];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface ConflictStatsRow {
|
|
51
|
-
pending_count: number | null;
|
|
52
|
-
resolved_count: number | null;
|
|
53
|
-
oldest_pending_created_at: number | null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
33
|
interface CleanupStatsRow {
|
|
57
|
-
resolved_backlog: number | null;
|
|
58
34
|
superseded_backlog: number | null;
|
|
59
|
-
resolved_completed_24h: number | null;
|
|
60
35
|
superseded_completed_24h: number | null;
|
|
61
36
|
}
|
|
62
37
|
|
|
63
|
-
/** Lightweight query for conflict/cleanup metrics only — no table counts or job totals. */
|
|
64
|
-
export function getMemoryConflictAndCleanupStats(): MemoryConflictAndCleanupStats {
|
|
65
|
-
const conflictStats = rawGet<ConflictStatsRow>(`
|
|
66
|
-
SELECT
|
|
67
|
-
SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
|
|
68
|
-
SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
|
|
69
|
-
MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
|
|
70
|
-
FROM memory_item_conflicts
|
|
71
|
-
`);
|
|
72
|
-
const pending = conflictStats?.pending_count ?? 0;
|
|
73
|
-
const oldestPendingCreatedAt =
|
|
74
|
-
conflictStats?.oldest_pending_created_at ?? null;
|
|
75
|
-
const oldestPendingAgeMs =
|
|
76
|
-
oldestPendingCreatedAt == null
|
|
77
|
-
? null
|
|
78
|
-
: Math.max(0, Date.now() - oldestPendingCreatedAt);
|
|
79
|
-
const throughputWindowStartMs = Date.now() - 24 * 60 * 60 * 1000;
|
|
80
|
-
const cleanupStats = rawGet<CleanupStatsRow>(
|
|
81
|
-
`
|
|
82
|
-
SELECT
|
|
83
|
-
SUM(CASE
|
|
84
|
-
WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
|
|
85
|
-
THEN 1 ELSE 0 END
|
|
86
|
-
) AS resolved_backlog,
|
|
87
|
-
SUM(CASE
|
|
88
|
-
WHEN type = 'cleanup_stale_superseded_items' AND status IN ('pending', 'running')
|
|
89
|
-
THEN 1 ELSE 0 END
|
|
90
|
-
) AS superseded_backlog,
|
|
91
|
-
SUM(CASE
|
|
92
|
-
WHEN type = 'cleanup_resolved_conflicts' AND status = 'completed' AND updated_at >= ?
|
|
93
|
-
THEN 1 ELSE 0 END
|
|
94
|
-
) AS resolved_completed_24h,
|
|
95
|
-
SUM(CASE
|
|
96
|
-
WHEN type = 'cleanup_stale_superseded_items' AND status = 'completed' AND updated_at >= ?
|
|
97
|
-
THEN 1 ELSE 0 END
|
|
98
|
-
) AS superseded_completed_24h
|
|
99
|
-
FROM memory_jobs
|
|
100
|
-
`,
|
|
101
|
-
throughputWindowStartMs,
|
|
102
|
-
throughputWindowStartMs,
|
|
103
|
-
);
|
|
104
|
-
return {
|
|
105
|
-
conflicts: {
|
|
106
|
-
pending,
|
|
107
|
-
resolved: conflictStats?.resolved_count ?? 0,
|
|
108
|
-
oldestPendingAgeMs,
|
|
109
|
-
},
|
|
110
|
-
cleanup: {
|
|
111
|
-
resolvedBacklog: cleanupStats?.resolved_backlog ?? 0,
|
|
112
|
-
supersededBacklog: cleanupStats?.superseded_backlog ?? 0,
|
|
113
|
-
resolvedCompleted24h: cleanupStats?.resolved_completed_24h ?? 0,
|
|
114
|
-
supersededCompleted24h: cleanupStats?.superseded_completed_24h ?? 0,
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
38
|
export function getMemorySystemStatus(): MemorySystemStatus {
|
|
120
39
|
const config = getConfig();
|
|
121
40
|
const backend = getMemoryBackendStatus(config);
|
|
@@ -125,36 +44,14 @@ export function getMemorySystemStatus(): MemorySystemStatus {
|
|
|
125
44
|
summaries: countTable("memory_summaries"),
|
|
126
45
|
embeddings: countTable("memory_embeddings"),
|
|
127
46
|
};
|
|
128
|
-
const conflictStats = rawGet<ConflictStatsRow>(`
|
|
129
|
-
SELECT
|
|
130
|
-
SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
|
|
131
|
-
SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
|
|
132
|
-
MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
|
|
133
|
-
FROM memory_item_conflicts
|
|
134
|
-
`);
|
|
135
|
-
const pending = conflictStats?.pending_count ?? 0;
|
|
136
|
-
const oldestPendingCreatedAt =
|
|
137
|
-
conflictStats?.oldest_pending_created_at ?? null;
|
|
138
|
-
const oldestPendingAgeMs =
|
|
139
|
-
oldestPendingCreatedAt == null
|
|
140
|
-
? null
|
|
141
|
-
: Math.max(0, Date.now() - oldestPendingCreatedAt);
|
|
142
47
|
const throughputWindowStartMs = Date.now() - 24 * 60 * 60 * 1000;
|
|
143
48
|
const cleanupStats = rawGet<CleanupStatsRow>(
|
|
144
49
|
`
|
|
145
50
|
SELECT
|
|
146
|
-
SUM(CASE
|
|
147
|
-
WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
|
|
148
|
-
THEN 1 ELSE 0 END
|
|
149
|
-
) AS resolved_backlog,
|
|
150
51
|
SUM(CASE
|
|
151
52
|
WHEN type = 'cleanup_stale_superseded_items' AND status IN ('pending', 'running')
|
|
152
53
|
THEN 1 ELSE 0 END
|
|
153
54
|
) AS superseded_backlog,
|
|
154
|
-
SUM(CASE
|
|
155
|
-
WHEN type = 'cleanup_resolved_conflicts' AND status = 'completed' AND updated_at >= ?
|
|
156
|
-
THEN 1 ELSE 0 END
|
|
157
|
-
) AS resolved_completed_24h,
|
|
158
55
|
SUM(CASE
|
|
159
56
|
WHEN type = 'cleanup_stale_superseded_items' AND status = 'completed' AND updated_at >= ?
|
|
160
57
|
THEN 1 ELSE 0 END
|
|
@@ -162,7 +59,6 @@ export function getMemorySystemStatus(): MemorySystemStatus {
|
|
|
162
59
|
FROM memory_jobs
|
|
163
60
|
`,
|
|
164
61
|
throughputWindowStartMs,
|
|
165
|
-
throughputWindowStartMs,
|
|
166
62
|
);
|
|
167
63
|
return {
|
|
168
64
|
enabled: backend.enabled,
|
|
@@ -171,15 +67,8 @@ export function getMemorySystemStatus(): MemorySystemStatus {
|
|
|
171
67
|
provider: backend.provider,
|
|
172
68
|
model: backend.model,
|
|
173
69
|
counts,
|
|
174
|
-
conflicts: {
|
|
175
|
-
pending,
|
|
176
|
-
resolved: conflictStats?.resolved_count ?? 0,
|
|
177
|
-
oldestPendingAgeMs,
|
|
178
|
-
},
|
|
179
70
|
cleanup: {
|
|
180
|
-
resolvedBacklog: cleanupStats?.resolved_backlog ?? 0,
|
|
181
71
|
supersededBacklog: cleanupStats?.superseded_backlog ?? 0,
|
|
182
|
-
resolvedCompleted24h: cleanupStats?.resolved_completed_24h ?? 0,
|
|
183
72
|
supersededCompleted24h: cleanupStats?.superseded_completed_24h ?? 0,
|
|
184
73
|
},
|
|
185
74
|
jobs: getMemoryJobCounts(),
|
|
@@ -203,95 +92,17 @@ export function requestMemoryRebuildIndex(): string {
|
|
|
203
92
|
}
|
|
204
93
|
|
|
205
94
|
export function requestMemoryCleanup(retentionMs?: number): {
|
|
206
|
-
resolvedConflictsJobId: string;
|
|
207
95
|
staleSupersededItemsJobId: string;
|
|
208
96
|
} {
|
|
209
|
-
const resolvedConflictsJobId =
|
|
210
|
-
enqueueCleanupResolvedConflictsJob(retentionMs);
|
|
211
97
|
const staleSupersededItemsJobId =
|
|
212
98
|
enqueueCleanupStaleSupersededItemsJob(retentionMs);
|
|
213
99
|
log.info(
|
|
214
|
-
{
|
|
100
|
+
{ staleSupersededItemsJobId, retentionMs },
|
|
215
101
|
"Queued memory cleanup jobs",
|
|
216
102
|
);
|
|
217
|
-
return {
|
|
103
|
+
return { staleSupersededItemsJobId };
|
|
218
104
|
}
|
|
219
105
|
|
|
220
106
|
export async function queryMemory(query: string, conversationId: string) {
|
|
221
107
|
return queryMemoryForCli(query, conversationId, getConfig());
|
|
222
108
|
}
|
|
223
|
-
|
|
224
|
-
export interface DismissConflictsResult {
|
|
225
|
-
dismissed: number;
|
|
226
|
-
remaining: number;
|
|
227
|
-
details: Array<{
|
|
228
|
-
id: string;
|
|
229
|
-
existingStatement: string;
|
|
230
|
-
candidateStatement: string;
|
|
231
|
-
}>;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Dismiss pending memory conflicts. With `all: true`, dismisses every
|
|
236
|
-
* pending conflict. Otherwise, dismisses only conflicts matching the
|
|
237
|
-
* given `pattern` regex against either statement.
|
|
238
|
-
*/
|
|
239
|
-
export function dismissPendingConflicts(options: {
|
|
240
|
-
all?: boolean;
|
|
241
|
-
pattern?: RegExp;
|
|
242
|
-
scopeId?: string;
|
|
243
|
-
}): DismissConflictsResult {
|
|
244
|
-
const scopeId = options.scopeId ?? "default";
|
|
245
|
-
const dismissed: DismissConflictsResult["details"] = [];
|
|
246
|
-
const BATCH_SIZE = 1000;
|
|
247
|
-
|
|
248
|
-
// Cursor-based pagination: track last seen (createdAt, id) to advance past
|
|
249
|
-
// previously inspected rows. This ensures pattern mode scans all pending
|
|
250
|
-
// conflicts even when non-matching rows outnumber the batch size.
|
|
251
|
-
let cursor: { createdAt: number; id: string } | undefined;
|
|
252
|
-
let batch = listPendingConflictDetails(scopeId, BATCH_SIZE);
|
|
253
|
-
while (batch.length > 0) {
|
|
254
|
-
for (const conflict of batch) {
|
|
255
|
-
const matches =
|
|
256
|
-
options.all ||
|
|
257
|
-
(options.pattern &&
|
|
258
|
-
(options.pattern.test(conflict.existingStatement) ||
|
|
259
|
-
options.pattern.test(conflict.candidateStatement)));
|
|
260
|
-
if (!matches) continue;
|
|
261
|
-
|
|
262
|
-
resolveConflict(conflict.id, {
|
|
263
|
-
status: "dismissed",
|
|
264
|
-
resolutionNote: options.all
|
|
265
|
-
? "Bulk dismissed via CLI (dismiss-conflicts --all)."
|
|
266
|
-
: `Dismissed via CLI (pattern: ${options.pattern?.source}).`,
|
|
267
|
-
});
|
|
268
|
-
dismissed.push({
|
|
269
|
-
id: conflict.id,
|
|
270
|
-
existingStatement: conflict.existingStatement,
|
|
271
|
-
candidateStatement: conflict.candidateStatement,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
// No more rows to inspect
|
|
275
|
-
if (batch.length < BATCH_SIZE) break;
|
|
276
|
-
const lastRow = batch[batch.length - 1];
|
|
277
|
-
cursor = { createdAt: lastRow.createdAt, id: lastRow.id };
|
|
278
|
-
batch = listPendingConflictDetails(scopeId, BATCH_SIZE, cursor);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Get true remaining count via SQL to avoid batch-size truncation
|
|
282
|
-
const remaining =
|
|
283
|
-
rawGet<{ c: number }>(
|
|
284
|
-
`SELECT COUNT(*) AS c FROM memory_item_conflicts WHERE scope_id = ? AND status = 'pending_clarification'`,
|
|
285
|
-
scopeId,
|
|
286
|
-
)?.c ?? 0;
|
|
287
|
-
|
|
288
|
-
log.info(
|
|
289
|
-
{ dismissed: dismissed.length, remaining, scopeId },
|
|
290
|
-
"Dismissed pending conflicts",
|
|
291
|
-
);
|
|
292
|
-
return {
|
|
293
|
-
dismissed: dismissed.length,
|
|
294
|
-
remaining,
|
|
295
|
-
details: dismissed,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
@@ -17,6 +17,21 @@ import {
|
|
|
17
17
|
canonicalGuardianRequests,
|
|
18
18
|
} from "./schema.js";
|
|
19
19
|
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Expiry helpers
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns true when a canonical request has passed its `expiresAt` deadline.
|
|
26
|
+
* Requests without an `expiresAt` are never considered expired by this check.
|
|
27
|
+
*/
|
|
28
|
+
export function isRequestExpired(
|
|
29
|
+
request: Pick<CanonicalGuardianRequest, "expiresAt">,
|
|
30
|
+
): boolean {
|
|
31
|
+
if (!request.expiresAt) return false;
|
|
32
|
+
return new Date(request.expiresAt).getTime() < Date.now();
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
// ---------------------------------------------------------------------------
|
|
21
36
|
// Types
|
|
22
37
|
// ---------------------------------------------------------------------------
|
|
@@ -444,6 +459,27 @@ export function resolveCanonicalGuardianRequest(
|
|
|
444
459
|
return getCanonicalGuardianRequest(id);
|
|
445
460
|
}
|
|
446
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Expire all pending canonical guardian requests in a single bulk update.
|
|
464
|
+
*
|
|
465
|
+
* Called at daemon startup to clean up requests that can never be completed
|
|
466
|
+
* because the in-memory pending-interactions Map (which holds session
|
|
467
|
+
* references needed by resolvers) was wiped on restart.
|
|
468
|
+
*
|
|
469
|
+
* Returns the number of requests transitioned from pending → expired.
|
|
470
|
+
*/
|
|
471
|
+
export function expireAllPendingCanonicalRequests(): number {
|
|
472
|
+
const db = getDb();
|
|
473
|
+
const now = new Date().toISOString();
|
|
474
|
+
|
|
475
|
+
db.update(canonicalGuardianRequests)
|
|
476
|
+
.set({ status: "expired", updatedAt: now })
|
|
477
|
+
.where(eq(canonicalGuardianRequests.status, "pending"))
|
|
478
|
+
.run();
|
|
479
|
+
|
|
480
|
+
return rawChanges();
|
|
481
|
+
}
|
|
482
|
+
|
|
447
483
|
// ---------------------------------------------------------------------------
|
|
448
484
|
// Canonical Guardian Deliveries
|
|
449
485
|
// ---------------------------------------------------------------------------
|
|
@@ -624,14 +660,14 @@ export function listPendingRequestsByConversationScope(
|
|
|
624
660
|
const result: CanonicalGuardianRequest[] = [];
|
|
625
661
|
|
|
626
662
|
for (const req of bySource) {
|
|
627
|
-
if (!seen.has(req.id)) {
|
|
663
|
+
if (!seen.has(req.id) && !isRequestExpired(req)) {
|
|
628
664
|
seen.add(req.id);
|
|
629
665
|
result.push(req);
|
|
630
666
|
}
|
|
631
667
|
}
|
|
632
668
|
|
|
633
669
|
for (const req of byDestination) {
|
|
634
|
-
if (!seen.has(req.id)) {
|
|
670
|
+
if (!seen.has(req.id) && !isRequestExpired(req)) {
|
|
635
671
|
seen.add(req.id);
|
|
636
672
|
result.push(req);
|
|
637
673
|
}
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
conversations,
|
|
20
20
|
llmRequestLogs,
|
|
21
21
|
memoryEmbeddings,
|
|
22
|
-
memoryItemEntities,
|
|
23
22
|
memoryItems,
|
|
24
23
|
memoryItemSources,
|
|
25
24
|
memorySegments,
|
|
@@ -503,19 +502,6 @@ export function clearAll(): { conversations: number; messages: number } {
|
|
|
503
502
|
// triggers so that the subsequent base-table DELETEs don't also fail
|
|
504
503
|
// (SQLite triggers are atomic with the triggering statement, so a
|
|
505
504
|
// corrupted FTS table would roll back every base-table DELETE).
|
|
506
|
-
let segmentFtsCorrupted = false;
|
|
507
|
-
try {
|
|
508
|
-
rawExec("DELETE FROM memory_segment_fts");
|
|
509
|
-
} catch (err) {
|
|
510
|
-
log.warn(
|
|
511
|
-
{ err },
|
|
512
|
-
"clearAll: failed to clear memory_segment_fts — dropping triggers so base-table cleanup can proceed",
|
|
513
|
-
);
|
|
514
|
-
rawExec("DROP TRIGGER IF EXISTS memory_segments_ai");
|
|
515
|
-
rawExec("DROP TRIGGER IF EXISTS memory_segments_ad");
|
|
516
|
-
rawExec("DROP TRIGGER IF EXISTS memory_segments_au");
|
|
517
|
-
segmentFtsCorrupted = true;
|
|
518
|
-
}
|
|
519
505
|
rawExec("DELETE FROM memory_item_sources");
|
|
520
506
|
rawExec("DELETE FROM memory_segments");
|
|
521
507
|
rawExec("DELETE FROM memory_items");
|
|
@@ -548,21 +534,6 @@ export function clearAll(): { conversations: number; messages: number } {
|
|
|
548
534
|
// DELETEs have completed. Dropping the virtual table clears the corruption,
|
|
549
535
|
// and recreating it + triggers means subsequent writes maintain FTS
|
|
550
536
|
// consistency without requiring a daemon restart.
|
|
551
|
-
if (segmentFtsCorrupted) {
|
|
552
|
-
rawExec("DROP TABLE IF EXISTS memory_segment_fts");
|
|
553
|
-
rawExec(
|
|
554
|
-
`CREATE VIRTUAL TABLE IF NOT EXISTS memory_segment_fts USING fts5(segment_id UNINDEXED, text)`,
|
|
555
|
-
);
|
|
556
|
-
rawExec(
|
|
557
|
-
`CREATE TRIGGER IF NOT EXISTS memory_segments_ai AFTER INSERT ON memory_segments BEGIN INSERT INTO memory_segment_fts(segment_id, text) VALUES (new.id, new.text); END`,
|
|
558
|
-
);
|
|
559
|
-
rawExec(
|
|
560
|
-
`CREATE TRIGGER IF NOT EXISTS memory_segments_ad AFTER DELETE ON memory_segments BEGIN DELETE FROM memory_segment_fts WHERE segment_id = old.id; END`,
|
|
561
|
-
);
|
|
562
|
-
rawExec(
|
|
563
|
-
`CREATE TRIGGER IF NOT EXISTS memory_segments_au AFTER UPDATE ON memory_segments BEGIN DELETE FROM memory_segment_fts WHERE segment_id = old.id; INSERT INTO memory_segment_fts(segment_id, text) VALUES (new.id, new.text); END`,
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
537
|
if (messagesFtsCorrupted) {
|
|
567
538
|
rawExec("DROP TABLE IF EXISTS messages_fts");
|
|
568
539
|
rawExec(
|
|
@@ -787,10 +758,6 @@ export function deleteMessageById(messageId: string): DeletedMemoryIds {
|
|
|
787
758
|
result.orphanedItemIds = orphanedIds;
|
|
788
759
|
|
|
789
760
|
if (orphanedIds.length > 0) {
|
|
790
|
-
// Delete memory_item_entities (no FK cascade on this table).
|
|
791
|
-
tx.delete(memoryItemEntities)
|
|
792
|
-
.where(inArray(memoryItemEntities.memoryItemId, orphanedIds))
|
|
793
|
-
.run();
|
|
794
761
|
// Delete embeddings referencing these items.
|
|
795
762
|
tx.delete(memoryEmbeddings)
|
|
796
763
|
.where(
|
|
@@ -117,6 +117,27 @@ export function getOrCreateConversation(conversationKey: string): {
|
|
|
117
117
|
return { conversationId: existing.conversationId, created: false };
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// Check if the conversationKey itself is an existing conversation ID.
|
|
121
|
+
// This happens when the client loads a thread from the conversations list
|
|
122
|
+
// and uses the server's conversationId as its local sessionId / conversationKey.
|
|
123
|
+
const existingConversation = tx
|
|
124
|
+
.select({ id: conversations.id })
|
|
125
|
+
.from(conversations)
|
|
126
|
+
.where(eq(conversations.id, conversationKey))
|
|
127
|
+
.get();
|
|
128
|
+
|
|
129
|
+
if (existingConversation) {
|
|
130
|
+
tx.insert(conversationKeys)
|
|
131
|
+
.values({
|
|
132
|
+
id: uuid(),
|
|
133
|
+
conversationKey,
|
|
134
|
+
conversationId: existingConversation.id,
|
|
135
|
+
createdAt: Date.now(),
|
|
136
|
+
})
|
|
137
|
+
.run();
|
|
138
|
+
return { conversationId: existingConversation.id, created: false };
|
|
139
|
+
}
|
|
140
|
+
|
|
120
141
|
const now = Date.now();
|
|
121
142
|
const conversationId = uuid();
|
|
122
143
|
|
|
@@ -6,10 +6,24 @@ import { parseConversation, parseMessage } from "./conversation-crud.js";
|
|
|
6
6
|
import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
|
|
7
7
|
import { getDb, rawAll } from "./db.js";
|
|
8
8
|
import { conversations, messages } from "./schema.js";
|
|
9
|
-
import { buildFtsMatchQuery } from "./search/lexical.js";
|
|
10
9
|
|
|
11
10
|
const log = getLogger("conversation-store");
|
|
12
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Build an FTS5 MATCH query string from natural text by extracting tokens.
|
|
14
|
+
* Used for messages_fts full-text search over conversation content.
|
|
15
|
+
*/
|
|
16
|
+
function buildFtsMatchQuery(text: string): string | null {
|
|
17
|
+
const tokens = text
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.split(/[^a-z0-9_]+/g)
|
|
20
|
+
.map((token) => token.trim())
|
|
21
|
+
.filter((token) => token.length >= 2);
|
|
22
|
+
if (tokens.length === 0) return null;
|
|
23
|
+
const unique = [...new Set(tokens)].slice(0, 24);
|
|
24
|
+
return unique.map((token) => `"${token.replace(/"/g, '""')}"`).join(" OR ");
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
export function listConversations(
|
|
14
28
|
limit?: number,
|
|
15
29
|
includeBackground = false,
|
|
@@ -160,7 +174,9 @@ export function isLastUserMessageToolResult(conversationId: string): boolean {
|
|
|
160
174
|
Array.isArray(parsed) &&
|
|
161
175
|
parsed.length > 0 &&
|
|
162
176
|
parsed.every(
|
|
163
|
-
(block: Record<string, unknown>) =>
|
|
177
|
+
(block: Record<string, unknown>) =>
|
|
178
|
+
block.type === "tool_result" ||
|
|
179
|
+
block.type === "web_search_tool_result",
|
|
164
180
|
)
|
|
165
181
|
) {
|
|
166
182
|
return true;
|
|
@@ -375,7 +391,10 @@ function buildExcerpt(rawContent: string, query: string): string {
|
|
|
375
391
|
if (typeof block === "object" && block != null) {
|
|
376
392
|
if (block.type === "text" && typeof block.text === "string") {
|
|
377
393
|
parts.push(block.text);
|
|
378
|
-
} else if (
|
|
394
|
+
} else if (
|
|
395
|
+
block.type === "tool_result" ||
|
|
396
|
+
block.type === "web_search_tool_result"
|
|
397
|
+
) {
|
|
379
398
|
const inner = Array.isArray(block.content) ? block.content : [];
|
|
380
399
|
for (const ib of inner) {
|
|
381
400
|
if (ib?.type === "text" && typeof ib.text === "string")
|
package/src/memory/db-init.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
createMediaAssetsTables,
|
|
29
29
|
createMessagesFts,
|
|
30
30
|
createNotificationTables,
|
|
31
|
+
createOAuthTables,
|
|
31
32
|
createScopedApprovalGrantsTable,
|
|
32
33
|
createSequenceTables,
|
|
33
34
|
createTasksAndWorkItemsTables,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
migrateBackfillContactInteractionStats,
|
|
37
38
|
migrateBackfillGuardianPrincipalId,
|
|
38
39
|
migrateBackfillUsageCacheAccounting,
|
|
40
|
+
migrateCallSessionInviteMetadata,
|
|
39
41
|
migrateCallSessionMode,
|
|
40
42
|
migrateCanonicalGuardianDeliveriesDestinationIndex,
|
|
41
43
|
migrateCanonicalGuardianRequesterChatId,
|
|
@@ -48,7 +50,10 @@ import {
|
|
|
48
50
|
migrateConversationsThreadTypeIndex,
|
|
49
51
|
migrateDropAccountsTable,
|
|
50
52
|
migrateDropAssistantIdColumns,
|
|
53
|
+
migrateDropConflicts,
|
|
54
|
+
migrateDropEntityTables,
|
|
51
55
|
migrateDropLegacyMemberGuardianTables,
|
|
56
|
+
migrateDropMemorySegmentFts,
|
|
52
57
|
migrateDropRemindersTable,
|
|
53
58
|
migrateDropUsageCompositeIndexes,
|
|
54
59
|
migrateFkCascadeRebuilds,
|
|
@@ -62,9 +67,12 @@ import {
|
|
|
62
67
|
migrateGuardianVerificationPurpose,
|
|
63
68
|
migrateGuardianVerificationSessions,
|
|
64
69
|
migrateInviteCodeHashColumn,
|
|
70
|
+
migrateMemoryItemSupersession,
|
|
65
71
|
migrateMessagesFtsBackfill,
|
|
66
72
|
migrateNormalizePhoneIdentities,
|
|
67
73
|
migrateNotificationDeliveryThreadDecision,
|
|
74
|
+
migrateOAuthAppsClientSecretPath,
|
|
75
|
+
migrateOAuthProvidersPingUrl,
|
|
68
76
|
migrateReminderRoutingIntent,
|
|
69
77
|
migrateRemindersToSchedules,
|
|
70
78
|
migrateRenameGuardianVerificationValues,
|
|
@@ -340,6 +348,30 @@ export function initializeDb(): void {
|
|
|
340
348
|
// 52. Drop the legacy reminders table after data migration
|
|
341
349
|
migrateDropRemindersTable(database);
|
|
342
350
|
|
|
351
|
+
// 53. OAuth provider/app/connection tables
|
|
352
|
+
createOAuthTables(database);
|
|
353
|
+
|
|
354
|
+
// 54. Add explicit client_secret_credential_path to oauth_apps
|
|
355
|
+
migrateOAuthAppsClientSecretPath(database);
|
|
356
|
+
|
|
357
|
+
// 55. Add ping_url column to oauth_providers
|
|
358
|
+
migrateOAuthProvidersPingUrl(database);
|
|
359
|
+
|
|
360
|
+
// 56. Add supersession tracking columns and override confidence to memory_items
|
|
361
|
+
migrateMemoryItemSupersession(database);
|
|
362
|
+
|
|
363
|
+
// 56b. Drop unused entity tables (entity search replaced by hybrid search on item statements)
|
|
364
|
+
migrateDropEntityTables(database);
|
|
365
|
+
|
|
366
|
+
// 57. Drop memory_segment_fts virtual table and triggers (replaced by Qdrant hybrid search)
|
|
367
|
+
migrateDropMemorySegmentFts(database);
|
|
368
|
+
|
|
369
|
+
// 58. Drop memory_item_conflicts table (conflict resolution system removed)
|
|
370
|
+
migrateDropConflicts(database);
|
|
371
|
+
|
|
372
|
+
// 59. Add invite metadata columns to call_sessions for outbound invite call routing
|
|
373
|
+
migrateCallSessionInviteMetadata(database);
|
|
374
|
+
|
|
343
375
|
validateMigrationState(database);
|
|
344
376
|
|
|
345
377
|
if (process.env.BUN_TEST === "1") {
|