@vellumai/assistant 0.12.1 → 0.12.2-staging.2
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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
// Two pointers move independently:
|
|
6
6
|
// - `lastProcessedMessageId` advances ONLY when a retrospective run
|
|
7
7
|
// completes successfully (correctness invariant — failures must
|
|
8
|
-
// re-process the same messages on the next attempt).
|
|
8
|
+
// re-process the same messages on the next attempt). Its companion
|
|
9
|
+
// `lastProcessedCreatedAt` is that row's `createdAt` at write time, so the
|
|
10
|
+
// `(createdAt, id)` cursor stays reconstructible after the row itself is
|
|
11
|
+
// deleted: a regenerated reply discards the latest assistant message,
|
|
12
|
+
// which is exactly where the cursor tends to sit.
|
|
9
13
|
// - `lastRunAt` advances at the end of every job that actually attempted a
|
|
10
14
|
// run (success or failure). Drives the per-conversation cooldown gate in
|
|
11
15
|
// the trigger-check helper so failing jobs can't loop in tight retries
|
|
@@ -25,20 +29,39 @@
|
|
|
25
29
|
// that connection is unavailable. The memory database has no `conversations`
|
|
26
30
|
// table, so there is no FK cascade — the `conversation-deleted` hook purges the
|
|
27
31
|
// row explicitly instead.
|
|
32
|
+
//
|
|
33
|
+
// `last_processed_created_at` is added to the table by
|
|
34
|
+
// `ensureRetrospectiveCursorColumn`: an idempotent, fail-open ALTER run lazily
|
|
35
|
+
// on first use in each process (daemon, memory worker, CLI) rather than by the
|
|
36
|
+
// global migration chain, which must not gate DB readiness on the memory
|
|
37
|
+
// database. The probe is memoized per memory connection, so a connection
|
|
38
|
+
// replaced by `resetDb()` (restores, imports) is probed again before its
|
|
39
|
+
// first read. When the column cannot be added, reads and writes fall back to
|
|
40
|
+
// the id-only cursor shape and the probe is retried after a short backoff.
|
|
28
41
|
|
|
29
42
|
import { desc, eq } from "drizzle-orm";
|
|
30
43
|
|
|
31
44
|
import type { DrizzleDb } from "../../../persistence/db-connection.js";
|
|
45
|
+
import { messageCreatedAtByIds } from "../../../persistence/message-reads.js";
|
|
32
46
|
import { memoryRetrospectiveState } from "../../../persistence/schema/index.js";
|
|
33
47
|
import { withSqliteRetry } from "./host-utils.js";
|
|
34
48
|
import { getLogger } from "./logging.js";
|
|
35
|
-
import { memoryDbOrNull } from "./memory-db.js";
|
|
49
|
+
import { memoryDbOrNull, memorySqliteOrNull } from "./memory-db.js";
|
|
36
50
|
|
|
37
51
|
const log = getLogger("memory-retrospective-state");
|
|
38
52
|
|
|
53
|
+
const TABLE = "memory_retrospective_state";
|
|
54
|
+
const CURSOR_CREATED_AT_COLUMN = "last_processed_created_at";
|
|
55
|
+
|
|
39
56
|
export interface MemoryRetrospectiveState {
|
|
40
57
|
conversationId: string;
|
|
41
58
|
lastProcessedMessageId: string;
|
|
59
|
+
/**
|
|
60
|
+
* `createdAt` of the `lastProcessedMessageId` row when the pointer was
|
|
61
|
+
* written, or null when unknown: rows written before the column existed,
|
|
62
|
+
* and the `""` sentinel. Lets the cursor bound a read after its row is gone.
|
|
63
|
+
*/
|
|
64
|
+
lastProcessedCreatedAt: number | null;
|
|
42
65
|
lastRunAt: number;
|
|
43
66
|
/**
|
|
44
67
|
* Cumulative `remember` contents from prior retrospective passes, oldest
|
|
@@ -99,6 +122,124 @@ function serializeRememberedLog(log: string[]): string | null {
|
|
|
99
122
|
return log.length === 0 ? null : JSON.stringify(log);
|
|
100
123
|
}
|
|
101
124
|
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Cursor timestamp column
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
type MemorySqlite = NonNullable<ReturnType<typeof memorySqliteOrNull>>;
|
|
130
|
+
|
|
131
|
+
/** The memory connection the column was confirmed on; any other re-probes. */
|
|
132
|
+
let cursorColumnEnsuredOn: MemorySqlite | null = null;
|
|
133
|
+
/**
|
|
134
|
+
* The connection the last probe failed on and when. The backoff applies to
|
|
135
|
+
* that connection only: a replaced connection is probed at once, so a
|
|
136
|
+
* restore right after a failure still gets the column before its first read.
|
|
137
|
+
*/
|
|
138
|
+
let cursorColumnFailedOn: MemorySqlite | null = null;
|
|
139
|
+
let lastCursorColumnFailureAt = 0;
|
|
140
|
+
/** Backoff before re-probing the same connection after a failed ALTER. */
|
|
141
|
+
const CURSOR_COLUMN_RETRY_MS = 60_000;
|
|
142
|
+
|
|
143
|
+
function isDuplicateColumnError(err: unknown): boolean {
|
|
144
|
+
return err instanceof Error && /duplicate column name/i.test(err.message);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Add `last_processed_created_at` to the state table when it is missing.
|
|
149
|
+
* Idempotent; memoized per memory connection, so a connection replaced by
|
|
150
|
+
* `resetDb()` is probed again and an imported database that lacks the column
|
|
151
|
+
* gets it before its first read. Fail-open: when the ALTER cannot run, the
|
|
152
|
+
* failure is logged, every read and write falls back to the id-only shape,
|
|
153
|
+
* and that connection is probed again after {@link CURSOR_COLUMN_RETRY_MS}.
|
|
154
|
+
* A table the migration chain has not created yet is neither memoized nor a
|
|
155
|
+
* failure.
|
|
156
|
+
*/
|
|
157
|
+
export function ensureRetrospectiveCursorColumn(context: string): boolean {
|
|
158
|
+
const raw = memorySqliteOrNull(context);
|
|
159
|
+
if (!raw) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (cursorColumnEnsuredOn === raw) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
if (
|
|
166
|
+
cursorColumnFailedOn === raw &&
|
|
167
|
+
Date.now() - lastCursorColumnFailureAt < CURSOR_COLUMN_RETRY_MS
|
|
168
|
+
) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
|
|
173
|
+
name: string;
|
|
174
|
+
}>;
|
|
175
|
+
if (columns.length === 0) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (!columns.some((column) => column.name === CURSOR_CREATED_AT_COLUMN)) {
|
|
179
|
+
raw.exec(
|
|
180
|
+
`ALTER TABLE ${TABLE} ADD COLUMN ${CURSOR_CREATED_AT_COLUMN} INTEGER`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (!isDuplicateColumnError(err)) {
|
|
185
|
+
cursorColumnFailedOn = raw;
|
|
186
|
+
lastCursorColumnFailureAt = Date.now();
|
|
187
|
+
log.warn(
|
|
188
|
+
{ err, context },
|
|
189
|
+
"could not add the retrospective cursor timestamp column; cursors fall back to id-only until the next probe",
|
|
190
|
+
);
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
cursorColumnEnsuredOn = raw;
|
|
195
|
+
cursorColumnFailedOn = null;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Forget the memoized column probe so the next call re-runs it. Intended
|
|
201
|
+
* ONLY for tests that recreate the memory database mid-process.
|
|
202
|
+
*/
|
|
203
|
+
export function _resetRetrospectiveCursorColumnForTests(): void {
|
|
204
|
+
cursorColumnEnsuredOn = null;
|
|
205
|
+
cursorColumnFailedOn = null;
|
|
206
|
+
lastCursorColumnFailureAt = 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Reads
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
const BASE_COLUMNS = {
|
|
214
|
+
conversationId: memoryRetrospectiveState.conversationId,
|
|
215
|
+
lastProcessedMessageId: memoryRetrospectiveState.lastProcessedMessageId,
|
|
216
|
+
lastRunAt: memoryRetrospectiveState.lastRunAt,
|
|
217
|
+
rememberedLog: memoryRetrospectiveState.rememberedLog,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const CURSOR_COLUMNS = {
|
|
221
|
+
...BASE_COLUMNS,
|
|
222
|
+
lastProcessedCreatedAt: memoryRetrospectiveState.lastProcessedCreatedAt,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
interface StateRow {
|
|
226
|
+
conversationId: string;
|
|
227
|
+
lastProcessedMessageId: string;
|
|
228
|
+
lastRunAt: number;
|
|
229
|
+
rememberedLog: string | null;
|
|
230
|
+
lastProcessedCreatedAt?: number | null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function toState(row: StateRow): MemoryRetrospectiveState {
|
|
234
|
+
return {
|
|
235
|
+
conversationId: row.conversationId,
|
|
236
|
+
lastProcessedMessageId: row.lastProcessedMessageId,
|
|
237
|
+
lastProcessedCreatedAt: row.lastProcessedCreatedAt ?? null,
|
|
238
|
+
lastRunAt: row.lastRunAt,
|
|
239
|
+
rememberedLog: parseRememberedLog(row.rememberedLog),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
102
243
|
/**
|
|
103
244
|
* Return the `limit` most-recently-run retrospective state rows, newest first.
|
|
104
245
|
*/
|
|
@@ -109,23 +250,22 @@ export function listRetrospectiveStates(
|
|
|
109
250
|
if (!mdb) {
|
|
110
251
|
return [];
|
|
111
252
|
}
|
|
112
|
-
const rows =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}));
|
|
253
|
+
const rows: StateRow[] = ensureRetrospectiveCursorColumn(
|
|
254
|
+
"listRetrospectiveStates",
|
|
255
|
+
)
|
|
256
|
+
? mdb
|
|
257
|
+
.select(CURSOR_COLUMNS)
|
|
258
|
+
.from(memoryRetrospectiveState)
|
|
259
|
+
.orderBy(desc(memoryRetrospectiveState.lastRunAt))
|
|
260
|
+
.limit(limit)
|
|
261
|
+
.all()
|
|
262
|
+
: mdb
|
|
263
|
+
.select(BASE_COLUMNS)
|
|
264
|
+
.from(memoryRetrospectiveState)
|
|
265
|
+
.orderBy(desc(memoryRetrospectiveState.lastRunAt))
|
|
266
|
+
.limit(limit)
|
|
267
|
+
.all();
|
|
268
|
+
return rows.map(toState);
|
|
129
269
|
}
|
|
130
270
|
|
|
131
271
|
/**
|
|
@@ -138,37 +278,45 @@ export function getRetrospectiveState(
|
|
|
138
278
|
if (!mdb) {
|
|
139
279
|
return null;
|
|
140
280
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
lastProcessedMessageId: row.lastProcessedMessageId,
|
|
157
|
-
lastRunAt: row.lastRunAt,
|
|
158
|
-
rememberedLog: parseRememberedLog(row.rememberedLog),
|
|
159
|
-
};
|
|
281
|
+
const where = eq(memoryRetrospectiveState.conversationId, conversationId);
|
|
282
|
+
const row: StateRow | undefined = ensureRetrospectiveCursorColumn(
|
|
283
|
+
"getRetrospectiveState",
|
|
284
|
+
)
|
|
285
|
+
? mdb
|
|
286
|
+
.select(CURSOR_COLUMNS)
|
|
287
|
+
.from(memoryRetrospectiveState)
|
|
288
|
+
.where(where)
|
|
289
|
+
.get()
|
|
290
|
+
: mdb
|
|
291
|
+
.select(BASE_COLUMNS)
|
|
292
|
+
.from(memoryRetrospectiveState)
|
|
293
|
+
.where(where)
|
|
294
|
+
.get();
|
|
295
|
+
return row ? toState(row) : null;
|
|
160
296
|
}
|
|
161
297
|
|
|
298
|
+
// ---------------------------------------------------------------------------
|
|
299
|
+
// Writes
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
|
|
162
302
|
/**
|
|
163
303
|
* Upsert both pointers atomically. Used on successful retrospective runs.
|
|
164
304
|
*
|
|
305
|
+
* `lastProcessedCreatedAt` is the id's companion and is rewritten with every
|
|
306
|
+
* pointer write: an omitted value records "unknown" for the new id rather
|
|
307
|
+
* than keeping the previous row's timestamp.
|
|
308
|
+
*
|
|
165
309
|
* `rememberedLog`, when provided, is written in the same statement so the
|
|
166
310
|
* cumulative dedup log can never drift from the pointer it was computed
|
|
167
311
|
* against. When omitted, the stored log is left untouched (and seeded NULL on
|
|
168
312
|
* first insert).
|
|
169
313
|
*/
|
|
170
314
|
export async function upsertRetrospectiveState(
|
|
171
|
-
args: Omit<
|
|
315
|
+
args: Omit<
|
|
316
|
+
MemoryRetrospectiveState,
|
|
317
|
+
"rememberedLog" | "lastProcessedCreatedAt"
|
|
318
|
+
> & {
|
|
319
|
+
lastProcessedCreatedAt?: number | null;
|
|
172
320
|
rememberedLog?: string[];
|
|
173
321
|
},
|
|
174
322
|
): Promise<void> {
|
|
@@ -176,6 +324,9 @@ export async function upsertRetrospectiveState(
|
|
|
176
324
|
if (!mdb) {
|
|
177
325
|
return;
|
|
178
326
|
}
|
|
327
|
+
const withCursor = ensureRetrospectiveCursorColumn(
|
|
328
|
+
"upsertRetrospectiveState",
|
|
329
|
+
);
|
|
179
330
|
const serializedLog =
|
|
180
331
|
args.rememberedLog === undefined
|
|
181
332
|
? undefined
|
|
@@ -185,12 +336,16 @@ export async function upsertRetrospectiveState(
|
|
|
185
336
|
// on first insert).
|
|
186
337
|
const set: {
|
|
187
338
|
lastProcessedMessageId: string;
|
|
339
|
+
lastProcessedCreatedAt?: number | null;
|
|
188
340
|
lastRunAt: number;
|
|
189
341
|
rememberedLog?: string | null;
|
|
190
342
|
} = {
|
|
191
343
|
lastProcessedMessageId: args.lastProcessedMessageId,
|
|
192
344
|
lastRunAt: args.lastRunAt,
|
|
193
345
|
};
|
|
346
|
+
if (withCursor) {
|
|
347
|
+
set.lastProcessedCreatedAt = args.lastProcessedCreatedAt ?? null;
|
|
348
|
+
}
|
|
194
349
|
if (serializedLog !== undefined) {
|
|
195
350
|
set.rememberedLog = serializedLog;
|
|
196
351
|
}
|
|
@@ -203,6 +358,9 @@ export async function upsertRetrospectiveState(
|
|
|
203
358
|
lastProcessedMessageId: args.lastProcessedMessageId,
|
|
204
359
|
lastRunAt: args.lastRunAt,
|
|
205
360
|
rememberedLog: serializedLog ?? null,
|
|
361
|
+
...(withCursor
|
|
362
|
+
? { lastProcessedCreatedAt: args.lastProcessedCreatedAt ?? null }
|
|
363
|
+
: {}),
|
|
206
364
|
})
|
|
207
365
|
.onConflictDoUpdate({
|
|
208
366
|
target: memoryRetrospectiveState.conversationId,
|
|
@@ -216,6 +374,46 @@ export async function upsertRetrospectiveState(
|
|
|
216
374
|
);
|
|
217
375
|
}
|
|
218
376
|
|
|
377
|
+
/**
|
|
378
|
+
* The copied source row that sits latest at or before `bound` in
|
|
379
|
+
* `(createdAt, id)` order, as its forked id and `createdAt`, or null when
|
|
380
|
+
* every copied row lies after the bound. Reads the source rows through the
|
|
381
|
+
* fork transaction's handle.
|
|
382
|
+
*/
|
|
383
|
+
function latestCopiedRowAtOrBefore(
|
|
384
|
+
database: DrizzleDb,
|
|
385
|
+
forkedMessageIds: Map<string, string>,
|
|
386
|
+
bound: { createdAt: number; id: string },
|
|
387
|
+
): { forkedId: string; createdAt: number } | null {
|
|
388
|
+
const createdAtBySourceId = messageCreatedAtByIds(
|
|
389
|
+
[...forkedMessageIds.keys()],
|
|
390
|
+
{ db: database },
|
|
391
|
+
);
|
|
392
|
+
let best: { sourceId: string; createdAt: number } | null = null;
|
|
393
|
+
for (const [sourceId, createdAt] of createdAtBySourceId) {
|
|
394
|
+
const atOrBefore =
|
|
395
|
+
createdAt < bound.createdAt ||
|
|
396
|
+
(createdAt === bound.createdAt && sourceId <= bound.id);
|
|
397
|
+
if (!atOrBefore) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const later =
|
|
401
|
+
best === null ||
|
|
402
|
+
createdAt > best.createdAt ||
|
|
403
|
+
(createdAt === best.createdAt && sourceId > best.sourceId);
|
|
404
|
+
if (later) {
|
|
405
|
+
best = { sourceId, createdAt };
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (best === null) {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
const forkedId = forkedMessageIds.get(best.sourceId);
|
|
412
|
+
return forkedId === undefined
|
|
413
|
+
? null
|
|
414
|
+
: { forkedId, createdAt: best.createdAt };
|
|
415
|
+
}
|
|
416
|
+
|
|
219
417
|
/**
|
|
220
418
|
* Carry the source conversation's retrospective state into a forked child so
|
|
221
419
|
* the fork doesn't re-process content the parent already covered. Synchronous
|
|
@@ -229,18 +427,23 @@ export async function upsertRetrospectiveState(
|
|
|
229
427
|
* succeeded) → child pointer is also `""`.
|
|
230
428
|
* - source pointer is within the copied range (`forkedMessageIds` has it) →
|
|
231
429
|
* child pointer is the mapped forked message ID.
|
|
232
|
-
* - source pointer is
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
430
|
+
* - source pointer is not in `forkedMessageIds` (its row was deleted, or it
|
|
431
|
+
* lies past the copied range) and carries a stored `createdAt` → child
|
|
432
|
+
* pointer is the latest copied row at or before the source's
|
|
433
|
+
* `(createdAt, id)` bound; copied rows after the bound stay unprocessed.
|
|
434
|
+
* - source pointer is not in `forkedMessageIds` and has no stored
|
|
435
|
+
* `createdAt` → child pointer is the last copied message's mapped ID, on
|
|
436
|
+
* the assumption it lies past the fork boundary.
|
|
236
437
|
*
|
|
438
|
+
* `lastProcessedCreatedAt` is read from the forked pointer's row through
|
|
439
|
+
* `database`, the fork transaction's main-DB handle, which is the only handle
|
|
440
|
+
* the freshly copied rows are visible through.
|
|
237
441
|
* `lastRunAt` is copied verbatim — the cooldown gate inherits from source.
|
|
238
442
|
* `rememberedLog` is copied verbatim — the parent's saves remain the child's
|
|
239
443
|
* dedup baseline.
|
|
240
444
|
*
|
|
241
|
-
* The row
|
|
242
|
-
*
|
|
243
|
-
* now, and an unavailable memory database is a best-effort no-op.
|
|
445
|
+
* The state row itself is written on the memory connection; an unavailable
|
|
446
|
+
* memory database is a best-effort no-op.
|
|
244
447
|
*/
|
|
245
448
|
export function forkRetrospectiveState(args: {
|
|
246
449
|
database: DrizzleDb;
|
|
@@ -250,6 +453,7 @@ export function forkRetrospectiveState(args: {
|
|
|
250
453
|
lastCopiedSourceMessageId: string | null;
|
|
251
454
|
}): void {
|
|
252
455
|
const {
|
|
456
|
+
database,
|
|
253
457
|
sourceConversationId,
|
|
254
458
|
forkedConversationId,
|
|
255
459
|
forkedMessageIds,
|
|
@@ -262,47 +466,84 @@ export function forkRetrospectiveState(args: {
|
|
|
262
466
|
return;
|
|
263
467
|
}
|
|
264
468
|
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
469
|
+
const withCursor = ensureRetrospectiveCursorColumn(
|
|
470
|
+
"forkRetrospectiveState",
|
|
471
|
+
);
|
|
472
|
+
const sourceRow: StateRow | undefined = withCursor
|
|
473
|
+
? mdb
|
|
474
|
+
.select(CURSOR_COLUMNS)
|
|
475
|
+
.from(memoryRetrospectiveState)
|
|
476
|
+
.where(
|
|
477
|
+
eq(memoryRetrospectiveState.conversationId, sourceConversationId),
|
|
478
|
+
)
|
|
479
|
+
.get()
|
|
480
|
+
: mdb
|
|
481
|
+
.select(BASE_COLUMNS)
|
|
482
|
+
.from(memoryRetrospectiveState)
|
|
483
|
+
.where(
|
|
484
|
+
eq(memoryRetrospectiveState.conversationId, sourceConversationId),
|
|
485
|
+
)
|
|
486
|
+
.get();
|
|
274
487
|
if (!sourceRow) {
|
|
275
488
|
return;
|
|
276
489
|
}
|
|
277
490
|
|
|
491
|
+
const sourcePointer = sourceRow.lastProcessedMessageId;
|
|
492
|
+
const sourceCreatedAt = sourceRow.lastProcessedCreatedAt ?? null;
|
|
278
493
|
let forkedPointer = "";
|
|
279
|
-
|
|
280
|
-
|
|
494
|
+
let forkedCreatedAt: number | null = null;
|
|
495
|
+
if (sourcePointer !== "") {
|
|
496
|
+
const mapped = forkedMessageIds.get(sourcePointer);
|
|
281
497
|
if (mapped !== undefined) {
|
|
282
498
|
forkedPointer = mapped;
|
|
499
|
+
forkedCreatedAt =
|
|
500
|
+
messageCreatedAtByIds([forkedPointer], { db: database }).get(
|
|
501
|
+
forkedPointer,
|
|
502
|
+
) ?? null;
|
|
503
|
+
} else if (sourceCreatedAt !== null) {
|
|
504
|
+
// The source pointer is not among the copied rows: either its row
|
|
505
|
+
// was deleted (a regenerated reply) or it lies past the copied range.
|
|
506
|
+
// Its stored `(createdAt, id)` bound still says where it sat, so the
|
|
507
|
+
// child takes the latest copied row at or before that bound. Copied
|
|
508
|
+
// rows after it (a replacement reply, later turns) stay unprocessed;
|
|
509
|
+
// a bound before every copied row leaves the child at "nothing
|
|
510
|
+
// processed yet".
|
|
511
|
+
const placed = latestCopiedRowAtOrBefore(database, forkedMessageIds, {
|
|
512
|
+
createdAt: sourceCreatedAt,
|
|
513
|
+
id: sourcePointer,
|
|
514
|
+
});
|
|
515
|
+
if (placed) {
|
|
516
|
+
forkedPointer = placed.forkedId;
|
|
517
|
+
forkedCreatedAt = placed.createdAt;
|
|
518
|
+
}
|
|
283
519
|
} else if (lastCopiedSourceMessageId !== null) {
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
// message so the fork waits for new post-fork
|
|
520
|
+
// No stored bound to place a missing pointer by (a row written before
|
|
521
|
+
// timestamps were kept): treat it as past the fork boundary and clamp
|
|
522
|
+
// to the last copied message so the fork waits for new post-fork
|
|
523
|
+
// messages.
|
|
287
524
|
forkedPointer = forkedMessageIds.get(lastCopiedSourceMessageId) ?? "";
|
|
525
|
+
forkedCreatedAt =
|
|
526
|
+
forkedPointer === ""
|
|
527
|
+
? null
|
|
528
|
+
: (messageCreatedAtByIds([forkedPointer], { db: database }).get(
|
|
529
|
+
forkedPointer,
|
|
530
|
+
) ?? null);
|
|
288
531
|
}
|
|
289
532
|
}
|
|
290
533
|
|
|
534
|
+
const values = {
|
|
535
|
+
lastProcessedMessageId: forkedPointer,
|
|
536
|
+
lastRunAt: sourceRow.lastRunAt,
|
|
537
|
+
rememberedLog: sourceRow.rememberedLog,
|
|
538
|
+
...(withCursor ? { lastProcessedCreatedAt: forkedCreatedAt } : {}),
|
|
539
|
+
};
|
|
540
|
+
|
|
291
541
|
mdb
|
|
292
542
|
.insert(memoryRetrospectiveState)
|
|
293
|
-
.values({
|
|
294
|
-
conversationId: forkedConversationId,
|
|
295
|
-
lastProcessedMessageId: forkedPointer,
|
|
296
|
-
lastRunAt: sourceRow.lastRunAt,
|
|
297
|
-
rememberedLog: sourceRow.rememberedLog,
|
|
298
|
-
})
|
|
543
|
+
.values({ conversationId: forkedConversationId, ...values })
|
|
299
544
|
.onConflictDoUpdate({
|
|
300
545
|
target: memoryRetrospectiveState.conversationId,
|
|
301
|
-
set:
|
|
302
|
-
lastProcessedMessageId: forkedPointer,
|
|
303
|
-
lastRunAt: sourceRow.lastRunAt,
|
|
304
|
-
rememberedLog: sourceRow.rememberedLog,
|
|
305
|
-
},
|
|
546
|
+
set: values,
|
|
306
547
|
})
|
|
307
548
|
.run();
|
|
308
549
|
} catch (err) {
|
|
@@ -78,6 +78,7 @@ import { conversations } from "../../../persistence/schema/index.js";
|
|
|
78
78
|
import { getLogger } from "./logging.js";
|
|
79
79
|
import { countRetrospectiveMessagesAfter } from "./memory-retrospective-accounting.js";
|
|
80
80
|
import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
|
|
81
|
+
import { retrospectiveCursor } from "./memory-retrospective-cursor.js";
|
|
81
82
|
import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
|
|
82
83
|
import { getRetrospectiveState } from "./memory-retrospective-state.js";
|
|
83
84
|
|
|
@@ -273,7 +274,7 @@ export async function runRetrospectiveSweep(
|
|
|
273
274
|
|
|
274
275
|
const unprocessed = countRetrospectiveMessagesAfter(
|
|
275
276
|
conversationId,
|
|
276
|
-
state
|
|
277
|
+
retrospectiveCursor(state),
|
|
277
278
|
);
|
|
278
279
|
if (unprocessed === 0) {
|
|
279
280
|
continue;
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
// (success or failure). Prevents tight retry loops across trigger
|
|
10
10
|
// types.
|
|
11
11
|
// 2. Interval threshold: time since last attempt >= `timeThresholdMs`.
|
|
12
|
-
// 3. Message count threshold: new messages since
|
|
13
|
-
//
|
|
12
|
+
// 3. Message count threshold: new messages since the persisted cursor
|
|
13
|
+
// (`lastProcessedMessageId` with its `createdAt`, so the count survives
|
|
14
|
+
// the cursor's row being deleted) >= `messageThreshold`.
|
|
14
15
|
//
|
|
15
16
|
// First-run case (no state row) skips the cooldown — `lastRunAt = 0` so the
|
|
16
17
|
// gap is effectively `Infinity`. The interval threshold trips immediately;
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
import type { AssistantConfig } from "../../../config/types.js";
|
|
25
26
|
import { getLogger } from "./logging.js";
|
|
26
27
|
import { countRetrospectiveMessagesAfter } from "./memory-retrospective-accounting.js";
|
|
28
|
+
import { retrospectiveCursor } from "./memory-retrospective-cursor.js";
|
|
27
29
|
import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
|
|
28
30
|
import { getRetrospectiveState } from "./memory-retrospective-state.js";
|
|
29
31
|
|
|
@@ -83,7 +85,7 @@ export function maybeEnqueueRetrospective(
|
|
|
83
85
|
const state = getRetrospectiveState(conversationId);
|
|
84
86
|
const newMessageCount = countRetrospectiveMessagesAfter(
|
|
85
87
|
conversationId,
|
|
86
|
-
state
|
|
88
|
+
retrospectiveCursor(state),
|
|
87
89
|
);
|
|
88
90
|
if (newMessageCount === 0) {
|
|
89
91
|
return;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin-local re-export of the workspace SKILL.md mtime poll so hook files
|
|
3
|
+
* under `hooks/` do not grow a new escaping specifier. The daemon module is
|
|
4
|
+
* already a memory-plugin baseline import from `startup.ts` / `worker.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export {
|
|
7
|
+
startWorkspaceSkillMdMtimePoll,
|
|
8
|
+
stopWorkspaceSkillMdMtimePoll,
|
|
9
|
+
} from "../../../daemon/skill-memory-refresh.js";
|
|
@@ -28,7 +28,10 @@ import { join } from "node:path";
|
|
|
28
28
|
import { usesConceptPageMemory } from "../../../config/memory-v3-gate.js";
|
|
29
29
|
import type { AssistantConfig } from "../../../config/schema.js";
|
|
30
30
|
import { reconcileEmbeddingIdentity } from "../../../daemon/embedding-reconcile.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
refreshSkillCapabilityMemories,
|
|
33
|
+
startWorkspaceSkillMdMtimePoll,
|
|
34
|
+
} from "../../../daemon/skill-memory-refresh.js";
|
|
32
35
|
import { selectEmbeddingBackend } from "../../../persistence/embeddings/embedding-backend.js";
|
|
33
36
|
import {
|
|
34
37
|
initMessagesLexicalIndex,
|
|
@@ -38,11 +41,15 @@ import {
|
|
|
38
41
|
clearRebuildSentinel,
|
|
39
42
|
initQdrantClient,
|
|
40
43
|
} from "../../../persistence/embeddings/qdrant-client.js";
|
|
41
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
createQdrantManager,
|
|
46
|
+
describeQdrantStartFailure,
|
|
47
|
+
} from "../../../persistence/embeddings/qdrant-manager.js";
|
|
42
48
|
import {
|
|
43
49
|
enqueueMemoryJob,
|
|
44
50
|
isMemoryEnabled,
|
|
45
51
|
} from "../../../persistence/jobs-store.js";
|
|
52
|
+
import { recordWatchdogEvent } from "../../../telemetry/watchdog-events-store.js";
|
|
46
53
|
import { resolveQdrantUrl } from "./embeddings.js";
|
|
47
54
|
import { startMemoryJobsWorker } from "./jobs-worker.js";
|
|
48
55
|
import { getLogger } from "./logging.js";
|
|
@@ -89,6 +96,23 @@ export async function runMemoryStartup(config: AssistantConfig): Promise<void> {
|
|
|
89
96
|
{ err },
|
|
90
97
|
"Qdrant failed to start after all attempts — memory features will be unavailable",
|
|
91
98
|
);
|
|
99
|
+
// Fleet-wide record of the failure: the step, the exit code and
|
|
100
|
+
// Qdrant's own reason line, bounded to telemetry-safe metadata by
|
|
101
|
+
// `describeQdrantStartFailure`. Observational only: the outbox insert
|
|
102
|
+
// can throw on a locked or half-migrated telemetry DB, and this path
|
|
103
|
+
// must still reach the worker start below.
|
|
104
|
+
try {
|
|
105
|
+
recordWatchdogEvent({
|
|
106
|
+
checkName: "qdrant_start_failed",
|
|
107
|
+
value: attempt,
|
|
108
|
+
detail: { attempts: attempt, ...describeQdrantStartFailure(err) },
|
|
109
|
+
});
|
|
110
|
+
} catch (telemetryErr) {
|
|
111
|
+
log.warn(
|
|
112
|
+
{ err: telemetryErr },
|
|
113
|
+
"Qdrant start failure could not be recorded to telemetry",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
92
116
|
}
|
|
93
117
|
}
|
|
94
118
|
}
|
|
@@ -263,6 +287,8 @@ export async function runMemoryStartup(config: AssistantConfig): Promise<void> {
|
|
|
263
287
|
log.warn({ err }, "Graph capability seeding failed — continuing");
|
|
264
288
|
}
|
|
265
289
|
|
|
290
|
+
startWorkspaceSkillMdMtimePoll();
|
|
291
|
+
|
|
266
292
|
// ---- v1 (legacy engine) — delete with v1 ----
|
|
267
293
|
// Auto-bootstrap: if the graph has no non-procedural nodes but historical
|
|
268
294
|
// segments exist, enqueue a one-time graph_bootstrap job to populate the
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { setWorkspaceMcp } from "../../../../../__tests__/helpers/set-workspace-mcp.js";
|
|
8
8
|
import type { SkillCapabilityInput } from "../skill-content.js";
|
|
9
9
|
|
|
10
10
|
describe("buildSkillContent", () => {
|
|
@@ -90,14 +90,12 @@ describe("augmentMcpSetupDescription", () => {
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
test("appends 'Configured: <names>' for mcp-setup with configured servers", async () => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"example-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"another-
|
|
99
|
-
transport: { type: "stdio", command: "another-cmd" },
|
|
100
|
-
},
|
|
93
|
+
setWorkspaceMcp({
|
|
94
|
+
"example-server": {
|
|
95
|
+
transport: { type: "stdio", command: "example-cmd", args: [] },
|
|
96
|
+
},
|
|
97
|
+
"another-server": {
|
|
98
|
+
transport: { type: "stdio", command: "another-cmd", args: [] },
|
|
101
99
|
},
|
|
102
100
|
});
|
|
103
101
|
const { augmentMcpSetupDescription } = await import("../skill-content.js");
|