@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/daemon/server.ts
CHANGED
|
@@ -20,13 +20,7 @@ import {
|
|
|
20
20
|
import { getConfig } from "../config/loader.js";
|
|
21
21
|
import { onContactChange } from "../contacts/contact-events.js";
|
|
22
22
|
import type { CesClient } from "../credential-execution/client.js";
|
|
23
|
-
import {
|
|
24
|
-
import { isCesToolsEnabled } from "../credential-execution/feature-gates.js";
|
|
25
|
-
import {
|
|
26
|
-
type CesProcessManager,
|
|
27
|
-
CesUnavailableError,
|
|
28
|
-
createCesProcessManager,
|
|
29
|
-
} from "../credential-execution/process-manager.js";
|
|
23
|
+
import type { CesProcessManager } from "../credential-execution/process-manager.js";
|
|
30
24
|
import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
|
|
31
25
|
import * as attachmentsStore from "../memory/attachments-store.js";
|
|
32
26
|
import {
|
|
@@ -45,7 +39,6 @@ import {
|
|
|
45
39
|
import { updateMetaFile } from "../memory/conversation-disk-view.js";
|
|
46
40
|
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
47
41
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
48
|
-
import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
|
|
49
42
|
import { RateLimitProvider } from "../providers/ratelimit.js";
|
|
50
43
|
import {
|
|
51
44
|
getFailoverProvider,
|
|
@@ -57,13 +50,11 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
|
57
50
|
import { getSigningKeyFingerprint } from "../runtime/auth/token-service.js";
|
|
58
51
|
import { bridgeConfirmationRequestToGuardian } from "../runtime/confirmation-request-guardian-bridge.js";
|
|
59
52
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
60
|
-
import { checkIngressForSecrets } from "../security/secret-ingress.js";
|
|
61
53
|
import { registerCancelCallback } from "../signals/cancel.js";
|
|
62
54
|
import { registerConversationUndoCallback } from "../signals/conversation-undo.js";
|
|
63
55
|
import { appendEventToStream } from "../signals/event-stream.js";
|
|
64
56
|
import { registerUserMessageCallback } from "../signals/user-message.js";
|
|
65
57
|
import { getSubagentManager } from "../subagent/index.js";
|
|
66
|
-
import { IngressBlockedError } from "../util/errors.js";
|
|
67
58
|
import { getLogger } from "../util/logger.js";
|
|
68
59
|
import {
|
|
69
60
|
getSandboxWorkingDir,
|
|
@@ -253,7 +244,6 @@ export class DaemonServer {
|
|
|
253
244
|
private conversationOptions = new Map<string, ConversationCreateOptions>();
|
|
254
245
|
private conversationCreating = new Map<string, Promise<Conversation>>();
|
|
255
246
|
private sharedRequestTimestamps: number[] = [];
|
|
256
|
-
private httpPort: number | undefined;
|
|
257
247
|
private unsubscribeContactChange: (() => void) | null = null;
|
|
258
248
|
private evictor: ConversationEvictor;
|
|
259
249
|
private _hubChain: Promise<void> = Promise.resolve();
|
|
@@ -262,8 +252,8 @@ export class DaemonServer {
|
|
|
262
252
|
private configWatcher = new ConfigWatcher();
|
|
263
253
|
|
|
264
254
|
// CES (Credential Execution Service) — process-level singleton.
|
|
265
|
-
//
|
|
266
|
-
//
|
|
255
|
+
// Lifecycle is managed by startCesProcess() in lifecycle.ts; the server
|
|
256
|
+
// receives the result via setCes().
|
|
267
257
|
private cesProcessManager?: CesProcessManager;
|
|
268
258
|
private cesClientPromise?: Promise<CesClient | undefined>;
|
|
269
259
|
private cesInitAbortController?: AbortController;
|
|
@@ -274,6 +264,31 @@ export class DaemonServer {
|
|
|
274
264
|
*/
|
|
275
265
|
assistantId: string = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
276
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Inject the CES client and process manager from the caller (lifecycle.ts).
|
|
269
|
+
* Must be called before start().
|
|
270
|
+
*/
|
|
271
|
+
setCes(result: {
|
|
272
|
+
client: CesClient | undefined;
|
|
273
|
+
processManager: CesProcessManager | undefined;
|
|
274
|
+
clientPromise: Promise<CesClient | undefined> | undefined;
|
|
275
|
+
abortController: AbortController | undefined;
|
|
276
|
+
}): void {
|
|
277
|
+
this.cesClientRef = result.client;
|
|
278
|
+
this.cesProcessManager = result.processManager;
|
|
279
|
+
this.cesInitAbortController = result.abortController;
|
|
280
|
+
|
|
281
|
+
// Wrap the external promise so that cesClientRef stays in sync once the
|
|
282
|
+
// handshake completes — the async work runs in lifecycle.ts but the
|
|
283
|
+
// server needs the resolved client reference for getCesClient().
|
|
284
|
+
if (result.clientPromise) {
|
|
285
|
+
this.cesClientPromise = result.clientPromise.then((client) => {
|
|
286
|
+
this.cesClientRef = client;
|
|
287
|
+
return client;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
277
292
|
/**
|
|
278
293
|
* Return the CES client reference (if available).
|
|
279
294
|
* Used by routes that need to push updates to CES (e.g. secret-routes).
|
|
@@ -538,73 +553,6 @@ export class DaemonServer {
|
|
|
538
553
|
this.broadcast({ type: "contacts_changed" });
|
|
539
554
|
});
|
|
540
555
|
|
|
541
|
-
// CES lifecycle — start the CES process and perform the RPC handshake
|
|
542
|
-
// once at server level. The managed sidecar accepts exactly one bootstrap
|
|
543
|
-
// connection, so this must be a process-level singleton.
|
|
544
|
-
if (isCesToolsEnabled(config)) {
|
|
545
|
-
const pm = createCesProcessManager({ assistantConfig: config });
|
|
546
|
-
this.cesProcessManager = pm;
|
|
547
|
-
const abortController = new AbortController();
|
|
548
|
-
this.cesInitAbortController = abortController;
|
|
549
|
-
this.cesClientPromise = (async () => {
|
|
550
|
-
try {
|
|
551
|
-
const transport = await pm.start();
|
|
552
|
-
if (abortController.signal.aborted) {
|
|
553
|
-
throw new Error("CES initialization aborted during shutdown");
|
|
554
|
-
}
|
|
555
|
-
const client = createCesClient(transport);
|
|
556
|
-
this.cesClientRef = client;
|
|
557
|
-
// Resolve the assistant API key so CES can use it for platform
|
|
558
|
-
// credential materialisation. In managed mode the key is provisioned
|
|
559
|
-
// after hatch and stored in the credential store — CES can't read
|
|
560
|
-
// the env var, so we pass it via the handshake.
|
|
561
|
-
const proxyCtx = await resolveManagedProxyContext();
|
|
562
|
-
const { accepted, reason } = await client.handshake(
|
|
563
|
-
proxyCtx.assistantApiKey
|
|
564
|
-
? { assistantApiKey: proxyCtx.assistantApiKey }
|
|
565
|
-
: undefined,
|
|
566
|
-
);
|
|
567
|
-
if (abortController.signal.aborted) {
|
|
568
|
-
client.close();
|
|
569
|
-
throw new Error("CES initialization aborted during shutdown");
|
|
570
|
-
}
|
|
571
|
-
if (accepted) {
|
|
572
|
-
log.info(
|
|
573
|
-
"CES client initialized and handshake accepted (server-level)",
|
|
574
|
-
);
|
|
575
|
-
return client;
|
|
576
|
-
}
|
|
577
|
-
log.warn(
|
|
578
|
-
{ reason },
|
|
579
|
-
"CES handshake rejected — CES tools will be unavailable",
|
|
580
|
-
);
|
|
581
|
-
client.close();
|
|
582
|
-
this.cesClientRef = undefined;
|
|
583
|
-
await pm.stop();
|
|
584
|
-
// Reset so next session can retry initialization
|
|
585
|
-
this.cesClientPromise = undefined;
|
|
586
|
-
return undefined;
|
|
587
|
-
} catch (err) {
|
|
588
|
-
if (err instanceof CesUnavailableError) {
|
|
589
|
-
log.info(
|
|
590
|
-
{ reason: err.message },
|
|
591
|
-
"CES is not available — CES tools will be unavailable",
|
|
592
|
-
);
|
|
593
|
-
} else {
|
|
594
|
-
log.warn(
|
|
595
|
-
{ error: err instanceof Error ? err.message : String(err) },
|
|
596
|
-
"Failed to initialize CES client — CES tools will be unavailable",
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
await pm.stop().catch(() => {});
|
|
600
|
-
// Reset so next session can retry initialization
|
|
601
|
-
this.cesClientRef = undefined;
|
|
602
|
-
this.cesClientPromise = undefined;
|
|
603
|
-
return undefined;
|
|
604
|
-
}
|
|
605
|
-
})();
|
|
606
|
-
}
|
|
607
|
-
|
|
608
556
|
log.info("DaemonServer started (HTTP-only mode)");
|
|
609
557
|
}
|
|
610
558
|
|
|
@@ -656,11 +604,9 @@ export class DaemonServer {
|
|
|
656
604
|
|
|
657
605
|
// ── Conversation management ──────────────────────────────────────────────
|
|
658
606
|
|
|
659
|
-
|
|
660
|
-
this.httpPort = port;
|
|
607
|
+
broadcastStatus(): void {
|
|
661
608
|
this.broadcast({
|
|
662
|
-
type: "
|
|
663
|
-
httpPort: port,
|
|
609
|
+
type: "assistant_status",
|
|
664
610
|
version: daemonVersion,
|
|
665
611
|
keyFingerprint: getSigningKeyFingerprint(),
|
|
666
612
|
});
|
|
@@ -884,14 +830,6 @@ export class DaemonServer {
|
|
|
884
830
|
filePath?: string;
|
|
885
831
|
}[];
|
|
886
832
|
}> {
|
|
887
|
-
const ingressCheck = checkIngressForSecrets(content);
|
|
888
|
-
if (ingressCheck.blocked) {
|
|
889
|
-
throw new IngressBlockedError(
|
|
890
|
-
ingressCheck.userNotice!,
|
|
891
|
-
ingressCheck.detectedTypes,
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
|
|
895
833
|
const conversation = await this.getOrCreateConversation(
|
|
896
834
|
conversationId,
|
|
897
835
|
options,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and,
|
|
1
|
+
import { and, asc, eq, lte, or, sql } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getDb } from "../memory/db.js";
|
|
@@ -217,7 +217,10 @@ export function getPendingAndOverdueFollowUps(): BriefFollowUp[] {
|
|
|
217
217
|
eq(followups.status, "nudged"),
|
|
218
218
|
),
|
|
219
219
|
)
|
|
220
|
-
.orderBy(
|
|
220
|
+
.orderBy(
|
|
221
|
+
sql`CASE WHEN ${followups.expectedResponseBy} IS NULL THEN 1 ELSE 0 END`,
|
|
222
|
+
asc(followups.expectedResponseBy),
|
|
223
|
+
)
|
|
221
224
|
.all();
|
|
222
225
|
|
|
223
226
|
return rows as BriefFollowUp[];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Platform callback route registration for containerized deployments.
|
|
3
3
|
*
|
|
4
4
|
* When the assistant daemon runs inside a container (IS_CONTAINERIZED=true)
|
|
5
|
-
* with a configured
|
|
5
|
+
* with a configured VELLUM_PLATFORM_URL and PLATFORM_ASSISTANT_ID, external
|
|
6
6
|
* service callbacks (Twilio webhooks, OAuth redirects, Telegram webhooks, etc.)
|
|
7
7
|
* must route through the platform's gateway proxy instead of hitting the
|
|
8
8
|
* assistant directly.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* webhooks to the correct containerized assistant instance.
|
|
13
13
|
*
|
|
14
14
|
* The platform endpoint is:
|
|
15
|
-
* POST {
|
|
15
|
+
* POST {VELLUM_PLATFORM_URL}/v1/internal/gateway/callback-routes/register/
|
|
16
16
|
*
|
|
17
17
|
* It accepts { assistant_id, callback_path, type } and returns a stable
|
|
18
18
|
* callback_url that external services should use.
|
|
@@ -30,7 +30,7 @@ const log = getLogger("platform-callback-registration");
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Whether the daemon should register callback routes with the platform.
|
|
33
|
-
* True when IS_CONTAINERIZED,
|
|
33
|
+
* True when IS_CONTAINERIZED, VELLUM_PLATFORM_URL, and PLATFORM_ASSISTANT_ID
|
|
34
34
|
* are all set. Intentionally does **not** require the managed proxy API key
|
|
35
35
|
* so that callback-only flows (OAuth transport, Telegram/Twilio callback
|
|
36
36
|
* registration) work during partial bootstrap before the key is injected.
|
package/src/instrument.ts
CHANGED
|
@@ -39,14 +39,17 @@ function redactObject(obj: unknown): unknown {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Call after dotenv has loaded so
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
42
|
+
* Call after dotenv has loaded so SENTRY_DSN_ASSISTANT is available.
|
|
43
|
+
* Initializes Sentry when the DSN is set; no-ops when empty/unset so
|
|
44
|
+
* local dev builds don't send crash reports. If the user later opts out
|
|
45
|
+
* via the sendDiagnostics config key (or VELLUM_DEV=1), call closeSentry()
|
|
46
|
+
* after config is loaded to stop future event capturing.
|
|
46
47
|
*/
|
|
47
48
|
export function initSentry(): void {
|
|
49
|
+
const dsn = getSentryDsn();
|
|
50
|
+
if (!dsn) return;
|
|
48
51
|
Sentry.init({
|
|
49
|
-
dsn
|
|
52
|
+
dsn,
|
|
50
53
|
release: `vellum-assistant@${APP_VERSION}`,
|
|
51
54
|
dist: COMMIT_SHA,
|
|
52
55
|
environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
|
|
@@ -47,18 +47,13 @@ import {
|
|
|
47
47
|
conversations,
|
|
48
48
|
conversationStarters,
|
|
49
49
|
llmRequestLogs,
|
|
50
|
-
memoryChunks,
|
|
51
50
|
memoryEmbeddings,
|
|
52
|
-
memoryEpisodes,
|
|
53
51
|
memoryItems,
|
|
54
52
|
memoryItemSources,
|
|
55
|
-
memoryObservations,
|
|
56
53
|
memorySegments,
|
|
57
54
|
memorySummaries,
|
|
58
55
|
messageAttachments,
|
|
59
56
|
messages,
|
|
60
|
-
openLoops,
|
|
61
|
-
timeContexts,
|
|
62
57
|
toolInvocations,
|
|
63
58
|
} from "./schema.js";
|
|
64
59
|
import { cancelPendingJobsForConversation } from "./task-memory-cleanup.js";
|
|
@@ -177,9 +172,6 @@ export interface ConversationRow {
|
|
|
177
172
|
forkParentMessageId: string | null;
|
|
178
173
|
isAutoTitle: number;
|
|
179
174
|
scheduleJobId: string | null;
|
|
180
|
-
memoryReducedThroughMessageId: string | null;
|
|
181
|
-
memoryDirtyTailSinceMessageId: string | null;
|
|
182
|
-
memoryLastReducedAt: number | null;
|
|
183
175
|
}
|
|
184
176
|
|
|
185
177
|
export const parseConversation = createRowMapper<
|
|
@@ -205,9 +197,6 @@ export const parseConversation = createRowMapper<
|
|
|
205
197
|
forkParentMessageId: "forkParentMessageId",
|
|
206
198
|
isAutoTitle: "isAutoTitle",
|
|
207
199
|
scheduleJobId: "scheduleJobId",
|
|
208
|
-
memoryReducedThroughMessageId: "memoryReducedThroughMessageId",
|
|
209
|
-
memoryDirtyTailSinceMessageId: "memoryDirtyTailSinceMessageId",
|
|
210
|
-
memoryLastReducedAt: "memoryLastReducedAt",
|
|
211
200
|
});
|
|
212
201
|
|
|
213
202
|
export interface MessageRow {
|
|
@@ -555,9 +544,6 @@ export function deleteConversation(id: string): DeletedMemoryIds {
|
|
|
555
544
|
segmentIds: [],
|
|
556
545
|
orphanedItemIds: [],
|
|
557
546
|
deletedSummaryIds: [],
|
|
558
|
-
deletedObservationIds: [],
|
|
559
|
-
deletedChunkIds: [],
|
|
560
|
-
deletedEpisodeIds: [],
|
|
561
547
|
};
|
|
562
548
|
|
|
563
549
|
// Capture createdAt before the transaction deletes the row — needed to
|
|
@@ -711,75 +697,6 @@ export function deleteConversation(id: string): DeletedMemoryIds {
|
|
|
711
697
|
tx.delete(conversationStarters)
|
|
712
698
|
.where(eq(conversationStarters.scopeId, memoryScopeId))
|
|
713
699
|
.run();
|
|
714
|
-
|
|
715
|
-
// Sweep brief-state tables scoped to this private conversation.
|
|
716
|
-
tx.delete(timeContexts)
|
|
717
|
-
.where(eq(timeContexts.scopeId, memoryScopeId))
|
|
718
|
-
.run();
|
|
719
|
-
tx.delete(openLoops).where(eq(openLoops.scopeId, memoryScopeId)).run();
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// Collect archive table IDs before the cascade delete removes them.
|
|
723
|
-
// Observations and episodes reference conversations with ON DELETE CASCADE,
|
|
724
|
-
// and chunks cascade from observations.
|
|
725
|
-
const observationRows = tx
|
|
726
|
-
.select({ id: memoryObservations.id })
|
|
727
|
-
.from(memoryObservations)
|
|
728
|
-
.where(eq(memoryObservations.conversationId, id))
|
|
729
|
-
.all();
|
|
730
|
-
const observationIds = observationRows.map((r) => r.id);
|
|
731
|
-
|
|
732
|
-
if (observationIds.length > 0) {
|
|
733
|
-
// Collect chunk IDs before observations cascade-delete them.
|
|
734
|
-
const chunkRows = tx
|
|
735
|
-
.select({ id: memoryChunks.id })
|
|
736
|
-
.from(memoryChunks)
|
|
737
|
-
.where(inArray(memoryChunks.observationId, observationIds))
|
|
738
|
-
.all();
|
|
739
|
-
const chunkIds = chunkRows.map((r) => r.id);
|
|
740
|
-
|
|
741
|
-
// Clean up embeddings for chunks.
|
|
742
|
-
if (chunkIds.length > 0) {
|
|
743
|
-
tx.delete(memoryEmbeddings)
|
|
744
|
-
.where(
|
|
745
|
-
and(
|
|
746
|
-
eq(memoryEmbeddings.targetType, "chunk"),
|
|
747
|
-
inArray(memoryEmbeddings.targetId, chunkIds),
|
|
748
|
-
),
|
|
749
|
-
)
|
|
750
|
-
.run();
|
|
751
|
-
result.deletedChunkIds.push(...chunkIds);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// Clean up embeddings for observations.
|
|
755
|
-
tx.delete(memoryEmbeddings)
|
|
756
|
-
.where(
|
|
757
|
-
and(
|
|
758
|
-
eq(memoryEmbeddings.targetType, "observation"),
|
|
759
|
-
inArray(memoryEmbeddings.targetId, observationIds),
|
|
760
|
-
),
|
|
761
|
-
)
|
|
762
|
-
.run();
|
|
763
|
-
result.deletedObservationIds.push(...observationIds);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
const episodeRows = tx
|
|
767
|
-
.select({ id: memoryEpisodes.id })
|
|
768
|
-
.from(memoryEpisodes)
|
|
769
|
-
.where(eq(memoryEpisodes.conversationId, id))
|
|
770
|
-
.all();
|
|
771
|
-
const episodeIds = episodeRows.map((r) => r.id);
|
|
772
|
-
|
|
773
|
-
if (episodeIds.length > 0) {
|
|
774
|
-
tx.delete(memoryEmbeddings)
|
|
775
|
-
.where(
|
|
776
|
-
and(
|
|
777
|
-
eq(memoryEmbeddings.targetType, "episode"),
|
|
778
|
-
inArray(memoryEmbeddings.targetId, episodeIds),
|
|
779
|
-
),
|
|
780
|
-
)
|
|
781
|
-
.run();
|
|
782
|
-
result.deletedEpisodeIds.push(...episodeIds);
|
|
783
700
|
}
|
|
784
701
|
|
|
785
702
|
tx.delete(conversations).where(eq(conversations.id, id)).run();
|
|
@@ -1005,9 +922,6 @@ export function purgePrivateConversations(): {
|
|
|
1005
922
|
segmentIds: [],
|
|
1006
923
|
orphanedItemIds: [],
|
|
1007
924
|
deletedSummaryIds: [],
|
|
1008
|
-
deletedObservationIds: [],
|
|
1009
|
-
deletedChunkIds: [],
|
|
1010
|
-
deletedEpisodeIds: [],
|
|
1011
925
|
},
|
|
1012
926
|
};
|
|
1013
927
|
}
|
|
@@ -1015,18 +929,12 @@ export function purgePrivateConversations(): {
|
|
|
1015
929
|
const allSegmentIds: string[] = [];
|
|
1016
930
|
const allOrphanedItemIds: string[] = [];
|
|
1017
931
|
const allDeletedSummaryIds: string[] = [];
|
|
1018
|
-
const allDeletedObservationIds: string[] = [];
|
|
1019
|
-
const allDeletedChunkIds: string[] = [];
|
|
1020
|
-
const allDeletedEpisodeIds: string[] = [];
|
|
1021
932
|
|
|
1022
933
|
for (const conv of privateConvs) {
|
|
1023
934
|
const deleted = deleteConversation(conv.id);
|
|
1024
935
|
allSegmentIds.push(...deleted.segmentIds);
|
|
1025
936
|
allOrphanedItemIds.push(...deleted.orphanedItemIds);
|
|
1026
937
|
allDeletedSummaryIds.push(...deleted.deletedSummaryIds);
|
|
1027
|
-
allDeletedObservationIds.push(...deleted.deletedObservationIds);
|
|
1028
|
-
allDeletedChunkIds.push(...deleted.deletedChunkIds);
|
|
1029
|
-
allDeletedEpisodeIds.push(...deleted.deletedEpisodeIds);
|
|
1030
938
|
}
|
|
1031
939
|
|
|
1032
940
|
return {
|
|
@@ -1035,9 +943,6 @@ export function purgePrivateConversations(): {
|
|
|
1035
943
|
segmentIds: allSegmentIds,
|
|
1036
944
|
orphanedItemIds: allOrphanedItemIds,
|
|
1037
945
|
deletedSummaryIds: allDeletedSummaryIds,
|
|
1038
|
-
deletedObservationIds: allDeletedObservationIds,
|
|
1039
|
-
deletedChunkIds: allDeletedChunkIds,
|
|
1040
|
-
deletedEpisodeIds: allDeletedEpisodeIds,
|
|
1041
946
|
},
|
|
1042
947
|
};
|
|
1043
948
|
}
|
|
@@ -1120,13 +1025,6 @@ export async function addMessage(
|
|
|
1120
1025
|
throw err;
|
|
1121
1026
|
}
|
|
1122
1027
|
}
|
|
1123
|
-
|
|
1124
|
-
// Mark the conversation dirty for delayed memory reduction. This runs
|
|
1125
|
-
// after the insert transaction succeeds so the reducer knows which
|
|
1126
|
-
// conversations have unprocessed messages. The helper preserves the
|
|
1127
|
-
// earliest unreduced boundary (no-op when already dirty).
|
|
1128
|
-
markConversationMemoryDirty(conversationId, messageId);
|
|
1129
|
-
|
|
1130
1028
|
const message = {
|
|
1131
1029
|
id: messageId,
|
|
1132
1030
|
conversationId,
|
|
@@ -1431,9 +1329,6 @@ export interface DeletedMemoryIds {
|
|
|
1431
1329
|
segmentIds: string[];
|
|
1432
1330
|
orphanedItemIds: string[];
|
|
1433
1331
|
deletedSummaryIds: string[];
|
|
1434
|
-
deletedObservationIds: string[];
|
|
1435
|
-
deletedChunkIds: string[];
|
|
1436
|
-
deletedEpisodeIds: string[];
|
|
1437
1332
|
}
|
|
1438
1333
|
|
|
1439
1334
|
export interface WipeConversationResult extends DeletedMemoryIds {
|
|
@@ -1507,9 +1402,6 @@ export function deleteMessageById(messageId: string): DeletedMemoryIds {
|
|
|
1507
1402
|
segmentIds: [],
|
|
1508
1403
|
orphanedItemIds: [],
|
|
1509
1404
|
deletedSummaryIds: [],
|
|
1510
|
-
deletedObservationIds: [],
|
|
1511
|
-
deletedChunkIds: [],
|
|
1512
|
-
deletedEpisodeIds: [],
|
|
1513
1405
|
};
|
|
1514
1406
|
|
|
1515
1407
|
// Collect attachment IDs linked to this message before cascade-delete
|
|
@@ -1598,134 +1490,6 @@ export function deleteMessageById(messageId: string): DeletedMemoryIds {
|
|
|
1598
1490
|
return result;
|
|
1599
1491
|
}
|
|
1600
1492
|
|
|
1601
|
-
/**
|
|
1602
|
-
* Mark a conversation as having unreduced messages starting from the given
|
|
1603
|
-
* message. Sets `memoryDirtyTailSinceMessageId` only when it is currently
|
|
1604
|
-
* null so the earliest unreduced boundary is preserved across multiple
|
|
1605
|
-
* messages — later messages must not clobber the original dirty marker.
|
|
1606
|
-
*
|
|
1607
|
-
* Also upserts a pending `reduce_conversation_memory` job scheduled at
|
|
1608
|
-
* `now + idleDelayMs`. If a pending job for this conversation already exists,
|
|
1609
|
-
* its `runAfter` is pushed forward (rescheduled) so the reducer waits for
|
|
1610
|
-
* the full idle window after the *latest* message — avoiding premature runs
|
|
1611
|
-
* while the user is still actively typing.
|
|
1612
|
-
*/
|
|
1613
|
-
export function markConversationMemoryDirty(
|
|
1614
|
-
conversationId: string,
|
|
1615
|
-
messageId: string,
|
|
1616
|
-
): void {
|
|
1617
|
-
const db = getDb();
|
|
1618
|
-
db.update(conversations)
|
|
1619
|
-
.set({ memoryDirtyTailSinceMessageId: messageId })
|
|
1620
|
-
.where(
|
|
1621
|
-
and(
|
|
1622
|
-
eq(conversations.id, conversationId),
|
|
1623
|
-
isNull(conversations.memoryDirtyTailSinceMessageId),
|
|
1624
|
-
),
|
|
1625
|
-
)
|
|
1626
|
-
.run();
|
|
1627
|
-
|
|
1628
|
-
// Schedule (or reschedule) a deferred reducer job for this conversation.
|
|
1629
|
-
scheduleReducerJob(conversationId);
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
/**
|
|
1633
|
-
* Upsert a pending `reduce_conversation_memory` job for the given
|
|
1634
|
-
* conversation, scheduled `idleDelayMs` from now. If one already exists in
|
|
1635
|
-
* pending state, its `runAfter` is pushed forward to restart the idle timer.
|
|
1636
|
-
* This ensures exactly one pending reducer job per conversation — new
|
|
1637
|
-
* messages reschedule rather than duplicate.
|
|
1638
|
-
*/
|
|
1639
|
-
export function scheduleReducerJob(
|
|
1640
|
-
conversationId: string,
|
|
1641
|
-
runAfter?: number,
|
|
1642
|
-
): void {
|
|
1643
|
-
const idleDelayMs = getReducerIdleDelayMs();
|
|
1644
|
-
const scheduledAt = runAfter ?? Date.now() + idleDelayMs;
|
|
1645
|
-
|
|
1646
|
-
const existing = rawGet<{ id: string; status: string }>(
|
|
1647
|
-
`SELECT id, status FROM memory_jobs
|
|
1648
|
-
WHERE type = 'reduce_conversation_memory'
|
|
1649
|
-
AND json_extract(payload, '$.conversationId') = ?
|
|
1650
|
-
AND status = 'pending'
|
|
1651
|
-
LIMIT 1`,
|
|
1652
|
-
conversationId,
|
|
1653
|
-
);
|
|
1654
|
-
|
|
1655
|
-
if (existing) {
|
|
1656
|
-
// Reschedule: push runAfter forward so the idle timer resets.
|
|
1657
|
-
rawRun(
|
|
1658
|
-
`UPDATE memory_jobs SET run_after = ?, updated_at = ? WHERE id = ?`,
|
|
1659
|
-
scheduledAt,
|
|
1660
|
-
Date.now(),
|
|
1661
|
-
existing.id,
|
|
1662
|
-
);
|
|
1663
|
-
} else {
|
|
1664
|
-
enqueueMemoryJob(
|
|
1665
|
-
"reduce_conversation_memory",
|
|
1666
|
-
{ conversationId },
|
|
1667
|
-
scheduledAt,
|
|
1668
|
-
);
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
/**
|
|
1673
|
-
* Startup sweep: find conversations that are marked dirty and whose tail
|
|
1674
|
-
* message is already older than the idle delay. For these conversations the
|
|
1675
|
-
* reducer should have run but didn't (daemon was down). Enqueue immediate
|
|
1676
|
-
* reducer jobs for each so they are processed on the next worker tick.
|
|
1677
|
-
*
|
|
1678
|
-
* Conversations whose tail is still within the idle window are skipped —
|
|
1679
|
-
* the normal `markConversationMemoryDirty` path will schedule them when
|
|
1680
|
-
* new messages arrive (or on the next conversation interaction).
|
|
1681
|
-
*
|
|
1682
|
-
* Returns the number of jobs enqueued.
|
|
1683
|
-
*/
|
|
1684
|
-
export function sweepStaleReducerJobs(): number {
|
|
1685
|
-
const idleDelayMs = getReducerIdleDelayMs();
|
|
1686
|
-
const cutoff = Date.now() - idleDelayMs;
|
|
1687
|
-
|
|
1688
|
-
// Find dirty conversations whose latest message is older than the idle
|
|
1689
|
-
// window AND that don't already have a pending reducer job.
|
|
1690
|
-
const stale = rawAll<{ conversationId: string }>(
|
|
1691
|
-
`SELECT c.id AS conversationId
|
|
1692
|
-
FROM conversations c
|
|
1693
|
-
WHERE c.memory_dirty_tail_since_message_id IS NOT NULL
|
|
1694
|
-
AND NOT EXISTS (
|
|
1695
|
-
SELECT 1 FROM memory_jobs mj
|
|
1696
|
-
WHERE mj.type = 'reduce_conversation_memory'
|
|
1697
|
-
AND json_extract(mj.payload, '$.conversationId') = c.id
|
|
1698
|
-
AND mj.status IN ('pending', 'running')
|
|
1699
|
-
)
|
|
1700
|
-
AND (
|
|
1701
|
-
SELECT MAX(m.created_at) FROM messages m
|
|
1702
|
-
WHERE m.conversation_id = c.id
|
|
1703
|
-
) <= ?`,
|
|
1704
|
-
cutoff,
|
|
1705
|
-
);
|
|
1706
|
-
|
|
1707
|
-
for (const { conversationId } of stale) {
|
|
1708
|
-
enqueueMemoryJob("reduce_conversation_memory", { conversationId });
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
return stale.length;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
function getReducerIdleDelayMs(): number {
|
|
1715
|
-
// Some test suites mock getConfig() with partial objects; fall back to the
|
|
1716
|
-
// schema default so reducer scheduling stays stable outside full config load.
|
|
1717
|
-
const config = getConfig() as {
|
|
1718
|
-
memory?: {
|
|
1719
|
-
simplified?: {
|
|
1720
|
-
reducer?: {
|
|
1721
|
-
idleDelayMs?: number;
|
|
1722
|
-
};
|
|
1723
|
-
};
|
|
1724
|
-
};
|
|
1725
|
-
};
|
|
1726
|
-
return config.memory?.simplified?.reducer?.idleDelayMs ?? 30_000;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
1493
|
export function setConversationOriginChannelIfUnset(
|
|
1730
1494
|
conversationId: string,
|
|
1731
1495
|
channel: ChannelId,
|