@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
|
@@ -116,7 +116,10 @@ import {
|
|
|
116
116
|
} from "./conversation-runtime-assembly.js";
|
|
117
117
|
import type { CurrentTurnSurface } from "./conversation-surfaces.js";
|
|
118
118
|
import { markSurfaceCompleted } from "./conversation-surfaces.js";
|
|
119
|
-
import {
|
|
119
|
+
import {
|
|
120
|
+
runDeferredTurnTail,
|
|
121
|
+
settleTurnContent,
|
|
122
|
+
} from "./conversation-turn-finalize.js";
|
|
120
123
|
import { recordUsage } from "./conversation-usage.js";
|
|
121
124
|
import { resolveTurnTimezoneContext } from "./date-context.js";
|
|
122
125
|
import { getDiskPressureStatus } from "./disk-pressure-guard.js";
|
|
@@ -133,6 +136,7 @@ import {
|
|
|
133
136
|
MEMORY_CONTEXT_PHASE_KEY,
|
|
134
137
|
TurnLatencyTracker,
|
|
135
138
|
} from "./turn-latency-tracker.js";
|
|
139
|
+
import { chainTurnTail } from "./turn-tail-chain.js";
|
|
136
140
|
|
|
137
141
|
const log = getLogger("conversation-agent-loop");
|
|
138
142
|
|
|
@@ -152,6 +156,43 @@ const DISK_PRESSURE_ERROR_CATEGORY = "disk_pressure";
|
|
|
152
156
|
const OUT_OF_CREDITS_ASSISTANT_REPLY =
|
|
153
157
|
"I couldn't reply because you ran out of credits. Add credits in Settings → Billing and we can pick up where we left off.";
|
|
154
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Assistant-voice wording persisted as the synthetic assistant row when a turn
|
|
161
|
+
* terminates because the daily credit limit is reached. The shared
|
|
162
|
+
* classification (`dailyLimitClassification` in conversation-error.ts) keeps
|
|
163
|
+
* its `userMessage` in banner voice because it also feeds the live
|
|
164
|
+
* `conversation_error` event the composer renders; here the row re-enters LLM
|
|
165
|
+
* history and is displayed as assistant speech, so first-person copy is
|
|
166
|
+
* accurate. Says "stop" rather than "reply" because the row can land mid-turn,
|
|
167
|
+
* after a tool round-trip the user already saw. Phrased about the past failure,
|
|
168
|
+
* not the current limit, because the row stays in the transcript (and renders
|
|
169
|
+
* as a plain bubble) after the limit resets.
|
|
170
|
+
*/
|
|
171
|
+
const DAILY_LIMIT_REACHED_ASSISTANT_REPLY =
|
|
172
|
+
"I had to stop because you hit your daily credit limit. Raise the limit in Settings → Billing and we can pick up where we left off, or I can continue once it resets.";
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The assistant-voice text a managed-billing failure persists in place of the
|
|
176
|
+
* classification's own `userMessage`, or `null` when the classification copy is
|
|
177
|
+
* already right for a transcript row.
|
|
178
|
+
*/
|
|
179
|
+
function managedBillingAssistantReply(
|
|
180
|
+
providerErrorCode: string | null,
|
|
181
|
+
providerErrorCategory: string | null,
|
|
182
|
+
): string | null {
|
|
183
|
+
if (providerErrorCode !== "PROVIDER_BILLING") {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
switch (providerErrorCategory) {
|
|
187
|
+
case "credits_exhausted":
|
|
188
|
+
return OUT_OF_CREDITS_ASSISTANT_REPLY;
|
|
189
|
+
case "daily_limit_reached":
|
|
190
|
+
return DAILY_LIMIT_REACHED_ASSISTANT_REPLY;
|
|
191
|
+
default:
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
155
196
|
/** Title-cased friendly labels for tool names, used in confirmation chips. */
|
|
156
197
|
const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
157
198
|
bash: "Run Command",
|
|
@@ -325,6 +366,13 @@ export async function runAgentLoopImpl(
|
|
|
325
366
|
* scheduled execute turn attributes its LLM spend to that firing.
|
|
326
367
|
*/
|
|
327
368
|
cronRunId?: string | null;
|
|
369
|
+
/**
|
|
370
|
+
* Trust this turn runs under. Queue drains pass the trust captured from
|
|
371
|
+
* the sender at enqueue; without it the initialization below would reset
|
|
372
|
+
* the turn to the conversation slot, which holds whichever actor sent
|
|
373
|
+
* most recently rather than the one this turn belongs to.
|
|
374
|
+
*/
|
|
375
|
+
turnTrustContext?: TrustContext;
|
|
328
376
|
},
|
|
329
377
|
): Promise<void> {
|
|
330
378
|
if (!ctx.abortController) {
|
|
@@ -335,9 +383,21 @@ export async function runAgentLoopImpl(
|
|
|
335
383
|
// voice-session-bridge, regenerate, etc.) that invoke runAgentLoop directly
|
|
336
384
|
// without going through processMessage/drainQueue. This ensures the system
|
|
337
385
|
// prompt callback always reads a valid snapshot rather than undefined.
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
|
|
386
|
+
//
|
|
387
|
+
// The invariant: a turn runs under the trust captured when that turn
|
|
388
|
+
// started, never under whatever the slot holds when the loop happens to
|
|
389
|
+
// open. Awaits sit between capture and this line, and the slot is writable
|
|
390
|
+
// throughout by paths that do not own the turn (channel ingress for another
|
|
391
|
+
// actor, live-voice hydration, pointer elevation, the voice bridge).
|
|
392
|
+
//
|
|
393
|
+
// Callers that own a turn are expected to capture at turn start and pass
|
|
394
|
+
// `turnTrustContext`. This has not been swept across all 13 call sites, so
|
|
395
|
+
// the fallback below is load-bearing for two different populations: callers
|
|
396
|
+
// that legitimately have no turn to capture (subagent manager, voice
|
|
397
|
+
// bridge, regenerate), and callers that should pass it and do not yet.
|
|
398
|
+
// Treat a caller reaching the fallback as unverified, not as correct.
|
|
399
|
+
// LUM-3148 removes the ambiguity by making trust ride the turn.
|
|
400
|
+
ctx.currentTurnTrustContext = options?.turnTrustContext ?? ctx.trustContext;
|
|
341
401
|
ctx.currentTurnChannelCapabilities = ctx.channelCapabilities;
|
|
342
402
|
|
|
343
403
|
// Re-resolve the system prompt under the snapshots just set and push it into
|
|
@@ -560,6 +620,11 @@ export async function runAgentLoopImpl(
|
|
|
560
620
|
// applies to later tool executions and nested subagents in the same turn.
|
|
561
621
|
ctx.currentTurnOverrideProfile = turnOverrideProfile;
|
|
562
622
|
|
|
623
|
+
// Mirrored onto the live conversation for `createToolExecutor` to read into
|
|
624
|
+
// `ToolContext.cronRunId`, so a tool that delegates LLM work (subagent spawn
|
|
625
|
+
// or message) stamps the delegated usage with this firing.
|
|
626
|
+
ctx.currentTurnCronRunId = turnCronRunId;
|
|
627
|
+
|
|
563
628
|
// Capture the turn channel context *before* any awaits so a second
|
|
564
629
|
// message from a different channel can't overwrite it mid-flight.
|
|
565
630
|
// When context is unavailable (e.g. regenerate after daemon restart),
|
|
@@ -637,6 +702,7 @@ export async function runAgentLoopImpl(
|
|
|
637
702
|
);
|
|
638
703
|
ctx.diskPressureCleanupModeActive =
|
|
639
704
|
diskPressureDecision.action === "allow-cleanup-mode";
|
|
705
|
+
const toolsDisabledForTurn = ctx.toolsDisabledDepth > 0;
|
|
640
706
|
|
|
641
707
|
ctx.lastAssistantAttachments = [];
|
|
642
708
|
ctx.lastAttachmentWarnings = [];
|
|
@@ -659,14 +725,106 @@ export async function runAgentLoopImpl(
|
|
|
659
725
|
| { outcome: "failed" | "cancelled"; failureCode?: string }
|
|
660
726
|
| undefined;
|
|
661
727
|
// True once a replied terminal SSE (message_complete / generation_handoff)
|
|
662
|
-
// has been emitted. Guards the catch block: an error thrown
|
|
663
|
-
//
|
|
728
|
+
// has been emitted. Guards the catch block: an error thrown by the
|
|
729
|
+
// content-settle steps that run after it must not relabel a visibly-replied
|
|
730
|
+
// turn.
|
|
664
731
|
let turnReplied = false;
|
|
665
732
|
// Narrower than `turnReplied`: true only for a `message_complete` branch that
|
|
666
733
|
// produced a genuine reply. A handed-off generation continues the run, and a
|
|
667
734
|
// provider-error turn's only assistant row is the synthetic error text, so
|
|
668
735
|
// the deferred tail must not treat either as a final reply.
|
|
669
736
|
let turnCompleted = false;
|
|
737
|
+
// True once `releaseTurn` has run. The happy path releases as soon as the
|
|
738
|
+
// turn's content is settled; the `finally` calls it again as the backstop for
|
|
739
|
+
// the cancel/error paths that never reached the early release.
|
|
740
|
+
let turnReleased = false;
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Free the conversation for its next turn.
|
|
744
|
+
*
|
|
745
|
+
* Ordering is load-bearing and identical on both call paths: stamp the
|
|
746
|
+
* turn's abnormal outcome first, because the telemetry reporter's
|
|
747
|
+
* settled-turn barrier only releases this turn once processing stops; null
|
|
748
|
+
* `abortController` before clearing the flag so a concurrent abort takes the
|
|
749
|
+
* force-clear branch rather than signalling a dead controller; unregister the
|
|
750
|
+
* in-flight turn only after processing stops, since daemon-side callers fall
|
|
751
|
+
* back to the live seq counter once that registration is gone (safe because
|
|
752
|
+
* `settlePendingPartialFlush` has already flushed the turn's content).
|
|
753
|
+
* Idempotent, so the `finally` can call it unconditionally.
|
|
754
|
+
*
|
|
755
|
+
* The release frees direct sends only. Queued messages are drained from the
|
|
756
|
+
* loop's `finally`, after the turn-boundary commit, so a dequeued turn's
|
|
757
|
+
* first file writes cannot be swept into the finished turn's commit.
|
|
758
|
+
*/
|
|
759
|
+
const releaseTurn = (): void => {
|
|
760
|
+
if (turnReleased) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
turnReleased = true;
|
|
764
|
+
if (abnormalOutcome) {
|
|
765
|
+
try {
|
|
766
|
+
stampTurnOutcome(userMessageId, abnormalOutcome.outcome, {
|
|
767
|
+
failureCode: abnormalOutcome.failureCode,
|
|
768
|
+
});
|
|
769
|
+
} catch (err) {
|
|
770
|
+
rlog.warn(
|
|
771
|
+
{ err },
|
|
772
|
+
"Failed to stamp turn outcome (non-fatal); releasing the turn anyway",
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
ctx.abortController = null;
|
|
777
|
+
ctx.setProcessing(false);
|
|
778
|
+
unregisterInflightTurn(ctx.conversationId, state);
|
|
779
|
+
|
|
780
|
+
// Tear down the remaining per-turn state in the same synchronous step as
|
|
781
|
+
// the release, so a turn that starts against the freed conversation cannot
|
|
782
|
+
// inherit stale turn scope (task-run permissions, allowed tools, override
|
|
783
|
+
// profile, command intent) or observe a half-cleared conversation.
|
|
784
|
+
ctx.onConfirmationOutcome = undefined;
|
|
785
|
+
ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
|
|
786
|
+
ctx.approvedViaPromptThisTurn = false;
|
|
787
|
+
ctx.currentRequestId = undefined;
|
|
788
|
+
ctx.currentActiveSurfaceId = undefined;
|
|
789
|
+
ctx.allowedToolNames = undefined;
|
|
790
|
+
ctx.diskPressureCleanupModeActive = false;
|
|
791
|
+
ctx.preactivatedSkillIds = undefined;
|
|
792
|
+
ctx.currentTurnOverrideProfile = undefined;
|
|
793
|
+
ctx.currentTurnCronRunId = undefined;
|
|
794
|
+
ctx.currentTurnModelProfileNoticeKey = undefined;
|
|
795
|
+
// Turn-scoped interactivity. Clear it so paths that bypass this loop
|
|
796
|
+
// (e.g. opportunity wakes calling `agentLoop.run` directly) don't inherit
|
|
797
|
+
// a stale value and instead fall back to live client state in the tool
|
|
798
|
+
// context.
|
|
799
|
+
ctx.currentTurnIsNonInteractive = undefined;
|
|
800
|
+
// Turn-scoped request origin. Clear so a later turn on a reused
|
|
801
|
+
// conversation cannot inherit a stale origin-scoped permission grant.
|
|
802
|
+
ctx.currentTurnRequestOrigin = undefined;
|
|
803
|
+
// Channel command intents (e.g. Telegram /start) are single-turn
|
|
804
|
+
// metadata. Clear at turn end so they never leak into subsequent
|
|
805
|
+
// unrelated messages.
|
|
806
|
+
ctx.commandIntent = undefined;
|
|
807
|
+
// The app on screen is view state owned by the message that reported it,
|
|
808
|
+
// not durable conversation state: nothing tells the daemon when the user
|
|
809
|
+
// closes an app. Clear both copies at turn end so a later turn that brings
|
|
810
|
+
// no client transport (a scheduled wake, a background follow-up) cannot
|
|
811
|
+
// claim the user is looking at an app they may have closed. Every inbound
|
|
812
|
+
// send re-applies it from transport before its own turn, including the
|
|
813
|
+
// queue drain, so live turns are unaffected.
|
|
814
|
+
ctx.visibleAppId = undefined;
|
|
815
|
+
ctx.currentTurnVisibleAppId = undefined;
|
|
816
|
+
// taskRunId scopes ephemeral task-run permissions to a single turn. Clear
|
|
817
|
+
// before the queue drain so queued/drained turns on a reused conversation
|
|
818
|
+
// cannot inherit stale in-task-run scope from the turn that just finished.
|
|
819
|
+
ctx.taskRunId = undefined;
|
|
820
|
+
|
|
821
|
+
// Close the turn's profiling window here rather than after the queue
|
|
822
|
+
// drain: the profiler is per-conversation and the next turn's
|
|
823
|
+
// `startToolProfilingRequest` resets it, so a summary emitted after a
|
|
824
|
+
// drained turn started would report that turn's window under this turn's
|
|
825
|
+
// request id.
|
|
826
|
+
emitToolProfilingSummary(ctx.conversationId, reqId);
|
|
827
|
+
};
|
|
670
828
|
|
|
671
829
|
const publishLoopMessagesChanged = (): void => {
|
|
672
830
|
if (
|
|
@@ -717,14 +875,20 @@ export async function runAgentLoopImpl(
|
|
|
717
875
|
return;
|
|
718
876
|
}
|
|
719
877
|
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
878
|
+
// Workspace Git readiness is required only when tools can run. Tool-less
|
|
879
|
+
// callers use the same depth gate consumed by tool resolution.
|
|
880
|
+
if (!toolsDisabledForTurn) {
|
|
881
|
+
try {
|
|
882
|
+
const getWorkspaceGitServiceFn =
|
|
883
|
+
ctx.getWorkspaceGitService ?? getWorkspaceGitService;
|
|
884
|
+
const gitService = getWorkspaceGitServiceFn(ctx.workingDir);
|
|
885
|
+
await gitService.ensureInitialized();
|
|
886
|
+
} catch (err) {
|
|
887
|
+
rlog.warn(
|
|
888
|
+
{ err },
|
|
889
|
+
"Failed to initialize workspace git repo (non-fatal)",
|
|
890
|
+
);
|
|
891
|
+
}
|
|
728
892
|
}
|
|
729
893
|
|
|
730
894
|
// Auto-complete stale interactive surfaces from previous turns.
|
|
@@ -737,13 +901,20 @@ export async function runAgentLoopImpl(
|
|
|
737
901
|
if (entry.surfaceType === "dynamic_page") {
|
|
738
902
|
continue;
|
|
739
903
|
}
|
|
904
|
+
// Persist before announcing: a client told the card was dismissed
|
|
905
|
+
// while the write failed would watch the next reseed revert it.
|
|
906
|
+
// An unannounced dismissal keeps its pending entry so client and
|
|
907
|
+
// daemon agree the card is still live and the one-interactive-surface
|
|
908
|
+
// gate keeps holding; the next user message sweeps it again.
|
|
909
|
+
if (!markSurfaceCompleted(ctx, surfaceId, "Dismissed")) {
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
740
912
|
onEvent({
|
|
741
913
|
type: "ui_surface_complete",
|
|
742
914
|
conversationId: ctx.conversationId,
|
|
743
915
|
surfaceId,
|
|
744
916
|
summary: "Dismissed",
|
|
745
917
|
});
|
|
746
|
-
markSurfaceCompleted(ctx, surfaceId, "Dismissed");
|
|
747
918
|
ctx.pendingSurfaceActions.delete(surfaceId);
|
|
748
919
|
}
|
|
749
920
|
}
|
|
@@ -1341,9 +1512,16 @@ export async function runAgentLoopImpl(
|
|
|
1341
1512
|
return { ...msg, content: cleanedBlocks };
|
|
1342
1513
|
});
|
|
1343
1514
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1515
|
+
// "The run delivered a final assistant reply", not "the run produced any
|
|
1516
|
+
// assistant-role message". A run that called tools already carries
|
|
1517
|
+
// assistant `tool_use` messages, and those are not a delivered reply: a
|
|
1518
|
+
// provider error that kills the run mid-turn leaves the tail as the
|
|
1519
|
+
// tool_result (user role), while a run that replied normally ends on the
|
|
1520
|
+
// assistant message. Testing only the tail keeps the synthetic error row
|
|
1521
|
+
// below reachable for mid-turn failures, which is the only durable record
|
|
1522
|
+
// of why the turn stopped.
|
|
1523
|
+
const hasAssistantResponse =
|
|
1524
|
+
newMessages[newMessages.length - 1]?.role === "assistant";
|
|
1347
1525
|
if (
|
|
1348
1526
|
!hasAssistantResponse &&
|
|
1349
1527
|
state.providerErrorUserMessage &&
|
|
@@ -1403,13 +1581,13 @@ export async function runAgentLoopImpl(
|
|
|
1403
1581
|
providerErrorCategory: state.providerErrorCategory ?? undefined,
|
|
1404
1582
|
};
|
|
1405
1583
|
// The persisted row re-enters LLM history and is displayed as
|
|
1406
|
-
// assistant speech, so managed-
|
|
1407
|
-
//
|
|
1584
|
+
// assistant speech, so the managed-billing categories swap the
|
|
1585
|
+
// banner-voice classification copy for assistant-voice wording.
|
|
1408
1586
|
const persistedErrorText =
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1587
|
+
managedBillingAssistantReply(
|
|
1588
|
+
state.providerErrorCode,
|
|
1589
|
+
state.providerErrorCategory,
|
|
1590
|
+
) ?? state.providerErrorUserMessage;
|
|
1413
1591
|
const errorAssistantMessage =
|
|
1414
1592
|
createAssistantMessage(persistedErrorText);
|
|
1415
1593
|
const errorRow = await addMessage(
|
|
@@ -1471,10 +1649,10 @@ export async function runAgentLoopImpl(
|
|
|
1471
1649
|
// compaction/overflow recovery (where a cache miss is expected).
|
|
1472
1650
|
//
|
|
1473
1651
|
// Post-turn tool-result truncation (spooling large results to disk and
|
|
1474
|
-
// shrinking the next turn's context) is deferred to `
|
|
1652
|
+
// shrinking the next turn's context) is deferred to `settleTurnContent`
|
|
1475
1653
|
// below. It only rewrites the in-memory history the NEXT turn is built
|
|
1476
|
-
// from
|
|
1477
|
-
//
|
|
1654
|
+
// from, never the just-delivered reply, so it must not sit on the critical
|
|
1655
|
+
// path to the terminal SSE that re-enables the composer.
|
|
1478
1656
|
ctx.messages = restoredHistory;
|
|
1479
1657
|
|
|
1480
1658
|
emitUsage(
|
|
@@ -1504,7 +1682,7 @@ export async function runAgentLoopImpl(
|
|
|
1504
1682
|
// Fast-path: when the user cancelled, skip expensive post-loop work
|
|
1505
1683
|
// (attachment resolution) and emit the cancellation event immediately
|
|
1506
1684
|
// so the client can re-enable the UI without delay. Disk sync and the rest
|
|
1507
|
-
// of the bookkeeping run
|
|
1685
|
+
// of the bookkeeping run after this SSE.
|
|
1508
1686
|
if (abortController.signal.aborted) {
|
|
1509
1687
|
abnormalOutcome = { outcome: "cancelled" };
|
|
1510
1688
|
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
@@ -1600,24 +1778,42 @@ export async function runAgentLoopImpl(
|
|
|
1600
1778
|
|
|
1601
1779
|
// The terminal SSE for this turn has now been emitted (message_complete,
|
|
1602
1780
|
// generation_handoff, or generation_cancelled), so the composer is already
|
|
1603
|
-
// re-enabling. Settle any pending debounced partial flush FIRST
|
|
1781
|
+
// re-enabling. Settle any pending debounced partial flush FIRST: a
|
|
1604
1782
|
// cancelled turn exits with the timer still pending, and a flush firing
|
|
1605
|
-
// after the
|
|
1606
|
-
//
|
|
1607
|
-
//
|
|
1608
|
-
//
|
|
1783
|
+
// after the stranded fold (or the voice bridge's transcript hygiene) would
|
|
1784
|
+
// write raw content into an already-settled row. Then settle the rest of
|
|
1785
|
+
// the turn's content, which rewrites state the next turn also writes and so
|
|
1786
|
+
// has to complete under the processing lock.
|
|
1609
1787
|
await settlePendingPartialFlush(state, deps);
|
|
1610
|
-
await
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1788
|
+
await settleTurnContent({ ctx, state, rlog });
|
|
1789
|
+
|
|
1790
|
+
// Content is settled, so the conversation is free. Release before the
|
|
1791
|
+
// deferred tail rather than in the `finally`: the tail's memory indexing is
|
|
1792
|
+
// network-bound and unbounded, and holding the lock across it is what makes
|
|
1793
|
+
// a fully-delivered reply still answer a follow-up send with a queue slot.
|
|
1794
|
+
// The queue itself is drained later, from the `finally` after the
|
|
1795
|
+
// turn-boundary commit.
|
|
1796
|
+
const criticalSectionMs = Date.now() - generationCompletedAt;
|
|
1797
|
+
releaseTurn();
|
|
1798
|
+
|
|
1799
|
+
// Detached, and chained on the conversation's tail chain so two turns'
|
|
1800
|
+
// tails run in turn order instead of concurrently. The chain is keyed by
|
|
1801
|
+
// conversation id rather than held on this instance, because the tail runs
|
|
1802
|
+
// while the conversation reads idle and can therefore outlive the instance
|
|
1803
|
+
// that scheduled it.
|
|
1804
|
+
chainTurnTail(ctx.conversationId, () =>
|
|
1805
|
+
runDeferredTurnTail({
|
|
1806
|
+
conversationId: ctx.conversationId,
|
|
1807
|
+
state,
|
|
1808
|
+
rlog,
|
|
1809
|
+
criticalSectionMs,
|
|
1810
|
+
turnCompleted,
|
|
1811
|
+
userMessageId: options?.notifyUserMessageId ?? userMessageId,
|
|
1812
|
+
...(options?.replyDeliveredInAppOnly
|
|
1813
|
+
? { replyDeliveredInAppOnly: true }
|
|
1814
|
+
: {}),
|
|
1815
|
+
}),
|
|
1816
|
+
);
|
|
1621
1817
|
} catch (err) {
|
|
1622
1818
|
clearConversationNotices(ctx.conversationId);
|
|
1623
1819
|
const errorCtx = {
|
|
@@ -1625,9 +1821,9 @@ export async function runAgentLoopImpl(
|
|
|
1625
1821
|
aborted: abortController.signal.aborted,
|
|
1626
1822
|
};
|
|
1627
1823
|
if (isUserCancellation(err, errorCtx)) {
|
|
1628
|
-
// Only label the turn when it hadn't already replied
|
|
1629
|
-
// surfacing after the terminal SSE (
|
|
1630
|
-
//
|
|
1824
|
+
// Only label the turn when it hadn't already replied: a cancellation
|
|
1825
|
+
// surfacing after the terminal SSE (the content-settle steps) must not
|
|
1826
|
+
// relabel a visibly-replied turn.
|
|
1631
1827
|
if (!turnReplied) {
|
|
1632
1828
|
abnormalOutcome = { outcome: "cancelled" };
|
|
1633
1829
|
}
|
|
@@ -1665,112 +1861,86 @@ export async function runAgentLoopImpl(
|
|
|
1665
1861
|
publishLoopMessagesChanged();
|
|
1666
1862
|
}
|
|
1667
1863
|
} finally {
|
|
1668
|
-
//
|
|
1669
|
-
//
|
|
1670
|
-
//
|
|
1671
|
-
//
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1864
|
+
// Backstop release for the cancel/error paths, which throw out of the try
|
|
1865
|
+
// before the happy path's release runs. Idempotent, so the happy path
|
|
1866
|
+
// reaches here already released. It stays first in the `finally` so the
|
|
1867
|
+
// turn-boundary commit below cannot throw ahead of it and leave the row
|
|
1868
|
+
// latched "mid-turn".
|
|
1869
|
+
releaseTurn();
|
|
1870
|
+
|
|
1871
|
+
// The queue drain runs after the turn-boundary commit, under a `finally`
|
|
1872
|
+
// so a throw in the commit section cannot strand the queue with nothing
|
|
1873
|
+
// left to re-trigger it. Ordering is load-bearing: `commitTurnChanges`
|
|
1874
|
+
// attributes the working tree's changes to the finished turn, so a queued
|
|
1875
|
+
// turn that started while it was preparing would have its first file
|
|
1876
|
+
// writes swept into the wrong commit. The wait is deadline-bounded, and
|
|
1877
|
+
// direct sends are already unblocked by the release above.
|
|
1878
|
+
try {
|
|
1879
|
+
if (turnStarted) {
|
|
1880
|
+
ctx.turnCount++;
|
|
1881
|
+
const runTurnCommit = async (): Promise<void> => {
|
|
1882
|
+
const config = getConfig();
|
|
1883
|
+
const maxWait = config.workspaceGit?.turnCommitMaxWaitMs ?? 4000;
|
|
1884
|
+
const deadlineMs = Date.now() + maxWait;
|
|
1885
|
+
|
|
1886
|
+
const commitTurnChangesFn =
|
|
1887
|
+
ctx.commitTurnChanges ?? commitTurnChanges;
|
|
1888
|
+
const commitPromise = commitTurnChangesFn(
|
|
1889
|
+
ctx.workingDir,
|
|
1890
|
+
ctx.conversationId,
|
|
1891
|
+
ctx.turnCount,
|
|
1892
|
+
undefined,
|
|
1893
|
+
deadlineMs,
|
|
1894
|
+
);
|
|
1895
|
+
const outcome = await raceWithTimeout(commitPromise, maxWait);
|
|
1896
|
+
if (outcome === "timed_out") {
|
|
1897
|
+
rlog.warn(
|
|
1898
|
+
{
|
|
1899
|
+
turnNumber: ctx.turnCount,
|
|
1900
|
+
maxWaitMs: maxWait,
|
|
1901
|
+
conversationId: ctx.conversationId,
|
|
1902
|
+
},
|
|
1903
|
+
"Turn-boundary commit timed out; continuing without waiting (commit still runs in background)",
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1686
1907
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1908
|
+
if (toolsDisabledForTurn) {
|
|
1909
|
+
// Let the caller and the queue drain below claim an immediate
|
|
1910
|
+
// follow-up turn before starting Git. That turn will commit the
|
|
1911
|
+
// accumulated disk view.
|
|
1912
|
+
setImmediate(() => {
|
|
1913
|
+
if (ctx.isProcessing()) {
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
void runTurnCommit().catch((err) => {
|
|
1917
|
+
rlog.warn({ err }, "Deferred turn-boundary commit failed");
|
|
1918
|
+
});
|
|
1919
|
+
});
|
|
1920
|
+
} else {
|
|
1921
|
+
await runTurnCommit();
|
|
1922
|
+
}
|
|
1692
1923
|
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
undefined,
|
|
1699
|
-
deadlineMs,
|
|
1700
|
-
);
|
|
1701
|
-
const outcome = await raceWithTimeout(commitPromise, maxWait);
|
|
1702
|
-
if (outcome === "timed_out") {
|
|
1703
|
-
rlog.warn(
|
|
1704
|
-
{
|
|
1705
|
-
turnNumber: ctx.turnCount,
|
|
1706
|
-
maxWaitMs: maxWait,
|
|
1707
|
-
conversationId: ctx.conversationId,
|
|
1708
|
-
},
|
|
1709
|
-
"Turn-boundary commit timed out — continuing without waiting (commit still runs in background)",
|
|
1710
|
-
);
|
|
1924
|
+
// Recompute relationship-state.json at turn boundary (fire-and-forget).
|
|
1925
|
+
// The writer swallows its own errors, but we still guard with catch()
|
|
1926
|
+
// here so a regression in the writer can never bubble out of the
|
|
1927
|
+
// agent loop and reject an otherwise-complete turn.
|
|
1928
|
+
void writeRelationshipState().catch(() => {});
|
|
1711
1929
|
}
|
|
1712
1930
|
|
|
1713
|
-
//
|
|
1714
|
-
//
|
|
1715
|
-
//
|
|
1716
|
-
//
|
|
1717
|
-
|
|
1931
|
+
// Consolidation deferred to compaction: keeping assistant + tool_result
|
|
1932
|
+
// messages unconsolidated preserves the exact message structure sent to
|
|
1933
|
+
// the API, enabling stable prefix caching across turns. Compaction
|
|
1934
|
+
// consolidates when it summarizes old messages (cache miss is expected).
|
|
1935
|
+
} finally {
|
|
1936
|
+
// kickDrainQueue never rejects: a drain failure here would otherwise be
|
|
1937
|
+
// an unhandled rejection that strands the queue with nothing left to
|
|
1938
|
+
// re-trigger it.
|
|
1939
|
+
void ctx.kickDrainQueue(
|
|
1940
|
+
yieldedForHandoff ? "checkpoint_handoff" : "loop_complete",
|
|
1941
|
+
"agent_loop_finally",
|
|
1942
|
+
);
|
|
1718
1943
|
}
|
|
1719
|
-
|
|
1720
|
-
emitToolProfilingSummary(ctx.conversationId, reqId);
|
|
1721
|
-
|
|
1722
|
-
// Tear down the remaining per-turn state. Abort reliably drives the loop to
|
|
1723
|
-
// this `finally` within a bounded time — cooperative signal propagation
|
|
1724
|
-
// (provider fetch + tool race) backed by the abort watchdog — so a
|
|
1725
|
-
// cancelled turn always unwinds before any resend can start a new one.
|
|
1726
|
-
// There is therefore only ever one turn alive, and clearing the shared
|
|
1727
|
-
// state below cannot clobber a concurrent turn.
|
|
1728
|
-
ctx.onConfirmationOutcome = undefined;
|
|
1729
|
-
ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
|
|
1730
|
-
ctx.approvedViaPromptThisTurn = false;
|
|
1731
|
-
ctx.currentRequestId = undefined;
|
|
1732
|
-
ctx.currentActiveSurfaceId = undefined;
|
|
1733
|
-
ctx.allowedToolNames = undefined;
|
|
1734
|
-
ctx.diskPressureCleanupModeActive = false;
|
|
1735
|
-
ctx.preactivatedSkillIds = undefined;
|
|
1736
|
-
ctx.currentTurnOverrideProfile = undefined;
|
|
1737
|
-
ctx.currentTurnModelProfileNoticeKey = undefined;
|
|
1738
|
-
// Turn-scoped interactivity. Clear it so paths that bypass this loop (e.g.
|
|
1739
|
-
// opportunity wakes calling `agentLoop.run` directly) don't inherit a stale
|
|
1740
|
-
// value and instead fall back to live client state in the tool context.
|
|
1741
|
-
ctx.currentTurnIsNonInteractive = undefined;
|
|
1742
|
-
// Turn-scoped request origin. Clear so a later turn on a reused
|
|
1743
|
-
// conversation cannot inherit a stale origin-scoped permission grant.
|
|
1744
|
-
ctx.currentTurnRequestOrigin = undefined;
|
|
1745
|
-
// Channel command intents (e.g. Telegram /start) are single-turn metadata.
|
|
1746
|
-
// Clear at turn end so they never leak into subsequent unrelated messages.
|
|
1747
|
-
ctx.commandIntent = undefined;
|
|
1748
|
-
// The app on screen is view state owned by the message that reported it,
|
|
1749
|
-
// not durable conversation state: nothing tells the daemon when the user
|
|
1750
|
-
// closes an app. Clear both copies at turn end so a later turn that brings
|
|
1751
|
-
// no client transport (a scheduled wake, a background follow-up) cannot
|
|
1752
|
-
// claim the user is looking at an app they may have closed. Every inbound
|
|
1753
|
-
// send re-applies it from transport before its own turn, including the
|
|
1754
|
-
// queue drain, so live turns are unaffected.
|
|
1755
|
-
ctx.visibleAppId = undefined;
|
|
1756
|
-
ctx.currentTurnVisibleAppId = undefined;
|
|
1757
|
-
// taskRunId scopes ephemeral task-run permissions to a single turn. Clear
|
|
1758
|
-
// before drainQueue so queued/drained turns on a reused conversation can't
|
|
1759
|
-
// inherit stale in-task-run scope from the turn that just finished.
|
|
1760
|
-
ctx.taskRunId = undefined;
|
|
1761
|
-
|
|
1762
|
-
// Consolidation deferred to compaction: keeping assistant + tool_result
|
|
1763
|
-
// messages unconsolidated preserves the exact message structure sent to
|
|
1764
|
-
// the API, enabling stable prefix caching across turns. Compaction
|
|
1765
|
-
// consolidates when it summarizes old messages (cache miss is expected).
|
|
1766
|
-
|
|
1767
|
-
// kickDrainQueue never rejects — a drain failure here would otherwise be
|
|
1768
|
-
// an unhandled rejection that strands the queue with nothing left to
|
|
1769
|
-
// re-trigger it.
|
|
1770
|
-
void ctx.kickDrainQueue(
|
|
1771
|
-
yieldedForHandoff ? "checkpoint_handoff" : "loop_complete",
|
|
1772
|
-
"agent_loop_finally",
|
|
1773
|
-
);
|
|
1774
1944
|
}
|
|
1775
1945
|
}
|
|
1776
1946
|
|
|
@@ -163,7 +163,7 @@ export async function resolveAssistantAttachments(
|
|
|
163
163
|
const draft = assistantAttachments[i];
|
|
164
164
|
let stored;
|
|
165
165
|
try {
|
|
166
|
-
stored = attachInlineAttachmentToMessage(
|
|
166
|
+
stored = await attachInlineAttachmentToMessage(
|
|
167
167
|
lastAssistantMessageId,
|
|
168
168
|
i,
|
|
169
169
|
draft.filename,
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ConversationErrorCode,
|
|
7
7
|
ConversationErrorEvent,
|
|
8
8
|
} from "../api/events/conversation-error.js";
|
|
9
|
+
import { getIsPlatform } from "../config/env-registry.js";
|
|
9
10
|
import {
|
|
10
11
|
isImageDimensionsTooLargeError,
|
|
11
12
|
isImageMediaTypeMismatchError,
|
|
@@ -352,7 +353,7 @@ function connectionResolutionUserMessage(
|
|
|
352
353
|
case "provider_mismatch":
|
|
353
354
|
return `${connection}${usedBy} is bound to a different provider than the profile declares. Update the profile's connection in ${fixPath}.`;
|
|
354
355
|
case "missing_connection":
|
|
355
|
-
return `No provider connection is configured${usedBy}.
|
|
356
|
+
return `No provider connection is configured${usedBy}. Ask me to set one up right here, or add an API key in ${fixPath}.`;
|
|
356
357
|
case "unroutable_managed_model":
|
|
357
358
|
return `The model "${error.model ?? "<unset>"}"${usedBy} isn't served by the Vellum managed route. Pick a model from the Vellum catalog, or choose a concrete provider in ${fixPath}.`;
|
|
358
359
|
case "missing_credential":
|
|
@@ -361,6 +362,12 @@ function connectionResolutionUserMessage(
|
|
|
361
362
|
// doesn't.
|
|
362
363
|
return `${connection}${usedBy} has no stored credential. Add an API key or reconnect it in ${fixPath}.`;
|
|
363
364
|
case "platform_unauthenticated":
|
|
365
|
+
// A platform-managed assistant cannot log in or switch providers, and
|
|
366
|
+
// this classifier only sees the reason code, so one honest wording covers
|
|
367
|
+
// both the transient and the re-provision cases.
|
|
368
|
+
if (getIsPlatform()) {
|
|
369
|
+
return `${connection}${usedBy} is unavailable. If this persists, the platform credential may need to be re-provisioned on the Vellum platform.`;
|
|
370
|
+
}
|
|
364
371
|
return `${connection}${usedBy} requires a Vellum platform login. Log in, or pick a different provider in ${fixPath}.`;
|
|
365
372
|
case "model_incompatible":
|
|
366
373
|
return `${error.model ? `Model "${error.model}"` : "The requested model"} isn't available on ${connectionName ? `connection "${connectionName}"` : "the configured connection"}${usedBy}. Pick a different model or connection in ${fixPath}.`;
|