@vellumai/assistant 0.12.1 → 0.12.2-staging.1
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/openapi.yaml +327 -52
- 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-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- 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 +212 -3
- package/src/__tests__/credential-security-invariants.test.ts +4 -2
- package/src/__tests__/cu-unified-flow.test.ts +8 -2
- 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 +539 -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 +113 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -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__/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 +19 -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__/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__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -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__/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/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/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/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 +58 -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 +37 -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 +53 -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 +59 -46
- package/src/calls/voice-triage-escalate.ts +175 -56
- 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/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 +20 -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 +24 -12
- package/src/config/loader.ts +1 -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 +8 -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 +2 -1
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +15 -9
- package/src/daemon/conversation-tool-setup.ts +37 -43
- 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 +186 -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-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -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__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +213 -693
- package/src/live-voice/protocol.ts +0 -2
- 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 +54 -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 +73 -0
- package/src/oauth/connection-resolver.ts +95 -2
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +204 -25
- 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-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -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-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +73 -0
- 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 +19 -10
- 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 +36 -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/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-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
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
// accounting; once newer real messages arrive it is copied into the next
|
|
32
32
|
// run's fork as inert prefix context.
|
|
33
33
|
|
|
34
|
-
import { and, eq,
|
|
34
|
+
import { and, eq, like, or } from "drizzle-orm";
|
|
35
35
|
|
|
36
36
|
import {
|
|
37
37
|
countMessagesAfter,
|
|
@@ -43,6 +43,11 @@ import {
|
|
|
43
43
|
SIGHT_FRAME_ATTACHMENT_IDS_KEY,
|
|
44
44
|
} from "../../../persistence/conversation-types.js";
|
|
45
45
|
import { getDb } from "../../../persistence/db-connection.js";
|
|
46
|
+
import {
|
|
47
|
+
messagesAfterBoundFilter,
|
|
48
|
+
type MessagesAfterRef,
|
|
49
|
+
resolveMessagesAfterBound,
|
|
50
|
+
} from "../../../persistence/message-cursor.js";
|
|
46
51
|
import { messages } from "../../../persistence/schema/index.js";
|
|
47
52
|
import { SKILL_CARD_MESSAGE_KIND } from "./memory-retrospective-constants.js";
|
|
48
53
|
|
|
@@ -98,9 +103,9 @@ export function isSkillCardMessage(row: { metadata: string | null }): boolean {
|
|
|
98
103
|
*/
|
|
99
104
|
export function getRetrospectiveMessagesAfter(
|
|
100
105
|
conversationId: string,
|
|
101
|
-
|
|
106
|
+
after: MessagesAfterRef,
|
|
102
107
|
): MessageRow[] {
|
|
103
|
-
const rows = getMessagesAfter(conversationId,
|
|
108
|
+
const rows = getMessagesAfter(conversationId, after);
|
|
104
109
|
const firstUnfinalized = rows.findIndex((row) => row.finalized !== 1);
|
|
105
110
|
const bounded =
|
|
106
111
|
firstUnfinalized === -1 ? rows : rows.slice(0, firstUnfinalized);
|
|
@@ -116,13 +121,13 @@ export function getRetrospectiveMessagesAfter(
|
|
|
116
121
|
*/
|
|
117
122
|
export function countRetrospectiveMessagesAfter(
|
|
118
123
|
conversationId: string,
|
|
119
|
-
|
|
124
|
+
after: MessagesAfterRef,
|
|
120
125
|
): number {
|
|
121
|
-
const total = countMessagesAfter(conversationId,
|
|
126
|
+
const total = countMessagesAfter(conversationId, after);
|
|
122
127
|
if (total === 0) {
|
|
123
128
|
return 0;
|
|
124
129
|
}
|
|
125
|
-
const excluded = countExcludedMessagesAfter(conversationId,
|
|
130
|
+
const excluded = countExcludedMessagesAfter(conversationId, after);
|
|
126
131
|
return Math.max(0, total - excluded);
|
|
127
132
|
}
|
|
128
133
|
|
|
@@ -167,7 +172,8 @@ export function messagesHaveUserActivity(
|
|
|
167
172
|
* a non-tool_result block. Powers the `memory.retrospective.requireUserActivity`
|
|
168
173
|
* enqueue gate, so only user rows are loaded. Cursor semantics mirror
|
|
169
174
|
* `countMessagesAfter`: a null/`""` reference scans the whole conversation,
|
|
170
|
-
*
|
|
175
|
+
* a cursor whose row is gone falls back to the timestamp it carries, and a
|
|
176
|
+
* bare id whose row is gone means no new work.
|
|
171
177
|
*
|
|
172
178
|
* Operates on the raw `content` column: rows that do not parse to a block
|
|
173
179
|
* array (file-backed `{ ref }` rows, legacy plain strings) count as
|
|
@@ -177,37 +183,15 @@ export function messagesHaveUserActivity(
|
|
|
177
183
|
*/
|
|
178
184
|
export function hasQualifyingUserMessageAfter(
|
|
179
185
|
conversationId: string,
|
|
180
|
-
|
|
186
|
+
after: MessagesAfterRef,
|
|
181
187
|
): boolean {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
let ref: { createdAt: number } | undefined;
|
|
187
|
-
if (cursorId !== null) {
|
|
188
|
-
ref = db
|
|
189
|
-
.select({ createdAt: messages.createdAt })
|
|
190
|
-
.from(messages)
|
|
191
|
-
.where(eq(messages.id, cursorId))
|
|
192
|
-
.get();
|
|
193
|
-
if (!ref) {
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
188
|
+
const start = resolveMessagesAfterBound(after);
|
|
189
|
+
if (start.kind === "vanished") {
|
|
190
|
+
return false;
|
|
196
191
|
}
|
|
197
|
-
|
|
198
192
|
const afterCursor =
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
or(
|
|
202
|
-
gt(messages.createdAt, ref.createdAt),
|
|
203
|
-
and(
|
|
204
|
-
eq(messages.createdAt, ref.createdAt),
|
|
205
|
-
gt(messages.id, cursorId),
|
|
206
|
-
),
|
|
207
|
-
),
|
|
208
|
-
]
|
|
209
|
-
: [];
|
|
210
|
-
const rows = db
|
|
193
|
+
start.kind === "after" ? [messagesAfterBoundFilter(start.bound)] : [];
|
|
194
|
+
const rows = getDb()
|
|
211
195
|
.select({ content: messages.content, metadata: messages.metadata })
|
|
212
196
|
.from(messages)
|
|
213
197
|
.where(
|
|
@@ -248,18 +232,14 @@ function rawUserContentCarriesActivity(raw: string | null): boolean {
|
|
|
248
232
|
* — at most one per successful retrospective run); each candidate is then
|
|
249
233
|
* JSON-verified by {@link isSkillCardMessage} so an incidental substring
|
|
250
234
|
* match in unrelated metadata can never exclude a real message from
|
|
251
|
-
* accounting. The cursor
|
|
252
|
-
*
|
|
253
|
-
*
|
|
235
|
+
* accounting. The cursor resolves exactly as `countMessagesAfter`'s does,
|
|
236
|
+
* including the null/`""` "count everything" cases and the vanished-reference
|
|
237
|
+
* "no new work" case.
|
|
254
238
|
*/
|
|
255
239
|
function countExcludedMessagesAfter(
|
|
256
240
|
conversationId: string,
|
|
257
|
-
|
|
241
|
+
after: MessagesAfterRef,
|
|
258
242
|
): number {
|
|
259
|
-
// The `""` sentinel (failure-only state rows) counts everything, matching
|
|
260
|
-
// `countMessagesAfter`.
|
|
261
|
-
const cursorId =
|
|
262
|
-
afterMessageId === null || afterMessageId === "" ? null : afterMessageId;
|
|
263
243
|
const db = getDb();
|
|
264
244
|
const candidates = db
|
|
265
245
|
.select({
|
|
@@ -282,18 +262,11 @@ function countExcludedMessagesAfter(
|
|
|
282
262
|
return 0;
|
|
283
263
|
}
|
|
284
264
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
.where(eq(messages.id, cursorId))
|
|
291
|
-
.get();
|
|
292
|
-
// Vanished reference: `countMessagesAfter` reported 0, so there is
|
|
293
|
-
// nothing to subtract from.
|
|
294
|
-
if (!ref) {
|
|
295
|
-
return 0;
|
|
296
|
-
}
|
|
265
|
+
const start = resolveMessagesAfterBound(after);
|
|
266
|
+
// Vanished reference: `countMessagesAfter` reported 0, so there is nothing
|
|
267
|
+
// to subtract from.
|
|
268
|
+
if (start.kind === "vanished") {
|
|
269
|
+
return 0;
|
|
297
270
|
}
|
|
298
271
|
|
|
299
272
|
let count = 0;
|
|
@@ -301,11 +274,12 @@ function countExcludedMessagesAfter(
|
|
|
301
274
|
if (!isExcludedFromRetrospectiveAccounting(row)) {
|
|
302
275
|
continue;
|
|
303
276
|
}
|
|
304
|
-
if (
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
277
|
+
if (start.kind === "after") {
|
|
278
|
+
const { createdAt, id } = start.bound;
|
|
279
|
+
const isAfter =
|
|
280
|
+
row.createdAt > createdAt ||
|
|
281
|
+
(row.createdAt === createdAt && row.id > id);
|
|
282
|
+
if (!isAfter) {
|
|
309
283
|
continue;
|
|
310
284
|
}
|
|
311
285
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective: cursor timestamp backfill.
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// State rows written before `last_processed_created_at` existed carry an
|
|
6
|
+
// id-only cursor, which stops bounding reads the moment its row is deleted
|
|
7
|
+
// (see `memory-retrospective-state.ts`). This pass copies `createdAt` from
|
|
8
|
+
// each such row's message while the message still exists. Rows whose message
|
|
9
|
+
// is already gone stay NULL: nothing remains to recover, and they are counted
|
|
10
|
+
// so the stall is visible in the log. Runs detached at daemon init (ahead of
|
|
11
|
+
// any client regenerating a reply) and again at memory-worker startup;
|
|
12
|
+
// idempotent, keyset-paginated by conversation id, and yielding between pages.
|
|
13
|
+
|
|
14
|
+
import { and, asc, eq, gt, isNull, ne } from "drizzle-orm";
|
|
15
|
+
|
|
16
|
+
import { messageCreatedAtByIds } from "../../../persistence/message-reads.js";
|
|
17
|
+
import { memoryRetrospectiveState } from "../../../persistence/schema/index.js";
|
|
18
|
+
import { withSqliteRetry } from "./host-utils.js";
|
|
19
|
+
import { getLogger } from "./logging.js";
|
|
20
|
+
import { memoryDbOrNull } from "./memory-db.js";
|
|
21
|
+
import { ensureRetrospectiveCursorColumn } from "./memory-retrospective-state.js";
|
|
22
|
+
|
|
23
|
+
const log = getLogger("memory-retrospective-cursor-backfill");
|
|
24
|
+
|
|
25
|
+
const DEFAULT_PAGE_SIZE = 500;
|
|
26
|
+
|
|
27
|
+
export interface CursorBackfillResult {
|
|
28
|
+
/** Rows with a cursor id but no timestamp. */
|
|
29
|
+
scanned: number;
|
|
30
|
+
/** Rows whose message still exists and received its `createdAt`. */
|
|
31
|
+
backfilled: number;
|
|
32
|
+
/** Rows whose cursor message no longer exists; left NULL. */
|
|
33
|
+
unrecoverable: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fill `last_processed_created_at` on every state row that has a cursor id
|
|
38
|
+
* but no timestamp. Best-effort: a missing memory connection or column is a
|
|
39
|
+
* no-op, and a row the job rewrites mid-pass is skipped by the update's
|
|
40
|
+
* `IS NULL` guard rather than stomped. Pages by conversation id so a large
|
|
41
|
+
* backlog never materializes at once or holds the event loop.
|
|
42
|
+
*/
|
|
43
|
+
export async function backfillRetrospectiveCursorTimestamps(opts?: {
|
|
44
|
+
pageSize?: number;
|
|
45
|
+
}): Promise<CursorBackfillResult> {
|
|
46
|
+
const pageSize = opts?.pageSize ?? DEFAULT_PAGE_SIZE;
|
|
47
|
+
const result: CursorBackfillResult = {
|
|
48
|
+
scanned: 0,
|
|
49
|
+
backfilled: 0,
|
|
50
|
+
unrecoverable: 0,
|
|
51
|
+
};
|
|
52
|
+
const context = "backfillRetrospectiveCursorTimestamps";
|
|
53
|
+
const mdb = memoryDbOrNull(context);
|
|
54
|
+
if (!mdb || !ensureRetrospectiveCursorColumn(context)) {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let afterConversationId = "";
|
|
59
|
+
for (;;) {
|
|
60
|
+
const page = mdb
|
|
61
|
+
.select({
|
|
62
|
+
conversationId: memoryRetrospectiveState.conversationId,
|
|
63
|
+
messageId: memoryRetrospectiveState.lastProcessedMessageId,
|
|
64
|
+
})
|
|
65
|
+
.from(memoryRetrospectiveState)
|
|
66
|
+
.where(
|
|
67
|
+
and(
|
|
68
|
+
isNull(memoryRetrospectiveState.lastProcessedCreatedAt),
|
|
69
|
+
ne(memoryRetrospectiveState.lastProcessedMessageId, ""),
|
|
70
|
+
gt(memoryRetrospectiveState.conversationId, afterConversationId),
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
.orderBy(asc(memoryRetrospectiveState.conversationId))
|
|
74
|
+
.limit(pageSize)
|
|
75
|
+
.all();
|
|
76
|
+
if (page.length === 0) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
afterConversationId = page[page.length - 1]!.conversationId;
|
|
80
|
+
result.scanned += page.length;
|
|
81
|
+
|
|
82
|
+
const createdAtById = messageCreatedAtByIds(
|
|
83
|
+
page.map((row) => row.messageId),
|
|
84
|
+
);
|
|
85
|
+
const recoverable = page.flatMap((row) => {
|
|
86
|
+
const createdAt = createdAtById.get(row.messageId);
|
|
87
|
+
return createdAt === undefined ? [] : [{ ...row, createdAt }];
|
|
88
|
+
});
|
|
89
|
+
result.unrecoverable += page.length - recoverable.length;
|
|
90
|
+
|
|
91
|
+
if (recoverable.length > 0) {
|
|
92
|
+
await withSqliteRetry(
|
|
93
|
+
() => {
|
|
94
|
+
mdb.transaction((tx) => {
|
|
95
|
+
for (const row of recoverable) {
|
|
96
|
+
tx.update(memoryRetrospectiveState)
|
|
97
|
+
.set({ lastProcessedCreatedAt: row.createdAt })
|
|
98
|
+
.where(
|
|
99
|
+
and(
|
|
100
|
+
eq(
|
|
101
|
+
memoryRetrospectiveState.conversationId,
|
|
102
|
+
row.conversationId,
|
|
103
|
+
),
|
|
104
|
+
eq(
|
|
105
|
+
memoryRetrospectiveState.lastProcessedMessageId,
|
|
106
|
+
row.messageId,
|
|
107
|
+
),
|
|
108
|
+
isNull(memoryRetrospectiveState.lastProcessedCreatedAt),
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
.run();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
{ op: context, context: { afterConversationId } },
|
|
116
|
+
);
|
|
117
|
+
result.backfilled += recoverable.length;
|
|
118
|
+
}
|
|
119
|
+
await Bun.sleep(0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (result.backfilled > 0 || result.unrecoverable > 0) {
|
|
123
|
+
log.info(result, "Retrospective cursor timestamps backfilled");
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective: keep the cursor's timestamp when its row is deleted.
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// The cursor normally sits on the latest assistant reply, and the retry route
|
|
6
|
+
// deletes exactly that row when the user regenerates it. A cursor written
|
|
7
|
+
// before the timestamp column existed carries only the id, so once the row is
|
|
8
|
+
// gone nothing can place it. The `message-deleted` hook delivers each deleted
|
|
9
|
+
// row's `(createdAt, id)` here: when the conversation's cursor is among the
|
|
10
|
+
// rows and has no timestamp yet, the row's `createdAt` is recorded. The
|
|
11
|
+
// timestamps travel in the call, so the write does not need the rows to
|
|
12
|
+
// still exist.
|
|
13
|
+
|
|
14
|
+
import { and, eq, isNull } from "drizzle-orm";
|
|
15
|
+
|
|
16
|
+
import { memoryRetrospectiveState } from "../../../persistence/schema/index.js";
|
|
17
|
+
import { withSqliteRetry } from "./host-utils.js";
|
|
18
|
+
import { getLogger } from "./logging.js";
|
|
19
|
+
import { memoryDbOrNull } from "./memory-db.js";
|
|
20
|
+
import { ensureRetrospectiveCursorColumn } from "./memory-retrospective-state.js";
|
|
21
|
+
|
|
22
|
+
const log = getLogger("memory-retrospective-cursor-preserve");
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Record `createdAt` on the conversation's retrospective cursor when it points
|
|
26
|
+
* at one of `rows` and has no timestamp yet. Best-effort: an unavailable
|
|
27
|
+
* memory connection or column is a no-op, and a cursor the job has moved
|
|
28
|
+
* since the caller read it is skipped by the `IS NULL` guard.
|
|
29
|
+
*/
|
|
30
|
+
export async function preserveRetrospectiveCursorTimestamps(
|
|
31
|
+
conversationId: string,
|
|
32
|
+
rows: ReadonlyArray<{ id: string; createdAt: number }>,
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
if (rows.length === 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const context = "preserveRetrospectiveCursorTimestamps";
|
|
38
|
+
try {
|
|
39
|
+
const mdb = memoryDbOrNull(context);
|
|
40
|
+
if (!mdb || !ensureRetrospectiveCursorColumn(context)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const state = mdb
|
|
44
|
+
.select({
|
|
45
|
+
messageId: memoryRetrospectiveState.lastProcessedMessageId,
|
|
46
|
+
createdAt: memoryRetrospectiveState.lastProcessedCreatedAt,
|
|
47
|
+
})
|
|
48
|
+
.from(memoryRetrospectiveState)
|
|
49
|
+
.where(eq(memoryRetrospectiveState.conversationId, conversationId))
|
|
50
|
+
.get();
|
|
51
|
+
if (!state || state.createdAt !== null) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const row = rows.find((candidate) => candidate.id === state.messageId);
|
|
55
|
+
if (!row) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await withSqliteRetry(
|
|
59
|
+
() =>
|
|
60
|
+
mdb
|
|
61
|
+
.update(memoryRetrospectiveState)
|
|
62
|
+
.set({ lastProcessedCreatedAt: row.createdAt })
|
|
63
|
+
.where(
|
|
64
|
+
and(
|
|
65
|
+
eq(memoryRetrospectiveState.conversationId, conversationId),
|
|
66
|
+
eq(memoryRetrospectiveState.lastProcessedMessageId, row.id),
|
|
67
|
+
isNull(memoryRetrospectiveState.lastProcessedCreatedAt),
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
.run(),
|
|
71
|
+
{ op: context, context: { conversationId } },
|
|
72
|
+
);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
log.warn(
|
|
75
|
+
{ err, conversationId },
|
|
76
|
+
"could not preserve the retrospective cursor timestamp before its row was deleted",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective: the cursor a state row hands to the messages-after
|
|
3
|
+
// reads.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
import type { MessageCursor } from "../../../persistence/message-cursor.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The `(createdAt, id)` cursor a retrospective state row carries, or null
|
|
10
|
+
* when nothing has been processed yet (no row, or the `""` sentinel left by
|
|
11
|
+
* failure-only attempts). The timestamp lets the reads keep their bound after
|
|
12
|
+
* the cursor's row is deleted, which is what a regenerated reply does to the
|
|
13
|
+
* latest assistant message the cursor usually sits on.
|
|
14
|
+
*/
|
|
15
|
+
export function retrospectiveCursor(
|
|
16
|
+
state: {
|
|
17
|
+
lastProcessedMessageId: string;
|
|
18
|
+
lastProcessedCreatedAt?: number | null;
|
|
19
|
+
} | null,
|
|
20
|
+
): MessageCursor | null {
|
|
21
|
+
if (!state || state.lastProcessedMessageId === "") {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
id: state.lastProcessedMessageId,
|
|
26
|
+
createdAt: state.lastProcessedCreatedAt ?? null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -47,6 +47,7 @@ import { resolveCapabilities } from "../../../runtime/capabilities.js";
|
|
|
47
47
|
import { getLogger } from "./logging.js";
|
|
48
48
|
import { hasQualifyingUserMessageAfter } from "./memory-retrospective-accounting.js";
|
|
49
49
|
import { isMemoryRetrospectiveSource } from "./memory-retrospective-constants.js";
|
|
50
|
+
import { retrospectiveCursor } from "./memory-retrospective-cursor.js";
|
|
50
51
|
import { getRetrospectiveState } from "./memory-retrospective-state.js";
|
|
51
52
|
|
|
52
53
|
const log = getLogger("memory-retrospective-enqueue");
|
|
@@ -139,7 +140,7 @@ function isRetrospectiveEnabled(): boolean {
|
|
|
139
140
|
/**
|
|
140
141
|
* The `memory.retrospective.requireUserActivity` gate: pass when the config
|
|
141
142
|
* is off or the unprocessed tail (everything after the conversation's
|
|
142
|
-
*
|
|
143
|
+
* retrospective cursor) contains at least one user message carrying
|
|
143
144
|
* non-tool_result content. A gate that cannot be evaluated (config or DB
|
|
144
145
|
* unavailable) passes — an unevaluable gate must not silence retrospectives.
|
|
145
146
|
*/
|
|
@@ -153,10 +154,7 @@ function passesUserActivityGate(
|
|
|
153
154
|
}
|
|
154
155
|
const state = getRetrospectiveState(conversationId);
|
|
155
156
|
if (
|
|
156
|
-
hasQualifyingUserMessageAfter(
|
|
157
|
-
conversationId,
|
|
158
|
-
state?.lastProcessedMessageId ?? null,
|
|
159
|
-
)
|
|
157
|
+
hasQualifyingUserMessageAfter(conversationId, retrospectiveCursor(state))
|
|
160
158
|
) {
|
|
161
159
|
return true;
|
|
162
160
|
}
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
parseClientOs,
|
|
59
59
|
parseInterfaceId,
|
|
60
60
|
} from "../../../channels/types.js";
|
|
61
|
-
import {
|
|
61
|
+
import { isSkillImprovementActive } from "../../../config/memory-v3-gate.js";
|
|
62
62
|
import type { AssistantConfig } from "../../../config/types.js";
|
|
63
63
|
import { warmGuardianBindings } from "../../../contacts/guardian-delivery-reader.js";
|
|
64
64
|
import { extractTurnContextTimestamp } from "../../../context/compactor.js";
|
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
MEMORY_RETROSPECTIVE_SOURCE,
|
|
96
96
|
SKILL_MANAGEMENT_SKILL_ID,
|
|
97
97
|
} from "./memory-retrospective-constants.js";
|
|
98
|
+
import { retrospectiveCursor } from "./memory-retrospective-cursor.js";
|
|
98
99
|
import { loadRetrospectiveRunMessages } from "./memory-retrospective-fork-boundary.js";
|
|
99
100
|
import { buildForkInstruction } from "./memory-retrospective-prompt.js";
|
|
100
101
|
import {
|
|
@@ -357,7 +358,7 @@ export async function runForkBasedRetrospective(
|
|
|
357
358
|
// `memory-retrospective-accounting.ts`.
|
|
358
359
|
const newMessages = getRetrospectiveMessagesAfter(
|
|
359
360
|
sourceConversationId,
|
|
360
|
-
|
|
361
|
+
retrospectiveCursor(state),
|
|
361
362
|
);
|
|
362
363
|
|
|
363
364
|
if (newMessages.length === 0) {
|
|
@@ -448,7 +449,7 @@ export async function runForkBasedRetrospective(
|
|
|
448
449
|
}
|
|
449
450
|
const forkId = forkConversationRow.id;
|
|
450
451
|
|
|
451
|
-
const procToSkillsActive =
|
|
452
|
+
const procToSkillsActive = isSkillImprovementActive(config);
|
|
452
453
|
const instruction = buildForkInstruction({
|
|
453
454
|
windowStartTimestamp,
|
|
454
455
|
windowAnchorKind: turnContextTimestamp ? "turn_context" : "created_at",
|
|
@@ -650,6 +651,7 @@ export async function runForkBasedRetrospective(
|
|
|
650
651
|
sourceConversationId,
|
|
651
652
|
retrospectiveConversationId: forkId,
|
|
652
653
|
cutoffMessageId,
|
|
654
|
+
cutoffCreatedAt: cutoffMessage.createdAt,
|
|
653
655
|
newMessageCount: newMessages.length,
|
|
654
656
|
prior,
|
|
655
657
|
priorRemembers,
|
|
@@ -947,6 +949,11 @@ async function finalizeSuccessfulRetrospective(args: {
|
|
|
947
949
|
sourceConversationId: string;
|
|
948
950
|
retrospectiveConversationId: string;
|
|
949
951
|
cutoffMessageId: string;
|
|
952
|
+
/**
|
|
953
|
+
* `createdAt` of the cutoff row, persisted beside its id so the cursor
|
|
954
|
+
* keeps bounding reads after the row is deleted.
|
|
955
|
+
*/
|
|
956
|
+
cutoffCreatedAt: number;
|
|
950
957
|
newMessageCount: number;
|
|
951
958
|
prior: PriorRetrospective | null;
|
|
952
959
|
priorRemembers: string[];
|
|
@@ -966,6 +973,7 @@ async function finalizeSuccessfulRetrospective(args: {
|
|
|
966
973
|
sourceConversationId,
|
|
967
974
|
retrospectiveConversationId,
|
|
968
975
|
cutoffMessageId,
|
|
976
|
+
cutoffCreatedAt,
|
|
969
977
|
newMessageCount,
|
|
970
978
|
prior,
|
|
971
979
|
priorRemembers,
|
|
@@ -977,6 +985,7 @@ async function finalizeSuccessfulRetrospective(args: {
|
|
|
977
985
|
await upsertRetrospectiveState({
|
|
978
986
|
conversationId: sourceConversationId,
|
|
979
987
|
lastProcessedMessageId: cutoffMessageId,
|
|
988
|
+
lastProcessedCreatedAt: cutoffCreatedAt,
|
|
980
989
|
lastRunAt: Date.now(),
|
|
981
990
|
rememberedLog: appendToRememberedLog(priorRemembers, runRemembers),
|
|
982
991
|
});
|
|
@@ -223,7 +223,7 @@ If your review window contains a PROCEDURE you actually carried out — a sequen
|
|
|
223
223
|
|
|
224
224
|
When you do capture a procedure:
|
|
225
225
|
|
|
226
|
-
1. Deduplicate against existing skills first. Call \`find_similar_skills\` with the procedure's goal as its \`goal\` argument. Each hit carries a \`source\` (bundled, managed, plugin, workspace, or extra), and a managed hit also carries \`author\` (\`"assistant"\` if you authored it, \`"user"\` if a person did, omitted if untagged). You may only overwrite or refine a skill YOU authored
|
|
226
|
+
1. Deduplicate against existing skills first. Call \`find_similar_skills\` with the procedure's goal as its \`goal\` argument. Each hit carries a \`source\` (bundled, managed, plugin, workspace, or extra), and a managed hit also carries \`author\` (\`"assistant"\` if you authored it, \`"user"\` if a person did, omitted if untagged). You may only overwrite or refine a skill YOU authored: a hit with \`source: "managed"\` AND \`author: "assistant"\`. ANY other hit means the procedure is ALREADY COVERED: a non-managed source (bundled, plugin, workspace, or extra), OR a managed skill that is NOT \`author: "assistant"\` (a person wrote it, or it is untagged). For an ALREADY COVERED hit do not \`overwrite\` it, do not shadow it by creating a skill with its \`skill_id\`, and do not create a near-duplicate. Skip it. Only when a returned skill is one of your own (\`source: "managed"\`, \`author: "assistant"\`) and is the SAME procedure, UPDATE it: call \`scaffold_managed_skill\` with that \`skill_id\` and \`overwrite: true\`, rewriting \`body_markdown\` from what you actually observed in the trace, and pass \`change_summary\` (the update is rejected without it): one or two short sentences (under 200 characters) for the person who reads the "Skill updated" notice, naming what you changed and what in the trace prompted it (for example "Added the retry after an expired session and the export endpoint that held steady."). The notice shows nothing else about the change, so name the concrete step, value, or gotcha rather than saying the skill was refined. Only CREATE a new skill (fresh \`skill_id\`) when no existing skill of any source covers the procedure. Bias strongly toward reusing or refining your own skills over spawning near-duplicates.
|
|
227
227
|
|
|
228
228
|
2. Capture procedure-scoped knowledge alongside the body. Failure modes, gotchas, and cached values you observed in the trace (error signatures and how you recovered, preconditions, IDs/paths/endpoints that held steady) belong in companion files passed via \`scaffold_managed_skill\`'s \`files\` input (for example \`references/failure-modes.md\`), and the SKILL.md body should reference them so a future load surfaces them.
|
|
229
229
|
|