@vellumai/assistant 0.11.2 → 0.11.3-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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-queue.test.ts +265 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -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-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-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-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 +216 -132
- 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/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 +296 -145
- 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 +85 -42
- package/src/daemon/conversation-process.ts +76 -28
- 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 +105 -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.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/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 +56 -8
- 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 +350 -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 +295 -42
- 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/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/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",
|
|
@@ -560,6 +601,11 @@ export async function runAgentLoopImpl(
|
|
|
560
601
|
// applies to later tool executions and nested subagents in the same turn.
|
|
561
602
|
ctx.currentTurnOverrideProfile = turnOverrideProfile;
|
|
562
603
|
|
|
604
|
+
// Mirrored onto the live conversation for `createToolExecutor` to read into
|
|
605
|
+
// `ToolContext.cronRunId`, so a tool that delegates LLM work (subagent spawn
|
|
606
|
+
// or message) stamps the delegated usage with this firing.
|
|
607
|
+
ctx.currentTurnCronRunId = turnCronRunId;
|
|
608
|
+
|
|
563
609
|
// Capture the turn channel context *before* any awaits so a second
|
|
564
610
|
// message from a different channel can't overwrite it mid-flight.
|
|
565
611
|
// When context is unavailable (e.g. regenerate after daemon restart),
|
|
@@ -637,6 +683,7 @@ export async function runAgentLoopImpl(
|
|
|
637
683
|
);
|
|
638
684
|
ctx.diskPressureCleanupModeActive =
|
|
639
685
|
diskPressureDecision.action === "allow-cleanup-mode";
|
|
686
|
+
const toolsDisabledForTurn = ctx.toolsDisabledDepth > 0;
|
|
640
687
|
|
|
641
688
|
ctx.lastAssistantAttachments = [];
|
|
642
689
|
ctx.lastAttachmentWarnings = [];
|
|
@@ -659,14 +706,106 @@ export async function runAgentLoopImpl(
|
|
|
659
706
|
| { outcome: "failed" | "cancelled"; failureCode?: string }
|
|
660
707
|
| undefined;
|
|
661
708
|
// True once a replied terminal SSE (message_complete / generation_handoff)
|
|
662
|
-
// has been emitted. Guards the catch block: an error thrown
|
|
663
|
-
//
|
|
709
|
+
// has been emitted. Guards the catch block: an error thrown by the
|
|
710
|
+
// content-settle steps that run after it must not relabel a visibly-replied
|
|
711
|
+
// turn.
|
|
664
712
|
let turnReplied = false;
|
|
665
713
|
// Narrower than `turnReplied`: true only for a `message_complete` branch that
|
|
666
714
|
// produced a genuine reply. A handed-off generation continues the run, and a
|
|
667
715
|
// provider-error turn's only assistant row is the synthetic error text, so
|
|
668
716
|
// the deferred tail must not treat either as a final reply.
|
|
669
717
|
let turnCompleted = false;
|
|
718
|
+
// True once `releaseTurn` has run. The happy path releases as soon as the
|
|
719
|
+
// turn's content is settled; the `finally` calls it again as the backstop for
|
|
720
|
+
// the cancel/error paths that never reached the early release.
|
|
721
|
+
let turnReleased = false;
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Free the conversation for its next turn.
|
|
725
|
+
*
|
|
726
|
+
* Ordering is load-bearing and identical on both call paths: stamp the
|
|
727
|
+
* turn's abnormal outcome first, because the telemetry reporter's
|
|
728
|
+
* settled-turn barrier only releases this turn once processing stops; null
|
|
729
|
+
* `abortController` before clearing the flag so a concurrent abort takes the
|
|
730
|
+
* force-clear branch rather than signalling a dead controller; unregister the
|
|
731
|
+
* in-flight turn only after processing stops, since daemon-side callers fall
|
|
732
|
+
* back to the live seq counter once that registration is gone (safe because
|
|
733
|
+
* `settlePendingPartialFlush` has already flushed the turn's content).
|
|
734
|
+
* Idempotent, so the `finally` can call it unconditionally.
|
|
735
|
+
*
|
|
736
|
+
* The release frees direct sends only. Queued messages are drained from the
|
|
737
|
+
* loop's `finally`, after the turn-boundary commit, so a dequeued turn's
|
|
738
|
+
* first file writes cannot be swept into the finished turn's commit.
|
|
739
|
+
*/
|
|
740
|
+
const releaseTurn = (): void => {
|
|
741
|
+
if (turnReleased) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
turnReleased = true;
|
|
745
|
+
if (abnormalOutcome) {
|
|
746
|
+
try {
|
|
747
|
+
stampTurnOutcome(userMessageId, abnormalOutcome.outcome, {
|
|
748
|
+
failureCode: abnormalOutcome.failureCode,
|
|
749
|
+
});
|
|
750
|
+
} catch (err) {
|
|
751
|
+
rlog.warn(
|
|
752
|
+
{ err },
|
|
753
|
+
"Failed to stamp turn outcome (non-fatal); releasing the turn anyway",
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
ctx.abortController = null;
|
|
758
|
+
ctx.setProcessing(false);
|
|
759
|
+
unregisterInflightTurn(ctx.conversationId, state);
|
|
760
|
+
|
|
761
|
+
// Tear down the remaining per-turn state in the same synchronous step as
|
|
762
|
+
// the release, so a turn that starts against the freed conversation cannot
|
|
763
|
+
// inherit stale turn scope (task-run permissions, allowed tools, override
|
|
764
|
+
// profile, command intent) or observe a half-cleared conversation.
|
|
765
|
+
ctx.onConfirmationOutcome = undefined;
|
|
766
|
+
ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
|
|
767
|
+
ctx.approvedViaPromptThisTurn = false;
|
|
768
|
+
ctx.currentRequestId = undefined;
|
|
769
|
+
ctx.currentActiveSurfaceId = undefined;
|
|
770
|
+
ctx.allowedToolNames = undefined;
|
|
771
|
+
ctx.diskPressureCleanupModeActive = false;
|
|
772
|
+
ctx.preactivatedSkillIds = undefined;
|
|
773
|
+
ctx.currentTurnOverrideProfile = undefined;
|
|
774
|
+
ctx.currentTurnCronRunId = undefined;
|
|
775
|
+
ctx.currentTurnModelProfileNoticeKey = undefined;
|
|
776
|
+
// Turn-scoped interactivity. Clear it so paths that bypass this loop
|
|
777
|
+
// (e.g. opportunity wakes calling `agentLoop.run` directly) don't inherit
|
|
778
|
+
// a stale value and instead fall back to live client state in the tool
|
|
779
|
+
// context.
|
|
780
|
+
ctx.currentTurnIsNonInteractive = undefined;
|
|
781
|
+
// Turn-scoped request origin. Clear so a later turn on a reused
|
|
782
|
+
// conversation cannot inherit a stale origin-scoped permission grant.
|
|
783
|
+
ctx.currentTurnRequestOrigin = undefined;
|
|
784
|
+
// Channel command intents (e.g. Telegram /start) are single-turn
|
|
785
|
+
// metadata. Clear at turn end so they never leak into subsequent
|
|
786
|
+
// unrelated messages.
|
|
787
|
+
ctx.commandIntent = undefined;
|
|
788
|
+
// The app on screen is view state owned by the message that reported it,
|
|
789
|
+
// not durable conversation state: nothing tells the daemon when the user
|
|
790
|
+
// closes an app. Clear both copies at turn end so a later turn that brings
|
|
791
|
+
// no client transport (a scheduled wake, a background follow-up) cannot
|
|
792
|
+
// claim the user is looking at an app they may have closed. Every inbound
|
|
793
|
+
// send re-applies it from transport before its own turn, including the
|
|
794
|
+
// queue drain, so live turns are unaffected.
|
|
795
|
+
ctx.visibleAppId = undefined;
|
|
796
|
+
ctx.currentTurnVisibleAppId = undefined;
|
|
797
|
+
// taskRunId scopes ephemeral task-run permissions to a single turn. Clear
|
|
798
|
+
// before the queue drain so queued/drained turns on a reused conversation
|
|
799
|
+
// cannot inherit stale in-task-run scope from the turn that just finished.
|
|
800
|
+
ctx.taskRunId = undefined;
|
|
801
|
+
|
|
802
|
+
// Close the turn's profiling window here rather than after the queue
|
|
803
|
+
// drain: the profiler is per-conversation and the next turn's
|
|
804
|
+
// `startToolProfilingRequest` resets it, so a summary emitted after a
|
|
805
|
+
// drained turn started would report that turn's window under this turn's
|
|
806
|
+
// request id.
|
|
807
|
+
emitToolProfilingSummary(ctx.conversationId, reqId);
|
|
808
|
+
};
|
|
670
809
|
|
|
671
810
|
const publishLoopMessagesChanged = (): void => {
|
|
672
811
|
if (
|
|
@@ -717,14 +856,20 @@ export async function runAgentLoopImpl(
|
|
|
717
856
|
return;
|
|
718
857
|
}
|
|
719
858
|
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
859
|
+
// Workspace Git readiness is required only when tools can run. Tool-less
|
|
860
|
+
// callers use the same depth gate consumed by tool resolution.
|
|
861
|
+
if (!toolsDisabledForTurn) {
|
|
862
|
+
try {
|
|
863
|
+
const getWorkspaceGitServiceFn =
|
|
864
|
+
ctx.getWorkspaceGitService ?? getWorkspaceGitService;
|
|
865
|
+
const gitService = getWorkspaceGitServiceFn(ctx.workingDir);
|
|
866
|
+
await gitService.ensureInitialized();
|
|
867
|
+
} catch (err) {
|
|
868
|
+
rlog.warn(
|
|
869
|
+
{ err },
|
|
870
|
+
"Failed to initialize workspace git repo (non-fatal)",
|
|
871
|
+
);
|
|
872
|
+
}
|
|
728
873
|
}
|
|
729
874
|
|
|
730
875
|
// Auto-complete stale interactive surfaces from previous turns.
|
|
@@ -737,13 +882,20 @@ export async function runAgentLoopImpl(
|
|
|
737
882
|
if (entry.surfaceType === "dynamic_page") {
|
|
738
883
|
continue;
|
|
739
884
|
}
|
|
885
|
+
// Persist before announcing: a client told the card was dismissed
|
|
886
|
+
// while the write failed would watch the next reseed revert it.
|
|
887
|
+
// An unannounced dismissal keeps its pending entry so client and
|
|
888
|
+
// daemon agree the card is still live and the one-interactive-surface
|
|
889
|
+
// gate keeps holding; the next user message sweeps it again.
|
|
890
|
+
if (!markSurfaceCompleted(ctx, surfaceId, "Dismissed")) {
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
740
893
|
onEvent({
|
|
741
894
|
type: "ui_surface_complete",
|
|
742
895
|
conversationId: ctx.conversationId,
|
|
743
896
|
surfaceId,
|
|
744
897
|
summary: "Dismissed",
|
|
745
898
|
});
|
|
746
|
-
markSurfaceCompleted(ctx, surfaceId, "Dismissed");
|
|
747
899
|
ctx.pendingSurfaceActions.delete(surfaceId);
|
|
748
900
|
}
|
|
749
901
|
}
|
|
@@ -1341,9 +1493,16 @@ export async function runAgentLoopImpl(
|
|
|
1341
1493
|
return { ...msg, content: cleanedBlocks };
|
|
1342
1494
|
});
|
|
1343
1495
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1496
|
+
// "The run delivered a final assistant reply", not "the run produced any
|
|
1497
|
+
// assistant-role message". A run that called tools already carries
|
|
1498
|
+
// assistant `tool_use` messages, and those are not a delivered reply: a
|
|
1499
|
+
// provider error that kills the run mid-turn leaves the tail as the
|
|
1500
|
+
// tool_result (user role), while a run that replied normally ends on the
|
|
1501
|
+
// assistant message. Testing only the tail keeps the synthetic error row
|
|
1502
|
+
// below reachable for mid-turn failures, which is the only durable record
|
|
1503
|
+
// of why the turn stopped.
|
|
1504
|
+
const hasAssistantResponse =
|
|
1505
|
+
newMessages[newMessages.length - 1]?.role === "assistant";
|
|
1347
1506
|
if (
|
|
1348
1507
|
!hasAssistantResponse &&
|
|
1349
1508
|
state.providerErrorUserMessage &&
|
|
@@ -1403,13 +1562,13 @@ export async function runAgentLoopImpl(
|
|
|
1403
1562
|
providerErrorCategory: state.providerErrorCategory ?? undefined,
|
|
1404
1563
|
};
|
|
1405
1564
|
// The persisted row re-enters LLM history and is displayed as
|
|
1406
|
-
// assistant speech, so managed-
|
|
1407
|
-
//
|
|
1565
|
+
// assistant speech, so the managed-billing categories swap the
|
|
1566
|
+
// banner-voice classification copy for assistant-voice wording.
|
|
1408
1567
|
const persistedErrorText =
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1568
|
+
managedBillingAssistantReply(
|
|
1569
|
+
state.providerErrorCode,
|
|
1570
|
+
state.providerErrorCategory,
|
|
1571
|
+
) ?? state.providerErrorUserMessage;
|
|
1413
1572
|
const errorAssistantMessage =
|
|
1414
1573
|
createAssistantMessage(persistedErrorText);
|
|
1415
1574
|
const errorRow = await addMessage(
|
|
@@ -1471,10 +1630,10 @@ export async function runAgentLoopImpl(
|
|
|
1471
1630
|
// compaction/overflow recovery (where a cache miss is expected).
|
|
1472
1631
|
//
|
|
1473
1632
|
// Post-turn tool-result truncation (spooling large results to disk and
|
|
1474
|
-
// shrinking the next turn's context) is deferred to `
|
|
1633
|
+
// shrinking the next turn's context) is deferred to `settleTurnContent`
|
|
1475
1634
|
// below. It only rewrites the in-memory history the NEXT turn is built
|
|
1476
|
-
// from
|
|
1477
|
-
//
|
|
1635
|
+
// from, never the just-delivered reply, so it must not sit on the critical
|
|
1636
|
+
// path to the terminal SSE that re-enables the composer.
|
|
1478
1637
|
ctx.messages = restoredHistory;
|
|
1479
1638
|
|
|
1480
1639
|
emitUsage(
|
|
@@ -1504,7 +1663,7 @@ export async function runAgentLoopImpl(
|
|
|
1504
1663
|
// Fast-path: when the user cancelled, skip expensive post-loop work
|
|
1505
1664
|
// (attachment resolution) and emit the cancellation event immediately
|
|
1506
1665
|
// so the client can re-enable the UI without delay. Disk sync and the rest
|
|
1507
|
-
// of the bookkeeping run
|
|
1666
|
+
// of the bookkeeping run after this SSE.
|
|
1508
1667
|
if (abortController.signal.aborted) {
|
|
1509
1668
|
abnormalOutcome = { outcome: "cancelled" };
|
|
1510
1669
|
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
@@ -1600,24 +1759,42 @@ export async function runAgentLoopImpl(
|
|
|
1600
1759
|
|
|
1601
1760
|
// The terminal SSE for this turn has now been emitted (message_complete,
|
|
1602
1761
|
// generation_handoff, or generation_cancelled), so the composer is already
|
|
1603
|
-
// re-enabling. Settle any pending debounced partial flush FIRST
|
|
1762
|
+
// re-enabling. Settle any pending debounced partial flush FIRST: a
|
|
1604
1763
|
// cancelled turn exits with the timer still pending, and a flush firing
|
|
1605
|
-
// after the
|
|
1606
|
-
//
|
|
1607
|
-
//
|
|
1608
|
-
//
|
|
1764
|
+
// after the stranded fold (or the voice bridge's transcript hygiene) would
|
|
1765
|
+
// write raw content into an already-settled row. Then settle the rest of
|
|
1766
|
+
// the turn's content, which rewrites state the next turn also writes and so
|
|
1767
|
+
// has to complete under the processing lock.
|
|
1609
1768
|
await settlePendingPartialFlush(state, deps);
|
|
1610
|
-
await
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1769
|
+
await settleTurnContent({ ctx, state, rlog });
|
|
1770
|
+
|
|
1771
|
+
// Content is settled, so the conversation is free. Release before the
|
|
1772
|
+
// deferred tail rather than in the `finally`: the tail's memory indexing is
|
|
1773
|
+
// network-bound and unbounded, and holding the lock across it is what makes
|
|
1774
|
+
// a fully-delivered reply still answer a follow-up send with a queue slot.
|
|
1775
|
+
// The queue itself is drained later, from the `finally` after the
|
|
1776
|
+
// turn-boundary commit.
|
|
1777
|
+
const criticalSectionMs = Date.now() - generationCompletedAt;
|
|
1778
|
+
releaseTurn();
|
|
1779
|
+
|
|
1780
|
+
// Detached, and chained on the conversation's tail chain so two turns'
|
|
1781
|
+
// tails run in turn order instead of concurrently. The chain is keyed by
|
|
1782
|
+
// conversation id rather than held on this instance, because the tail runs
|
|
1783
|
+
// while the conversation reads idle and can therefore outlive the instance
|
|
1784
|
+
// that scheduled it.
|
|
1785
|
+
chainTurnTail(ctx.conversationId, () =>
|
|
1786
|
+
runDeferredTurnTail({
|
|
1787
|
+
conversationId: ctx.conversationId,
|
|
1788
|
+
state,
|
|
1789
|
+
rlog,
|
|
1790
|
+
criticalSectionMs,
|
|
1791
|
+
turnCompleted,
|
|
1792
|
+
userMessageId: options?.notifyUserMessageId ?? userMessageId,
|
|
1793
|
+
...(options?.replyDeliveredInAppOnly
|
|
1794
|
+
? { replyDeliveredInAppOnly: true }
|
|
1795
|
+
: {}),
|
|
1796
|
+
}),
|
|
1797
|
+
);
|
|
1621
1798
|
} catch (err) {
|
|
1622
1799
|
clearConversationNotices(ctx.conversationId);
|
|
1623
1800
|
const errorCtx = {
|
|
@@ -1625,9 +1802,9 @@ export async function runAgentLoopImpl(
|
|
|
1625
1802
|
aborted: abortController.signal.aborted,
|
|
1626
1803
|
};
|
|
1627
1804
|
if (isUserCancellation(err, errorCtx)) {
|
|
1628
|
-
// Only label the turn when it hadn't already replied
|
|
1629
|
-
// surfacing after the terminal SSE (
|
|
1630
|
-
//
|
|
1805
|
+
// Only label the turn when it hadn't already replied: a cancellation
|
|
1806
|
+
// surfacing after the terminal SSE (the content-settle steps) must not
|
|
1807
|
+
// relabel a visibly-replied turn.
|
|
1631
1808
|
if (!turnReplied) {
|
|
1632
1809
|
abnormalOutcome = { outcome: "cancelled" };
|
|
1633
1810
|
}
|
|
@@ -1665,112 +1842,86 @@ export async function runAgentLoopImpl(
|
|
|
1665
1842
|
publishLoopMessagesChanged();
|
|
1666
1843
|
}
|
|
1667
1844
|
} finally {
|
|
1668
|
-
//
|
|
1669
|
-
//
|
|
1670
|
-
//
|
|
1671
|
-
//
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1845
|
+
// Backstop release for the cancel/error paths, which throw out of the try
|
|
1846
|
+
// before the happy path's release runs. Idempotent, so the happy path
|
|
1847
|
+
// reaches here already released. It stays first in the `finally` so the
|
|
1848
|
+
// turn-boundary commit below cannot throw ahead of it and leave the row
|
|
1849
|
+
// latched "mid-turn".
|
|
1850
|
+
releaseTurn();
|
|
1851
|
+
|
|
1852
|
+
// The queue drain runs after the turn-boundary commit, under a `finally`
|
|
1853
|
+
// so a throw in the commit section cannot strand the queue with nothing
|
|
1854
|
+
// left to re-trigger it. Ordering is load-bearing: `commitTurnChanges`
|
|
1855
|
+
// attributes the working tree's changes to the finished turn, so a queued
|
|
1856
|
+
// turn that started while it was preparing would have its first file
|
|
1857
|
+
// writes swept into the wrong commit. The wait is deadline-bounded, and
|
|
1858
|
+
// direct sends are already unblocked by the release above.
|
|
1859
|
+
try {
|
|
1860
|
+
if (turnStarted) {
|
|
1861
|
+
ctx.turnCount++;
|
|
1862
|
+
const runTurnCommit = async (): Promise<void> => {
|
|
1863
|
+
const config = getConfig();
|
|
1864
|
+
const maxWait = config.workspaceGit?.turnCommitMaxWaitMs ?? 4000;
|
|
1865
|
+
const deadlineMs = Date.now() + maxWait;
|
|
1866
|
+
|
|
1867
|
+
const commitTurnChangesFn =
|
|
1868
|
+
ctx.commitTurnChanges ?? commitTurnChanges;
|
|
1869
|
+
const commitPromise = commitTurnChangesFn(
|
|
1870
|
+
ctx.workingDir,
|
|
1871
|
+
ctx.conversationId,
|
|
1872
|
+
ctx.turnCount,
|
|
1873
|
+
undefined,
|
|
1874
|
+
deadlineMs,
|
|
1875
|
+
);
|
|
1876
|
+
const outcome = await raceWithTimeout(commitPromise, maxWait);
|
|
1877
|
+
if (outcome === "timed_out") {
|
|
1878
|
+
rlog.warn(
|
|
1879
|
+
{
|
|
1880
|
+
turnNumber: ctx.turnCount,
|
|
1881
|
+
maxWaitMs: maxWait,
|
|
1882
|
+
conversationId: ctx.conversationId,
|
|
1883
|
+
},
|
|
1884
|
+
"Turn-boundary commit timed out; continuing without waiting (commit still runs in background)",
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1686
1888
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1889
|
+
if (toolsDisabledForTurn) {
|
|
1890
|
+
// Let the caller and the queue drain below claim an immediate
|
|
1891
|
+
// follow-up turn before starting Git. That turn will commit the
|
|
1892
|
+
// accumulated disk view.
|
|
1893
|
+
setImmediate(() => {
|
|
1894
|
+
if (ctx.isProcessing()) {
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
void runTurnCommit().catch((err) => {
|
|
1898
|
+
rlog.warn({ err }, "Deferred turn-boundary commit failed");
|
|
1899
|
+
});
|
|
1900
|
+
});
|
|
1901
|
+
} else {
|
|
1902
|
+
await runTurnCommit();
|
|
1903
|
+
}
|
|
1692
1904
|
|
|
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
|
-
);
|
|
1905
|
+
// Recompute relationship-state.json at turn boundary (fire-and-forget).
|
|
1906
|
+
// The writer swallows its own errors, but we still guard with catch()
|
|
1907
|
+
// here so a regression in the writer can never bubble out of the
|
|
1908
|
+
// agent loop and reject an otherwise-complete turn.
|
|
1909
|
+
void writeRelationshipState().catch(() => {});
|
|
1711
1910
|
}
|
|
1712
1911
|
|
|
1713
|
-
//
|
|
1714
|
-
//
|
|
1715
|
-
//
|
|
1716
|
-
//
|
|
1717
|
-
|
|
1912
|
+
// Consolidation deferred to compaction: keeping assistant + tool_result
|
|
1913
|
+
// messages unconsolidated preserves the exact message structure sent to
|
|
1914
|
+
// the API, enabling stable prefix caching across turns. Compaction
|
|
1915
|
+
// consolidates when it summarizes old messages (cache miss is expected).
|
|
1916
|
+
} finally {
|
|
1917
|
+
// kickDrainQueue never rejects: a drain failure here would otherwise be
|
|
1918
|
+
// an unhandled rejection that strands the queue with nothing left to
|
|
1919
|
+
// re-trigger it.
|
|
1920
|
+
void ctx.kickDrainQueue(
|
|
1921
|
+
yieldedForHandoff ? "checkpoint_handoff" : "loop_complete",
|
|
1922
|
+
"agent_loop_finally",
|
|
1923
|
+
);
|
|
1718
1924
|
}
|
|
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
1925
|
}
|
|
1775
1926
|
}
|
|
1776
1927
|
|
|
@@ -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}.`;
|