@vellumai/assistant 0.12.1-staging.1 → 0.12.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 +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/openapi.yaml +1 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- 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 +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +1 -2
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- 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 +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +0 -93
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -8
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +21 -75
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- 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-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +0 -2
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +21 -8
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -117
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -144
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
-
import { tableExists } from "./schema-introspection.js";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Add a required contact_id column to assistant_ingress_invites.
|
|
@@ -11,16 +10,8 @@ import { tableExists } from "./schema-introspection.js";
|
|
|
11
10
|
* 1. Add the column as nullable.
|
|
12
11
|
* 2. Delete legacy rows that have no contact binding (NULL).
|
|
13
12
|
* 3. Rebuild the table to enforce NOT NULL (SQLite cannot ALTER COLUMN).
|
|
14
|
-
*
|
|
15
|
-
* The rebuild copies whichever session-id column is live:
|
|
16
|
-
* `source_conversation_id` (after migrateRenameCreatedBySessionIdColumns)
|
|
17
|
-
* or `created_by_session_id`.
|
|
18
13
|
*/
|
|
19
14
|
export function migrateInviteContactId(database: DrizzleDb): void {
|
|
20
|
-
if (!tableExists(database, "assistant_ingress_invites")) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
15
|
const raw = getSqliteFrom(database);
|
|
25
16
|
|
|
26
17
|
const cols = (
|
|
@@ -29,28 +20,25 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
29
20
|
notnull: number;
|
|
30
21
|
}>
|
|
31
22
|
).map((c) => ({ name: c.name, notnull: c.notnull }));
|
|
32
|
-
const colNames = new Set(cols.map((c) => c.name));
|
|
33
23
|
|
|
34
24
|
const col = cols.find((c) => c.name === "contact_id");
|
|
35
25
|
|
|
26
|
+
// Step 1: Add the column as nullable
|
|
36
27
|
if (!col) {
|
|
37
28
|
raw.exec(
|
|
38
29
|
/*sql*/ `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
|
|
39
30
|
);
|
|
40
31
|
}
|
|
41
32
|
|
|
33
|
+
// Step 2: Delete legacy rows with no contact binding
|
|
42
34
|
raw.exec(
|
|
43
35
|
/*sql*/ `DELETE FROM assistant_ingress_invites WHERE contact_id IS NULL OR contact_id = ''`,
|
|
44
36
|
);
|
|
45
37
|
|
|
38
|
+
// Step 3: Rebuild the table with NOT NULL on contact_id
|
|
46
39
|
if (col && col.notnull === 1) {
|
|
47
40
|
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const sessionCol = colNames.has("source_conversation_id")
|
|
51
|
-
? "source_conversation_id"
|
|
52
|
-
: "created_by_session_id";
|
|
53
|
-
const sessionSelect = colNames.has(sessionCol) ? sessionCol : "NULL";
|
|
41
|
+
} // already NOT NULL
|
|
54
42
|
|
|
55
43
|
raw.exec("PRAGMA foreign_keys = OFF");
|
|
56
44
|
try {
|
|
@@ -61,7 +49,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
61
49
|
id TEXT PRIMARY KEY,
|
|
62
50
|
source_channel TEXT NOT NULL,
|
|
63
51
|
token_hash TEXT NOT NULL,
|
|
64
|
-
|
|
52
|
+
created_by_session_id TEXT,
|
|
65
53
|
note TEXT,
|
|
66
54
|
max_uses INTEGER NOT NULL DEFAULT 1 CHECK (max_uses > 0),
|
|
67
55
|
use_count INTEGER NOT NULL DEFAULT 0 CHECK (use_count >= 0),
|
|
@@ -82,7 +70,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
82
70
|
);
|
|
83
71
|
|
|
84
72
|
INSERT INTO assistant_ingress_invites_new
|
|
85
|
-
SELECT id, source_channel, token_hash,
|
|
73
|
+
SELECT id, source_channel, token_hash, created_by_session_id, note,
|
|
86
74
|
max_uses, use_count, expires_at, status,
|
|
87
75
|
redeemed_by_external_user_id, redeemed_by_external_chat_id,
|
|
88
76
|
redeemed_at, expected_external_user_id, voice_code_hash,
|
|
@@ -104,11 +104,6 @@ export const memoryRetrospectiveState = sqliteTable(
|
|
|
104
104
|
conversationId: text("conversation_id").primaryKey(),
|
|
105
105
|
lastProcessedMessageId: text("last_processed_message_id").notNull(),
|
|
106
106
|
lastRunAt: integer("last_run_at").notNull(),
|
|
107
|
-
// `createdAt` of the `last_processed_message_id` row when the pointer was
|
|
108
|
-
// written, so the cursor still bounds reads after that row is deleted.
|
|
109
|
-
// NULL when unknown. Added lazily by `ensureRetrospectiveCursorColumn`
|
|
110
|
-
// (memory-retrospective-state.ts), not by the migration chain.
|
|
111
|
-
lastProcessedCreatedAt: integer("last_processed_created_at"),
|
|
112
107
|
// JSON array of strings — cumulative `remember` contents from prior
|
|
113
108
|
// retrospective passes (capped; see memory-retrospective-state.ts).
|
|
114
109
|
// NULL for rows that predate migration 281 or have no saves yet.
|
|
@@ -24,9 +24,7 @@ mock.module("../providers/platform-proxy/context.js", () => ({
|
|
|
24
24
|
resolveManagedProxyContext: () => mockResolveManagedProxyContext(),
|
|
25
25
|
}));
|
|
26
26
|
|
|
27
|
-
const actualEnv = await import("../config/env.js");
|
|
28
27
|
mock.module("../config/env.js", () => ({
|
|
29
|
-
...actualEnv,
|
|
30
28
|
getPlatformAssistantId: () => mockAssistantId,
|
|
31
29
|
}));
|
|
32
30
|
|
package/src/platform/client.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { PlatformCredentialVerificationStatus } from "@vellumai/service-contracts/platform-credential";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { getPlatformAssistantId } from "../config/env.js";
|
|
11
11
|
import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js";
|
|
12
12
|
import { credentialKey } from "../security/credential-key.js";
|
|
13
13
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -63,7 +63,7 @@ async function resolvePlatformClientConfig(): Promise<PlatformClientConfig | nul
|
|
|
63
63
|
|
|
64
64
|
let baseUrl = ctx.enabled ? ctx.platformBaseUrl : "";
|
|
65
65
|
let apiKey = ctx.enabled ? ctx.assistantApiKey : "";
|
|
66
|
-
|
|
66
|
+
let assistantId = getPlatformAssistantId();
|
|
67
67
|
|
|
68
68
|
// Fall back to credential store for values not yet rehydrated (standalone CLI).
|
|
69
69
|
if (!baseUrl) {
|
|
@@ -76,6 +76,14 @@ async function resolvePlatformClientConfig(): Promise<PlatformClientConfig | nul
|
|
|
76
76
|
(await getSecureKeyAsync(credentialKey("vellum", "assistant_api_key"))) ??
|
|
77
77
|
"";
|
|
78
78
|
}
|
|
79
|
+
if (!assistantId) {
|
|
80
|
+
assistantId =
|
|
81
|
+
(
|
|
82
|
+
await getSecureKeyAsync(
|
|
83
|
+
credentialKey("vellum", "platform_assistant_id"),
|
|
84
|
+
)
|
|
85
|
+
)?.trim() ?? "";
|
|
86
|
+
}
|
|
79
87
|
|
|
80
88
|
if (!baseUrl || !apiKey) {
|
|
81
89
|
const level = _missingPrereqsWarned ? "debug" : "warn";
|
|
@@ -34,8 +34,6 @@ export const HOOKS = {
|
|
|
34
34
|
CONVERSATION_DELETED: "conversation-deleted",
|
|
35
35
|
/** Fires once when every conversation is wiped at once (the clear-all reset), after the main tables are cleared. Carries no `conversationId`; cleanup hooks wipe their own per-conversation state wholesale. */
|
|
36
36
|
CONVERSATIONS_CLEARED: "conversations-cleared",
|
|
37
|
-
/** Fires once per deleted message row, after the row is removed, carrying the row's `(createdAt, id)` so a hook can settle state that pointed at it. Fire-and-forget cleanup signal, like `conversation-deleted`; whole-conversation deletes dispatch that hook instead. */
|
|
38
|
-
MESSAGE_DELETED: "message-deleted",
|
|
39
37
|
} as const;
|
|
40
38
|
|
|
41
39
|
/** Union of every hook name declared in {@link HOOKS}. */
|
package/src/plugin-api/index.ts
CHANGED
package/src/plugin-api/types.ts
CHANGED
|
@@ -16,7 +16,6 @@ export type {
|
|
|
16
16
|
ConversationDeletedContext,
|
|
17
17
|
ConversationsClearedContext,
|
|
18
18
|
HookBroadcast,
|
|
19
|
-
MessageDeletedContext,
|
|
20
19
|
PluginLogger,
|
|
21
20
|
PostCompactContext,
|
|
22
21
|
PostModelCallContext,
|
|
@@ -61,7 +60,6 @@ export type {
|
|
|
61
60
|
* - `post-model-call` — {@link PostModelCallContext}
|
|
62
61
|
* - `conversation-deleted` — {@link ConversationDeletedContext}
|
|
63
62
|
* - `conversations-cleared` — {@link ConversationsClearedContext}
|
|
64
|
-
* - `message-deleted`: {@link MessageDeletedContext}
|
|
65
63
|
*/
|
|
66
64
|
export type HookFunction<TCtx = unknown> = (
|
|
67
65
|
ctx: TCtx,
|
|
@@ -65,7 +65,6 @@ import maxTokensContinuePkg from "./max-tokens-continue/package.json" with { typ
|
|
|
65
65
|
import memoryConversationDeleted from "./memory/hooks/conversation-deleted.js";
|
|
66
66
|
import memoryConversationsCleared from "./memory/hooks/conversations-cleared.js";
|
|
67
67
|
import memoryInit from "./memory/hooks/init.js";
|
|
68
|
-
import memoryMessageDeleted from "./memory/hooks/message-deleted.js";
|
|
69
68
|
import memoryPostCompact from "./memory/hooks/post-compact.js";
|
|
70
69
|
import memoryShutdown from "./memory/hooks/shutdown.js";
|
|
71
70
|
import memoryUserPromptSubmit from "./memory/hooks/user-prompt-submit.js";
|
|
@@ -200,7 +199,6 @@ export const defaultMemoryPlugin: Plugin = {
|
|
|
200
199
|
"post-compact": memoryPostCompact,
|
|
201
200
|
"conversation-deleted": memoryConversationDeleted,
|
|
202
201
|
"conversations-cleared": memoryConversationsCleared,
|
|
203
|
-
"message-deleted": memoryMessageDeleted,
|
|
204
202
|
},
|
|
205
203
|
injectors: memoryInjectors,
|
|
206
204
|
};
|
|
@@ -434,49 +434,3 @@ describe("ambient camera frames are not retrospective work", () => {
|
|
|
434
434
|
expect(hasQualifyingUserMessageAfter(CONV, null)).toBe(true);
|
|
435
435
|
});
|
|
436
436
|
});
|
|
437
|
-
|
|
438
|
-
describe("retrospective accounting: a cursor survives its row's deletion", () => {
|
|
439
|
-
beforeEach(() => {
|
|
440
|
-
const db = getDb();
|
|
441
|
-
db.run(`DELETE FROM messages`);
|
|
442
|
-
db.run(`DELETE FROM conversations`);
|
|
443
|
-
createConversation({ id: CONV });
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
test("a deleted cursor row with a stored timestamp still bounds the count, the slice, and the user-activity probe", () => {
|
|
447
|
-
insertRaw({ role: "user", content: TEXT, createdAt: 1_000 });
|
|
448
|
-
const reply = insertRaw({
|
|
449
|
-
role: "assistant",
|
|
450
|
-
content: TEXT,
|
|
451
|
-
createdAt: 2_000,
|
|
452
|
-
});
|
|
453
|
-
// Regenerate: the reply the cursor sits on is discarded and replaced.
|
|
454
|
-
getDb().delete(messages).where(eq(messages.id, reply)).run();
|
|
455
|
-
const regenerated = insertRaw({
|
|
456
|
-
role: "assistant",
|
|
457
|
-
content: TEXT,
|
|
458
|
-
createdAt: 3_000,
|
|
459
|
-
});
|
|
460
|
-
const followUp = insertRaw({
|
|
461
|
-
role: "user",
|
|
462
|
-
content: TEXT,
|
|
463
|
-
createdAt: 4_000,
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
const cursor = { id: reply, createdAt: 2_000 };
|
|
467
|
-
expect(countRetrospectiveMessagesAfter(CONV, cursor)).toBe(2);
|
|
468
|
-
expect(
|
|
469
|
-
getRetrospectiveMessagesAfter(CONV, cursor).map((r) => r.id),
|
|
470
|
-
).toEqual([regenerated, followUp]);
|
|
471
|
-
expect(hasQualifyingUserMessageAfter(CONV, cursor)).toBe(true);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
test("a deleted cursor row without a timestamp still reads as no new work", () => {
|
|
475
|
-
insertRaw({ role: "user", content: TEXT, createdAt: 1_000 });
|
|
476
|
-
|
|
477
|
-
const cursor = { id: "gone", createdAt: null };
|
|
478
|
-
expect(countRetrospectiveMessagesAfter(CONV, cursor)).toBe(0);
|
|
479
|
-
expect(getRetrospectiveMessagesAfter(CONV, cursor)).toEqual([]);
|
|
480
|
-
expect(hasQualifyingUserMessageAfter(CONV, cursor)).toBe(false);
|
|
481
|
-
});
|
|
482
|
-
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import type { MessagesAfterRef } from "../../../../persistence/message-cursor.js";
|
|
4
|
-
|
|
5
3
|
// ---------------------------------------------------------------------------
|
|
6
4
|
// Mock state — reset between tests.
|
|
7
5
|
// ---------------------------------------------------------------------------
|
|
@@ -19,7 +17,6 @@ let cfgThrows = false;
|
|
|
19
17
|
let mockStateRow: {
|
|
20
18
|
conversationId: string;
|
|
21
19
|
lastProcessedMessageId: string;
|
|
22
|
-
lastProcessedCreatedAt: number | null;
|
|
23
20
|
lastRunAt: number;
|
|
24
21
|
rememberedLog: string[];
|
|
25
22
|
} | null = null;
|
|
@@ -27,7 +24,7 @@ let tailQualifies = true;
|
|
|
27
24
|
let gateProbeThrows = false;
|
|
28
25
|
let gateProbeCalls: Array<{
|
|
29
26
|
conversationId: string;
|
|
30
|
-
|
|
27
|
+
afterMessageId: string | null;
|
|
31
28
|
}> = [];
|
|
32
29
|
|
|
33
30
|
mock.module("../../../../persistence/conversation-crud.js", () => ({
|
|
@@ -71,9 +68,9 @@ mock.module("../memory-retrospective-state.js", () => ({
|
|
|
71
68
|
mock.module("../memory-retrospective-accounting.js", () => ({
|
|
72
69
|
hasQualifyingUserMessageAfter: (
|
|
73
70
|
conversationId: string,
|
|
74
|
-
|
|
71
|
+
afterMessageId: string | null,
|
|
75
72
|
) => {
|
|
76
|
-
gateProbeCalls.push({ conversationId,
|
|
73
|
+
gateProbeCalls.push({ conversationId, afterMessageId });
|
|
77
74
|
if (gateProbeThrows) {
|
|
78
75
|
throw new Error("messages table unavailable");
|
|
79
76
|
}
|
|
@@ -173,11 +170,10 @@ describe("enqueueMemoryRetrospectiveIfEnabled", () => {
|
|
|
173
170
|
expect(gateProbeCalls).toHaveLength(0);
|
|
174
171
|
});
|
|
175
172
|
|
|
176
|
-
test("gate probes the tail from the state row's cursor
|
|
173
|
+
test("gate probes the tail from the state row's cursor", () => {
|
|
177
174
|
mockStateRow = {
|
|
178
175
|
conversationId: "c1",
|
|
179
176
|
lastProcessedMessageId: "m9",
|
|
180
|
-
lastProcessedCreatedAt: 9_000,
|
|
181
177
|
lastRunAt: 1,
|
|
182
178
|
rememberedLog: [],
|
|
183
179
|
};
|
|
@@ -187,7 +183,7 @@ describe("enqueueMemoryRetrospectiveIfEnabled", () => {
|
|
|
187
183
|
});
|
|
188
184
|
|
|
189
185
|
expect(gateProbeCalls).toEqual([
|
|
190
|
-
{ conversationId: "c1",
|
|
186
|
+
{ conversationId: "c1", afterMessageId: "m9" },
|
|
191
187
|
]);
|
|
192
188
|
});
|
|
193
189
|
|
|
@@ -20,7 +20,6 @@ let mockState: StateRow = null;
|
|
|
20
20
|
let stateUpserts: Array<{
|
|
21
21
|
conversationId: string;
|
|
22
22
|
lastProcessedMessageId: string;
|
|
23
|
-
lastProcessedCreatedAt?: number | null;
|
|
24
23
|
lastRunAt: number;
|
|
25
24
|
rememberedLog?: string[];
|
|
26
25
|
}> = [];
|
|
@@ -150,7 +149,6 @@ mock.module("../memory-retrospective-state.js", () => ({
|
|
|
150
149
|
upsertRetrospectiveState: (args: {
|
|
151
150
|
conversationId: string;
|
|
152
151
|
lastProcessedMessageId: string;
|
|
153
|
-
lastProcessedCreatedAt?: number | null;
|
|
154
152
|
lastRunAt: number;
|
|
155
153
|
rememberedLog?: string[];
|
|
156
154
|
}) => {
|
|
@@ -334,16 +332,15 @@ mock.module("../../../../persistence/jobs-store.js", () => ({
|
|
|
334
332
|
},
|
|
335
333
|
}));
|
|
336
334
|
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
let
|
|
335
|
+
// The v3-tier gate. Drives both `buildForkInstruction`'s skill-authoring
|
|
336
|
+
// section (proc-to-skills) and the wake's origin pin behavior. Default inactive
|
|
337
|
+
// (remember-only), matching a stock install; tests flip it on to assert the
|
|
338
|
+
// authoring section.
|
|
339
|
+
let mockV3TierActive = false;
|
|
342
340
|
mock.module("../../../../config/memory-v3-gate.js", () => ({
|
|
343
341
|
isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
|
|
344
342
|
config?.memory?.enabled !== false,
|
|
345
343
|
isV3TierActive: () => mockV3TierActive,
|
|
346
|
-
isSkillImprovementActive: () => mockSkillImprovementActive,
|
|
347
344
|
isMemoryV3Live: () => mockV3TierActive,
|
|
348
345
|
usesConceptPageMemory: (memory?: {
|
|
349
346
|
enabled?: boolean;
|
|
@@ -507,8 +504,7 @@ describe("memoryRetrospectiveJob", () => {
|
|
|
507
504
|
processingStartedAtById = {};
|
|
508
505
|
mockResolvedUserSlug = "alice";
|
|
509
506
|
resolveUserSlugCalls = [];
|
|
510
|
-
mockV3TierActive =
|
|
511
|
-
mockSkillImprovementActive = false;
|
|
507
|
+
mockV3TierActive = false;
|
|
512
508
|
});
|
|
513
509
|
|
|
514
510
|
test("first-run happy path: no state row, no prior retrospective, both pointer fields set on success", async () => {
|
|
@@ -522,11 +518,6 @@ describe("memoryRetrospectiveJob", () => {
|
|
|
522
518
|
}
|
|
523
519
|
expect(stateUpserts).toHaveLength(1);
|
|
524
520
|
expect(stateUpserts[0]!.lastProcessedMessageId).toBe("m3");
|
|
525
|
-
// The cutoff's `createdAt` rides along so the cursor keeps bounding reads
|
|
526
|
-
// after a regenerate deletes m3.
|
|
527
|
-
expect(stateUpserts[0]!.lastProcessedCreatedAt).toBe(
|
|
528
|
-
Date.parse("2026-05-11T10:10:00Z"),
|
|
529
|
-
);
|
|
530
521
|
expect(lastRunAtBumps).toHaveLength(0);
|
|
531
522
|
expect(wakeCalls).toHaveLength(1);
|
|
532
523
|
// Forks off the source so future runs can find it via
|
|
@@ -1317,7 +1308,7 @@ describe("memoryRetrospectiveJob", () => {
|
|
|
1317
1308
|
});
|
|
1318
1309
|
|
|
1319
1310
|
test("wake allows memory saves + skill authoring and suppresses the internal wake surface", async () => {
|
|
1320
|
-
|
|
1311
|
+
mockV3TierActive = true;
|
|
1321
1312
|
await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
1322
1313
|
|
|
1323
1314
|
expect(forkCalls).toHaveLength(1);
|
|
@@ -1340,9 +1331,8 @@ describe("memoryRetrospectiveJob", () => {
|
|
|
1340
1331
|
expect(opts.hintRole).toBe("user");
|
|
1341
1332
|
});
|
|
1342
1333
|
|
|
1343
|
-
test("wake is remember-only when
|
|
1344
|
-
mockV3TierActive =
|
|
1345
|
-
mockSkillImprovementActive = false;
|
|
1334
|
+
test("wake is remember-only when proc-to-skills is inactive", async () => {
|
|
1335
|
+
mockV3TierActive = false;
|
|
1346
1336
|
await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
1347
1337
|
|
|
1348
1338
|
expect(wakeCalls).toHaveLength(1);
|
|
@@ -2548,7 +2538,7 @@ describe("memoryRetrospectiveJob", () => {
|
|
|
2548
2538
|
});
|
|
2549
2539
|
|
|
2550
2540
|
test("proc-to-skills active: instruction carries the pre-check + dedup + companion-file directives", async () => {
|
|
2551
|
-
|
|
2541
|
+
mockV3TierActive = true;
|
|
2552
2542
|
|
|
2553
2543
|
await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
2554
2544
|
|
|
@@ -6,22 +6,16 @@ import { setConfig } from "../../../../__tests__/helpers/set-config.js";
|
|
|
6
6
|
// pipeline (both flags default true under the real loader).
|
|
7
7
|
setConfig("memory", { enabled: false, v2: { enabled: false } });
|
|
8
8
|
|
|
9
|
-
import { createConversation } from "../../../../persistence/conversation-crud.js";
|
|
10
9
|
import {
|
|
11
10
|
getDb,
|
|
12
11
|
getMemorySqlite,
|
|
13
|
-
resetDb,
|
|
14
12
|
} from "../../../../persistence/db-connection.js";
|
|
15
13
|
import { initializeDb } from "../../../../persistence/db-init.js";
|
|
16
|
-
import { messages } from "../../../../persistence/schema/index.js";
|
|
17
14
|
import {
|
|
18
|
-
_resetRetrospectiveCursorColumnForTests,
|
|
19
15
|
appendToRememberedLog,
|
|
20
16
|
bumpRetrospectiveLastRunAt,
|
|
21
|
-
ensureRetrospectiveCursorColumn,
|
|
22
17
|
forkRetrospectiveState,
|
|
23
18
|
getRetrospectiveState,
|
|
24
|
-
listRetrospectiveStates,
|
|
25
19
|
REMEMBERED_LOG_MAX_BYTES,
|
|
26
20
|
REMEMBERED_LOG_MAX_ENTRIES,
|
|
27
21
|
upsertRetrospectiveState,
|
|
@@ -182,219 +176,6 @@ describe("memory-retrospective-state remembered log persistence", () => {
|
|
|
182
176
|
});
|
|
183
177
|
});
|
|
184
178
|
|
|
185
|
-
describe("memory-retrospective-state cursor timestamp", () => {
|
|
186
|
-
beforeEach(() => {
|
|
187
|
-
resetTables();
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test("upsert persists lastProcessedCreatedAt and both reads return it", async () => {
|
|
191
|
-
await upsertRetrospectiveState({
|
|
192
|
-
conversationId: "conv-ts",
|
|
193
|
-
lastProcessedMessageId: "m1",
|
|
194
|
-
lastProcessedCreatedAt: 1_234,
|
|
195
|
-
lastRunAt: 1000,
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
expect(getRetrospectiveState("conv-ts")?.lastProcessedCreatedAt).toBe(
|
|
199
|
-
1_234,
|
|
200
|
-
);
|
|
201
|
-
expect(
|
|
202
|
-
listRetrospectiveStates(10).find((s) => s.conversationId === "conv-ts")
|
|
203
|
-
?.lastProcessedCreatedAt,
|
|
204
|
-
).toBe(1_234);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("an upsert that omits the timestamp records unknown for the new pointer", async () => {
|
|
208
|
-
await upsertRetrospectiveState({
|
|
209
|
-
conversationId: "conv-ts",
|
|
210
|
-
lastProcessedMessageId: "m1",
|
|
211
|
-
lastProcessedCreatedAt: 1_234,
|
|
212
|
-
lastRunAt: 1000,
|
|
213
|
-
});
|
|
214
|
-
await upsertRetrospectiveState({
|
|
215
|
-
conversationId: "conv-ts",
|
|
216
|
-
lastProcessedMessageId: "m2",
|
|
217
|
-
lastRunAt: 2000,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const state = getRetrospectiveState("conv-ts");
|
|
221
|
-
expect(state?.lastProcessedMessageId).toBe("m2");
|
|
222
|
-
expect(state?.lastProcessedCreatedAt).toBeNull();
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("bumpRetrospectiveLastRunAt leaves the timestamp untouched", async () => {
|
|
226
|
-
await upsertRetrospectiveState({
|
|
227
|
-
conversationId: "conv-ts",
|
|
228
|
-
lastProcessedMessageId: "m1",
|
|
229
|
-
lastProcessedCreatedAt: 1_234,
|
|
230
|
-
lastRunAt: 1000,
|
|
231
|
-
});
|
|
232
|
-
await bumpRetrospectiveLastRunAt("conv-ts", 5000);
|
|
233
|
-
|
|
234
|
-
const state = getRetrospectiveState("conv-ts");
|
|
235
|
-
expect(state?.lastRunAt).toBe(5000);
|
|
236
|
-
expect(state?.lastProcessedCreatedAt).toBe(1_234);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
test("forking carries the forked pointer's createdAt, read through the main handle", async () => {
|
|
240
|
-
const db = getDb();
|
|
241
|
-
createConversation({ id: "conv-fork-ts-src" });
|
|
242
|
-
createConversation({ id: "conv-fork-ts-dst" });
|
|
243
|
-
for (const [id, conversationId] of [
|
|
244
|
-
["src-m1", "conv-fork-ts-src"],
|
|
245
|
-
["dst-m1", "conv-fork-ts-dst"],
|
|
246
|
-
] as const) {
|
|
247
|
-
db.insert(messages)
|
|
248
|
-
.values({
|
|
249
|
-
id,
|
|
250
|
-
conversationId,
|
|
251
|
-
role: "user",
|
|
252
|
-
content: "[]",
|
|
253
|
-
createdAt: 4_000,
|
|
254
|
-
metadata: null,
|
|
255
|
-
})
|
|
256
|
-
.run();
|
|
257
|
-
}
|
|
258
|
-
await upsertRetrospectiveState({
|
|
259
|
-
conversationId: "conv-fork-ts-src",
|
|
260
|
-
lastProcessedMessageId: "src-m1",
|
|
261
|
-
lastProcessedCreatedAt: 4_000,
|
|
262
|
-
lastRunAt: 1,
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
forkRetrospectiveState({
|
|
266
|
-
database: db,
|
|
267
|
-
sourceConversationId: "conv-fork-ts-src",
|
|
268
|
-
forkedConversationId: "conv-fork-ts-dst",
|
|
269
|
-
forkedMessageIds: new Map([["src-m1", "dst-m1"]]),
|
|
270
|
-
lastCopiedSourceMessageId: "src-m1",
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const child = getRetrospectiveState("conv-fork-ts-dst");
|
|
274
|
-
expect(child?.lastProcessedMessageId).toBe("dst-m1");
|
|
275
|
-
expect(child?.lastProcessedCreatedAt).toBe(4_000);
|
|
276
|
-
|
|
277
|
-
db.run(`DELETE FROM messages`);
|
|
278
|
-
db.run(`DELETE FROM conversations`);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
test("a source cursor whose row was regenerated away is placed by its stored bound, not clamped past the copies", async () => {
|
|
282
|
-
const db = getDb();
|
|
283
|
-
createConversation({ id: "conv-fork-bound-src" });
|
|
284
|
-
createConversation({ id: "conv-fork-bound-dst" });
|
|
285
|
-
// src-m2 (createdAt 2_000) was the cursor; a regenerate deleted it and
|
|
286
|
-
// src-m3 replaced it. The fork copies src-m1 and src-m3.
|
|
287
|
-
for (const [id, conversationId, createdAt] of [
|
|
288
|
-
["src-m1", "conv-fork-bound-src", 1_000],
|
|
289
|
-
["src-m3", "conv-fork-bound-src", 3_000],
|
|
290
|
-
["dst-m1", "conv-fork-bound-dst", 1_000],
|
|
291
|
-
["dst-m3", "conv-fork-bound-dst", 3_000],
|
|
292
|
-
] as const) {
|
|
293
|
-
db.insert(messages)
|
|
294
|
-
.values({
|
|
295
|
-
id,
|
|
296
|
-
conversationId,
|
|
297
|
-
role: "user",
|
|
298
|
-
content: "[]",
|
|
299
|
-
createdAt,
|
|
300
|
-
metadata: null,
|
|
301
|
-
})
|
|
302
|
-
.run();
|
|
303
|
-
}
|
|
304
|
-
await upsertRetrospectiveState({
|
|
305
|
-
conversationId: "conv-fork-bound-src",
|
|
306
|
-
lastProcessedMessageId: "src-m2",
|
|
307
|
-
lastProcessedCreatedAt: 2_000,
|
|
308
|
-
lastRunAt: 1,
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
forkRetrospectiveState({
|
|
312
|
-
database: db,
|
|
313
|
-
sourceConversationId: "conv-fork-bound-src",
|
|
314
|
-
forkedConversationId: "conv-fork-bound-dst",
|
|
315
|
-
forkedMessageIds: new Map([
|
|
316
|
-
["src-m1", "dst-m1"],
|
|
317
|
-
["src-m3", "dst-m3"],
|
|
318
|
-
]),
|
|
319
|
-
lastCopiedSourceMessageId: "src-m3",
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
const child = getRetrospectiveState("conv-fork-bound-dst");
|
|
323
|
-
expect(child?.lastProcessedMessageId).toBe("dst-m1");
|
|
324
|
-
expect(child?.lastProcessedCreatedAt).toBe(1_000);
|
|
325
|
-
|
|
326
|
-
// A bound before every copied row leaves the child with nothing processed.
|
|
327
|
-
await upsertRetrospectiveState({
|
|
328
|
-
conversationId: "conv-fork-bound-src",
|
|
329
|
-
lastProcessedMessageId: "src-m0",
|
|
330
|
-
lastProcessedCreatedAt: 500,
|
|
331
|
-
lastRunAt: 1,
|
|
332
|
-
});
|
|
333
|
-
forkRetrospectiveState({
|
|
334
|
-
database: db,
|
|
335
|
-
sourceConversationId: "conv-fork-bound-src",
|
|
336
|
-
forkedConversationId: "conv-fork-bound-dst",
|
|
337
|
-
forkedMessageIds: new Map([
|
|
338
|
-
["src-m1", "dst-m1"],
|
|
339
|
-
["src-m3", "dst-m3"],
|
|
340
|
-
]),
|
|
341
|
-
lastCopiedSourceMessageId: "src-m3",
|
|
342
|
-
});
|
|
343
|
-
expect(
|
|
344
|
-
getRetrospectiveState("conv-fork-bound-dst")?.lastProcessedMessageId,
|
|
345
|
-
).toBe("");
|
|
346
|
-
|
|
347
|
-
db.run(`DELETE FROM messages`);
|
|
348
|
-
db.run(`DELETE FROM conversations`);
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
test("ensureRetrospectiveCursorColumn adds the column to a legacy table once and is a no-op after", () => {
|
|
352
|
-
const raw = getMemorySqlite()!;
|
|
353
|
-
raw.exec("DROP TABLE memory_retrospective_state");
|
|
354
|
-
raw.exec(`
|
|
355
|
-
CREATE TABLE memory_retrospective_state (
|
|
356
|
-
conversation_id TEXT PRIMARY KEY,
|
|
357
|
-
last_processed_message_id TEXT NOT NULL,
|
|
358
|
-
last_run_at INTEGER NOT NULL,
|
|
359
|
-
remembered_log TEXT
|
|
360
|
-
)
|
|
361
|
-
`);
|
|
362
|
-
_resetRetrospectiveCursorColumnForTests();
|
|
363
|
-
|
|
364
|
-
expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
|
|
365
|
-
expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
|
|
366
|
-
|
|
367
|
-
const columns = raw
|
|
368
|
-
.query("PRAGMA table_info(memory_retrospective_state)")
|
|
369
|
-
.all() as Array<{ name: string }>;
|
|
370
|
-
expect(
|
|
371
|
-
columns.filter((c) => c.name === "last_processed_created_at"),
|
|
372
|
-
).toHaveLength(1);
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
test("a replaced memory connection is probed again, so a restored database without the column gets it", () => {
|
|
376
|
-
expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
|
|
377
|
-
|
|
378
|
-
// What a restore or import does: the stored connections are dropped and
|
|
379
|
-
// reopened. Strip the column on the reopened file to stand in for an
|
|
380
|
-
// older database.
|
|
381
|
-
resetDb();
|
|
382
|
-
const reopened = getMemorySqlite()!;
|
|
383
|
-
reopened.exec(
|
|
384
|
-
"ALTER TABLE memory_retrospective_state DROP COLUMN last_processed_created_at",
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
expect(getRetrospectiveState("conv-none")).toBeNull();
|
|
388
|
-
expect(ensureRetrospectiveCursorColumn("test")).toBe(true);
|
|
389
|
-
const columns = reopened
|
|
390
|
-
.query("PRAGMA table_info(memory_retrospective_state)")
|
|
391
|
-
.all() as Array<{ name: string }>;
|
|
392
|
-
expect(columns.some((c) => c.name === "last_processed_created_at")).toBe(
|
|
393
|
-
true,
|
|
394
|
-
);
|
|
395
|
-
});
|
|
396
|
-
});
|
|
397
|
-
|
|
398
179
|
describe("fail-soft when the underlying statement fails", () => {
|
|
399
180
|
// The memory connection is present, but the relocated table is gone (a
|
|
400
181
|
// corrupt/dropped table, SQLITE_FULL, I/O error, or SQLITE_BUSY after
|
|
@@ -412,34 +412,3 @@ describe("listSweepCandidateConversationIds", () => {
|
|
|
412
412
|
]);
|
|
413
413
|
});
|
|
414
414
|
});
|
|
415
|
-
|
|
416
|
-
describe("runRetrospectiveSweep: cursor survives a regenerated reply", () => {
|
|
417
|
-
beforeEach(() => {
|
|
418
|
-
resetTables();
|
|
419
|
-
enqueueCalls = [];
|
|
420
|
-
enqueueDeclines = new Set();
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
test("a stale conversation whose cursor row was regenerated away is still swept", async () => {
|
|
424
|
-
const conv = createConversation({ id: "conv-a" });
|
|
425
|
-
insertMessage(conv.id, { createdAt: 1_000 });
|
|
426
|
-
const reply = insertMessage(conv.id, {
|
|
427
|
-
role: "assistant",
|
|
428
|
-
createdAt: 2_000,
|
|
429
|
-
});
|
|
430
|
-
await upsertRetrospectiveState({
|
|
431
|
-
conversationId: conv.id,
|
|
432
|
-
lastProcessedMessageId: reply,
|
|
433
|
-
lastProcessedCreatedAt: 2_000,
|
|
434
|
-
lastRunAt: Date.now() - SWEEP_INTERVAL_MS - 60_000,
|
|
435
|
-
});
|
|
436
|
-
getDb().delete(messages).where(eq(messages.id, reply)).run();
|
|
437
|
-
insertMessage(conv.id, { role: "assistant", createdAt: 3_000 });
|
|
438
|
-
|
|
439
|
-
await runRetrospectiveSweep(makeConfig());
|
|
440
|
-
|
|
441
|
-
expect(enqueueCalls).toEqual([
|
|
442
|
-
{ conversationId: conv.id, trigger: "sweep" },
|
|
443
|
-
]);
|
|
444
|
-
});
|
|
445
|
-
});
|