@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
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for workspace migration `140-repair-seed-pinned-memory-v3-live`.
|
|
3
|
+
*
|
|
4
|
+
* The pre-#39847 first-launch seed persisted `memory.v3.live = false` before
|
|
5
|
+
* migration 105 could record the real decision, stranding brand-new
|
|
6
|
+
* assistants on v2 and demoting existing v3 assistants whose config.json was
|
|
7
|
+
* quarantined and reseeded. The repair flips `live` back to true only for
|
|
8
|
+
* those two victim classes and never over a deliberate opt-out.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
existsSync,
|
|
13
|
+
mkdirSync,
|
|
14
|
+
mkdtempSync,
|
|
15
|
+
readFileSync,
|
|
16
|
+
rmSync,
|
|
17
|
+
writeFileSync,
|
|
18
|
+
} from "node:fs";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { Database } from "bun:sqlite";
|
|
22
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
23
|
+
|
|
24
|
+
import { repairSeedPinnedMemoryV3LiveMigration } from "../workspace/migrations/140-repair-seed-pinned-memory-v3-live.js";
|
|
25
|
+
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
26
|
+
import type { MigrationRunContext } from "../workspace/migrations/types.js";
|
|
27
|
+
|
|
28
|
+
const NEW_WORKSPACE_CTX: MigrationRunContext = { isNewWorkspace: true };
|
|
29
|
+
const UPGRADE_CTX: MigrationRunContext = { isNewWorkspace: false };
|
|
30
|
+
|
|
31
|
+
let workspaceDir: string;
|
|
32
|
+
let configPath: string;
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
workspaceDir = mkdtempSync(join(tmpdir(), "vellum-migration-140-test-"));
|
|
36
|
+
configPath = join(workspaceDir, "config.json");
|
|
37
|
+
mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
if (existsSync(workspaceDir)) {
|
|
42
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
function readConfig(): Record<string, unknown> {
|
|
47
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function readLive(): unknown {
|
|
51
|
+
const memory = (readConfig().memory ?? {}) as Record<string, unknown>;
|
|
52
|
+
const v3 = (memory.v3 ?? {}) as Record<string, unknown>;
|
|
53
|
+
return v3.live;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function writeConfig(config: Record<string, unknown>): void {
|
|
57
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A checkpoint file whose 105 entry ran `gapMs` after the earliest entry. */
|
|
61
|
+
function writeCheckpoints(gapMs: number): void {
|
|
62
|
+
const base = Date.parse("2026-06-20T12:00:00.000Z");
|
|
63
|
+
writeFileSync(
|
|
64
|
+
join(workspaceDir, "data", ".workspace-migrations.json"),
|
|
65
|
+
JSON.stringify(
|
|
66
|
+
{
|
|
67
|
+
applied: {
|
|
68
|
+
"001-avatar-rename": {
|
|
69
|
+
appliedAt: new Date(base).toISOString(),
|
|
70
|
+
status: "completed",
|
|
71
|
+
},
|
|
72
|
+
"105-enable-memory-v3-live-for-new-workspaces": {
|
|
73
|
+
appliedAt: new Date(base + gapMs).toISOString(),
|
|
74
|
+
status: "completed",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
null,
|
|
79
|
+
2,
|
|
80
|
+
) + "\n",
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const FIRST_BOOT_GAP_MS = 5_000;
|
|
85
|
+
const UPGRADE_SWEEP_GAP_MS = 30 * 24 * 60 * 60 * 1000;
|
|
86
|
+
|
|
87
|
+
function writeSelectionRows(file: string): void {
|
|
88
|
+
const db = new Database(join(workspaceDir, "data", "db", file));
|
|
89
|
+
db.exec(`
|
|
90
|
+
CREATE TABLE memory_v3_selections (
|
|
91
|
+
conversation_id TEXT NOT NULL,
|
|
92
|
+
turn INTEGER NOT NULL,
|
|
93
|
+
slug TEXT NOT NULL,
|
|
94
|
+
source TEXT NOT NULL,
|
|
95
|
+
pinned INTEGER NOT NULL DEFAULT 0
|
|
96
|
+
);
|
|
97
|
+
INSERT INTO memory_v3_selections (conversation_id, turn, slug, source)
|
|
98
|
+
VALUES ('conv-1', 1, 'some-page', 'needle');
|
|
99
|
+
`);
|
|
100
|
+
db.close();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
describe("140-repair-seed-pinned-memory-v3-live migration", () => {
|
|
104
|
+
test("has correct id and is registered last", () => {
|
|
105
|
+
expect(repairSeedPinnedMemoryV3LiveMigration.id).toBe(
|
|
106
|
+
"140-repair-seed-pinned-memory-v3-live",
|
|
107
|
+
);
|
|
108
|
+
expect(repairSeedPinnedMemoryV3LiveMigration.description).toContain(
|
|
109
|
+
"memory.v3.live",
|
|
110
|
+
);
|
|
111
|
+
// getLastWorkspaceMigrationId() reports the final entry as the registry
|
|
112
|
+
// ceiling, so ordering matters: this must be registered, and everything
|
|
113
|
+
// after it must carry a higher id. Asserting it stays literally last
|
|
114
|
+
// would break on every migration appended after it.
|
|
115
|
+
const index = WORKSPACE_MIGRATIONS.findIndex(
|
|
116
|
+
(migration) => migration.id === "140-repair-seed-pinned-memory-v3-live",
|
|
117
|
+
);
|
|
118
|
+
expect(index).toBeGreaterThan(-1);
|
|
119
|
+
for (const later of WORKSPACE_MIGRATIONS.slice(index + 1)) {
|
|
120
|
+
expect(later.id > "140").toBe(true);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("flips a seed-race victim: born in the 105 era, live=false, v3 never ran", () => {
|
|
125
|
+
writeConfig({
|
|
126
|
+
memory: { v2: { enabled: true }, v3: { live: false } },
|
|
127
|
+
llm: { activeProfile: "balanced" },
|
|
128
|
+
});
|
|
129
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
130
|
+
|
|
131
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
132
|
+
|
|
133
|
+
expect(readLive()).toBe(true);
|
|
134
|
+
// The rest of the config is untouched.
|
|
135
|
+
const config = readConfig();
|
|
136
|
+
expect((config.llm as Record<string, unknown>).activeProfile).toBe(
|
|
137
|
+
"balanced",
|
|
138
|
+
);
|
|
139
|
+
expect(
|
|
140
|
+
((config.memory as Record<string, unknown>).v2 as Record<string, unknown>)
|
|
141
|
+
.enabled,
|
|
142
|
+
).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("skips new workspaces so a hatch-time opt-out override wins", () => {
|
|
146
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
147
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
148
|
+
|
|
149
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, NEW_WORKSPACE_CTX);
|
|
150
|
+
|
|
151
|
+
expect(readLive()).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("leaves an absent leaf alone: pre-105 assistants stay on the manual-upgrade path", () => {
|
|
155
|
+
writeConfig({ memory: { v2: { enabled: true } } });
|
|
156
|
+
writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
|
|
157
|
+
|
|
158
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
159
|
+
|
|
160
|
+
expect(readLive()).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("leaves live=true alone (idempotent after its own repair)", () => {
|
|
164
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
165
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
166
|
+
|
|
167
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
168
|
+
expect(readLive()).toBe(true);
|
|
169
|
+
const afterFirstRun = readFileSync(configPath, "utf-8");
|
|
170
|
+
|
|
171
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
172
|
+
expect(readFileSync(configPath, "utf-8")).toBe(afterFirstRun);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("skips a live=false workspace that was NOT born in the 105 era", () => {
|
|
176
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
177
|
+
writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
|
|
178
|
+
|
|
179
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
180
|
+
|
|
181
|
+
expect(readLive()).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("skips when the checkpoint file is missing (no era evidence)", () => {
|
|
185
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
186
|
+
|
|
187
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
188
|
+
|
|
189
|
+
expect(readLive()).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("respects a hatch-time opt-out recorded in the archived default overlay", () => {
|
|
193
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
194
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
195
|
+
writeFileSync(
|
|
196
|
+
join(workspaceDir, "default-config.json"),
|
|
197
|
+
JSON.stringify({ memory: { v3: { live: false } } }, null, 2),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
201
|
+
|
|
202
|
+
expect(readLive()).toBe(false);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("an archived overlay without a memory.v3.live opt-out does not block repair", () => {
|
|
206
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
207
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
208
|
+
writeFileSync(
|
|
209
|
+
join(workspaceDir, "default-config.json"),
|
|
210
|
+
JSON.stringify({ llm: { activeProfile: "balanced" } }, null, 2),
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
214
|
+
|
|
215
|
+
expect(readLive()).toBe(true);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("respects a deliberate opt-out: v3 selection rows exist", () => {
|
|
219
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
220
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
221
|
+
writeSelectionRows("assistant-memory.db");
|
|
222
|
+
|
|
223
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
224
|
+
|
|
225
|
+
expect(readLive()).toBe(false);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("finds selection rows staged under the __relocating name mid-drain", () => {
|
|
229
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
230
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
231
|
+
const db = new Database(join(workspaceDir, "data", "db", "assistant.db"));
|
|
232
|
+
db.exec(`
|
|
233
|
+
CREATE TABLE memory_v3_selections__relocating (
|
|
234
|
+
conversation_id TEXT NOT NULL,
|
|
235
|
+
turn INTEGER NOT NULL,
|
|
236
|
+
slug TEXT NOT NULL,
|
|
237
|
+
source TEXT NOT NULL
|
|
238
|
+
);
|
|
239
|
+
INSERT INTO memory_v3_selections__relocating
|
|
240
|
+
(conversation_id, turn, slug, source)
|
|
241
|
+
VALUES ('conv-1', 1, 'some-page', 'needle');
|
|
242
|
+
`);
|
|
243
|
+
db.close();
|
|
244
|
+
|
|
245
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
246
|
+
|
|
247
|
+
expect(readLive()).toBe(false);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("finds selection rows in the pre-relocation assistant.db too", () => {
|
|
251
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
252
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
253
|
+
writeSelectionRows("assistant.db");
|
|
254
|
+
|
|
255
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
256
|
+
|
|
257
|
+
expect(readLive()).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("an empty selections table is not usage evidence", () => {
|
|
261
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
262
|
+
writeCheckpoints(FIRST_BOOT_GAP_MS);
|
|
263
|
+
const db = new Database(
|
|
264
|
+
join(workspaceDir, "data", "db", "assistant-memory.db"),
|
|
265
|
+
);
|
|
266
|
+
db.exec(
|
|
267
|
+
`CREATE TABLE memory_v3_selections (conversation_id TEXT, turn INTEGER)`,
|
|
268
|
+
);
|
|
269
|
+
db.close();
|
|
270
|
+
|
|
271
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
272
|
+
|
|
273
|
+
expect(readLive()).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test("quarantine carry-forward flips a demoted v3 assistant even with usage rows and an old workspace", () => {
|
|
277
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
278
|
+
writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
|
|
279
|
+
writeSelectionRows("assistant-memory.db");
|
|
280
|
+
writeFileSync(
|
|
281
|
+
join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
|
|
282
|
+
JSON.stringify({ memory: { v3: { live: true } } }, null, 2),
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
286
|
+
|
|
287
|
+
expect(readLive()).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("salvages live=true from a truncated (unparseable) quarantined config", () => {
|
|
291
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
292
|
+
writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
|
|
293
|
+
writeFileSync(
|
|
294
|
+
join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
|
|
295
|
+
`{\n "memory": {\n "v3": {\n "live": true\n }\n },\n "llm": {\n "activeProf`,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
299
|
+
|
|
300
|
+
expect(readLive()).toBe(true);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("the NEWEST quarantined config wins", () => {
|
|
304
|
+
writeConfig({ memory: { v3: { live: false } } });
|
|
305
|
+
writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
|
|
306
|
+
writeFileSync(
|
|
307
|
+
join(workspaceDir, "config.json.corrupt-2026-07-01T10-00-00.000Z.json"),
|
|
308
|
+
JSON.stringify({ memory: { v3: { live: true } } }),
|
|
309
|
+
);
|
|
310
|
+
writeFileSync(
|
|
311
|
+
join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
|
|
312
|
+
JSON.stringify({ memory: { v3: { live: false } } }),
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
316
|
+
|
|
317
|
+
expect(readLive()).toBe(false);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("no-ops when config.json is missing or corrupt", () => {
|
|
321
|
+
// Missing.
|
|
322
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
323
|
+
expect(existsSync(configPath)).toBe(false);
|
|
324
|
+
|
|
325
|
+
// Corrupt.
|
|
326
|
+
writeFileSync(configPath, "{ not json");
|
|
327
|
+
repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
|
|
328
|
+
expect(readFileSync(configPath, "utf-8")).toBe("{ not json");
|
|
329
|
+
});
|
|
330
|
+
});
|
package/src/acp/failure-error.ts
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
* `{"error":{"message":"..."}}`. This picks the most specific signal available:
|
|
7
7
|
* a structured stderr error, else the last stderr line, else the ack message.
|
|
8
8
|
*
|
|
9
|
-
* Pure
|
|
9
|
+
* Pure; the only dependency is the shared escape-sequence strip.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
// with their log lines: ESC `[`, parameter/intermediate bytes, then final byte.
|
|
14
|
-
const ANSI_ESCAPE = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
12
|
+
import { stripAnsiSequences } from "../util/ansi.js";
|
|
15
13
|
|
|
16
14
|
export function deriveFailureError(ackMessage: string, stderr: string): string {
|
|
17
|
-
const clean = stderr
|
|
15
|
+
const clean = stripAnsiSequences(stderr).trim();
|
|
18
16
|
|
|
19
17
|
// Most precise: a structured adapter error — prefer it over the ack.
|
|
20
18
|
const jsonMessage = lastJsonErrorMessage(clean);
|
package/src/agent/attachments.ts
CHANGED
|
@@ -76,35 +76,37 @@ export function attachmentsToReferenceBlocks(
|
|
|
76
76
|
|
|
77
77
|
export function attachmentsToContentBlocks(
|
|
78
78
|
attachments: MessageAttachmentInput[],
|
|
79
|
-
): ContentBlock[] {
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
): Promise<ContentBlock[]> {
|
|
80
|
+
return Promise.all(
|
|
81
|
+
attachments.map(async (attachment) => {
|
|
82
|
+
if (attachment.mimeType.toLowerCase().startsWith("image/")) {
|
|
83
|
+
const { data, mediaType } = await optimizeImageForTransport(
|
|
84
|
+
attachment.data,
|
|
85
|
+
attachment.mimeType,
|
|
86
|
+
);
|
|
87
|
+
return {
|
|
88
|
+
type: "image",
|
|
89
|
+
source: {
|
|
90
|
+
type: "base64",
|
|
91
|
+
media_type: mediaType,
|
|
92
|
+
data,
|
|
93
|
+
},
|
|
94
|
+
} as ContentBlock;
|
|
95
|
+
}
|
|
96
|
+
|
|
86
97
|
return {
|
|
87
|
-
type: "
|
|
98
|
+
type: "file",
|
|
88
99
|
source: {
|
|
89
100
|
type: "base64",
|
|
90
|
-
media_type:
|
|
91
|
-
data,
|
|
101
|
+
media_type: attachment.mimeType,
|
|
102
|
+
data: attachment.data,
|
|
103
|
+
filename: attachment.filename,
|
|
92
104
|
},
|
|
105
|
+
extracted_text: attachment.extractedText,
|
|
106
|
+
...(attachment.id ? { _attachmentId: attachment.id } : {}),
|
|
93
107
|
} as ContentBlock;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
type: "file",
|
|
98
|
-
source: {
|
|
99
|
-
type: "base64",
|
|
100
|
-
media_type: attachment.mimeType,
|
|
101
|
-
data: attachment.data,
|
|
102
|
-
filename: attachment.filename,
|
|
103
|
-
},
|
|
104
|
-
extracted_text: attachment.extractedText,
|
|
105
|
-
...(attachment.id ? { _attachmentId: attachment.id } : {}),
|
|
106
|
-
} as ContentBlock;
|
|
107
|
-
});
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
/**
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* recover — so detection and repair of ordering drift live together as one unit.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { analyzeServerToolPairing } from "../../providers/server-tool-pairing.js";
|
|
18
19
|
import type {
|
|
19
20
|
ContentBlock,
|
|
20
21
|
Message,
|
|
@@ -69,6 +70,10 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
69
70
|
let pendingToolUseIds = new Set<string>();
|
|
70
71
|
// tool_result blocks stripped from assistant messages, keyed by tool_use_id
|
|
71
72
|
let recoveredResults = new Map<string, ToolResultContent>();
|
|
73
|
+
// Server-tool pairs can legitimately span messages (deferred execution) or
|
|
74
|
+
// sit unanswered at the tail (the provider runs the search on the next
|
|
75
|
+
// request), so orphanhood is judged against the whole list, not per message.
|
|
76
|
+
const serverToolPairing = analyzeServerToolPairing(messages);
|
|
72
77
|
|
|
73
78
|
for (const [msgIndex, msg] of messages.entries()) {
|
|
74
79
|
if (msg.role === "assistant") {
|
|
@@ -100,36 +105,32 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
108
|
+
// Repair orphaned server-side tool blocks. Server tools (e.g.
|
|
109
|
+
// web_search) emit server_tool_use + matching web_search_tool_result;
|
|
110
|
+
// orphanhood comes from `serverToolPairing`, which resolves pairs
|
|
111
|
+
// across messages and exempts the deferred tail. The synthetic result
|
|
112
|
+
// is inserted IMMEDIATELY AFTER the orphan server_tool_use (not
|
|
107
113
|
// appended to the end) so ensureToolPairing's split at tool_use
|
|
108
114
|
// boundaries cannot separate the pair. An orphan
|
|
109
|
-
// web_search_tool_result
|
|
110
|
-
//
|
|
111
|
-
const serverToolIds = new Set(
|
|
112
|
-
cleanedContent
|
|
113
|
-
.filter(
|
|
114
|
-
(b): b is ServerToolUseContent => b.type === "server_tool_use",
|
|
115
|
-
)
|
|
116
|
-
.map((b) => b.id),
|
|
117
|
-
);
|
|
118
|
-
const matchedServerIds = new Set(
|
|
119
|
-
cleanedContent
|
|
120
|
-
.filter((b) => b.type === "web_search_tool_result")
|
|
121
|
-
.map((b) => (b as { tool_use_id: string }).tool_use_id),
|
|
122
|
-
);
|
|
115
|
+
// web_search_tool_result with no use anywhere is downgraded to text.
|
|
116
|
+
// Anthropic rejects the request otherwise.
|
|
123
117
|
const orphanedServerIds = new Set<string>();
|
|
124
|
-
for (const id of serverToolIds) {
|
|
125
|
-
if (!matchedServerIds.has(id)) {
|
|
126
|
-
orphanedServerIds.add(id);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
118
|
const orphanedWebSearchResultIds = new Set<string>();
|
|
130
|
-
for (const
|
|
131
|
-
if (
|
|
132
|
-
|
|
119
|
+
for (const b of cleanedContent) {
|
|
120
|
+
if (b.type === "server_tool_use") {
|
|
121
|
+
const id = (b as ServerToolUseContent).id;
|
|
122
|
+
if (
|
|
123
|
+
!serverToolPairing.resolvedPairIds.has(id) &&
|
|
124
|
+
!serverToolPairing.deferredUseIds.has(id)
|
|
125
|
+
) {
|
|
126
|
+
orphanedServerIds.add(id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (b.type === "web_search_tool_result") {
|
|
130
|
+
const id = (b as { tool_use_id: string }).tool_use_id;
|
|
131
|
+
if (!serverToolPairing.resolvedPairIds.has(id)) {
|
|
132
|
+
orphanedWebSearchResultIds.add(id);
|
|
133
|
+
}
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -110,10 +110,10 @@ export function upscaleTargetDimensions(dims: {
|
|
|
110
110
|
* Reactive only: called by the image-recovery plugin after an actual
|
|
111
111
|
* "Could not process image" rejection, never on the pre-send path.
|
|
112
112
|
*/
|
|
113
|
-
export function upscaleImageToMinimum(
|
|
113
|
+
export async function upscaleImageToMinimum(
|
|
114
114
|
base64Data: string,
|
|
115
115
|
mediaType: string,
|
|
116
|
-
): { data: string; mediaType: string } | null {
|
|
116
|
+
): Promise<{ data: string; mediaType: string } | null> {
|
|
117
117
|
const dims = parseImageDimensions(base64Data, mediaType);
|
|
118
118
|
if (!dims) {
|
|
119
119
|
return null;
|
|
@@ -122,7 +122,7 @@ export function upscaleImageToMinimum(
|
|
|
122
122
|
if (!target) {
|
|
123
123
|
return null;
|
|
124
124
|
}
|
|
125
|
-
const upscaled = convertImageToJpeg(Buffer.from(base64Data, "base64"), {
|
|
125
|
+
const upscaled = await convertImageToJpeg(Buffer.from(base64Data, "base64"), {
|
|
126
126
|
resizeToPx: target,
|
|
127
127
|
quality: JPEG_QUALITY,
|
|
128
128
|
});
|
|
@@ -144,10 +144,10 @@ export function upscaleImageToMinimum(
|
|
|
144
144
|
* Conversion (and its content-addressed disk cache) is shared with attachment
|
|
145
145
|
* storage normalization — see `util/image-conversion.ts`.
|
|
146
146
|
*/
|
|
147
|
-
export function optimizeImageForTransport(
|
|
147
|
+
export async function optimizeImageForTransport(
|
|
148
148
|
base64Data: string,
|
|
149
149
|
mediaType: string,
|
|
150
|
-
): { data: string; mediaType: string } {
|
|
150
|
+
): Promise<{ data: string; mediaType: string }> {
|
|
151
151
|
const rawBytes = Buffer.from(base64Data, "base64");
|
|
152
152
|
const dims = parseImageDimensions(base64Data, mediaType);
|
|
153
153
|
|
|
@@ -155,7 +155,7 @@ export function optimizeImageForTransport(
|
|
|
155
155
|
return { data: base64Data, mediaType };
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
const optimized = convertImageToJpeg(rawBytes, {
|
|
158
|
+
const optimized = await convertImageToJpeg(rawBytes, {
|
|
159
159
|
maxDimensionPx: MAX_DIMENSION,
|
|
160
160
|
quality: JPEG_QUALITY,
|
|
161
161
|
});
|
package/src/agent/loop.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isMemoryV3Live } from "../config/memory-v3-gate.js";
|
|
1
|
+
import type { AnsweredQuestion } from "../api/events/question-answered.js";
|
|
3
2
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
4
3
|
import { recordEstimate } from "../context/estimator-calibration.js";
|
|
5
4
|
import { preModelCallSanitize } from "../context/outbound-sanitize.js";
|
|
5
|
+
import { turnStartUserMessageHasSpotlight } from "../context/strip-injections.js";
|
|
6
6
|
import {
|
|
7
7
|
estimatePromptTokensRaw,
|
|
8
8
|
estimatePromptTokensWithTools,
|
|
@@ -116,9 +116,9 @@ export interface AgentLoopConfig {
|
|
|
116
116
|
* This is a SERVER tool the provider runs itself, distinct from the client
|
|
117
117
|
* tool list (`tools` / `resolveTools`): it is never executed by
|
|
118
118
|
* {@link AgentLoopConstructorOptions.toolExecutor} and does not require any
|
|
119
|
-
* client-tool allowlist entry. Used by the
|
|
120
|
-
*
|
|
121
|
-
*
|
|
119
|
+
* client-tool allowlist entry. Used by the advisor consult to ground its
|
|
120
|
+
* guidance with live web access on top of its read-only client tools.
|
|
121
|
+
* Defaults to false.
|
|
122
122
|
*/
|
|
123
123
|
enableNativeWebSearch?: boolean;
|
|
124
124
|
}
|
|
@@ -289,6 +289,8 @@ export type AgentEvent =
|
|
|
289
289
|
approvalReason?: string;
|
|
290
290
|
riskThreshold?: string;
|
|
291
291
|
activityMetadata?: ToolActivityMetadata;
|
|
292
|
+
/** Answered `ask_question` record (see `ToolExecutionResult.answeredQuestion`). */
|
|
293
|
+
answeredQuestion?: AnsweredQuestion;
|
|
292
294
|
/** Stable machine-readable error classification (see `ToolExecutionResult.errorCode`). */
|
|
293
295
|
errorCode?: string;
|
|
294
296
|
/**
|
|
@@ -698,6 +700,7 @@ export type LoopToolExecutor = (
|
|
|
698
700
|
approvalReason?: string;
|
|
699
701
|
riskThreshold?: string;
|
|
700
702
|
activityMetadata?: ToolActivityMetadata;
|
|
703
|
+
answeredQuestion?: AnsweredQuestion;
|
|
701
704
|
errorCode?: string;
|
|
702
705
|
}>;
|
|
703
706
|
|
|
@@ -1355,9 +1358,9 @@ export class AgentLoop {
|
|
|
1355
1358
|
// `this.provider.supportsNativeWebSearch` snapshot; providers without
|
|
1356
1359
|
// the routing-aware probe fall back to the static flag. This is a SERVER
|
|
1357
1360
|
// tool — it bypasses the client allowlist and the tool executor — so the
|
|
1358
|
-
//
|
|
1359
|
-
//
|
|
1360
|
-
//
|
|
1361
|
+
// advisor consult can ground its guidance with live web access on top of
|
|
1362
|
+
// its read-only client tools. Skip when a `web_search` tool is already
|
|
1363
|
+
// present so we never duplicate the name.
|
|
1361
1364
|
const supportsRoutedNativeWebSearch = this.provider
|
|
1362
1365
|
.supportsNativeWebSearchFor
|
|
1363
1366
|
? this.provider.supportsNativeWebSearchFor(
|
|
@@ -1420,9 +1423,7 @@ export class AgentLoop {
|
|
|
1420
1423
|
if (this.config.toolChoice) {
|
|
1421
1424
|
providerConfig.tool_choice = this.config.toolChoice;
|
|
1422
1425
|
} else if (attachNativeWebSearch) {
|
|
1423
|
-
//
|
|
1424
|
-
// advisor consult is otherwise tool-less). Let the model decide
|
|
1425
|
-
// whether to search rather than forcing it.
|
|
1426
|
+
// Let the model decide whether to search rather than forcing it.
|
|
1426
1427
|
providerConfig.tool_choice = { type: "auto" };
|
|
1427
1428
|
}
|
|
1428
1429
|
|
|
@@ -1430,14 +1431,18 @@ export class AgentLoop {
|
|
|
1430
1431
|
providerConfig.cacheTtl = this.config.cacheTtl;
|
|
1431
1432
|
}
|
|
1432
1433
|
|
|
1433
|
-
// Cache-anchor signal for
|
|
1434
|
-
// memory-v3
|
|
1435
|
-
//
|
|
1436
|
-
//
|
|
1437
|
-
//
|
|
1438
|
-
//
|
|
1439
|
-
//
|
|
1440
|
-
|
|
1434
|
+
// Cache-anchor signal for turns whose opening message is volatile. The
|
|
1435
|
+
// memory-v3 `<memory_spotlight>` block is the only injected block that
|
|
1436
|
+
// is strip-and-replaced from every user message each turn, so when it
|
|
1437
|
+
// is present that message's bytes do not recur next turn and a
|
|
1438
|
+
// long-TTL breakpoint on it could never be read back. The provider
|
|
1439
|
+
// marks it at the short TTL instead. Derived from the history actually
|
|
1440
|
+
// being sent rather than from configuration, so turns where memory
|
|
1441
|
+
// contributed no spotlight keep a normal anchor. Read off the
|
|
1442
|
+
// turn-starting message, so the signal holds for every request in the
|
|
1443
|
+
// turn rather than flipping once tool results arrive. Only set when
|
|
1444
|
+
// true so the wire/config stays byte-identical when absent.
|
|
1445
|
+
if (turnStartUserMessageHasSpotlight(history)) {
|
|
1441
1446
|
providerConfig.mutableLatestUserMessage = true;
|
|
1442
1447
|
}
|
|
1443
1448
|
|
|
@@ -1459,8 +1464,17 @@ export class AgentLoop {
|
|
|
1459
1464
|
// conversation id). Absent for standalone `AgentLoop` instances
|
|
1460
1465
|
// (unit tests constructed without a conversation id) — those fall
|
|
1461
1466
|
// back to per-call random mix selection.
|
|
1467
|
+
//
|
|
1468
|
+
// The same id also travels as `conversationId`, which
|
|
1469
|
+
// `RetryProvider.normalizeSendMessageOptions` uses to resolve the
|
|
1470
|
+
// conversation's subagent role and spawn mode for the runtime
|
|
1471
|
+
// proxy's billing-attribution headers. Both are stripped before any
|
|
1472
|
+
// provider wire request; they are carried separately because
|
|
1473
|
+
// `selectionSeed` is an opaque hashing input that callers may set to
|
|
1474
|
+
// something other than a conversation id.
|
|
1462
1475
|
if (this.conversationId) {
|
|
1463
1476
|
providerConfig.selectionSeed = this.conversationId;
|
|
1477
|
+
providerConfig.conversationId = this.conversationId;
|
|
1464
1478
|
}
|
|
1465
1479
|
}
|
|
1466
1480
|
|
|
@@ -2201,13 +2215,16 @@ export class AgentLoop {
|
|
|
2201
2215
|
// message between calls would invalidate the prompt-cache prefix on
|
|
2202
2216
|
// every iteration).
|
|
2203
2217
|
if (conversationDir) {
|
|
2204
|
-
const
|
|
2205
|
-
toolUseBlocks.map((tu) => [
|
|
2218
|
+
const toolCallByUseId = new Map(
|
|
2219
|
+
toolUseBlocks.map((tu) => [
|
|
2220
|
+
tu.id,
|
|
2221
|
+
{ name: tu.name, input: tu.input },
|
|
2222
|
+
]),
|
|
2206
2223
|
);
|
|
2207
2224
|
try {
|
|
2208
2225
|
spoolAndStubOversizedToolResults(rawResultBlocks, {
|
|
2209
2226
|
conversationDir,
|
|
2210
|
-
|
|
2227
|
+
toolCallById: (id) => toolCallByUseId.get(id),
|
|
2211
2228
|
});
|
|
2212
2229
|
} catch (err) {
|
|
2213
2230
|
rlog.warn(
|
|
@@ -2286,6 +2303,7 @@ export class AgentLoop {
|
|
|
2286
2303
|
approvalReason: result.approvalReason,
|
|
2287
2304
|
riskThreshold: result.riskThreshold,
|
|
2288
2305
|
activityMetadata: result.activityMetadata,
|
|
2306
|
+
answeredQuestion: result.answeredQuestion,
|
|
2289
2307
|
errorCode: result.errorCode,
|
|
2290
2308
|
});
|
|
2291
2309
|
}
|