@vellumai/assistant 0.5.5 → 0.5.7
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/.env.example +16 -2
- package/ARCHITECTURE.md +6 -75
- package/Dockerfile +4 -5
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docs/architecture/keychain-broker.md +45 -240
- package/docs/architecture/security.md +0 -17
- package/docs/credential-execution-service.md +2 -2
- package/node_modules/@vellumai/ces-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
- package/node_modules/@vellumai/credential-storage/package.json +1 -0
- package/node_modules/@vellumai/egress-proxy/package.json +1 -0
- package/package.json +2 -3
- package/src/__tests__/actor-token-service.test.ts +1 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -5
- package/src/__tests__/channel-readiness-service.test.ts +1 -60
- package/src/__tests__/checker.test.ts +4 -2
- package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +3 -3
- package/src/__tests__/context-window-manager.test.ts +78 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-title-service.test.ts +117 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
- package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
- package/src/__tests__/credential-security-e2e.test.ts +0 -66
- package/src/__tests__/credential-security-invariants.test.ts +4 -45
- package/src/__tests__/credentials-cli.test.ts +78 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- package/src/__tests__/guardian-routing-state.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -7
- package/src/__tests__/http-user-message-parity.test.ts +3 -103
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
- package/src/__tests__/intent-routing.test.ts +0 -13
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
- package/src/__tests__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/memory-regressions.test.ts +8 -30
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-import-commit-http.test.ts +2 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
- package/src/__tests__/migration-validate-http.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +0 -5
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/require-fresh-approval.test.ts +4 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +83 -263
- package/src/__tests__/shell-identity.test.ts +96 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
- package/src/__tests__/skill-feature-flags.test.ts +46 -45
- package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
- package/src/__tests__/skill-load-inline-command.test.ts +8 -12
- package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
- package/src/__tests__/skill-load-tool.test.ts +0 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
- package/src/__tests__/skills.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +0 -4
- package/src/__tests__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/tool-executor.test.ts +4 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +85 -7
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +117 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/twilio-routes.ts +2 -1
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +26 -5
- package/src/calls/voice-session-bridge.ts +6 -12
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/conversations.ts +0 -18
- package/src/cli/commands/credentials.ts +34 -4
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +179 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-tool-registry.ts +1 -11
- package/src/config/env-registry.ts +1 -1
- package/src/config/env.ts +16 -16
- package/src/config/feature-flag-registry.json +48 -16
- package/src/config/loader.ts +98 -31
- package/src/config/schema.ts +4 -25
- package/src/config/schemas/calls.ts +13 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/platform.ts +1 -1
- package/src/config/schemas/security.ts +4 -4
- package/src/config/types.ts +0 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/context/window-manager.ts +53 -2
- package/src/credential-execution/approval-bridge.ts +1 -0
- package/src/credential-execution/executable-discovery.ts +28 -4
- package/src/credential-execution/feature-gates.ts +16 -0
- package/src/credential-execution/process-manager.ts +38 -0
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +6 -4
- package/src/daemon/conversation-agent-loop.ts +0 -60
- package/src/daemon/conversation-memory.ts +0 -117
- package/src/daemon/conversation-runtime-assembly.ts +0 -2
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +10 -1
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/conversations.ts +0 -11
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +229 -96
- package/src/daemon/message-types/conversations.ts +3 -4
- package/src/daemon/message-types/diagnostics.ts +3 -22
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/message-types/upgrades.ts +8 -0
- package/src/daemon/server.ts +30 -92
- package/src/events/domain-events.ts +2 -1
- package/src/followups/followup-store.ts +5 -2
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/conversation-crud.ts +0 -236
- package/src/memory/conversation-title-service.ts +76 -11
- package/src/memory/db-init.ts +15 -11
- package/src/memory/indexer.ts +15 -106
- package/src/memory/items-extractor.ts +15 -1
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/job-handlers/embedding.ts +0 -79
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +30 -13
- package/src/memory/jobs-worker.ts +31 -27
- package/src/memory/migrations/001-job-deferrals.ts +19 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
- package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
- package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
- package/src/memory/migrations/116-messages-fts.ts +106 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
- package/src/memory/migrations/141-rename-verification-table.ts +54 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
- package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
- package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
- package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
- package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
- package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
- package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
- package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
- package/src/memory/migrations/index.ts +5 -3
- package/src/memory/migrations/registry.ts +90 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-client.ts +4 -6
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/conversations.ts +0 -3
- package/src/memory/schema/index.ts +0 -2
- package/src/messaging/draft-store.ts +2 -2
- package/src/notifications/decision-engine.ts +4 -1
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/defaults.ts +3 -3
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/trust-client.ts +2 -13
- package/src/permissions/trust-store.ts +8 -3
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/persona-resolver.ts +138 -0
- package/src/prompts/system-prompt.ts +36 -4
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/registry.ts +27 -40
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
- package/src/runtime/auth/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +29 -1
- package/src/runtime/auth/token-service.ts +53 -15
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/http-server.ts +29 -2
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/conversation-management-routes.ts +0 -36
- package/src/runtime/routes/conversation-query-routes.ts +106 -2
- package/src/runtime/routes/conversation-routes.ts +4 -43
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/identity-routes.ts +18 -29
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/integrations/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.test.ts +221 -3
- package/src/runtime/routes/memory-item-routes.ts +144 -4
- package/src/runtime/routes/migration-rollback-routes.ts +209 -0
- package/src/runtime/routes/migration-routes.ts +17 -1
- package/src/runtime/routes/notification-routes.ts +58 -0
- package/src/runtime/routes/schedule-routes.ts +65 -0
- package/src/runtime/routes/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +86 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
- package/src/runtime/routes/workspace-commit-routes.ts +62 -0
- package/src/runtime/routes/workspace-routes.test.ts +22 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +86 -2
- package/src/schedule/schedule-store.ts +0 -21
- package/src/security/ces-credential-client.ts +59 -22
- package/src/security/ces-rpc-credential-backend.ts +85 -0
- package/src/security/credential-backend.ts +12 -88
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +94 -113
- package/src/skills/catalog-install.ts +13 -7
- package/src/skills/inline-command-render.ts +5 -1
- package/src/skills/inline-command-runner.ts +30 -2
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/executor.ts +0 -4
- package/src/tools/memory/handlers.ts +1 -129
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/permission-checker.ts +18 -0
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +9 -2
- package/src/tools/types.ts +0 -8
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +8 -55
- package/src/util/xml.ts +8 -0
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/heartbeat-service.ts +5 -24
- package/src/workspace/migrations/001-avatar-rename.ts +15 -0
- package/src/workspace/migrations/003-seed-device-id.ts +17 -1
- package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
- package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
- package/src/workspace/migrations/006-services-config.ts +49 -0
- package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/__tests__/archive-recall.test.ts +0 -560
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
- package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
- package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
- package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
- package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
- package/src/__tests__/memory-brief-time.test.ts +0 -285
- package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
- package/src/__tests__/memory-chunk-archive.test.ts +0 -400
- package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
- package/src/__tests__/memory-episode-archive.test.ts +0 -370
- package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
- package/src/__tests__/memory-observation-archive.test.ts +0 -375
- package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
- package/src/__tests__/memory-reducer-job.test.ts +0 -538
- package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
- package/src/__tests__/memory-reducer-store.test.ts +0 -728
- package/src/__tests__/memory-reducer-types.test.ts +0 -707
- package/src/__tests__/memory-reducer.test.ts +0 -704
- package/src/__tests__/memory-simplified-config.test.ts +0 -281
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
- package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
- package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
- package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
- package/src/__tests__/swarm-orchestrator.test.ts +0 -463
- package/src/__tests__/swarm-plan-validator.test.ts +0 -384
- package/src/__tests__/swarm-recursion.test.ts +0 -197
- package/src/__tests__/swarm-router-planner.test.ts +0 -234
- package/src/__tests__/swarm-tool.test.ts +0 -185
- package/src/__tests__/swarm-worker-backend.test.ts +0 -144
- package/src/__tests__/swarm-worker-runner.test.ts +0 -288
- package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
- package/src/commands/cc-command-registry.ts +0 -248
- package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
- package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
- package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
- package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
- package/src/config/schemas/memory-simplified.ts +0 -101
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/memory/archive-recall.ts +0 -516
- package/src/memory/archive-store.ts +0 -400
- package/src/memory/brief-formatting.ts +0 -33
- package/src/memory/brief-open-loops.ts +0 -266
- package/src/memory/brief-time.ts +0 -162
- package/src/memory/brief.ts +0 -75
- package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
- package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
- package/src/memory/migrations/185-memory-brief-state.ts +0 -52
- package/src/memory/migrations/186-memory-archive.ts +0 -109
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
- package/src/memory/reducer-scheduler.ts +0 -242
- package/src/memory/reducer-store.ts +0 -271
- package/src/memory/reducer-types.ts +0 -106
- package/src/memory/reducer.ts +0 -467
- package/src/memory/schema/memory-archive.ts +0 -121
- package/src/memory/schema/memory-brief.ts +0 -55
- package/src/runtime/local-gateway-health.ts +0 -275
- package/src/security/secret-ingress.ts +0 -68
- package/src/swarm/backend-claude-code.ts +0 -225
- package/src/swarm/checkpoint.ts +0 -137
- package/src/swarm/graph-utils.ts +0 -53
- package/src/swarm/index.ts +0 -55
- package/src/swarm/limits.ts +0 -66
- package/src/swarm/orchestrator.ts +0 -424
- package/src/swarm/plan-validator.ts +0 -117
- package/src/swarm/router-planner.ts +0 -162
- package/src/swarm/router-prompts.ts +0 -39
- package/src/swarm/synthesizer.ts +0 -81
- package/src/swarm/types.ts +0 -72
- package/src/swarm/worker-backend.ts +0 -131
- package/src/swarm/worker-prompts.ts +0 -80
- package/src/swarm/worker-runner.ts +0 -170
- package/src/tools/claude-code/claude-code.ts +0 -610
- package/src/tools/swarm/delegate.ts +0 -205
package/src/memory/jobs-store.ts
CHANGED
|
@@ -4,6 +4,10 @@ import { v4 as uuid } from "uuid";
|
|
|
4
4
|
import { getLogger } from "../util/logger.js";
|
|
5
5
|
import { truncate } from "../util/truncate.js";
|
|
6
6
|
import { getDb, rawAll, rawChanges } from "./db.js";
|
|
7
|
+
import {
|
|
8
|
+
isQdrantBreakerOpen,
|
|
9
|
+
shouldAllowQdrantProbe,
|
|
10
|
+
} from "./qdrant-circuit-breaker.js";
|
|
7
11
|
import { memoryJobs } from "./schema.js";
|
|
8
12
|
|
|
9
13
|
const log = getLogger("memory-jobs-store");
|
|
@@ -12,9 +16,6 @@ export type MemoryJobType =
|
|
|
12
16
|
| "embed_segment"
|
|
13
17
|
| "embed_item"
|
|
14
18
|
| "embed_summary"
|
|
15
|
-
| "embed_chunk"
|
|
16
|
-
| "embed_episode"
|
|
17
|
-
| "embed_observation"
|
|
18
19
|
| "extract_items"
|
|
19
20
|
| "extract_entities"
|
|
20
21
|
| "cleanup_stale_superseded_items"
|
|
@@ -30,8 +31,6 @@ export type MemoryJobType =
|
|
|
30
31
|
| "embed_media"
|
|
31
32
|
| "embed_attachment"
|
|
32
33
|
| "generate_conversation_starters"
|
|
33
|
-
| "reduce_conversation_memory"
|
|
34
|
-
| "backfill_simplified_memory"
|
|
35
34
|
| "generate_capability_cards" // legacy compat — silently dropped by worker (capability cards removed)
|
|
36
35
|
| "generate_thread_starters"; // legacy compat — silently dropped by worker (renamed to generate_conversation_starters)
|
|
37
36
|
|
|
@@ -39,9 +38,6 @@ const EMBED_JOB_TYPES: MemoryJobType[] = [
|
|
|
39
38
|
"embed_segment",
|
|
40
39
|
"embed_item",
|
|
41
40
|
"embed_summary",
|
|
42
|
-
"embed_chunk",
|
|
43
|
-
"embed_episode",
|
|
44
|
-
"embed_observation",
|
|
45
41
|
"embed_media",
|
|
46
42
|
"embed_attachment",
|
|
47
43
|
];
|
|
@@ -209,14 +205,33 @@ export function claimMemoryJobs(limit: number): MemoryJob[] {
|
|
|
209
205
|
.all();
|
|
210
206
|
|
|
211
207
|
const remainingSlots = limit - nonEmbedCandidates.length;
|
|
208
|
+
|
|
209
|
+
// When the Qdrant circuit breaker is open, skip embed jobs entirely —
|
|
210
|
+
// they would just be claimed → fail → deferred, wasting CPU cycles.
|
|
211
|
+
// Exception: if the cooldown has elapsed (breaker ready for half-open probe),
|
|
212
|
+
// allow exactly 1 embed job through so the breaker can self-heal.
|
|
213
|
+
const breakerOpen = isQdrantBreakerOpen();
|
|
214
|
+
const probeAllowed = breakerOpen && shouldAllowQdrantProbe();
|
|
215
|
+
const skipEmbedJobs = breakerOpen && !probeAllowed;
|
|
216
|
+
const embedLimit = probeAllowed ? 1 : remainingSlots;
|
|
217
|
+
|
|
218
|
+
if (skipEmbedJobs && remainingSlots > 0) {
|
|
219
|
+
log.debug("Skipping embed job claims — Qdrant circuit breaker is open");
|
|
220
|
+
}
|
|
221
|
+
if (probeAllowed && remainingSlots > 0) {
|
|
222
|
+
log.debug(
|
|
223
|
+
"Allowing 1 embed probe job — Qdrant circuit breaker cooldown elapsed",
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
212
227
|
const embedCandidates =
|
|
213
|
-
remainingSlots > 0
|
|
228
|
+
remainingSlots > 0 && !skipEmbedJobs
|
|
214
229
|
? db
|
|
215
230
|
.select()
|
|
216
231
|
.from(memoryJobs)
|
|
217
232
|
.where(and(pendingFilter, inArray(memoryJobs.type, EMBED_JOB_TYPES)))
|
|
218
233
|
.orderBy(asc(memoryJobs.runAfter), asc(memoryJobs.createdAt))
|
|
219
|
-
.limit(
|
|
234
|
+
.limit(embedLimit)
|
|
220
235
|
.all()
|
|
221
236
|
: [];
|
|
222
237
|
|
|
@@ -251,8 +266,8 @@ export function completeMemoryJob(id: string): void {
|
|
|
251
266
|
|
|
252
267
|
/** Max times a job can be deferred before it is marked as failed. */
|
|
253
268
|
const MAX_DEFERRALS = 50;
|
|
254
|
-
/**
|
|
255
|
-
const
|
|
269
|
+
/** Log warnings at these milestone counts to avoid flooding logs. */
|
|
270
|
+
const DEFERRAL_WARN_MILESTONES = [40, 45];
|
|
256
271
|
/** Base delay in ms for deferred jobs (grows with exponential backoff). */
|
|
257
272
|
const DEFER_BASE_DELAY_MS = 30_000;
|
|
258
273
|
/** Maximum delay cap for deferred jobs (5 minutes). */
|
|
@@ -294,7 +309,9 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
294
309
|
return "failed";
|
|
295
310
|
}
|
|
296
311
|
|
|
297
|
-
|
|
312
|
+
// Log at milestones only (40, 45) to avoid flooding logs.
|
|
313
|
+
// At 50, the job fails via the check above, so 40 and 45 are the warnings.
|
|
314
|
+
if (DEFERRAL_WARN_MILESTONES.includes(deferrals)) {
|
|
298
315
|
log.warn(
|
|
299
316
|
{ jobId: id, type: row.type, deferrals, max: MAX_DEFERRALS },
|
|
300
317
|
"Job approaching max deferral limit",
|
|
@@ -3,7 +3,6 @@ import type { AssistantConfig } from "../config/types.js";
|
|
|
3
3
|
import { getLogger } from "../util/logger.js";
|
|
4
4
|
import { rawRun } from "./db.js";
|
|
5
5
|
import { backfillJob } from "./job-handlers/backfill.js";
|
|
6
|
-
import { backfillSimplifiedMemoryJob } from "./job-handlers/backfill-simplified-memory.js";
|
|
7
6
|
import {
|
|
8
7
|
cleanupStaleSupersededItemsJob,
|
|
9
8
|
pruneOldConversationsJob,
|
|
@@ -12,11 +11,8 @@ import { generateConversationStartersJob } from "./job-handlers/conversation-sta
|
|
|
12
11
|
// ── Per-job-type handlers ──────────────────────────────────────────
|
|
13
12
|
import {
|
|
14
13
|
embedAttachmentJob,
|
|
15
|
-
embedChunkJob,
|
|
16
|
-
embedEpisodeJob,
|
|
17
14
|
embedItemJob,
|
|
18
15
|
embedMediaJob,
|
|
19
|
-
embedObservationJob,
|
|
20
16
|
embedSegmentJob,
|
|
21
17
|
embedSummaryJob,
|
|
22
18
|
} from "./job-handlers/embedding.js";
|
|
@@ -26,7 +22,6 @@ import {
|
|
|
26
22
|
rebuildIndexJob,
|
|
27
23
|
} from "./job-handlers/index-maintenance.js";
|
|
28
24
|
import { mediaProcessingJob } from "./job-handlers/media-processing.js";
|
|
29
|
-
import { reduceConversationMemoryJob } from "./job-handlers/reduce-conversation-memory.js";
|
|
30
25
|
import { buildConversationSummaryJob } from "./job-handlers/summarization.js";
|
|
31
26
|
import {
|
|
32
27
|
BackendUnavailableError,
|
|
@@ -49,6 +44,9 @@ import { QdrantCircuitOpenError } from "./qdrant-circuit-breaker.js";
|
|
|
49
44
|
|
|
50
45
|
const log = getLogger("memory-jobs-worker");
|
|
51
46
|
|
|
47
|
+
export const POLL_INTERVAL_MIN_MS = 1_500;
|
|
48
|
+
export const POLL_INTERVAL_MAX_MS = 30_000;
|
|
49
|
+
|
|
52
50
|
export interface MemoryJobsWorker {
|
|
53
51
|
runOnce(): Promise<number>;
|
|
54
52
|
stop(): void;
|
|
@@ -62,24 +60,45 @@ export function startMemoryJobsWorker(): MemoryJobsWorker {
|
|
|
62
60
|
|
|
63
61
|
let stopped = false;
|
|
64
62
|
let tickRunning = false;
|
|
63
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
64
|
+
let currentIntervalMs = POLL_INTERVAL_MIN_MS;
|
|
65
65
|
|
|
66
66
|
const tick = async () => {
|
|
67
67
|
if (stopped || tickRunning) return;
|
|
68
68
|
tickRunning = true;
|
|
69
69
|
try {
|
|
70
|
-
await runMemoryJobsOnce({
|
|
70
|
+
const processed = await runMemoryJobsOnce({
|
|
71
|
+
enableScheduledCleanup: true,
|
|
72
|
+
});
|
|
73
|
+
if (processed > 0) {
|
|
74
|
+
currentIntervalMs = POLL_INTERVAL_MIN_MS;
|
|
75
|
+
} else {
|
|
76
|
+
currentIntervalMs = Math.min(
|
|
77
|
+
currentIntervalMs * 2,
|
|
78
|
+
POLL_INTERVAL_MAX_MS,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
71
81
|
} catch (err) {
|
|
72
82
|
log.error({ err }, "Memory worker tick failed");
|
|
83
|
+
currentIntervalMs = Math.min(currentIntervalMs * 2, POLL_INTERVAL_MAX_MS);
|
|
73
84
|
} finally {
|
|
74
85
|
tickRunning = false;
|
|
75
86
|
}
|
|
76
87
|
};
|
|
77
88
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
const scheduleTick = () => {
|
|
90
|
+
if (stopped) return;
|
|
91
|
+
timer = setTimeout(() => {
|
|
92
|
+
void tick().then(() => {
|
|
93
|
+
if (!stopped) scheduleTick();
|
|
94
|
+
});
|
|
95
|
+
}, currentIntervalMs);
|
|
96
|
+
(timer as NodeJS.Timeout).unref?.();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
void tick().then(() => {
|
|
100
|
+
if (!stopped) scheduleTick();
|
|
101
|
+
});
|
|
83
102
|
|
|
84
103
|
return {
|
|
85
104
|
async runOnce(): Promise<number> {
|
|
@@ -87,7 +106,7 @@ export function startMemoryJobsWorker(): MemoryJobsWorker {
|
|
|
87
106
|
},
|
|
88
107
|
stop(): void {
|
|
89
108
|
stopped = true;
|
|
90
|
-
|
|
109
|
+
clearTimeout(timer);
|
|
91
110
|
},
|
|
92
111
|
};
|
|
93
112
|
}
|
|
@@ -272,15 +291,6 @@ async function processJob(
|
|
|
272
291
|
case "embed_summary":
|
|
273
292
|
await embedSummaryJob(job, config);
|
|
274
293
|
return;
|
|
275
|
-
case "embed_chunk":
|
|
276
|
-
await embedChunkJob(job, config);
|
|
277
|
-
return;
|
|
278
|
-
case "embed_episode":
|
|
279
|
-
await embedEpisodeJob(job, config);
|
|
280
|
-
return;
|
|
281
|
-
case "embed_observation":
|
|
282
|
-
await embedObservationJob(job, config);
|
|
283
|
-
return;
|
|
284
294
|
case "extract_items":
|
|
285
295
|
await extractItemsJob(job);
|
|
286
296
|
return;
|
|
@@ -321,12 +331,6 @@ async function processJob(
|
|
|
321
331
|
case "embed_attachment":
|
|
322
332
|
await embedAttachmentJob(job, config);
|
|
323
333
|
return;
|
|
324
|
-
case "reduce_conversation_memory":
|
|
325
|
-
await reduceConversationMemoryJob(job);
|
|
326
|
-
return;
|
|
327
|
-
case "backfill_simplified_memory":
|
|
328
|
-
await backfillSimplifiedMemoryJob(job);
|
|
329
|
-
return;
|
|
330
334
|
case "generate_conversation_starters":
|
|
331
335
|
await generateConversationStartersJob(job);
|
|
332
336
|
return;
|
|
@@ -49,3 +49,22 @@ export function migrateJobDeferrals(database: DrizzleDb): void {
|
|
|
49
49
|
throw e;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reverse the deferral reconciliation by moving `deferrals` back into `attempts`
|
|
55
|
+
* for pending embed jobs. Best-effort: jobs that accumulated real deferral counts
|
|
56
|
+
* after the forward migration ran cannot be distinguished from migrated ones.
|
|
57
|
+
*/
|
|
58
|
+
export function downJobDeferrals(database: DrizzleDb): void {
|
|
59
|
+
const raw = getSqliteFrom(database);
|
|
60
|
+
raw.exec(/*sql*/ `
|
|
61
|
+
UPDATE memory_jobs
|
|
62
|
+
SET attempts = deferrals,
|
|
63
|
+
deferrals = 0,
|
|
64
|
+
updated_at = ${Date.now()}
|
|
65
|
+
WHERE status = 'pending'
|
|
66
|
+
AND deferrals > 0
|
|
67
|
+
AND attempts = 0
|
|
68
|
+
AND type IN ('embed_segment', 'embed_item', 'embed_summary')
|
|
69
|
+
`);
|
|
70
|
+
}
|
|
@@ -91,3 +91,13 @@ export function migrateMemoryEntityRelationDedup(database: DrizzleDb): void {
|
|
|
91
91
|
throw e;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* No-op down: deduplication is a lossy operation — deleted duplicate rows
|
|
97
|
+
* cannot be restored. The forward migration merged rows by keeping the most
|
|
98
|
+
* recent evidence per (source, target, relation) triple; the discarded rows
|
|
99
|
+
* are permanently lost.
|
|
100
|
+
*/
|
|
101
|
+
export function downMemoryEntityRelationDedup(_database: DrizzleDb): void {
|
|
102
|
+
// Intentionally empty — irreversible lossy migration.
|
|
103
|
+
}
|
|
@@ -93,3 +93,79 @@ export function migrateMemoryItemsFingerprintScopeUnique(
|
|
|
93
93
|
raw.exec("PRAGMA foreign_keys = ON");
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Reverse the compound (fingerprint, scope_id) unique index change by rebuilding
|
|
99
|
+
* memory_items with a column-level UNIQUE on fingerprint.
|
|
100
|
+
*
|
|
101
|
+
* WARNING: This is dangerous if data now relies on the compound constraint
|
|
102
|
+
* (i.e., the same fingerprint exists in multiple scopes). In that case, the
|
|
103
|
+
* rebuild will fail with a UNIQUE constraint violation. This is intentional —
|
|
104
|
+
* it prevents silent data loss on rollback.
|
|
105
|
+
*/
|
|
106
|
+
export function downMemoryItemsFingerprintScopeUnique(
|
|
107
|
+
database: DrizzleDb,
|
|
108
|
+
): void {
|
|
109
|
+
const raw = getSqliteFrom(database);
|
|
110
|
+
|
|
111
|
+
// Check if the column-level UNIQUE already exists — if so, nothing to do.
|
|
112
|
+
const tableDdl = raw
|
|
113
|
+
.query(
|
|
114
|
+
`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memory_items'`,
|
|
115
|
+
)
|
|
116
|
+
.get() as { sql: string } | null;
|
|
117
|
+
if (
|
|
118
|
+
!tableDdl ||
|
|
119
|
+
tableDdl.sql.match(/fingerprint\s+TEXT\s+NOT\s+NULL\s+UNIQUE/i)
|
|
120
|
+
) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
raw.exec("PRAGMA foreign_keys = OFF");
|
|
125
|
+
try {
|
|
126
|
+
raw.exec("BEGIN");
|
|
127
|
+
|
|
128
|
+
raw.exec(/*sql*/ `
|
|
129
|
+
CREATE TABLE memory_items_new (
|
|
130
|
+
id TEXT PRIMARY KEY,
|
|
131
|
+
kind TEXT NOT NULL,
|
|
132
|
+
subject TEXT NOT NULL,
|
|
133
|
+
statement TEXT NOT NULL,
|
|
134
|
+
status TEXT NOT NULL,
|
|
135
|
+
confidence REAL NOT NULL,
|
|
136
|
+
fingerprint TEXT NOT NULL UNIQUE,
|
|
137
|
+
first_seen_at INTEGER NOT NULL,
|
|
138
|
+
last_seen_at INTEGER NOT NULL,
|
|
139
|
+
last_used_at INTEGER,
|
|
140
|
+
importance REAL,
|
|
141
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
142
|
+
valid_from INTEGER,
|
|
143
|
+
invalid_at INTEGER,
|
|
144
|
+
verification_state TEXT NOT NULL DEFAULT 'assistant_inferred',
|
|
145
|
+
scope_id TEXT NOT NULL DEFAULT 'default'
|
|
146
|
+
)
|
|
147
|
+
`);
|
|
148
|
+
|
|
149
|
+
raw.exec(/*sql*/ `
|
|
150
|
+
INSERT INTO memory_items_new
|
|
151
|
+
SELECT id, kind, subject, statement, status, confidence, fingerprint,
|
|
152
|
+
first_seen_at, last_seen_at, last_used_at, importance, access_count,
|
|
153
|
+
valid_from, invalid_at, verification_state, scope_id
|
|
154
|
+
FROM memory_items
|
|
155
|
+
`);
|
|
156
|
+
|
|
157
|
+
raw.exec(/*sql*/ `DROP TABLE memory_items`);
|
|
158
|
+
raw.exec(/*sql*/ `ALTER TABLE memory_items_new RENAME TO memory_items`);
|
|
159
|
+
|
|
160
|
+
raw.exec("COMMIT");
|
|
161
|
+
} catch (e) {
|
|
162
|
+
try {
|
|
163
|
+
raw.exec("ROLLBACK");
|
|
164
|
+
} catch {
|
|
165
|
+
/* no active transaction */
|
|
166
|
+
}
|
|
167
|
+
throw e;
|
|
168
|
+
} finally {
|
|
169
|
+
raw.exec("PRAGMA foreign_keys = ON");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
1
3
|
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
4
|
import { computeMemoryFingerprint } from "../fingerprint.js";
|
|
3
5
|
|
|
@@ -75,3 +77,51 @@ export function migrateMemoryItemsScopeSaltedFingerprints(
|
|
|
75
77
|
throw e;
|
|
76
78
|
}
|
|
77
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Reverse the scope-salted fingerprint migration by recomputing fingerprints
|
|
83
|
+
* WITHOUT the scope_id prefix.
|
|
84
|
+
*
|
|
85
|
+
* Old format: sha256(`${kind}|${subject.toLowerCase()}|${statement.toLowerCase()}`)
|
|
86
|
+
*/
|
|
87
|
+
export function downMemoryItemsScopeSaltedFingerprints(
|
|
88
|
+
database: DrizzleDb,
|
|
89
|
+
): void {
|
|
90
|
+
const raw = getSqliteFrom(database);
|
|
91
|
+
|
|
92
|
+
interface ItemRow {
|
|
93
|
+
id: string;
|
|
94
|
+
kind: string;
|
|
95
|
+
subject: string;
|
|
96
|
+
statement: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const items = raw
|
|
100
|
+
.query(`SELECT id, kind, subject, statement FROM memory_items`)
|
|
101
|
+
.all() as ItemRow[];
|
|
102
|
+
|
|
103
|
+
if (items.length === 0) return;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
raw.exec("BEGIN");
|
|
107
|
+
|
|
108
|
+
const updateStmt = raw.prepare(
|
|
109
|
+
`UPDATE memory_items SET fingerprint = ? WHERE id = ?`,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
for (const item of items) {
|
|
113
|
+
const normalized = `${item.kind}|${item.subject.toLowerCase()}|${item.statement.toLowerCase()}`;
|
|
114
|
+
const fingerprint = createHash("sha256").update(normalized).digest("hex");
|
|
115
|
+
updateStmt.run(fingerprint, item.id);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
raw.exec("COMMIT");
|
|
119
|
+
} catch (e) {
|
|
120
|
+
try {
|
|
121
|
+
raw.exec("ROLLBACK");
|
|
122
|
+
} catch {
|
|
123
|
+
/* no active transaction */
|
|
124
|
+
}
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -265,3 +265,13 @@ export function migrateAssistantIdToSelf(database: DrizzleDb): void {
|
|
|
265
265
|
throw e;
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* No-op down: the original assistant_id values are not recoverable. The forward
|
|
271
|
+
* migration normalized all assistant_id values to "self" and merged/deduplicated
|
|
272
|
+
* rows where the same logical entity existed under both the real assistantId and
|
|
273
|
+
* "self". The original per-assistant IDs are permanently lost.
|
|
274
|
+
*/
|
|
275
|
+
export function downAssistantIdToSelf(_database: DrizzleDb): void {
|
|
276
|
+
// Intentionally empty — original assistant_id values cannot be restored.
|
|
277
|
+
}
|
|
@@ -228,3 +228,37 @@ export function migrateRemoveAssistantIdColumns(database: DrizzleDb): void {
|
|
|
228
228
|
raw.exec("PRAGMA foreign_keys = ON");
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Add the assistant_id column back to the 4 tables that had it removed.
|
|
234
|
+
*
|
|
235
|
+
* NOTE: The data previously stored in assistant_id is lost — all rows will
|
|
236
|
+
* have assistant_id = 'self' after this down migration. This only restores
|
|
237
|
+
* the column structure so that older code expecting the column can function.
|
|
238
|
+
*/
|
|
239
|
+
export function downRemoveAssistantIdColumns(database: DrizzleDb): void {
|
|
240
|
+
const raw = getSqliteFrom(database);
|
|
241
|
+
|
|
242
|
+
const tables = [
|
|
243
|
+
"conversation_keys",
|
|
244
|
+
"attachments",
|
|
245
|
+
"channel_inbound_events",
|
|
246
|
+
"message_runs",
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
for (const table of tables) {
|
|
250
|
+
// Check if the table exists and lacks assistant_id
|
|
251
|
+
const ddl = raw
|
|
252
|
+
.query(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`)
|
|
253
|
+
.get(table) as { sql: string } | null;
|
|
254
|
+
if (!ddl || ddl.sql.includes("assistant_id")) continue;
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
raw.exec(
|
|
258
|
+
/*sql*/ `ALTER TABLE ${table} ADD COLUMN assistant_id TEXT NOT NULL DEFAULT 'self'`,
|
|
259
|
+
);
|
|
260
|
+
} catch {
|
|
261
|
+
/* column already exists */
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -95,3 +95,29 @@ export function migrateLlmUsageEventsDropAssistantId(
|
|
|
95
95
|
raw.exec("PRAGMA foreign_keys = ON");
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Add the assistant_id column back to llm_usage_events.
|
|
101
|
+
*
|
|
102
|
+
* NOTE: The data previously stored in assistant_id is lost — all rows will
|
|
103
|
+
* have assistant_id = NULL after this down migration. This only restores
|
|
104
|
+
* the column structure so that older code expecting the column can function.
|
|
105
|
+
*/
|
|
106
|
+
export function downLlmUsageEventsDropAssistantId(database: DrizzleDb): void {
|
|
107
|
+
const raw = getSqliteFrom(database);
|
|
108
|
+
|
|
109
|
+
const ddl = raw
|
|
110
|
+
.query(
|
|
111
|
+
`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'llm_usage_events'`,
|
|
112
|
+
)
|
|
113
|
+
.get() as { sql: string } | null;
|
|
114
|
+
if (!ddl || ddl.sql.includes("assistant_id")) return;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
raw.exec(
|
|
118
|
+
/*sql*/ `ALTER TABLE llm_usage_events ADD COLUMN assistant_id TEXT`,
|
|
119
|
+
);
|
|
120
|
+
} catch {
|
|
121
|
+
/* column already exists */
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -88,3 +88,13 @@ export function migrateBackfillInboxThreadStateFromBindings(
|
|
|
88
88
|
throw e;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* No-op down: the seeded inbox thread state rows are expected to remain.
|
|
94
|
+
* The forward migration used INSERT OR IGNORE, so existing rows were never
|
|
95
|
+
* modified. Removing the seeded rows could leave the inbox empty for
|
|
96
|
+
* pre-existing conversations, which is worse than keeping them.
|
|
97
|
+
*/
|
|
98
|
+
export function downBackfillInboxThreadState(_database: DrizzleDb): void {
|
|
99
|
+
// Intentionally empty — seeded data is expected to remain.
|
|
100
|
+
}
|
|
@@ -31,3 +31,20 @@ export function migrateDropActiveSearchIndex(database: DrizzleDb): void {
|
|
|
31
31
|
throw e;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Recreate the old idx_memory_items_active_search index with its original
|
|
37
|
+
* covering columns (before the migration added status and invalid_at as
|
|
38
|
+
* indexed columns).
|
|
39
|
+
*/
|
|
40
|
+
export function downDropActiveSearchIndex(database: DrizzleDb): void {
|
|
41
|
+
const raw = getSqliteFrom(database);
|
|
42
|
+
|
|
43
|
+
// Drop the current index if it exists, then recreate with the old column set.
|
|
44
|
+
raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_memory_items_active_search`);
|
|
45
|
+
raw.exec(/*sql*/ `
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_memory_items_active_search
|
|
47
|
+
ON memory_items(last_seen_at DESC, subject, statement, id, kind, confidence, importance, first_seen_at, scope_id)
|
|
48
|
+
WHERE status = 'active' AND invalid_at IS NULL
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
@@ -82,3 +82,15 @@ export function migrateNotificationTablesSchema(database: DrizzleDb): void {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* No-op down: the old enum-based notification tables cannot be recreated
|
|
88
|
+
* without the original schema definitions (column names, types, constraints,
|
|
89
|
+
* and enum values). The forward migration dropped these tables entirely.
|
|
90
|
+
* Any data that was in them is permanently lost. The new signal-contract
|
|
91
|
+
* schema tables are structurally incompatible with the old enum-based ones.
|
|
92
|
+
*/
|
|
93
|
+
export function downNotificationTablesSchema(_database: DrizzleDb): void {
|
|
94
|
+
// Intentionally empty — old enum-based tables cannot be recreated without
|
|
95
|
+
// the original schema, and any data they contained is permanently lost.
|
|
96
|
+
}
|
|
@@ -130,3 +130,124 @@ export function migrateRenameChannelToVellum(database: DrizzleDb): void {
|
|
|
130
130
|
throw e;
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reverse the channel rename by changing "vellum" back to "macos" in all tables.
|
|
136
|
+
*
|
|
137
|
+
* NOTE: The forward migration renamed both "macos" and "ios" to "vellum", so we
|
|
138
|
+
* cannot distinguish which rows were originally "ios". This down migration
|
|
139
|
+
* conservatively maps all "vellum" values back to "macos" since that was the
|
|
140
|
+
* primary desktop channel identifier.
|
|
141
|
+
*/
|
|
142
|
+
export function downRenameChannelToVellum(database: DrizzleDb): void {
|
|
143
|
+
const raw = getSqliteFrom(database);
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
raw.exec("BEGIN");
|
|
147
|
+
|
|
148
|
+
// guardian_action_deliveries.destination_channel
|
|
149
|
+
const gadExists = raw
|
|
150
|
+
.query(
|
|
151
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'guardian_action_deliveries'`,
|
|
152
|
+
)
|
|
153
|
+
.get();
|
|
154
|
+
if (gadExists) {
|
|
155
|
+
raw
|
|
156
|
+
.query(
|
|
157
|
+
`UPDATE guardian_action_deliveries SET destination_channel = 'macos' WHERE destination_channel = 'vellum'`,
|
|
158
|
+
)
|
|
159
|
+
.run();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// messages.user_message_channel / assistant_message_channel
|
|
163
|
+
const msgsExists = raw
|
|
164
|
+
.query(
|
|
165
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'messages'`,
|
|
166
|
+
)
|
|
167
|
+
.get();
|
|
168
|
+
if (msgsExists) {
|
|
169
|
+
const hasUserMsgChannel = raw
|
|
170
|
+
.query(
|
|
171
|
+
`SELECT 1 FROM pragma_table_info('messages') WHERE name = 'user_message_channel'`,
|
|
172
|
+
)
|
|
173
|
+
.get();
|
|
174
|
+
if (hasUserMsgChannel) {
|
|
175
|
+
raw
|
|
176
|
+
.query(
|
|
177
|
+
`UPDATE messages SET user_message_channel = 'macos' WHERE user_message_channel = 'vellum'`,
|
|
178
|
+
)
|
|
179
|
+
.run();
|
|
180
|
+
}
|
|
181
|
+
const hasAssistantMsgChannel = raw
|
|
182
|
+
.query(
|
|
183
|
+
`SELECT 1 FROM pragma_table_info('messages') WHERE name = 'assistant_message_channel'`,
|
|
184
|
+
)
|
|
185
|
+
.get();
|
|
186
|
+
if (hasAssistantMsgChannel) {
|
|
187
|
+
raw
|
|
188
|
+
.query(
|
|
189
|
+
`UPDATE messages SET assistant_message_channel = 'macos' WHERE assistant_message_channel = 'vellum'`,
|
|
190
|
+
)
|
|
191
|
+
.run();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// external_conversation_bindings.source_channel
|
|
196
|
+
const ecbExists = raw
|
|
197
|
+
.query(
|
|
198
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'external_conversation_bindings'`,
|
|
199
|
+
)
|
|
200
|
+
.get();
|
|
201
|
+
if (ecbExists) {
|
|
202
|
+
raw
|
|
203
|
+
.query(
|
|
204
|
+
`UPDATE external_conversation_bindings SET source_channel = 'macos' WHERE source_channel = 'vellum'`,
|
|
205
|
+
)
|
|
206
|
+
.run();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// assistant_inbox_thread_state.source_channel
|
|
210
|
+
const aitsExists = raw
|
|
211
|
+
.query(
|
|
212
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'assistant_inbox_thread_state'`,
|
|
213
|
+
)
|
|
214
|
+
.get();
|
|
215
|
+
if (aitsExists) {
|
|
216
|
+
raw
|
|
217
|
+
.query(
|
|
218
|
+
`UPDATE assistant_inbox_thread_state SET source_channel = 'macos' WHERE source_channel = 'vellum'`,
|
|
219
|
+
)
|
|
220
|
+
.run();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// conversations.origin_channel
|
|
224
|
+
const convExists = raw
|
|
225
|
+
.query(
|
|
226
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'conversations'`,
|
|
227
|
+
)
|
|
228
|
+
.get();
|
|
229
|
+
if (convExists) {
|
|
230
|
+
const hasOriginChannel = raw
|
|
231
|
+
.query(
|
|
232
|
+
`SELECT 1 FROM pragma_table_info('conversations') WHERE name = 'origin_channel'`,
|
|
233
|
+
)
|
|
234
|
+
.get();
|
|
235
|
+
if (hasOriginChannel) {
|
|
236
|
+
raw
|
|
237
|
+
.query(
|
|
238
|
+
`UPDATE conversations SET origin_channel = 'macos' WHERE origin_channel = 'vellum'`,
|
|
239
|
+
)
|
|
240
|
+
.run();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
raw.exec("COMMIT");
|
|
245
|
+
} catch (e) {
|
|
246
|
+
try {
|
|
247
|
+
raw.exec("ROLLBACK");
|
|
248
|
+
} catch {
|
|
249
|
+
/* no active transaction */
|
|
250
|
+
}
|
|
251
|
+
throw e;
|
|
252
|
+
}
|
|
253
|
+
}
|