@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
|
@@ -83,10 +83,10 @@ import { FALLBACK_TURN_TRUST, resolveTrustClass } from "./trust-context.js";
|
|
|
83
83
|
|
|
84
84
|
const log = getLogger("conversation-tool-setup");
|
|
85
85
|
|
|
86
|
-
import type {
|
|
86
|
+
import type { SubagentToolStats } from "./tool-setup-types.js";
|
|
87
87
|
export type {
|
|
88
88
|
SubagentToolGateMode,
|
|
89
|
-
|
|
89
|
+
SubagentToolStats,
|
|
90
90
|
WakeToolContextPin,
|
|
91
91
|
} from "./tool-setup-types.js";
|
|
92
92
|
|
|
@@ -112,7 +112,7 @@ export type {
|
|
|
112
112
|
*/
|
|
113
113
|
export function resolveConversationAttribution(
|
|
114
114
|
ctx: Pick<
|
|
115
|
-
|
|
115
|
+
Conversation,
|
|
116
116
|
"conversationId" | "currentCallSite" | "currentTurnOverrideProfile"
|
|
117
117
|
>,
|
|
118
118
|
): UsageAttributionSnapshot | null {
|
|
@@ -197,8 +197,13 @@ export function getEffectiveEnabledPluginSet(conv: {
|
|
|
197
197
|
* own implementation) does not slip through. `skill_execute` is the dispatcher —
|
|
198
198
|
* its resolved inner tool is classified by the same check in the executor gate,
|
|
199
199
|
* so exposing the wrapper is safe.
|
|
200
|
+
*
|
|
201
|
+
* Exported so a role allowlist that relies on this gate for its read-only
|
|
202
|
+
* guarantee (the advisor consult) can be asserted to stay inside the set: a name
|
|
203
|
+
* outside it is admitted by the role and then refused at dispatch, which reads
|
|
204
|
+
* as a broken tool rather than a policy decision.
|
|
200
205
|
*/
|
|
201
|
-
const READ_ONLY_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
|
|
206
|
+
export const READ_ONLY_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
|
|
202
207
|
"file_read",
|
|
203
208
|
"file_list",
|
|
204
209
|
"code_search",
|
|
@@ -232,7 +237,7 @@ export function createToolExecutor(
|
|
|
232
237
|
executor: ToolExecutor,
|
|
233
238
|
prompter: PermissionPrompter,
|
|
234
239
|
secretPrompter: SecretPrompter,
|
|
235
|
-
ctx:
|
|
240
|
+
ctx: Conversation,
|
|
236
241
|
): (
|
|
237
242
|
name: string,
|
|
238
243
|
input: Record<string, unknown>,
|
|
@@ -311,6 +316,45 @@ export function createToolExecutor(
|
|
|
311
316
|
};
|
|
312
317
|
};
|
|
313
318
|
|
|
319
|
+
// Machine tool-call accounting for the subagent truth envelope. Recorded
|
|
320
|
+
// here because this closure is the single dispatch choke point every tool
|
|
321
|
+
// call passes through, including the `skill_execute` indirection (counted
|
|
322
|
+
// under the resolved inner tool name, not the wrapper). Non-subagent
|
|
323
|
+
// conversations never reach the counters.
|
|
324
|
+
const subagentStats = (): SubagentToolStats | undefined =>
|
|
325
|
+
ctx.isSubagent === true ? ctx.subagentToolStats : undefined;
|
|
326
|
+
|
|
327
|
+
const recordToolDispatch = (): void => {
|
|
328
|
+
const stats = subagentStats();
|
|
329
|
+
if (stats) {
|
|
330
|
+
stats.calls++;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const recordToolResult = (
|
|
335
|
+
toolName: string,
|
|
336
|
+
toolInput: Record<string, unknown>,
|
|
337
|
+
result: ToolExecutionResult,
|
|
338
|
+
): void => {
|
|
339
|
+
const stats = subagentStats();
|
|
340
|
+
if (!stats || result.isError) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
stats.succeeded++;
|
|
344
|
+
// Both file tools name their target `path`. A Set dedupes repeated edits
|
|
345
|
+
// of the same file, so the count reads as "files touched", not "writes".
|
|
346
|
+
// These two are the only writes with a path to attribute: a builder can
|
|
347
|
+
// also write through the shell, a document tool, or an MCP tool, and those
|
|
348
|
+
// are invisible here, which is why the footer names the two tools it
|
|
349
|
+
// counts (see `formatSubagentToolStats`).
|
|
350
|
+
if (toolName === "file_write" || toolName === "file_edit") {
|
|
351
|
+
const target = toolInput.path;
|
|
352
|
+
if (typeof target === "string" && target.length > 0) {
|
|
353
|
+
stats.filesWritten.add(target);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
314
358
|
return async (
|
|
315
359
|
name: string,
|
|
316
360
|
input: Record<string, unknown>,
|
|
@@ -357,7 +401,7 @@ export function createToolExecutor(
|
|
|
357
401
|
trustClass: resolveTrustClass(turnTrust),
|
|
358
402
|
executionChannel: turnTrust.sourceChannel,
|
|
359
403
|
requestOrigin: ctx.currentTurnRequestOrigin,
|
|
360
|
-
sourceActorPrincipalId:
|
|
404
|
+
sourceActorPrincipalId: ctx.getTurnActorPrincipalId(),
|
|
361
405
|
callSessionId: ctx.callSessionId,
|
|
362
406
|
triggeredBySurfaceAction:
|
|
363
407
|
ctx.surfaceActionRequestIds?.has(ctx.currentRequestId ?? "") ?? false,
|
|
@@ -390,6 +434,7 @@ export function createToolExecutor(
|
|
|
390
434
|
isPlatformHosted: getIsPlatform(),
|
|
391
435
|
transportInterface: ctx.transportInterface,
|
|
392
436
|
overrideProfile: ctx.currentTurnOverrideProfile,
|
|
437
|
+
cronRunId: ctx.currentTurnCronRunId,
|
|
393
438
|
invokingCallSite: ctx.currentCallSite ?? "mainAgent",
|
|
394
439
|
attribution: resolveConversationAttribution(ctx),
|
|
395
440
|
enabledPluginSet: effectiveEnabledPluginSet,
|
|
@@ -505,12 +550,14 @@ export function createToolExecutor(
|
|
|
505
550
|
return pluginRejection;
|
|
506
551
|
}
|
|
507
552
|
|
|
553
|
+
recordToolDispatch();
|
|
508
554
|
const rawResult = await executor.execute(
|
|
509
555
|
toolName,
|
|
510
556
|
toolInput,
|
|
511
557
|
toolContext,
|
|
512
558
|
);
|
|
513
559
|
const result = augmentSkillExecuteError(toolName, toolInput, rawResult);
|
|
560
|
+
recordToolResult(toolName, toolInput, result);
|
|
514
561
|
if (toolContext.approvedViaPrompt) {
|
|
515
562
|
ctx.approvedViaPromptThisTurn = true;
|
|
516
563
|
}
|
|
@@ -520,11 +567,13 @@ export function createToolExecutor(
|
|
|
520
567
|
return result;
|
|
521
568
|
}
|
|
522
569
|
|
|
570
|
+
recordToolDispatch();
|
|
523
571
|
const result = await executor.execute(
|
|
524
572
|
executionName,
|
|
525
573
|
executionInput,
|
|
526
574
|
toolContext,
|
|
527
575
|
);
|
|
576
|
+
recordToolResult(executionName, executionInput, result);
|
|
528
577
|
if (toolContext.approvedViaPrompt) {
|
|
529
578
|
ctx.approvedViaPromptThisTurn = true;
|
|
530
579
|
}
|
|
@@ -547,7 +596,7 @@ export function createToolExecutor(
|
|
|
547
596
|
*/
|
|
548
597
|
export function createProxyApprovalCallback(
|
|
549
598
|
_prompter: PermissionPrompter,
|
|
550
|
-
_ctx:
|
|
599
|
+
_ctx: Conversation,
|
|
551
600
|
): ProxyApprovalCallback {
|
|
552
601
|
return async (_request: ProxyApprovalRequest): Promise<boolean> => {
|
|
553
602
|
// Proxied asks follow the same non-host auto-allow contract as regular
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* End-of-turn finalize work that runs
|
|
2
|
+
* End-of-turn finalize work that runs after the terminal SSE.
|
|
3
3
|
*
|
|
4
4
|
* The web/Capacitor/CLI clients re-enable the composer the moment they observe
|
|
5
5
|
* the terminal `message_complete` / `assistant_activity_state("idle")` SSE, so
|
|
@@ -9,10 +9,21 @@
|
|
|
9
9
|
* None of the work here gates delivery of the reply: memory/attention indexing
|
|
10
10
|
* only feeds the NEXT turn's retrieval and a sidebar indicator, tool-result
|
|
11
11
|
* truncation only reshapes the in-memory history the next turn is built from,
|
|
12
|
-
* and the disk-view mirror is a durability convenience. The
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* and the disk-view mirror is a durability convenience. The work is split by
|
|
13
|
+
* whether a step is safe to overlap the NEXT turn:
|
|
14
|
+
*
|
|
15
|
+
* - {@link settleTurnContent} runs while the turn still holds the processing
|
|
16
|
+
* lock. Its steps rewrite `ctx.messages` and append to the conversation's disk
|
|
17
|
+
* view, both of which the next turn also writes, so they must finish before
|
|
18
|
+
* the lock releases. Every step is synchronous apart from the stranded-content
|
|
19
|
+
* fold, so holding the lock across them costs the queue nothing: synchronous
|
|
20
|
+
* work blocks the event loop either way.
|
|
21
|
+
* - {@link runDeferredTurnTail} runs detached, after the lock releases, chained
|
|
22
|
+
* by `chainTurnTail` so two turns' tails never overlap each other. Its steps
|
|
23
|
+
* are keyed by the message ids this turn produced and are network-bound
|
|
24
|
+
* (embeddings, vector upserts, the assistant-reply push notification), which
|
|
25
|
+
* is the work that must not hold the lock:
|
|
26
|
+
* a slow index otherwise leaves the next send queued behind an idle-looking UI.
|
|
16
27
|
*/
|
|
17
28
|
|
|
18
29
|
import type pino from "pino";
|
|
@@ -42,20 +53,25 @@ import {
|
|
|
42
53
|
} from "./inflight-message-content.js";
|
|
43
54
|
import { conversationMetadataSyncTag } from "./message-types/sync.js";
|
|
44
55
|
|
|
45
|
-
/** Minimal live-conversation surface the
|
|
56
|
+
/** Minimal live-conversation surface the finalize steps read and rewrite. */
|
|
46
57
|
interface TurnTailContext {
|
|
47
58
|
readonly conversationId: string;
|
|
48
59
|
messages: Message[];
|
|
49
60
|
}
|
|
50
61
|
|
|
51
|
-
/** Minimal per-run handler state
|
|
52
|
-
interface
|
|
53
|
-
readonly deferredFinalizeEffects: ReadonlyArray<() => Promise<void>>;
|
|
62
|
+
/** Minimal per-run handler state {@link settleTurnContent} consumes. */
|
|
63
|
+
interface TurnContentState {
|
|
54
64
|
readonly lastAssistantMessageId: string | undefined;
|
|
55
65
|
/** In-flight content writers the turn left behind (see EventHandlerState). */
|
|
56
66
|
readonly inflightWriters: Map<string, InflightContentWriter>;
|
|
57
67
|
}
|
|
58
68
|
|
|
69
|
+
/** Minimal per-run handler state the detached tail consumes. */
|
|
70
|
+
interface TurnTailState {
|
|
71
|
+
readonly deferredFinalizeEffects: ReadonlyArray<() => Promise<void>>;
|
|
72
|
+
readonly lastAssistantMessageId: string | undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
59
75
|
/**
|
|
60
76
|
* Build the deferred finalize side-effect for one finalized assistant row:
|
|
61
77
|
* memory segment indexing, lexical indexing, and attention projection.
|
|
@@ -129,95 +145,36 @@ export function buildDeferredFinalizeEffect(params: {
|
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
/**
|
|
132
|
-
*
|
|
133
|
-
* composer but before the agent loop's `finally` commits and drains the queue
|
|
134
|
-
* for the next turn. Ordering with the next turn is preserved (this completes
|
|
135
|
-
* before `drainQueue`), while the last-token→send-button latency no longer
|
|
136
|
-
* includes it. Every step is best-effort.
|
|
148
|
+
* Settle the turn's content while the processing lock is still held.
|
|
137
149
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
150
|
+
* These steps run after the terminal SSE (so they are off the last-token to
|
|
151
|
+
* composer-enabled path) but before the lock releases, because each one writes
|
|
152
|
+
* a resource the next turn also writes: the in-memory history array and the
|
|
153
|
+
* conversation's append-only disk view. The processing lock is the only
|
|
154
|
+
* per-conversation serialization those resources have, so letting these steps
|
|
155
|
+
* run past the release would let a fast follow-up turn interleave with them.
|
|
156
|
+
* Every step is best-effort.
|
|
141
157
|
*/
|
|
142
|
-
export async function
|
|
158
|
+
export async function settleTurnContent(params: {
|
|
143
159
|
ctx: TurnTailContext;
|
|
144
|
-
state:
|
|
160
|
+
state: TurnContentState;
|
|
145
161
|
rlog: pino.Logger;
|
|
146
|
-
generationCompletedAt: number;
|
|
147
|
-
/**
|
|
148
|
-
* True only for a `message_complete` turn that produced a genuine reply. A
|
|
149
|
-
* handed-off generation is not the end of the run, a cancelled one has no
|
|
150
|
-
* final reply, and a provider-error turn's only assistant row is the
|
|
151
|
-
* synthetic error text.
|
|
152
|
-
*/
|
|
153
|
-
turnCompleted: boolean;
|
|
154
|
-
/** Id of the row that opened this turn, for the notification producer. */
|
|
155
|
-
userMessageId: string | undefined;
|
|
156
|
-
/**
|
|
157
|
-
* True when this turn's reply streams to the app and nowhere else, for the
|
|
158
|
-
* notification producer's delivery-surface gates.
|
|
159
|
-
*/
|
|
160
|
-
replyDeliveredInAppOnly?: boolean;
|
|
161
162
|
}): Promise<void> {
|
|
162
|
-
const {
|
|
163
|
-
ctx,
|
|
164
|
-
state,
|
|
165
|
-
rlog,
|
|
166
|
-
generationCompletedAt,
|
|
167
|
-
turnCompleted,
|
|
168
|
-
userMessageId,
|
|
169
|
-
replyDeliveredInAppOnly,
|
|
170
|
-
} = params;
|
|
171
|
-
const tailStartedAt = Date.now();
|
|
163
|
+
const { ctx, state, rlog } = params;
|
|
172
164
|
|
|
173
|
-
// Conversation row for the
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Per-message memory/attention finalize side-effects deferred from
|
|
184
|
-
// `handleMessageComplete`: one closure per assistant row produced this turn,
|
|
185
|
-
// in production order.
|
|
186
|
-
for (const effect of state.deferredFinalizeEffects) {
|
|
187
|
-
try {
|
|
188
|
-
await effect();
|
|
189
|
-
} catch (err) {
|
|
190
|
-
rlog.warn({ err }, "Deferred finalize side-effect failed (non-fatal)");
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Notify about a finished reply the user is no longer looking at. Ordered
|
|
195
|
-
// after the loop above so the producer's unseen check reads the attention
|
|
196
|
-
// cursor this turn's last row just projected. Not awaited: the pipeline
|
|
197
|
-
// awaits the platform adapter's HTTP dispatch, which retries with backoff,
|
|
198
|
-
// and nothing below here depends on the emit. The producer never rejects.
|
|
199
|
-
if (turnCompleted && state.lastAssistantMessageId) {
|
|
200
|
-
void emitAssistantReplyNotification({
|
|
201
|
-
conversationId: ctx.conversationId,
|
|
202
|
-
assistantMessageId: state.lastAssistantMessageId,
|
|
203
|
-
userMessageId,
|
|
204
|
-
...(replyDeliveredInAppOnly ? { replyDeliveredInAppOnly: true } : {}),
|
|
205
|
-
rlog,
|
|
206
|
-
conversation,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Fresh row for the two filesystem steps below. The awaited work above is
|
|
211
|
-
// long enough for the user to delete the conversation, and the row read at
|
|
212
|
-
// the top of the tail stays truthy across that deletion, so spooling or
|
|
213
|
-
// mirroring against it would rebuild a deleted conversation's directory from
|
|
214
|
-
// in-memory history. A row that is gone skips both steps exactly as an
|
|
215
|
-
// unreadable one does.
|
|
165
|
+
// Conversation row for the two filesystem steps below. Read here rather than
|
|
166
|
+
// reused from anywhere earlier in the turn: the turn is long enough for the
|
|
167
|
+
// user to delete the conversation, and a row read before that deletion stays
|
|
168
|
+
// truthy across it, so spooling or mirroring against it would rebuild a
|
|
169
|
+
// deleted conversation's directory from in-memory history. A row that is gone
|
|
170
|
+
// skips both steps exactly as an unreadable one does. Guarded like every step
|
|
171
|
+
// below, because this runs after the terminal SSE and a SQLite hiccup must not
|
|
172
|
+
// escape into the loop's outer catch.
|
|
216
173
|
let liveConversation: ConversationRow | null = null;
|
|
217
174
|
try {
|
|
218
175
|
liveConversation = getConversation(ctx.conversationId);
|
|
219
176
|
} catch (err) {
|
|
220
|
-
rlog.warn({ err }, "Failed to
|
|
177
|
+
rlog.warn({ err }, "Failed to read conversation for end-of-turn work");
|
|
221
178
|
}
|
|
222
179
|
|
|
223
180
|
// Post-turn tool-result truncation: spool oversized results to disk and
|
|
@@ -275,10 +232,98 @@ export async function runDeferredTurnTail(params: {
|
|
|
275
232
|
} catch (err) {
|
|
276
233
|
rlog.warn({ err }, "Failed to sync assistant message to disk (non-fatal)");
|
|
277
234
|
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Drain a turn's deferred bookkeeping after the processing lock has released.
|
|
239
|
+
*
|
|
240
|
+
* Runs detached from the agent loop and chained through `chainTurnTail`, so a
|
|
241
|
+
* slow index never holds the next turn's send behind an idle composer, yet two
|
|
242
|
+
* turns' tails still run in turn order even when the second turn ran on a
|
|
243
|
+
* rebuilt `Conversation` instance. Every step is best-effort and keyed by a
|
|
244
|
+
* message id this turn produced, so it neither reads nor writes state the next
|
|
245
|
+
* turn owns.
|
|
246
|
+
*
|
|
247
|
+
* `criticalSectionMs` is the lock-held window the agent loop measured from the
|
|
248
|
+
* end of generation; paired with `deferredTailMs` it splits the end-of-turn
|
|
249
|
+
* window into the part a waiting sender feels and the part it no longer does.
|
|
250
|
+
*/
|
|
251
|
+
export async function runDeferredTurnTail(params: {
|
|
252
|
+
conversationId: string;
|
|
253
|
+
state: TurnTailState;
|
|
254
|
+
rlog: pino.Logger;
|
|
255
|
+
criticalSectionMs: number;
|
|
256
|
+
/**
|
|
257
|
+
* True only for a `message_complete` turn that produced a genuine reply. A
|
|
258
|
+
* handed-off generation is not the end of the run, a cancelled one has no
|
|
259
|
+
* final reply, and a provider-error turn's only assistant row is the
|
|
260
|
+
* synthetic error text.
|
|
261
|
+
*/
|
|
262
|
+
turnCompleted: boolean;
|
|
263
|
+
/** Id of the row that opened this turn, for the notification producer. */
|
|
264
|
+
userMessageId: string | undefined;
|
|
265
|
+
/**
|
|
266
|
+
* True when this turn's reply streams to the app and nowhere else, for the
|
|
267
|
+
* notification producer's delivery-surface gates.
|
|
268
|
+
*/
|
|
269
|
+
replyDeliveredInAppOnly?: boolean;
|
|
270
|
+
}): Promise<void> {
|
|
271
|
+
const {
|
|
272
|
+
conversationId,
|
|
273
|
+
state,
|
|
274
|
+
rlog,
|
|
275
|
+
criticalSectionMs,
|
|
276
|
+
turnCompleted,
|
|
277
|
+
userMessageId,
|
|
278
|
+
replyDeliveredInAppOnly,
|
|
279
|
+
} = params;
|
|
280
|
+
const tailStartedAt = Date.now();
|
|
281
|
+
|
|
282
|
+
// Conversation row for the notification producer below. Guarded like every
|
|
283
|
+
// step here, because this runs after the terminal SSE and a SQLite hiccup must
|
|
284
|
+
// not escape into the detached tail's caller.
|
|
285
|
+
let conversation: ConversationRow | null = null;
|
|
286
|
+
try {
|
|
287
|
+
conversation = getConversation(conversationId);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
rlog.warn({ err }, "Failed to read conversation for end-of-turn work");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Per-message memory/attention finalize side-effects deferred from
|
|
293
|
+
// `handleMessageComplete`: one closure per assistant row produced this turn,
|
|
294
|
+
// in production order.
|
|
295
|
+
for (const effect of state.deferredFinalizeEffects) {
|
|
296
|
+
try {
|
|
297
|
+
await effect();
|
|
298
|
+
} catch (err) {
|
|
299
|
+
rlog.warn({ err }, "Deferred finalize side-effect failed (non-fatal)");
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Notify about a finished reply the user is no longer looking at. Ordered
|
|
304
|
+
// after the loop above so the producer's unseen check reads the attention
|
|
305
|
+
// cursor this turn's last row just projected; that projection is the
|
|
306
|
+
// network-bound work this whole tail exists to keep off the lock, so the
|
|
307
|
+
// check necessarily runs with the conversation already free. A follow-up
|
|
308
|
+
// send that beats it there advances the cursor and suppresses the push,
|
|
309
|
+
// which is the right answer: a user typing the next message is looking at
|
|
310
|
+
// the reply. Not awaited: the pipeline awaits the platform adapter's HTTP
|
|
311
|
+
// dispatch, which retries with backoff, and nothing below here depends on
|
|
312
|
+
// the emit. The producer never rejects.
|
|
313
|
+
if (turnCompleted && state.lastAssistantMessageId) {
|
|
314
|
+
void emitAssistantReplyNotification({
|
|
315
|
+
conversationId,
|
|
316
|
+
assistantMessageId: state.lastAssistantMessageId,
|
|
317
|
+
userMessageId,
|
|
318
|
+
...(replyDeliveredInAppOnly ? { replyDeliveredInAppOnly: true } : {}),
|
|
319
|
+
rlog,
|
|
320
|
+
conversation,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
278
323
|
|
|
279
324
|
rlog.info(
|
|
280
325
|
{
|
|
281
|
-
criticalSectionMs
|
|
326
|
+
criticalSectionMs,
|
|
282
327
|
deferredTailMs: Date.now() - tailStartedAt,
|
|
283
328
|
},
|
|
284
329
|
"End-of-turn work complete",
|
|
@@ -96,6 +96,7 @@ import type { OnboardingContext } from "../types/onboarding-context.js";
|
|
|
96
96
|
import type { AbortReason } from "../util/abort-reasons.js";
|
|
97
97
|
import { UserError } from "../util/errors.js";
|
|
98
98
|
import { getLogger } from "../util/logger.js";
|
|
99
|
+
import { withSqliteRetry } from "../util/sqlite-retry.js";
|
|
99
100
|
import type { WorkspaceGitService } from "../workspace/git-service.js";
|
|
100
101
|
import type { commitTurnChanges } from "../workspace/turn-commit.js";
|
|
101
102
|
import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
|
|
@@ -154,7 +155,7 @@ import {
|
|
|
154
155
|
} from "./conversation-surfaces.js";
|
|
155
156
|
import type {
|
|
156
157
|
SubagentToolGateMode,
|
|
157
|
-
|
|
158
|
+
SubagentToolStats,
|
|
158
159
|
WakeToolContextPin,
|
|
159
160
|
} from "./conversation-tool-setup.js";
|
|
160
161
|
import {
|
|
@@ -275,8 +276,8 @@ export interface ConversationConstructorOptions {
|
|
|
275
276
|
* Give this conversation's LLM calls provider-native (server-side) web
|
|
276
277
|
* search when the resolved provider supports it (see
|
|
277
278
|
* {@link AgentLoopConfig.enableNativeWebSearch}). Set by the subagent manager
|
|
278
|
-
* for the
|
|
279
|
-
*
|
|
279
|
+
* for the advisor consult so it can ground guidance with live web access;
|
|
280
|
+
* non-native providers get nothing. Defaults to false.
|
|
280
281
|
*/
|
|
281
282
|
enableNativeWebSearch?: boolean;
|
|
282
283
|
/**
|
|
@@ -360,6 +361,20 @@ export class Conversation {
|
|
|
360
361
|
* @internal
|
|
361
362
|
*/
|
|
362
363
|
subagentDeniedToolNames = new Set<string>();
|
|
364
|
+
/**
|
|
365
|
+
* Machine tool-call counters for this conversation when it runs as a
|
|
366
|
+
* subagent child. Recorded by the tool executor (gated on {@link isSubagent},
|
|
367
|
+
* so parent conversations never accumulate anything here) and harvested by
|
|
368
|
+
* the SubagentManager into the child's state when the run ends, where it
|
|
369
|
+
* becomes the stats footer on the parent's completion notification and on
|
|
370
|
+
* `subagent_read`. Ephemeral, never persisted.
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
subagentToolStats: SubagentToolStats = {
|
|
374
|
+
calls: 0,
|
|
375
|
+
succeeded: 0,
|
|
376
|
+
filesWritten: new Set<string>(),
|
|
377
|
+
};
|
|
363
378
|
/**
|
|
364
379
|
* How {@link subagentAllowedTools} is enforced — see
|
|
365
380
|
* {@link SubagentToolGateMode}. Set and restored alongside the allowlist
|
|
@@ -481,6 +496,14 @@ export class Conversation {
|
|
|
481
496
|
*/
|
|
482
497
|
wakePersonaOverride?: SystemPromptPersonaOverride;
|
|
483
498
|
/** @internal */ currentTurnOverrideProfile?: string;
|
|
499
|
+
/**
|
|
500
|
+
* The firing's `cron_runs.id` when a schedule triggered the current turn.
|
|
501
|
+
* Exposed on the live conversation so the tool context can forward it to
|
|
502
|
+
* delegated LLM work (subagent spawns and messages), whose usage rows then
|
|
503
|
+
* attribute to the same firing.
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
currentTurnCronRunId?: string | null;
|
|
484
507
|
/** @internal */ currentTurnIsNonInteractive?: boolean;
|
|
485
508
|
/** @internal */ currentTurnModelProfileNoticeKey?: string;
|
|
486
509
|
/** @internal */ currentTurnRequestOrigin?: string;
|
|
@@ -538,11 +561,23 @@ export class Conversation {
|
|
|
538
561
|
* @internal
|
|
539
562
|
*/
|
|
540
563
|
pendingSteerRepair = false;
|
|
564
|
+
/**
|
|
565
|
+
* Set by `abortConversation` when a user interrupt (Stop / Esc / the CLI
|
|
566
|
+
* cancel signal) ends a turn that still has messages queued behind it. Those
|
|
567
|
+
* messages survive the abort and drain into the next turn, so the drain path
|
|
568
|
+
* owes them the same synthetic tool_result repair a steer gets: the killed
|
|
569
|
+
* turn may have left `tool_use` blocks with no results. Unlike
|
|
570
|
+
* `pendingSteerRepair` this does not promote a single head message. An
|
|
571
|
+
* interrupt has nothing to promote, so the drain batches the queue the way it
|
|
572
|
+
* would after any other turn. Cleared after repair.
|
|
573
|
+
* @internal
|
|
574
|
+
*/
|
|
575
|
+
pendingInterruptRepair = false;
|
|
541
576
|
/**
|
|
542
577
|
* When true, side-effect tools must prompt even if a trust/allow rule
|
|
543
578
|
* would auto-allow. Set by non-interactive callers (e.g. non-guardian
|
|
544
579
|
* phone voice) so their auto-deny handler reliably sees a
|
|
545
|
-
* `confirmation_request` event. See
|
|
580
|
+
* `confirmation_request` event. See `forcePromptSideEffects` below.
|
|
546
581
|
* @internal
|
|
547
582
|
*/
|
|
548
583
|
forcePromptSideEffects = false;
|
|
@@ -605,7 +640,7 @@ export class Conversation {
|
|
|
605
640
|
/** @internal */ clientTimezone?: string;
|
|
606
641
|
/**
|
|
607
642
|
* @internal
|
|
608
|
-
* The client's OS surface
|
|
643
|
+
* The client's OS surface, reported separately
|
|
609
644
|
* from the transport `interfaceId` so the assistant's per-turn context can
|
|
610
645
|
* show the real platform without affecting host-proxy/transport gating.
|
|
611
646
|
* This is the LIVE value (re-applied from transport on every inbound
|
|
@@ -765,7 +800,7 @@ export class Conversation {
|
|
|
765
800
|
this.executor,
|
|
766
801
|
this.prompter,
|
|
767
802
|
this.secretPrompter,
|
|
768
|
-
this
|
|
803
|
+
this,
|
|
769
804
|
);
|
|
770
805
|
|
|
771
806
|
const config = getConfig();
|
|
@@ -1564,38 +1599,45 @@ export class Conversation {
|
|
|
1564
1599
|
* Mutate the server-authoritative `processing` flag. Web/Capacitor/CLI
|
|
1565
1600
|
* caches treat this flag as the source of truth for the avatar streaming
|
|
1566
1601
|
* ring and thinking indicator, so the `true → false` clear must announce
|
|
1567
|
-
* itself: the daemon flips it
|
|
1568
|
-
* the user-visible terminal SSE events, and a racing metadata refetch
|
|
1569
|
-
* otherwise re-read the not-yet-cleared `true` and clobber the client's
|
|
1602
|
+
* itself: the daemon flips it once the finished turn's content is settled,
|
|
1603
|
+
* after the user-visible terminal SSE events, and a racing metadata refetch
|
|
1604
|
+
* can otherwise re-read the not-yet-cleared `true` and clobber the client's
|
|
1570
1605
|
* optimistic `false`.
|
|
1571
1606
|
*
|
|
1572
1607
|
* Emitting a metadata invalidation on the clear lets every client GET the
|
|
1573
1608
|
* authoritative `false`, per the multi-client-sync contract in AGENTS.md
|
|
1574
1609
|
* ("emit the invalidation after the canonical state write succeeds").
|
|
1610
|
+
*
|
|
1611
|
+
* The two directions have different failure semantics because the in-memory
|
|
1612
|
+
* flag and the persisted column serve different readers. Acquiring is
|
|
1613
|
+
* strict: a failed persist reverts the in-memory flag and re-throws, so the
|
|
1614
|
+
* caller's existing failure handling runs and the two never disagree about a
|
|
1615
|
+
* turn that is starting. Clearing is not: the in-memory flag is the queue
|
|
1616
|
+
* gate this process enforces, while the column is advisory state for
|
|
1617
|
+
* out-of-process readers that the boot-time stale-processing sweep already
|
|
1618
|
+
* recovers. Reverting a clear because a mirror write lost a race with
|
|
1619
|
+
* SQLITE_BUSY would latch the conversation into "busy" for the rest of the
|
|
1620
|
+
* daemon's life, so the clear always sticks.
|
|
1575
1621
|
*/
|
|
1576
1622
|
setProcessing(value: boolean): void {
|
|
1577
1623
|
const wasProcessing = this._processing;
|
|
1578
1624
|
this._processing = value;
|
|
1579
1625
|
// Persist the cross-process source of truth so out-of-process callers
|
|
1580
1626
|
// (retrospective CLI, future detached workers) can detect mid-turn state
|
|
1581
|
-
// by reading the conversations row directly.
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
);
|
|
1591
|
-
} catch (err) {
|
|
1592
|
-
this._processing = wasProcessing;
|
|
1593
|
-
throw err;
|
|
1627
|
+
// by reading the conversations row directly.
|
|
1628
|
+
if (value) {
|
|
1629
|
+
try {
|
|
1630
|
+
setConversationProcessingStartedAt(this.conversationId, Date.now());
|
|
1631
|
+
} catch (err) {
|
|
1632
|
+
this._processing = wasProcessing;
|
|
1633
|
+
throw err;
|
|
1634
|
+
}
|
|
1635
|
+
} else {
|
|
1636
|
+
this.mirrorProcessingCleared();
|
|
1594
1637
|
}
|
|
1595
1638
|
if (!value && this.idleWaiters.size > 0) {
|
|
1596
|
-
//
|
|
1597
|
-
//
|
|
1598
|
-
// observe a release that never happened. Copy-and-clear so a waiter
|
|
1639
|
+
// The in-memory flag is the release, so waiters are notified on it
|
|
1640
|
+
// rather than on the advisory mirror write. Copy-and-clear so a waiter
|
|
1599
1641
|
// registered from inside a notification can't be re-entered.
|
|
1600
1642
|
const waiters = [...this.idleWaiters];
|
|
1601
1643
|
this.idleWaiters.clear();
|
|
@@ -1610,6 +1652,37 @@ export class Conversation {
|
|
|
1610
1652
|
}
|
|
1611
1653
|
}
|
|
1612
1654
|
|
|
1655
|
+
/**
|
|
1656
|
+
* Mirror a released processing lock into the advisory `processing_started_at`
|
|
1657
|
+
* column, without ever reporting failure back to the release.
|
|
1658
|
+
*
|
|
1659
|
+
* `withSqliteRetry` runs its first attempt synchronously, so the common case
|
|
1660
|
+
* is the same single write the acquire direction performs; only a contended
|
|
1661
|
+
* write falls back to the backoff retries, which run detached. The retry
|
|
1662
|
+
* re-checks the in-memory flag because a new turn may have acquired the lock
|
|
1663
|
+
* (and written its own timestamp) while the backoff slept, and a late clear
|
|
1664
|
+
* would then blank a column that describes a live turn.
|
|
1665
|
+
*/
|
|
1666
|
+
private mirrorProcessingCleared(): void {
|
|
1667
|
+
void withSqliteRetry(
|
|
1668
|
+
() => {
|
|
1669
|
+
if (this._processing) {
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
setConversationProcessingStartedAt(this.conversationId, null);
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
op: "conversation:clearProcessing",
|
|
1676
|
+
context: { conversationId: this.conversationId },
|
|
1677
|
+
},
|
|
1678
|
+
).catch((err: unknown) => {
|
|
1679
|
+
log.error(
|
|
1680
|
+
{ err, conversationId: this.conversationId },
|
|
1681
|
+
"Failed to clear the persisted processing marker; the conversation is released in memory and the boot-time stale-processing sweep recovers the column",
|
|
1682
|
+
);
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1613
1686
|
/**
|
|
1614
1687
|
* Wait until this conversation's processing lock releases.
|
|
1615
1688
|
*
|
|
@@ -1746,8 +1819,13 @@ export class Conversation {
|
|
|
1746
1819
|
return this.queue.snapshot();
|
|
1747
1820
|
}
|
|
1748
1821
|
|
|
1749
|
-
|
|
1750
|
-
|
|
1822
|
+
/**
|
|
1823
|
+
* Drop a queued message by request id. Returns the removed entry so callers
|
|
1824
|
+
* can pair a cancellation event with the same visibility metadata the
|
|
1825
|
+
* enqueue ack used, or `undefined` when nothing matched.
|
|
1826
|
+
*/
|
|
1827
|
+
removeQueuedMessage(requestId: string): QueuedMessage | undefined {
|
|
1828
|
+
return this.queue.removeByRequestId(requestId);
|
|
1751
1829
|
}
|
|
1752
1830
|
|
|
1753
1831
|
canHandoffAtCheckpoint(): boolean {
|
|
@@ -2583,6 +2661,12 @@ export class Conversation {
|
|
|
2583
2661
|
* forwarded into {@link runAgentLoopImpl} and threaded to `recordUsage`.
|
|
2584
2662
|
*/
|
|
2585
2663
|
cronRunId?: string | null;
|
|
2664
|
+
/**
|
|
2665
|
+
* See {@link runAgentLoopImpl}: trust this turn runs under. Queue
|
|
2666
|
+
* drains pass the sender's trust captured at enqueue so the run is not
|
|
2667
|
+
* reset to the conversation's most recent actor.
|
|
2668
|
+
*/
|
|
2669
|
+
turnTrustContext?: TrustContext;
|
|
2586
2670
|
},
|
|
2587
2671
|
): Promise<void> {
|
|
2588
2672
|
const { onEvent, ...rest } = options ?? {};
|
|
@@ -16,10 +16,10 @@ const log = getLogger("disk-pressure-guard-lifecycle");
|
|
|
16
16
|
|
|
17
17
|
let diskPressureStartupSampleTimer: ReturnType<typeof setTimeout> | null = null;
|
|
18
18
|
|
|
19
|
-
function runDeferredDiskPressureStartupSample(): void {
|
|
19
|
+
async function runDeferredDiskPressureStartupSample(): Promise<void> {
|
|
20
20
|
diskPressureStartupSampleTimer = null;
|
|
21
21
|
try {
|
|
22
|
-
const status = evaluateDiskPressureNow();
|
|
22
|
+
const status = await evaluateDiskPressureNow();
|
|
23
23
|
if (status.error) {
|
|
24
24
|
log.warn(
|
|
25
25
|
{ error: status.error },
|