@vellumai/assistant 0.11.2 → 0.11.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { describe, expect, test } from "bun:test";
|
|
5
5
|
|
|
6
|
+
import { MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT } from "../memory-retrospective-constants.js";
|
|
6
7
|
import {
|
|
7
8
|
buildForkInstruction,
|
|
8
9
|
type ForkInstructionArgs,
|
|
@@ -47,7 +48,7 @@ Two dedup sources to skip:
|
|
|
47
48
|
1. Anything semantically captured in <already_remembered> above (from prior retrospective passes).
|
|
48
49
|
2. Anything you already called \`remember\` on inline within your review window — those appear as \`tool_use\` blocks with \`name: "remember"\` in your history.
|
|
49
50
|
|
|
50
|
-
For everything else in your review window, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. When several facts are worth saving, pass them all as an array to a single \`remember\` call rather than calling it once per fact. If nothing new is worth saving,
|
|
51
|
+
For everything else in your review window, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. When several facts are worth saving, pass them all as an array to a single \`remember\` call rather than calling it once per fact. If nothing new is worth saving, reply with exactly "Nothing new to save." and stop.
|
|
51
52
|
`);
|
|
52
53
|
});
|
|
53
54
|
|
|
@@ -120,7 +121,7 @@ For everything else in your review window, use the \`remember\` tool on facts, p
|
|
|
120
121
|
expect(out).not.toContain("PROCEDURE");
|
|
121
122
|
expect(
|
|
122
123
|
out.endsWith(
|
|
123
|
-
'If nothing new is worth saving,
|
|
124
|
+
'If nothing new is worth saving, reply with exactly "Nothing new to save." and stop.\n',
|
|
124
125
|
),
|
|
125
126
|
).toBe(true);
|
|
126
127
|
});
|
|
@@ -175,7 +176,32 @@ describe("promptOverridePath", () => {
|
|
|
175
176
|
writeFileSync(overridePath, "Just remember the good parts.\n");
|
|
176
177
|
expect(
|
|
177
178
|
buildForkInstruction(makeArgs({ promptOverridePath: overridePath })),
|
|
178
|
-
).toBe(
|
|
179
|
+
).toBe(
|
|
180
|
+
"Just remember the good parts.\n\n\n" +
|
|
181
|
+
`If nothing new is worth saving, reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`,
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("an override that drops the no-findings mandate still carries the finalizer's exact-reply contract", () => {
|
|
186
|
+
// The finalizer advances a no-findings window only on a persisted reply
|
|
187
|
+
// that trims to exactly MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT. An
|
|
188
|
+
// override author who never read that code would otherwise stall every
|
|
189
|
+
// no-findings window forever, so the mandate must survive any override.
|
|
190
|
+
const overridePath = join(dir, "mandate-free.md");
|
|
191
|
+
writeFileSync(
|
|
192
|
+
overridePath,
|
|
193
|
+
"Review the window and save what matters. If nothing matters, do nothing.\n",
|
|
194
|
+
);
|
|
195
|
+
const out = buildForkInstruction(
|
|
196
|
+
makeArgs({ promptOverridePath: overridePath }),
|
|
197
|
+
);
|
|
198
|
+
expect(out).toContain(
|
|
199
|
+
`reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}"`,
|
|
200
|
+
);
|
|
201
|
+
// The mandate references the same constant the finalizer compares
|
|
202
|
+
// against, so the two cannot drift; guard the constant's exact value here
|
|
203
|
+
// to make an accidental rewording loud.
|
|
204
|
+
expect(MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT).toBe("Nothing new to save.");
|
|
179
205
|
});
|
|
180
206
|
|
|
181
207
|
test("missing override file falls back to the bundled rendering", () => {
|
|
@@ -200,3 +226,13 @@ describe("promptOverridePath", () => {
|
|
|
200
226
|
expect(out).not.toContain("SENSITIVE FILE CONTENTS");
|
|
201
227
|
});
|
|
202
228
|
});
|
|
229
|
+
|
|
230
|
+
// The finalizer's explicit-no-findings gate matches persisted assistant text
|
|
231
|
+
// against MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT by strict equality, and the
|
|
232
|
+
// bundled instruction is what teaches the model to emit it. This guard fails
|
|
233
|
+
// if either side drifts.
|
|
234
|
+
test("bundled template mandates the exact no-findings sentinel the finalizer matches", () => {
|
|
235
|
+
expect(RETROSPECTIVE_INSTRUCTION_TEMPLATE).toContain(
|
|
236
|
+
`reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`,
|
|
237
|
+
);
|
|
238
|
+
});
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LUM-3013 regression: the retrospective's fail-closed advancement gate must
|
|
3
|
+
* hold through the REAL producer chain, not just against a mocked wake.
|
|
4
|
+
*
|
|
5
|
+
* These tests run the real `memoryRetrospectiveJob` handler → the real
|
|
6
|
+
* `wakeAgentForOpportunity` (runtime/agent-wake.ts, NOT mocked) → a
|
|
7
|
+
* conversation double whose `agentLoop` is a real `AgentLoop` driven by a
|
|
8
|
+
* scripted fake `Provider`. Only the provider and the daemon/persistence
|
|
9
|
+
* boundaries are test doubles, so the chain exercises the actual mechanism
|
|
10
|
+
* behind the bug:
|
|
11
|
+
*
|
|
12
|
+
* - `AgentLoop.run` SWALLOWS provider rejections: the outer catch
|
|
13
|
+
* (agent/loop.ts, `onEvent({ type: "error" })` + `stopTurn("error")`)
|
|
14
|
+
* returns normally with the history unchanged.
|
|
15
|
+
* - The wake then finds no tail output and takes its silent no-op branch
|
|
16
|
+
* (agent-wake.ts), returning `{ invoked: true, producedToolCalls: false }`.
|
|
17
|
+
* - `invoked: true` alone must therefore NOT advance
|
|
18
|
+
* `memory_retrospective_state`: the handler re-reads the fork's persisted
|
|
19
|
+
* rows (`collectRetrospectiveRunEvidence` → `loadRetrospectiveRunMessages`
|
|
20
|
+
* → `getMessages`) and only advances when a durable memory-writing
|
|
21
|
+
* `tool_use` (`remember` / `scaffold_managed_skill`) was persisted by THIS
|
|
22
|
+
* run.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Mock state. Reset between tests.
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
const SOURCE_ID = "src-conv-1";
|
|
32
|
+
const FORK_ID = "fork-conv-1";
|
|
33
|
+
|
|
34
|
+
let stateUpserts: Array<{
|
|
35
|
+
conversationId: string;
|
|
36
|
+
lastProcessedMessageId: string;
|
|
37
|
+
lastRunAt: number;
|
|
38
|
+
rememberedLog?: string[];
|
|
39
|
+
}> = [];
|
|
40
|
+
let lastRunAtBumps: Array<{ conversationId: string; lastRunAt: number }> = [];
|
|
41
|
+
|
|
42
|
+
let newMessages: Array<{
|
|
43
|
+
id: string;
|
|
44
|
+
createdAt: number;
|
|
45
|
+
role?: string;
|
|
46
|
+
content?: string | Array<Record<string, unknown>>;
|
|
47
|
+
metadata?: string | null;
|
|
48
|
+
}> = [];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Persisted message rows, keyed by conversation id. `addMessage` appends here
|
|
52
|
+
* and `getMessages` reads it back. The same store serves the handler's
|
|
53
|
+
* instruction staging, the wake's tail persistence, and the finalizer's
|
|
54
|
+
* durable-evidence read, so the evidence gate sees exactly what the real
|
|
55
|
+
* producer chain persisted.
|
|
56
|
+
*/
|
|
57
|
+
type PersistedRow = {
|
|
58
|
+
role: string;
|
|
59
|
+
content: string;
|
|
60
|
+
createdAt: number;
|
|
61
|
+
metadata: string | null;
|
|
62
|
+
};
|
|
63
|
+
let messageStores: Record<string, PersistedRow[]> = {};
|
|
64
|
+
let persistedMessageCounter = 0;
|
|
65
|
+
|
|
66
|
+
let deletedConversationIds: string[] = [];
|
|
67
|
+
let forkCalls: Array<{ conversationId: string; throughMessageId?: string }> =
|
|
68
|
+
[];
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Retrospective-side mocks (mirroring memory-retrospective-job.test.ts, but
|
|
72
|
+
// WITHOUT mocking ../../../../runtime/agent-wake.js: the wake runs real).
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
mock.module("../memory-retrospective-state.js", () => ({
|
|
76
|
+
getRetrospectiveState: (_id: string) => null,
|
|
77
|
+
upsertRetrospectiveState: (args: {
|
|
78
|
+
conversationId: string;
|
|
79
|
+
lastProcessedMessageId: string;
|
|
80
|
+
lastRunAt: number;
|
|
81
|
+
rememberedLog?: string[];
|
|
82
|
+
}) => {
|
|
83
|
+
stateUpserts.push(args);
|
|
84
|
+
},
|
|
85
|
+
bumpRetrospectiveLastRunAt: (conversationId: string, lastRunAt: number) => {
|
|
86
|
+
lastRunAtBumps.push({ conversationId, lastRunAt });
|
|
87
|
+
},
|
|
88
|
+
appendToRememberedLog: (existing: string[], newEntries: string[]) => [
|
|
89
|
+
...existing,
|
|
90
|
+
...newEntries,
|
|
91
|
+
],
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
mock.module("../find-most-recent-retrospective-for.js", () => ({
|
|
95
|
+
findMostRecentRetrospectiveFor: (_id: string) => null,
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
mock.module("../../../../persistence/conversation-crud.js", () => ({
|
|
99
|
+
getMessagesAfter: (_id: string, _afterId: string | null) => newMessages,
|
|
100
|
+
getMessages: (id: string) => messageStores[id] ?? [],
|
|
101
|
+
// `defaultResolveTarget` in the REAL wake reads the FORK id's row for the
|
|
102
|
+
// archived check, so both rows carry archivedAt/createdAt. The fork's
|
|
103
|
+
// "user" source makes `loadRetrospectiveRunMessages` treat every persisted
|
|
104
|
+
// row as the run's own (legacy-kind), the simplest faithful setup here.
|
|
105
|
+
getConversation: (id: string) => {
|
|
106
|
+
if (id === FORK_ID) {
|
|
107
|
+
return {
|
|
108
|
+
source: "user",
|
|
109
|
+
forkParentMessageId: null,
|
|
110
|
+
title: "Fork",
|
|
111
|
+
archivedAt: null,
|
|
112
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
source: "user",
|
|
117
|
+
forkParentMessageId: null,
|
|
118
|
+
title: "Source conversation",
|
|
119
|
+
archivedAt: null,
|
|
120
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
isConversationProcessing: (_id: string) => false,
|
|
124
|
+
getConversationProcessingStartedAt: (_id: string) => null,
|
|
125
|
+
forkConversationForRetrospective: async (params: {
|
|
126
|
+
conversationId: string;
|
|
127
|
+
throughMessageId?: string;
|
|
128
|
+
}) => {
|
|
129
|
+
forkCalls.push(params);
|
|
130
|
+
return { id: FORK_ID };
|
|
131
|
+
},
|
|
132
|
+
addMessage: async (
|
|
133
|
+
conversationId: string,
|
|
134
|
+
role: string,
|
|
135
|
+
content: string,
|
|
136
|
+
_options: unknown,
|
|
137
|
+
) => {
|
|
138
|
+
const store = (messageStores[conversationId] ??= []);
|
|
139
|
+
store.push({ role, content, createdAt: Date.now(), metadata: null });
|
|
140
|
+
persistedMessageCounter += 1;
|
|
141
|
+
return { id: `msg-${persistedMessageCounter}` };
|
|
142
|
+
},
|
|
143
|
+
deleteConversation: (id: string) => {
|
|
144
|
+
deletedConversationIds.push(id);
|
|
145
|
+
},
|
|
146
|
+
deleteConversationGently: async (id: string) => {
|
|
147
|
+
deletedConversationIds.push(id);
|
|
148
|
+
return { segmentIds: [], deletedSummaryIds: [] };
|
|
149
|
+
},
|
|
150
|
+
resolveOverrideProfile: () => undefined,
|
|
151
|
+
getConversationOverrideProfile: () => undefined,
|
|
152
|
+
provenanceFromTrustContext: () => ({}),
|
|
153
|
+
reserveMessage: async () => ({ id: "msg-reserve" }),
|
|
154
|
+
}));
|
|
155
|
+
|
|
156
|
+
mock.module("../../../../daemon/trust-context.js", () => ({
|
|
157
|
+
INTERNAL_GUARDIAN_TRUST_CONTEXT: {
|
|
158
|
+
sourceChannel: "vellum",
|
|
159
|
+
trustClass: "guardian",
|
|
160
|
+
},
|
|
161
|
+
}));
|
|
162
|
+
|
|
163
|
+
mock.module("../../../../prompts/persona-resolver.js", () => ({
|
|
164
|
+
resolveUserSlug: (_trustContext: unknown) => "alice",
|
|
165
|
+
}));
|
|
166
|
+
|
|
167
|
+
mock.module("../../../../persistence/jobs-store.js", () => ({
|
|
168
|
+
enqueueMemoryJob: () => "follow-up-job-id",
|
|
169
|
+
upsertMemoryRetrospectiveJob: () => {},
|
|
170
|
+
}));
|
|
171
|
+
|
|
172
|
+
mock.module("../../../../telemetry/watchdog-events-store.js", () => ({
|
|
173
|
+
recordWatchdogEvent: () => {},
|
|
174
|
+
}));
|
|
175
|
+
|
|
176
|
+
mock.module("../../../../config/memory-v3-gate.js", () => ({
|
|
177
|
+
isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
|
|
178
|
+
config?.memory?.enabled !== false,
|
|
179
|
+
isV3TierActive: () => false,
|
|
180
|
+
isMemoryV3Live: () => false,
|
|
181
|
+
usesConceptPageMemory: () => false,
|
|
182
|
+
}));
|
|
183
|
+
|
|
184
|
+
mock.module("../../../../daemon/conversation-registry.js", () => ({
|
|
185
|
+
findConversation: (_id: string | undefined) => undefined,
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Wake-side boundary mocks (mirroring runtime/__tests__/agent-wake.test.ts,
|
|
190
|
+
// with relative paths adjusted for this directory).
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
mock.module("../../../../persistence/conversation-disk-view.js", () => ({
|
|
194
|
+
syncMessageToDisk: () => {},
|
|
195
|
+
}));
|
|
196
|
+
|
|
197
|
+
mock.module("../../../../runtime/assistant-event-hub.js", () => ({
|
|
198
|
+
broadcastMessage: () => {},
|
|
199
|
+
}));
|
|
200
|
+
|
|
201
|
+
mock.module("../../../../runtime/sync/resource-sync-events.js", () => ({
|
|
202
|
+
publishConversationMessagesChanged: () => {},
|
|
203
|
+
}));
|
|
204
|
+
|
|
205
|
+
mock.module("../../../../daemon/conversation-store.js", () => ({
|
|
206
|
+
// The real wake's `defaultResolveTarget` lands here after the archived
|
|
207
|
+
// check; it must yield the live fork conversation the run executes on.
|
|
208
|
+
getOrCreateConversation: async (
|
|
209
|
+
_conversationId: string,
|
|
210
|
+
_options?: unknown,
|
|
211
|
+
) => makeForkConversationDouble(),
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
mock.module("../../../../config/llm-context-resolution.js", () => ({
|
|
215
|
+
resolveEffectiveContextWindow: () => ({ maxInputTokens: 200_000 }),
|
|
216
|
+
}));
|
|
217
|
+
|
|
218
|
+
mock.module("../../../../daemon/disk-pressure-guard.js", () => ({
|
|
219
|
+
getDiskPressureStatus: () => ({
|
|
220
|
+
enabled: false,
|
|
221
|
+
state: "disabled",
|
|
222
|
+
locked: false,
|
|
223
|
+
acknowledged: false,
|
|
224
|
+
overrideActive: false,
|
|
225
|
+
effectivelyLocked: false,
|
|
226
|
+
lockId: null,
|
|
227
|
+
usagePercent: null,
|
|
228
|
+
thresholdPercent: 95,
|
|
229
|
+
path: null,
|
|
230
|
+
lastCheckedAt: null,
|
|
231
|
+
blockedCapabilities: [],
|
|
232
|
+
error: null,
|
|
233
|
+
}),
|
|
234
|
+
}));
|
|
235
|
+
|
|
236
|
+
mock.module("../../../../daemon/conversation-usage.js", () => ({
|
|
237
|
+
recordUsage: () => {},
|
|
238
|
+
}));
|
|
239
|
+
|
|
240
|
+
mock.module("../../../../persistence/llm-request-log-store.js", () => ({
|
|
241
|
+
recordRequestLog: () => "log-id",
|
|
242
|
+
backfillMessageIdOnLogs: () => {},
|
|
243
|
+
setAgentLoopExitReasonOnLatestLog: () => {},
|
|
244
|
+
buildProviderErrorResponsePayload: (error: unknown) => ({
|
|
245
|
+
error: String(error),
|
|
246
|
+
}),
|
|
247
|
+
}));
|
|
248
|
+
|
|
249
|
+
import { AgentLoop } from "../../../../agent/loop.js";
|
|
250
|
+
import type { Conversation } from "../../../../daemon/conversation.js";
|
|
251
|
+
import type { MemoryJob } from "../../../../persistence/jobs-store.js";
|
|
252
|
+
import type {
|
|
253
|
+
Message,
|
|
254
|
+
Provider,
|
|
255
|
+
ProviderResponse,
|
|
256
|
+
SendMessageOptions,
|
|
257
|
+
} from "../../../../providers/types.js";
|
|
258
|
+
import { ProviderError } from "../../../../util/errors.js";
|
|
259
|
+
import { memoryRetrospectiveJob } from "../memory-retrospective-job.js";
|
|
260
|
+
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
// Fake provider: the ONLY seam scripted per scenario. Everything between the
|
|
263
|
+
// job handler and this `sendMessage` is real production code.
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
let providerCalls: Array<{ messages: Message[] }> = [];
|
|
267
|
+
let providerImpl: (
|
|
268
|
+
messages: Message[],
|
|
269
|
+
options?: SendMessageOptions,
|
|
270
|
+
) => Promise<ProviderResponse> = async () => textOnlyResponse("unused");
|
|
271
|
+
|
|
272
|
+
const fakeProvider: Provider = {
|
|
273
|
+
name: "fake-provider",
|
|
274
|
+
async sendMessage(
|
|
275
|
+
messages: Message[],
|
|
276
|
+
options?: SendMessageOptions,
|
|
277
|
+
): Promise<ProviderResponse> {
|
|
278
|
+
providerCalls.push({ messages: [...messages] });
|
|
279
|
+
return providerImpl(messages, options);
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
function textOnlyResponse(text: string): ProviderResponse {
|
|
284
|
+
return {
|
|
285
|
+
content: [{ type: "text", text }],
|
|
286
|
+
model: "test-model",
|
|
287
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
288
|
+
stopReason: "end_turn",
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function rememberToolUseResponse(): ProviderResponse {
|
|
293
|
+
return {
|
|
294
|
+
content: [
|
|
295
|
+
{ type: "text", text: "Saving one fact." },
|
|
296
|
+
{
|
|
297
|
+
type: "tool_use",
|
|
298
|
+
id: "tu-1",
|
|
299
|
+
name: "remember",
|
|
300
|
+
input: { content: "provider-path fact" },
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
model: "test-model",
|
|
304
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
305
|
+
stopReason: "tool_use",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
// Conversation double: minimal structural stand-in for the fork the wake
|
|
311
|
+
// resolves. Its `agentLoop` is a REAL AgentLoop over the fake provider; its
|
|
312
|
+
// message history hydrates from the persisted store (so the instruction row
|
|
313
|
+
// the handler staged is the run's baseline, exactly like a DB rehydration).
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
function makeForkConversationDouble(): Conversation {
|
|
317
|
+
const messages: Message[] = (messageStores[FORK_ID] ?? []).map((row) => ({
|
|
318
|
+
role: row.role as Message["role"],
|
|
319
|
+
content: JSON.parse(row.content) as Message["content"],
|
|
320
|
+
}));
|
|
321
|
+
const realLoop = new AgentLoop({
|
|
322
|
+
provider: fakeProvider,
|
|
323
|
+
systemPrompt: "test",
|
|
324
|
+
conversationId: FORK_ID,
|
|
325
|
+
// Real executor round-trip: the finalizer's durable-evidence gate
|
|
326
|
+
// requires a matching successful tool_result, so the loop must execute
|
|
327
|
+
// the remember call and persist its result exactly as production does.
|
|
328
|
+
toolExecutor: async (name: string) => {
|
|
329
|
+
if (name === "remember") {
|
|
330
|
+
return { content: "Saved.", isError: false };
|
|
331
|
+
}
|
|
332
|
+
return { content: `unknown tool ${name}`, isError: true };
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
const conversation = {
|
|
336
|
+
conversationId: FORK_ID,
|
|
337
|
+
messages,
|
|
338
|
+
getMessages: () => messages,
|
|
339
|
+
isProcessing: () => false,
|
|
340
|
+
setProcessing: (_on: boolean) => {},
|
|
341
|
+
waitForIdle: async (_opts: { timeoutMs: number }) => true,
|
|
342
|
+
drainQueue: async () => {},
|
|
343
|
+
maybeCompact: async () => null,
|
|
344
|
+
subagentAllowedTools: undefined,
|
|
345
|
+
setSubagentAllowedTools: (_tools: Set<string> | undefined) => {},
|
|
346
|
+
preactivatedSkillIds: undefined,
|
|
347
|
+
setPreactivatedSkillIds: (_ids: readonly string[] | undefined) => {},
|
|
348
|
+
trustContext: undefined,
|
|
349
|
+
setTrustContext: (_ctx: unknown) => {},
|
|
350
|
+
currentTurnTrustContext: undefined,
|
|
351
|
+
wakePersonaOverride: undefined,
|
|
352
|
+
contextWindowManager: { estimateInputTokens: () => 0 },
|
|
353
|
+
getTurnChannelContext: () => null,
|
|
354
|
+
getTurnInterfaceContext: () => null,
|
|
355
|
+
buildCurrentSystemPrompt: () => "test-system-prompt",
|
|
356
|
+
provider: { name: "fake-provider" },
|
|
357
|
+
usageStats: {},
|
|
358
|
+
modelOverride: undefined,
|
|
359
|
+
agentLoop: {
|
|
360
|
+
run: (options: Parameters<AgentLoop["run"]>[0]) => realLoop.run(options),
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
return conversation as unknown as Conversation;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
// Job/config helpers (shape copied from memory-retrospective-job.test.ts).
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
function makeConfig(): Parameters<typeof memoryRetrospectiveJob>[1] {
|
|
371
|
+
return {
|
|
372
|
+
memory: {
|
|
373
|
+
v2: { enabled: true },
|
|
374
|
+
retrospective: {
|
|
375
|
+
enabled: true,
|
|
376
|
+
keepSupersededRuns: false,
|
|
377
|
+
matchConversationProfile: false,
|
|
378
|
+
promptPath: null,
|
|
379
|
+
requireUserActivity: false,
|
|
380
|
+
sweepIntervalMs: 8 * 60 * 60 * 1000,
|
|
381
|
+
sweepLookbackMs: 7 * 24 * 60 * 60 * 1000,
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
ui: {
|
|
385
|
+
userTimezone: undefined,
|
|
386
|
+
detectedTimezone: undefined,
|
|
387
|
+
},
|
|
388
|
+
} as unknown as Parameters<typeof memoryRetrospectiveJob>[1];
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const stubConfig = makeConfig();
|
|
392
|
+
|
|
393
|
+
function makeJob(conversationId = SOURCE_ID): MemoryJob<{
|
|
394
|
+
conversationId?: string;
|
|
395
|
+
}> {
|
|
396
|
+
return {
|
|
397
|
+
id: "job-1",
|
|
398
|
+
type: "memory_retrospective",
|
|
399
|
+
payload: { conversationId },
|
|
400
|
+
status: "pending",
|
|
401
|
+
attempts: 0,
|
|
402
|
+
deferrals: 0,
|
|
403
|
+
runAfter: 0,
|
|
404
|
+
lastError: null,
|
|
405
|
+
startedAt: null,
|
|
406
|
+
createdAt: 0,
|
|
407
|
+
updatedAt: 0,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
describe("memoryRetrospectiveJob through the real wake + real agent loop", () => {
|
|
412
|
+
beforeEach(() => {
|
|
413
|
+
stateUpserts = [];
|
|
414
|
+
lastRunAtBumps = [];
|
|
415
|
+
deletedConversationIds = [];
|
|
416
|
+
forkCalls = [];
|
|
417
|
+
messageStores = {};
|
|
418
|
+
persistedMessageCounter = 0;
|
|
419
|
+
providerCalls = [];
|
|
420
|
+
providerImpl = async () => textOnlyResponse("unused");
|
|
421
|
+
newMessages = [
|
|
422
|
+
{ id: "m1", createdAt: Date.parse("2026-05-11T10:00:00Z") },
|
|
423
|
+
{ id: "m2", createdAt: Date.parse("2026-05-11T10:05:00Z") },
|
|
424
|
+
{ id: "m3", createdAt: Date.parse("2026-05-11T10:10:00Z") },
|
|
425
|
+
];
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test("real provider rejection is classified at the wake layer and leaves the window retryable", async () => {
|
|
429
|
+
// The wake's exit-reason classifier fails a swallowed rejection before
|
|
430
|
+
// finalization (invoked: false, reason run_error), so the handler
|
|
431
|
+
// reports wake_failed. Full rejection-chain coverage (state
|
|
432
|
+
// preservation, prior-fork survival, retry consuming the window) lives
|
|
433
|
+
// in memory-retrospective-wake-chain.test.ts; this case pins only the
|
|
434
|
+
// layered outcome and that the finalizer was never reached.
|
|
435
|
+
providerImpl = async () => {
|
|
436
|
+
throw new ProviderError(
|
|
437
|
+
"This model (test-model) doesn't support image input. Remove the image or switch to a vision-capable model.",
|
|
438
|
+
"openai",
|
|
439
|
+
400,
|
|
440
|
+
);
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
444
|
+
|
|
445
|
+
expect(outcome.kind).toBe("wake_failed");
|
|
446
|
+
if (outcome.kind === "wake_failed") {
|
|
447
|
+
expect(outcome.reason).toBe("run_error");
|
|
448
|
+
}
|
|
449
|
+
expect(providerCalls.length).toBeGreaterThanOrEqual(1);
|
|
450
|
+
expect(stateUpserts).toHaveLength(0);
|
|
451
|
+
expect(lastRunAtBumps).toHaveLength(1);
|
|
452
|
+
expect(deletedConversationIds).toEqual([FORK_ID]);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test("durable remember persisted through the real loop advances the cursor", async () => {
|
|
456
|
+
// Scenario B: first call emits a `remember` tool_use; the loop (built
|
|
457
|
+
// without a tool executor) stops after persisting the tool-bearing
|
|
458
|
+
// assistant message, and the wake's tail persistence writes it through
|
|
459
|
+
// `addMessage`. Subsequent calls (defensive) return plain text.
|
|
460
|
+
let call = 0;
|
|
461
|
+
providerImpl = async () => {
|
|
462
|
+
call += 1;
|
|
463
|
+
return call === 1 ? rememberToolUseResponse() : textOnlyResponse("Done.");
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
467
|
+
|
|
468
|
+
expect(outcome.kind).toBe("invoked");
|
|
469
|
+
expect(providerCalls.length).toBeGreaterThanOrEqual(1);
|
|
470
|
+
expect(stateUpserts).toHaveLength(1);
|
|
471
|
+
expect(stateUpserts[0]!.lastProcessedMessageId).toBe("m3");
|
|
472
|
+
expect(stateUpserts[0]!.rememberedLog).toContain("provider-path fact");
|
|
473
|
+
// The durable evidence really flowed through persistence: the fork store
|
|
474
|
+
// holds the instruction row plus the wake-persisted tool_use tail.
|
|
475
|
+
const persistedRoles = messageStores[FORK_ID]!.map((row) => row.role);
|
|
476
|
+
expect(persistedRoles[0]).toBe("user");
|
|
477
|
+
expect(persistedRoles).toContain("assistant");
|
|
478
|
+
expect(lastRunAtBumps).toHaveLength(0);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("clean empty reply through the real loop does not advance", async () => {
|
|
482
|
+
// Scenario C: the model answers with analysis text and no tool calls.
|
|
483
|
+
// The wake persists the text tail (visible output), but with zero
|
|
484
|
+
// durable memory-writing tool calls the gate must refuse to advance.
|
|
485
|
+
providerImpl = async () => textOnlyResponse("Nothing worth saving.");
|
|
486
|
+
|
|
487
|
+
const outcome = await memoryRetrospectiveJob(makeJob(), stubConfig);
|
|
488
|
+
|
|
489
|
+
expect(outcome.kind).toBe("no_usable_output");
|
|
490
|
+
expect(providerCalls.length).toBeGreaterThanOrEqual(1);
|
|
491
|
+
expect(stateUpserts).toHaveLength(0);
|
|
492
|
+
});
|
|
493
|
+
});
|
|
@@ -409,9 +409,10 @@ describe("memory retrospective wake state chain (real AgentLoop)", () => {
|
|
|
409
409
|
expect(listRetroForksOf(fixture.sourceId)).toEqual([fixture.priorRetroId]);
|
|
410
410
|
|
|
411
411
|
// (2) The window stays retryable: the same slice succeeds on retry.
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
412
|
+
// The finalizer's usable-output gate accepts free text only when it is
|
|
413
|
+
// exactly the mandated no-findings sentinel; a verified remember write
|
|
414
|
+
// is the other accepted evidence. Use the sentinel for the control.
|
|
415
|
+
providerScript = [{ response: textResponse("Nothing new to save.") }];
|
|
415
416
|
providerCallCount = 0;
|
|
416
417
|
const retry = await runForkBasedRetrospective(
|
|
417
418
|
fixture.sourceId,
|
|
@@ -459,7 +460,7 @@ describe("memory retrospective wake state chain (real AgentLoop)", () => {
|
|
|
459
460
|
expect(listRetroForksOf(fixture.sourceId)).toEqual([fixture.priorRetroId]);
|
|
460
461
|
|
|
461
462
|
// The window stays retryable and a usable reply consumes it.
|
|
462
|
-
providerScript = [{ response: textResponse("
|
|
463
|
+
providerScript = [{ response: textResponse("Nothing new to save.") }];
|
|
463
464
|
providerCallCount = 0;
|
|
464
465
|
const retry = await runForkBasedRetrospective(
|
|
465
466
|
fixture.sourceId,
|
|
@@ -196,7 +196,7 @@ interface TierKeyExemption {
|
|
|
196
196
|
* shape.
|
|
197
197
|
* - `telemetry/config-setting-snapshot.ts` (both) — reports both tier keys
|
|
198
198
|
* as-is.
|
|
199
|
-
* - the
|
|
199
|
+
* - the named migrations: append-only history that rewrites or reads the
|
|
200
200
|
* historical tier keys it was written for. Listed per file, not per
|
|
201
201
|
* directory: a future migration reading a tier key is a new decision and
|
|
202
202
|
* gets challenged like any other.
|
|
@@ -257,6 +257,10 @@ const TIER_KEY_READ_ALLOWLIST: readonly TierKeyExemption[] = [
|
|
|
257
257
|
path: "src/workspace/migrations/135-copy-substrate-tunables.ts",
|
|
258
258
|
keys: ["substrate", "v2"],
|
|
259
259
|
},
|
|
260
|
+
{
|
|
261
|
+
path: "src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts",
|
|
262
|
+
keys: ["v3"],
|
|
263
|
+
},
|
|
260
264
|
];
|
|
261
265
|
|
|
262
266
|
/** Tier directory a plugin-root-relative path lives in, or `"spine"`. */
|