@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
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
type ConversationRow,
|
|
47
47
|
deleteConversation,
|
|
48
48
|
getConversation,
|
|
49
|
+
getConversationProcessingStartedAt,
|
|
49
50
|
isConversationProcessing,
|
|
50
51
|
} from "@vellumai/plugin-api";
|
|
51
52
|
|
|
@@ -56,7 +57,7 @@ import {
|
|
|
56
57
|
} from "../../../channels/types.js";
|
|
57
58
|
import { isV3TierActive } from "../../../config/memory-v3-gate.js";
|
|
58
59
|
import type { AssistantConfig } from "../../../config/types.js";
|
|
59
|
-
import {
|
|
60
|
+
import { warmGuardianBindings } from "../../../contacts/guardian-delivery-reader.js";
|
|
60
61
|
import { extractTurnContextTimestamp } from "../../../context/compactor.js";
|
|
61
62
|
import {
|
|
62
63
|
formatLocalTimestamp,
|
|
@@ -72,7 +73,6 @@ import {
|
|
|
72
73
|
enqueueMemoryJob,
|
|
73
74
|
type MemoryJob,
|
|
74
75
|
type MemoryJobType,
|
|
75
|
-
upsertMemoryRetrospectiveJob,
|
|
76
76
|
} from "../../../persistence/jobs-store.js";
|
|
77
77
|
import { resolveUserSlug } from "../../../prompts/persona-resolver.js";
|
|
78
78
|
import type { SystemPromptPersonaOverride } from "../../../prompts/system-prompt.js";
|
|
@@ -88,6 +88,7 @@ import {
|
|
|
88
88
|
MEMORY_RETROSPECTIVE_FORK_SOURCE,
|
|
89
89
|
MEMORY_RETROSPECTIVE_GROUP_ID,
|
|
90
90
|
MEMORY_RETROSPECTIVE_INSTRUCTION_KIND,
|
|
91
|
+
MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT,
|
|
91
92
|
MEMORY_RETROSPECTIVE_ORIGIN,
|
|
92
93
|
MEMORY_RETROSPECTIVE_SOURCE,
|
|
93
94
|
SKILL_MANAGEMENT_SKILL_ID,
|
|
@@ -112,15 +113,17 @@ const log = getLogger("memory-retrospective-job");
|
|
|
112
113
|
const FOLLOW_UP_JOB_TYPES: readonly MemoryJobType[] = [] as const;
|
|
113
114
|
|
|
114
115
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* only
|
|
120
|
-
*
|
|
121
|
-
*
|
|
116
|
+
* Age past which a source conversation's persisted `processing_started_at`
|
|
117
|
+
* stamp is treated as stranded rather than live, and the retrospective
|
|
118
|
+
* proceeds despite it. A turn-end flag clear can fail and be swallowed under
|
|
119
|
+
* DB-lock contention while the daemon stays up, and the monitor-process
|
|
120
|
+
* reaper only clears flags older than the daemon's boot time, so an
|
|
121
|
+
* in-process stranded flag otherwise blocks a conversation's retrospectives
|
|
122
|
+
* indefinitely. Proceeding risks only forking a half-finished display turn
|
|
123
|
+
* (a review-quality concern; the fork copies complete persisted turns), which
|
|
124
|
+
* is strictly better than never forming memories for the conversation again.
|
|
122
125
|
*/
|
|
123
|
-
export const
|
|
126
|
+
export const STALE_SOURCE_PROCESSING_OVERRIDE_MS = 6 * 60 * 60 * 1000;
|
|
124
127
|
|
|
125
128
|
/** Watchdog check_name for the per-run retrospective outcome counter. */
|
|
126
129
|
const MEMORY_RETROSPECTIVE_RUN_CHECK_NAME = "memory_retrospective_run";
|
|
@@ -132,6 +135,7 @@ export type MemoryRetrospectiveOutcome =
|
|
|
132
135
|
| { kind: "source_dormant" }
|
|
133
136
|
| { kind: "source_processing" }
|
|
134
137
|
| { kind: "wake_failed"; reason?: string; conversationId?: string }
|
|
138
|
+
| { kind: "no_usable_output"; reason?: string; conversationId?: string }
|
|
135
139
|
| {
|
|
136
140
|
kind: "invoked";
|
|
137
141
|
backgroundConversationId: string;
|
|
@@ -150,6 +154,20 @@ export async function memoryRetrospectiveJob(
|
|
|
150
154
|
return { kind: "no_new_messages" };
|
|
151
155
|
}
|
|
152
156
|
|
|
157
|
+
// Execution-time twin of the enqueue funnel's `memory.retrospective.enabled`
|
|
158
|
+
// gate: rows queued before the flag was turned off drain as no-ops instead
|
|
159
|
+
// of forking. The CLI's manual `memory retrospective run` calls
|
|
160
|
+
// `runForkBasedRetrospective` directly and so is unaffected: an operator's
|
|
161
|
+
// explicit request overrides the flag, matching the lookback and
|
|
162
|
+
// user-activity gates.
|
|
163
|
+
if (!config.memory.retrospective.enabled) {
|
|
164
|
+
log.info(
|
|
165
|
+
{ jobId: job.id, sourceConversationId },
|
|
166
|
+
"Skipping job: memory.retrospective.enabled is false",
|
|
167
|
+
);
|
|
168
|
+
return { kind: "disabled" };
|
|
169
|
+
}
|
|
170
|
+
|
|
153
171
|
// Central health counter (admin analytics groups on the watchdog
|
|
154
172
|
// check_name): one event per run with its outcome kind. A run that
|
|
155
173
|
// throws records outcome "error" before the exception continues to the
|
|
@@ -186,7 +204,9 @@ export async function memoryRetrospectiveJob(
|
|
|
186
204
|
}
|
|
187
205
|
emitRunOutcome(
|
|
188
206
|
outcome.kind,
|
|
189
|
-
outcome.kind === "wake_failed"
|
|
207
|
+
outcome.kind === "wake_failed" || outcome.kind === "no_usable_output"
|
|
208
|
+
? outcome.reason
|
|
209
|
+
: undefined,
|
|
190
210
|
);
|
|
191
211
|
return outcome;
|
|
192
212
|
}
|
|
@@ -271,34 +291,36 @@ export async function runForkBasedRetrospective(
|
|
|
271
291
|
// persisted message — including the turn's final assistant message — so an
|
|
272
292
|
// unbumped `lastRunAt` lets that turn-end pass re-enqueue with no cooldown
|
|
273
293
|
// suppression. That is the primary, event-driven requeue: the retrospective
|
|
274
|
-
// runs right after the colliding turn completes.
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
// lost.
|
|
281
|
-
//
|
|
294
|
+
// runs right after the colliding turn completes. The `source_processing`
|
|
295
|
+
// outcome maps to a bounded deferral of the SAME job row at the worker
|
|
296
|
+
// (see `resolveRetrospectiveOutcome` in `job-handlers.ts`); turn-end
|
|
297
|
+
// trigger upserts coalesce onto that pending row, so the event-driven
|
|
298
|
+
// retry keeps its immediacy while a stranded flag can no longer mint an
|
|
299
|
+
// unbounded stream of fresh rows. Both state pointers stay untouched, so
|
|
300
|
+
// nothing is lost.
|
|
301
|
+
//
|
|
302
|
+
// Stranded-flag override: a swallowed turn-end flag clear leaves the
|
|
303
|
+
// persisted stamp set while the daemon stays up, where the monitor
|
|
304
|
+
// process's boot-time-fenced reaper never touches it. A stamp older than
|
|
305
|
+
// `STALE_SOURCE_PROCESSING_OVERRIDE_MS` is treated as stranded and the run
|
|
306
|
+
// proceeds; a set-but-stampless flag reads as live (deferral bounds it).
|
|
282
307
|
if (await isConversationProcessing(sourceConversationId)) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
308
|
+
const processingStartedAt =
|
|
309
|
+
await getConversationProcessingStartedAt(sourceConversationId);
|
|
310
|
+
const stale =
|
|
311
|
+
processingStartedAt != null &&
|
|
312
|
+
startedAtMs - processingStartedAt > STALE_SOURCE_PROCESSING_OVERRIDE_MS;
|
|
313
|
+
if (!stale) {
|
|
288
314
|
log.info(
|
|
289
|
-
{
|
|
290
|
-
|
|
291
|
-
requeueDelayMs: SOURCE_PROCESSING_REQUEUE_DELAY_MS,
|
|
292
|
-
},
|
|
293
|
-
"memory-retrospective (fork): source conversation is mid-turn; requeued",
|
|
294
|
-
);
|
|
295
|
-
} catch (err) {
|
|
296
|
-
log.warn(
|
|
297
|
-
{ err, sourceConversationId },
|
|
298
|
-
"memory-retrospective (fork): mid-turn fallback requeue failed; relying on the turn-end trigger check",
|
|
315
|
+
{ sourceConversationId, processingStartedAt },
|
|
316
|
+
"memory-retrospective (fork): source conversation is mid-turn; deferring",
|
|
299
317
|
);
|
|
318
|
+
return { kind: "source_processing" };
|
|
300
319
|
}
|
|
301
|
-
|
|
320
|
+
log.warn(
|
|
321
|
+
{ sourceConversationId, processingStartedAt },
|
|
322
|
+
"memory-retrospective (fork): processing flag is stale beyond the override window; proceeding despite it",
|
|
323
|
+
);
|
|
302
324
|
}
|
|
303
325
|
|
|
304
326
|
const state = getRetrospectiveState(sourceConversationId);
|
|
@@ -457,10 +479,11 @@ export async function runForkBasedRetrospective(
|
|
|
457
479
|
// parity — the fork always runs execution gate mode below, so the source's
|
|
458
480
|
// full tool surface stays on the wire while the allowlist holds at
|
|
459
481
|
// execution time.
|
|
460
|
-
// Warm
|
|
461
|
-
// resolveSourceParityPins (resolveUserSlug(undefined))
|
|
462
|
-
//
|
|
463
|
-
|
|
482
|
+
// Warm both guardian-delivery cache keys (vellum + unfiltered) so the sync
|
|
483
|
+
// slug resolution inside resolveSourceParityPins (resolveUserSlug(undefined)),
|
|
484
|
+
// including its any-channel fallback, hits fresh keys instead of falling
|
|
485
|
+
// back to "default" on a cold/TTL-expired cache.
|
|
486
|
+
await warmGuardianBindings();
|
|
464
487
|
const { personaOverride, toolContextPin } = resolveSourceParityPins(
|
|
465
488
|
sourceConversation,
|
|
466
489
|
newMessages,
|
|
@@ -549,25 +572,65 @@ export async function runForkBasedRetrospective(
|
|
|
549
572
|
}
|
|
550
573
|
|
|
551
574
|
if (wakeSucceeded) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
575
|
+
// Fail-closed finalization: `invoked: true` proves only that the wake
|
|
576
|
+
// went live, not that the run produced anything. The agent loop swallows
|
|
577
|
+
// provider rejections into a normal no-output return, an exhausted output
|
|
578
|
+
// budget can stop a run before any visible text or tool call, and a
|
|
579
|
+
// model may reply with analysis (or nothing) without saving. Advancement
|
|
580
|
+
// past the window therefore requires POSITIVE evidence from THIS run,
|
|
581
|
+
// one of:
|
|
582
|
+
// - a memory-writing tool call on the fork's post-boundary tail whose
|
|
583
|
+
// execution verifiably succeeded (matching non-error tool_result), or
|
|
584
|
+
// - the explicit no-findings reply the instruction mandates (an
|
|
585
|
+
// assistant text block that is exactly the sentinel phrase), with no
|
|
586
|
+
// memory-writing tool attempts at all; a run that attempted a save
|
|
587
|
+
// and failed cannot advance by also claiming no findings.
|
|
588
|
+
// The evidence read is run-specific by construction
|
|
589
|
+
// (`loadRetrospectiveRunMessages` scopes to rows after the fork
|
|
590
|
+
// boundary), so a prior run's persisted saves can never satisfy it, and
|
|
591
|
+
// it reads the DB rather than the returned history, so a checkpoint that
|
|
592
|
+
// went live and persisted saves counts even when a later in-loop repair
|
|
593
|
+
// rebased the returned tail. A run with neither evidence kind follows
|
|
594
|
+
// the wake-failure path: cursor, remembered log, and the prior
|
|
595
|
+
// retrospective (the dedup baseline) stay untouched and the window
|
|
596
|
+
// remains retryable.
|
|
597
|
+
const runEvidence = await collectRetrospectiveRunEvidence(forkId);
|
|
598
|
+
const reviewedNoFindings =
|
|
599
|
+
runEvidence.explicitNoFindings &&
|
|
600
|
+
runEvidence.durableToolAttemptCount === 0;
|
|
601
|
+
if (runEvidence.durableToolCallCount === 0 && !reviewedNoFindings) {
|
|
602
|
+
log.warn(
|
|
603
|
+
{
|
|
604
|
+
sourceConversationId,
|
|
605
|
+
forkId,
|
|
606
|
+
newMessageCount: newMessages.length,
|
|
607
|
+
durableToolAttempts: runEvidence.durableToolAttemptCount,
|
|
608
|
+
},
|
|
609
|
+
"memory-retrospective (fork): run produced neither a verified durable write nor an explicit no-findings reply; leaving window retryable",
|
|
610
|
+
);
|
|
611
|
+
} else {
|
|
612
|
+
return await finalizeSuccessfulRetrospective({
|
|
613
|
+
config,
|
|
614
|
+
sourceConversationId,
|
|
615
|
+
retrospectiveConversationId: forkId,
|
|
616
|
+
cutoffMessageId,
|
|
617
|
+
newMessageCount: newMessages.length,
|
|
618
|
+
prior,
|
|
619
|
+
priorRemembers,
|
|
620
|
+
runRemembers: runEvidence.remembers,
|
|
621
|
+
logFields: {
|
|
622
|
+
kind: "fork",
|
|
623
|
+
windowStartTimestamp,
|
|
624
|
+
durationMs: Date.now() - startedAtMs,
|
|
625
|
+
noFindings: reviewedNoFindings,
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
|
+
}
|
|
566
629
|
}
|
|
567
630
|
|
|
568
|
-
// Wake failed. Bump `lastRunAt` only so the
|
|
569
|
-
// `lastProcessedMessageId` alone so the next
|
|
570
|
-
// same messages. Then clean up the orphan fork.
|
|
631
|
+
// Wake failed or produced no usable output. Bump `lastRunAt` only so the
|
|
632
|
+
// cooldown gate applies, leave `lastProcessedMessageId` alone so the next
|
|
633
|
+
// attempt re-processes the same messages. Then clean up the orphan fork.
|
|
571
634
|
await bumpRetrospectiveLastRunAt(sourceConversationId, Date.now());
|
|
572
635
|
await safeDeleteRetrospectiveConversation(
|
|
573
636
|
forkId,
|
|
@@ -578,6 +641,13 @@ export async function runForkBasedRetrospective(
|
|
|
578
641
|
throw threw;
|
|
579
642
|
}
|
|
580
643
|
|
|
644
|
+
if (wakeSucceeded) {
|
|
645
|
+
return {
|
|
646
|
+
kind: "no_usable_output",
|
|
647
|
+
reason: failureReason ?? "run persisted no memory-writing tool call",
|
|
648
|
+
conversationId: forkId,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
581
651
|
return {
|
|
582
652
|
kind: "wake_failed",
|
|
583
653
|
reason: failureReason,
|
|
@@ -786,6 +856,12 @@ async function finalizeSuccessfulRetrospective(args: {
|
|
|
786
856
|
newMessageCount: number;
|
|
787
857
|
prior: PriorRetrospective | null;
|
|
788
858
|
priorRemembers: string[];
|
|
859
|
+
/**
|
|
860
|
+
* The `remember` contents extracted from this run's persisted tail by the
|
|
861
|
+
* caller's usable-output check; passed through so the evidence that gated
|
|
862
|
+
* advancement is exactly the evidence folded into the log.
|
|
863
|
+
*/
|
|
864
|
+
runRemembers: string[];
|
|
789
865
|
/** Per-kind extras for the success log line (e.g. `kind`, fork anchor). */
|
|
790
866
|
logFields: Record<string, unknown>;
|
|
791
867
|
}): Promise<MemoryRetrospectiveOutcome> {
|
|
@@ -797,12 +873,10 @@ async function finalizeSuccessfulRetrospective(args: {
|
|
|
797
873
|
newMessageCount,
|
|
798
874
|
prior,
|
|
799
875
|
priorRemembers,
|
|
876
|
+
runRemembers,
|
|
800
877
|
logFields,
|
|
801
878
|
} = args;
|
|
802
879
|
|
|
803
|
-
const runRemembers = await extractRetrospectiveRunRemembers(
|
|
804
|
-
retrospectiveConversationId,
|
|
805
|
-
);
|
|
806
880
|
await upsertRetrospectiveState({
|
|
807
881
|
conversationId: sourceConversationId,
|
|
808
882
|
lastProcessedMessageId: cutoffMessageId,
|
|
@@ -1003,9 +1077,204 @@ async function extractRetrospectiveRunRemembers(
|
|
|
1003
1077
|
if (runMessages == null) {
|
|
1004
1078
|
return [];
|
|
1005
1079
|
}
|
|
1080
|
+
// Deliberately unfiltered by execution success: this reads a PRIOR run for
|
|
1081
|
+
// the <already_remembered> dedup baseline, where over-inclusion is the
|
|
1082
|
+
// safe direction (worst case a fact is not re-saved) and old runs predate
|
|
1083
|
+
// result-verified evidence. The CURRENT run's log append goes through
|
|
1084
|
+
// `collectRetrospectiveRunEvidence`, which does verify execution.
|
|
1006
1085
|
return extractRememberContents(runMessages);
|
|
1007
1086
|
}
|
|
1008
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* Tool names whose persisted `tool_use` blocks count as durable memory work
|
|
1090
|
+
* for the fail-closed advancement gate: `remember` writes the memory buffer,
|
|
1091
|
+
* `scaffold_managed_skill` writes a managed skill. Read-only tools on the
|
|
1092
|
+
* retrospective allowlist (`skill_load`, `find_similar_skills`) deliberately
|
|
1093
|
+
* do not qualify: a run that only browsed produced nothing durable.
|
|
1094
|
+
*/
|
|
1095
|
+
const DURABLE_RETROSPECTIVE_TOOLS: ReadonlySet<string> = new Set([
|
|
1096
|
+
"remember",
|
|
1097
|
+
"scaffold_managed_skill",
|
|
1098
|
+
]);
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* Read the durable evidence a retrospective run persisted: its `remember`
|
|
1102
|
+
* contents plus a count of every memory-writing tool call on the run's
|
|
1103
|
+
* post-boundary tail whose EXECUTION succeeded. A `tool_use` block alone
|
|
1104
|
+
* proves only that the model asked; the durable write happens inside the
|
|
1105
|
+
* executor, so a call counts (and its facts feed the remembered log) only
|
|
1106
|
+
* when a matching non-error `tool_result` is persisted on the same tail. A
|
|
1107
|
+
* failed or missing execution therefore leaves the window retryable, and a
|
|
1108
|
+
* failed `remember`'s facts never enter the `<already_remembered>` baseline
|
|
1109
|
+
* where they would suppress the retry's re-save. A load failure
|
|
1110
|
+
* (`runMessages == null`) reports zero durable calls, which the advancement
|
|
1111
|
+
* gate treats as "not proven usable" (fail-closed).
|
|
1112
|
+
*/
|
|
1113
|
+
async function collectRetrospectiveRunEvidence(
|
|
1114
|
+
conversationId: string,
|
|
1115
|
+
): Promise<{
|
|
1116
|
+
remembers: string[];
|
|
1117
|
+
/** Memory-writing tool calls whose execution verifiably succeeded. */
|
|
1118
|
+
durableToolCallCount: number;
|
|
1119
|
+
/** Memory-writing tool calls the run attempted, regardless of outcome. */
|
|
1120
|
+
durableToolAttemptCount: number;
|
|
1121
|
+
/**
|
|
1122
|
+
* The run replied with exactly the mandated no-findings sentinel text
|
|
1123
|
+
* ({@link MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}) in a persisted assistant
|
|
1124
|
+
* text block. Strict whole-block equality: prose that merely mentions the
|
|
1125
|
+
* phrase does not qualify, so an analysis-only reply stays unusable.
|
|
1126
|
+
*/
|
|
1127
|
+
explicitNoFindings: boolean;
|
|
1128
|
+
}> {
|
|
1129
|
+
const conv = await getConversation(conversationId);
|
|
1130
|
+
const runMessages = await loadRetrospectiveRunMessages(
|
|
1131
|
+
conversationId,
|
|
1132
|
+
conv?.source ?? null,
|
|
1133
|
+
);
|
|
1134
|
+
if (runMessages == null) {
|
|
1135
|
+
return {
|
|
1136
|
+
remembers: [],
|
|
1137
|
+
durableToolCallCount: 0,
|
|
1138
|
+
durableToolAttemptCount: 0,
|
|
1139
|
+
explicitNoFindings: false,
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
const succeededIds = collectSuccessfulToolResultIds(runMessages);
|
|
1143
|
+
return {
|
|
1144
|
+
remembers: extractRememberContents(runMessages, succeededIds),
|
|
1145
|
+
durableToolCallCount: countDurableToolUses(runMessages, succeededIds),
|
|
1146
|
+
durableToolAttemptCount: countDurableToolUses(runMessages, null),
|
|
1147
|
+
explicitNoFindings: hasExplicitNoFindingsReply(runMessages),
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Whether any persisted assistant row on the run's tail carries a text block
|
|
1153
|
+
* that is exactly the no-findings sentinel (after trimming). The instruction
|
|
1154
|
+
* template mandates this exact reply for a reviewed-and-nothing-to-save
|
|
1155
|
+
* pass, making it the positive persisted artifact that distinguishes a
|
|
1156
|
+
* legitimate no-findings review from an empty or unusable response.
|
|
1157
|
+
*/
|
|
1158
|
+
function hasExplicitNoFindingsReply(messages: MessageLike[]): boolean {
|
|
1159
|
+
for (const msg of messages) {
|
|
1160
|
+
if (msg.role !== "assistant") {
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
let blocks: unknown = msg.content;
|
|
1164
|
+
if (typeof blocks === "string") {
|
|
1165
|
+
try {
|
|
1166
|
+
blocks = JSON.parse(blocks);
|
|
1167
|
+
} catch {
|
|
1168
|
+
continue;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (!Array.isArray(blocks)) {
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
for (const block of blocks) {
|
|
1175
|
+
if (!block || typeof block !== "object") {
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
const b = block as Record<string, unknown>;
|
|
1179
|
+
if (
|
|
1180
|
+
b.type === "text" &&
|
|
1181
|
+
typeof b.text === "string" &&
|
|
1182
|
+
b.text.trim() === MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT
|
|
1183
|
+
) {
|
|
1184
|
+
return true;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Ids of `tool_result` blocks on the run's user rows whose execution did not
|
|
1193
|
+
* report an error. Robust to malformed content JSON the same way
|
|
1194
|
+
* `extractRememberContents` is.
|
|
1195
|
+
*/
|
|
1196
|
+
function collectSuccessfulToolResultIds(messages: MessageLike[]): Set<string> {
|
|
1197
|
+
const ids = new Set<string>();
|
|
1198
|
+
for (const msg of messages) {
|
|
1199
|
+
if (msg.role !== "user") {
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
let blocks: unknown = msg.content;
|
|
1203
|
+
if (typeof blocks === "string") {
|
|
1204
|
+
try {
|
|
1205
|
+
blocks = JSON.parse(blocks);
|
|
1206
|
+
} catch {
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (!Array.isArray(blocks)) {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
for (const block of blocks) {
|
|
1214
|
+
if (!block || typeof block !== "object") {
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const b = block as Record<string, unknown>;
|
|
1218
|
+
// guard:allow-tool-result-only: success evidence for locally-executed
|
|
1219
|
+
// durable memory tools; server-side web_search_tool_result never
|
|
1220
|
+
// corresponds to a durable write and carries no is_error flag.
|
|
1221
|
+
if (
|
|
1222
|
+
b.type === "tool_result" &&
|
|
1223
|
+
typeof b.tool_use_id === "string" &&
|
|
1224
|
+
b.is_error !== true
|
|
1225
|
+
) {
|
|
1226
|
+
ids.add(b.tool_use_id);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return ids;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Count persisted `tool_use` blocks whose `name` is in
|
|
1235
|
+
* {@link DURABLE_RETROSPECTIVE_TOOLS} across the run's assistant rows.
|
|
1236
|
+
* With a `succeededIds` set, only calls whose id has a matching successful
|
|
1237
|
+
* `tool_result` count (verified executions); with `null`, every attempt
|
|
1238
|
+
* counts regardless of outcome.
|
|
1239
|
+
*/
|
|
1240
|
+
function countDurableToolUses(
|
|
1241
|
+
messages: MessageLike[],
|
|
1242
|
+
succeededIds: ReadonlySet<string> | null,
|
|
1243
|
+
): number {
|
|
1244
|
+
let count = 0;
|
|
1245
|
+
for (const msg of messages) {
|
|
1246
|
+
if (msg.role !== "assistant") {
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1249
|
+
let blocks: unknown = msg.content;
|
|
1250
|
+
if (typeof blocks === "string") {
|
|
1251
|
+
try {
|
|
1252
|
+
blocks = JSON.parse(blocks);
|
|
1253
|
+
} catch {
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (!Array.isArray(blocks)) {
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
for (const block of blocks) {
|
|
1261
|
+
if (!block || typeof block !== "object") {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
const b = block as Record<string, unknown>;
|
|
1265
|
+
if (
|
|
1266
|
+
b.type === "tool_use" &&
|
|
1267
|
+
DURABLE_RETROSPECTIVE_TOOLS.has(String(b.name)) &&
|
|
1268
|
+
(succeededIds === null ||
|
|
1269
|
+
(typeof b.id === "string" && succeededIds.has(b.id)))
|
|
1270
|
+
) {
|
|
1271
|
+
count += 1;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return count;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1009
1278
|
interface MessageLike {
|
|
1010
1279
|
role: string;
|
|
1011
1280
|
content: string | ContentBlock[];
|
|
@@ -1016,7 +1285,10 @@ interface MessageLike {
|
|
|
1016
1285
|
* `"remember"` and return the `input.content` strings in order. Robust to
|
|
1017
1286
|
* malformed content JSON — unparseable rows are skipped, not propagated.
|
|
1018
1287
|
*/
|
|
1019
|
-
function extractRememberContents(
|
|
1288
|
+
function extractRememberContents(
|
|
1289
|
+
messages: MessageLike[],
|
|
1290
|
+
succeededIds?: ReadonlySet<string>,
|
|
1291
|
+
): string[] {
|
|
1020
1292
|
const contents: string[] = [];
|
|
1021
1293
|
for (const msg of messages) {
|
|
1022
1294
|
if (msg.role !== "assistant") {
|
|
@@ -1044,6 +1316,16 @@ function extractRememberContents(messages: MessageLike[]): string[] {
|
|
|
1044
1316
|
if (b.name !== "remember") {
|
|
1045
1317
|
continue;
|
|
1046
1318
|
}
|
|
1319
|
+
// When a success set is provided, only executions that reported a
|
|
1320
|
+
// non-error tool_result contribute facts: a failed remember never
|
|
1321
|
+
// wrote the buffer, and logging its facts would suppress the retry's
|
|
1322
|
+
// re-save via <already_remembered>.
|
|
1323
|
+
if (
|
|
1324
|
+
succeededIds !== undefined &&
|
|
1325
|
+
(typeof b.id !== "string" || !succeededIds.has(b.id))
|
|
1326
|
+
) {
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1047
1329
|
const input = b.input;
|
|
1048
1330
|
if (!input || typeof input !== "object") {
|
|
1049
1331
|
continue;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { getLogger } from "./logging.js";
|
|
30
|
+
import { MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT } from "./memory-retrospective-constants.js";
|
|
30
31
|
import { getWorkspaceDir } from "./paths.js";
|
|
31
32
|
import { loadPromptOverride } from "./prompt-override.js";
|
|
32
33
|
|
|
@@ -43,6 +44,13 @@ function neutralizeSentinels(s: string): string {
|
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* The sentence mandating the exact no-findings reply. Built from
|
|
49
|
+
* {@link MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT} so the instruction and the
|
|
50
|
+
* finalizer's acceptance check can never drift apart.
|
|
51
|
+
*/
|
|
52
|
+
const NO_FINDINGS_MANDATE = `If nothing new is worth saving, reply with exactly "${MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT}" and stop.`;
|
|
53
|
+
|
|
46
54
|
/**
|
|
47
55
|
* Bundled fork-instruction template. Exported so tests (and any future
|
|
48
56
|
* "Load default" affordance) can reference the canonical body verbatim.
|
|
@@ -63,7 +71,7 @@ Two dedup sources to skip:
|
|
|
63
71
|
1. Anything semantically captured in <already_remembered> above (from prior retrospective passes).
|
|
64
72
|
2. Anything you already called \`remember\` on inline within your review window — those appear as \`tool_use\` blocks with \`name: "remember"\` in your history.
|
|
65
73
|
|
|
66
|
-
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.
|
|
74
|
+
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. ${NO_FINDINGS_MANDATE}
|
|
67
75
|
{{SKILL_AUTHORING_SECTION}}`;
|
|
68
76
|
|
|
69
77
|
/** Placeholder names recognized in the bundled template and overrides. */
|
|
@@ -140,7 +148,9 @@ export interface ForkInstructionArgs {
|
|
|
140
148
|
* override resolves to a usable file (bounded to a regular file under 1 MiB by
|
|
141
149
|
* the shared {@link loadPromptOverride}), else the bundled
|
|
142
150
|
* {@link RETROSPECTIVE_INSTRUCTION_TEMPLATE}; both get the same placeholder
|
|
143
|
-
* substitution.
|
|
151
|
+
* substitution. An override additionally gets the no-findings mandate
|
|
152
|
+
* appended after its body: the exact-reply sentinel is the finalizer's
|
|
153
|
+
* advancement contract, so it holds regardless of what the override says.
|
|
144
154
|
*/
|
|
145
155
|
export function buildForkInstruction({
|
|
146
156
|
windowStartTimestamp,
|
|
@@ -175,7 +185,7 @@ export function buildForkInstruction({
|
|
|
175
185
|
label: "retrospective prompt",
|
|
176
186
|
});
|
|
177
187
|
|
|
178
|
-
|
|
188
|
+
const rendered = substituteInstructionParts(
|
|
179
189
|
override ?? RETROSPECTIVE_INSTRUCTION_TEMPLATE,
|
|
180
190
|
{
|
|
181
191
|
AVAILABLE_TOOLS_LINE: availableToolsLine,
|
|
@@ -186,6 +196,16 @@ export function buildForkInstruction({
|
|
|
186
196
|
: "",
|
|
187
197
|
},
|
|
188
198
|
);
|
|
199
|
+
if (override == null) {
|
|
200
|
+
return rendered;
|
|
201
|
+
}
|
|
202
|
+
// The finalizer recognizes a no-findings review only by the exact
|
|
203
|
+
// MEMORY_RETROSPECTIVE_NO_FINDINGS_TEXT reply, so the mandate is part of
|
|
204
|
+
// the advancement contract, not prompt styling: an override body that
|
|
205
|
+
// drops it would leave every no-findings window permanently retryable.
|
|
206
|
+
// Appended outside the override so a custom prompt cannot break the
|
|
207
|
+
// contract.
|
|
208
|
+
return `${rendered}\n\n${NO_FINDINGS_MANDATE}`;
|
|
189
209
|
}
|
|
190
210
|
|
|
191
211
|
/**
|
|
@@ -31,11 +31,16 @@ const log = getLogger("memory-v2-consolidate");
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Hard timeout for the consolidation run. Consolidation reads the buffer,
|
|
34
|
-
* rewrites several files, and re-encodes essentials/threads:
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* rewrites several files, and re-encodes essentials/threads: on a mature
|
|
35
|
+
* corpus a full pass legitimately runs ~20 minutes under cross-process write
|
|
36
|
+
* contention, so the bound leaves headroom above that while still keeping a
|
|
37
|
+
* stuck run from pinning the worker indefinitely. Matches the default
|
|
38
|
+
* `timeouts.backgroundTurnTimeoutSec` budget for heartbeat/background turns.
|
|
39
|
+
* Overrunning it marks the run failed and skips its follow-up jobs (reembeds,
|
|
40
|
+
* v3 maintenance) even though the agent's file edits land, so the bound must
|
|
41
|
+
* comfortably exceed a healthy run's duration.
|
|
37
42
|
*/
|
|
38
|
-
export const CONSOLIDATION_TIMEOUT_MS =
|
|
43
|
+
export const CONSOLIDATION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
46
|
* Age past which a lock held by an apparently-live PID is taken over anyway.
|
|
@@ -36,6 +36,7 @@ import { z } from "zod";
|
|
|
36
36
|
|
|
37
37
|
import { usesConceptPageMemory } from "../../../../config/memory-v3-gate.js";
|
|
38
38
|
import type { AssistantConfig } from "../../../../config/types.js";
|
|
39
|
+
import { warmGuardianBindings } from "../../../../contacts/guardian-delivery-reader.js";
|
|
39
40
|
import { emitNotificationSignal } from "../../../../notifications/emit-signal.js";
|
|
40
41
|
import { getDb } from "../../../../persistence/db-connection.js";
|
|
41
42
|
import type { MemoryJob } from "../../../../persistence/jobs-store.js";
|
|
@@ -155,6 +156,12 @@ export async function memoryV2SweepJob(
|
|
|
155
156
|
return 0;
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
// Warm both guardian-delivery cache keys (vellum + unfiltered) so
|
|
160
|
+
// resolveUserName's sync guardian-file resolution, including its
|
|
161
|
+
// any-channel fallback, hits fresh keys instead of falling back to
|
|
162
|
+
// users/default.md on this worker process's cold cache.
|
|
163
|
+
await warmGuardianBindings();
|
|
164
|
+
|
|
158
165
|
const systemPrompt = renderSweepPrompt({
|
|
159
166
|
assistantName: getAssistantName(),
|
|
160
167
|
userName: resolveUserName(workspaceDir),
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
|
|
43
43
|
import type { AssistantConfig } from "../../../../config/types.js";
|
|
44
|
+
import { warmGuardianBindings } from "../../../../contacts/guardian-delivery-reader.js";
|
|
44
45
|
import {
|
|
45
46
|
cachedTextBlock,
|
|
46
47
|
extractToolUse,
|
|
@@ -393,6 +394,13 @@ async function runRouterBatch(
|
|
|
393
394
|
provider,
|
|
394
395
|
} = params;
|
|
395
396
|
|
|
397
|
+
// Warm both guardian-delivery cache keys (vellum + unfiltered) so
|
|
398
|
+
// resolveUserName's sync guardian-file resolution, including its
|
|
399
|
+
// any-channel fallback, hits fresh keys instead of falling back to
|
|
400
|
+
// users/default.md on a cold/TTL-expired cache. Two local-socket IPC
|
|
401
|
+
// reads per batch, dwarfed by the batch's provider call.
|
|
402
|
+
await warmGuardianBindings();
|
|
403
|
+
|
|
396
404
|
const systemPrompt = resolveRouterPrompt(
|
|
397
405
|
config.memory?.v2?.router?.router_prompt_path ?? null,
|
|
398
406
|
workspaceDir,
|