@vellumai/assistant 0.11.2 → 0.11.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `assistant` command installer.
|
|
3
|
+
*
|
|
4
|
+
* The two layouts that matter are the compiled desktop bundle (a binary beside
|
|
5
|
+
* the daemon) and the npm-installed runtime the desktop app actually ships (a
|
|
6
|
+
* bun entry under `node_modules`, which needs a wrapper that pins bun). A repo
|
|
7
|
+
* checkout must install nothing: developers own their PATH.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
chmodSync,
|
|
12
|
+
existsSync,
|
|
13
|
+
lstatSync,
|
|
14
|
+
mkdirSync,
|
|
15
|
+
mkdtempSync,
|
|
16
|
+
readFileSync,
|
|
17
|
+
rmSync,
|
|
18
|
+
symlinkSync,
|
|
19
|
+
writeFileSync,
|
|
20
|
+
} from "node:fs";
|
|
21
|
+
import { tmpdir } from "node:os";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
installCommandAt,
|
|
27
|
+
resolveAssistantCommandTarget,
|
|
28
|
+
} from "../install-assistant-command.js";
|
|
29
|
+
|
|
30
|
+
let root: string;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
root = mkdtempSync(join(tmpdir(), "assistant-command-"));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
rmSync(root, { recursive: true, force: true });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/** Build `<root>/<prefix>/node_modules/@vellumai/assistant/src/daemon`. */
|
|
41
|
+
function seedInstalledLayout(options: { withBin: boolean }): string {
|
|
42
|
+
const nodeModules = join(root, "cli", "latest", "node_modules");
|
|
43
|
+
const moduleDir = join(
|
|
44
|
+
nodeModules,
|
|
45
|
+
"@vellumai",
|
|
46
|
+
"assistant",
|
|
47
|
+
"src",
|
|
48
|
+
"daemon",
|
|
49
|
+
);
|
|
50
|
+
mkdirSync(moduleDir, { recursive: true });
|
|
51
|
+
writeFileSync(join(moduleDir, "..", "index.ts"), "#!/usr/bin/env bun\n");
|
|
52
|
+
|
|
53
|
+
if (options.withBin) {
|
|
54
|
+
mkdirSync(join(nodeModules, ".bin"), { recursive: true });
|
|
55
|
+
writeFileSync(
|
|
56
|
+
join(nodeModules, ".bin", "assistant"),
|
|
57
|
+
"#!/usr/bin/env bun\n",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return moduleDir;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe("resolveAssistantCommandTarget", () => {
|
|
64
|
+
test("npm install resolves the .bin/assistant shim under a pinned bun", () => {
|
|
65
|
+
const moduleDir = seedInstalledLayout({ withBin: true });
|
|
66
|
+
|
|
67
|
+
const target = resolveAssistantCommandTarget({
|
|
68
|
+
execPath: "/Applications/Vellum.app/Contents/Resources/bun",
|
|
69
|
+
moduleDir,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(target).toEqual({
|
|
73
|
+
kind: "bun-entry",
|
|
74
|
+
bun: "/Applications/Vellum.app/Contents/Resources/bun",
|
|
75
|
+
entry: join(root, "cli", "latest", "node_modules", ".bin", "assistant"),
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("npm install without the meta package falls back to the CLI entry", () => {
|
|
80
|
+
const moduleDir = seedInstalledLayout({ withBin: false });
|
|
81
|
+
|
|
82
|
+
const target = resolveAssistantCommandTarget({
|
|
83
|
+
execPath: "/usr/local/bin/bun",
|
|
84
|
+
moduleDir,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(target).toEqual({
|
|
88
|
+
kind: "bun-entry",
|
|
89
|
+
bun: "/usr/local/bin/bun",
|
|
90
|
+
entry: join(
|
|
91
|
+
root,
|
|
92
|
+
"cli",
|
|
93
|
+
"latest",
|
|
94
|
+
"node_modules",
|
|
95
|
+
"@vellumai",
|
|
96
|
+
"assistant",
|
|
97
|
+
"src",
|
|
98
|
+
"index.ts",
|
|
99
|
+
),
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("repo checkout installs nothing", () => {
|
|
104
|
+
const moduleDir = join(root, "repo", "assistant", "src", "daemon");
|
|
105
|
+
mkdirSync(moduleDir, { recursive: true });
|
|
106
|
+
writeFileSync(join(moduleDir, "..", "index.ts"), "#!/usr/bin/env bun\n");
|
|
107
|
+
|
|
108
|
+
expect(
|
|
109
|
+
resolveAssistantCommandTarget({
|
|
110
|
+
execPath: "/usr/local/bin/bun",
|
|
111
|
+
moduleDir,
|
|
112
|
+
}),
|
|
113
|
+
).toBeNull();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("compiled bundle resolves the sibling binary", () => {
|
|
117
|
+
const macosDir = join(root, "Vellum.app", "Contents", "MacOS");
|
|
118
|
+
mkdirSync(macosDir, { recursive: true });
|
|
119
|
+
writeFileSync(join(macosDir, "vellum-assistant"), "");
|
|
120
|
+
|
|
121
|
+
const target = resolveAssistantCommandTarget({
|
|
122
|
+
execPath: join(macosDir, "vellum-daemon"),
|
|
123
|
+
moduleDir: join(root, "irrelevant"),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(target).toEqual({
|
|
127
|
+
kind: "binary",
|
|
128
|
+
binary: join(macosDir, "vellum-assistant"),
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("a compiled runtime outside a bundle installs nothing", () => {
|
|
133
|
+
const moduleDir = seedInstalledLayout({ withBin: true });
|
|
134
|
+
|
|
135
|
+
expect(
|
|
136
|
+
resolveAssistantCommandTarget({
|
|
137
|
+
execPath: "/opt/vellum/vellum-daemon",
|
|
138
|
+
moduleDir,
|
|
139
|
+
}),
|
|
140
|
+
).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("installCommandAt", () => {
|
|
145
|
+
const target = {
|
|
146
|
+
kind: "bun-entry" as const,
|
|
147
|
+
bun: "/Applications/Vellum Staging.app/Contents/Resources/bun",
|
|
148
|
+
entry:
|
|
149
|
+
"/Users/x/Library/Application Support/@vellumai/macos/.bin/assistant",
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
test("writes an executable wrapper that quotes paths with spaces", () => {
|
|
153
|
+
const commandPath = join(root, "bin", "assistant");
|
|
154
|
+
|
|
155
|
+
expect(installCommandAt(commandPath, target)).toBe(true);
|
|
156
|
+
|
|
157
|
+
const content = readFileSync(commandPath, "utf-8");
|
|
158
|
+
expect(content.startsWith("#!/bin/sh\n")).toBe(true);
|
|
159
|
+
expect(content).toContain(
|
|
160
|
+
`exec '/Applications/Vellum Staging.app/Contents/Resources/bun' ` +
|
|
161
|
+
`'/Users/x/Library/Application Support/@vellumai/macos/.bin/assistant' "$@"`,
|
|
162
|
+
);
|
|
163
|
+
expect(lstatSync(commandPath).mode & 0o111).toBeGreaterThan(0);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("running the wrapper forwards arguments to the pinned interpreter", () => {
|
|
167
|
+
const interpreter = join(root, "fake bun");
|
|
168
|
+
writeFileSync(interpreter, '#!/bin/sh\necho "$@"\n');
|
|
169
|
+
chmodSync(interpreter, 0o755);
|
|
170
|
+
|
|
171
|
+
const commandPath = join(root, "assistant");
|
|
172
|
+
installCommandAt(commandPath, {
|
|
173
|
+
kind: "bun-entry",
|
|
174
|
+
bun: interpreter,
|
|
175
|
+
entry: join(root, "entry with space.ts"),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const proc = Bun.spawnSync({ cmd: [commandPath, "browser", "status"] });
|
|
179
|
+
expect(proc.exitCode).toBe(0);
|
|
180
|
+
expect(proc.stdout.toString().trim()).toBe(
|
|
181
|
+
`${join(root, "entry with space.ts")} browser status`,
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("is idempotent and rewrites a stale wrapper", () => {
|
|
186
|
+
const commandPath = join(root, "assistant");
|
|
187
|
+
|
|
188
|
+
expect(installCommandAt(commandPath, target)).toBe(true);
|
|
189
|
+
const first = readFileSync(commandPath, "utf-8");
|
|
190
|
+
expect(installCommandAt(commandPath, target)).toBe(true);
|
|
191
|
+
expect(readFileSync(commandPath, "utf-8")).toBe(first);
|
|
192
|
+
|
|
193
|
+
const moved = { ...target, bun: "/opt/homebrew/bin/bun" };
|
|
194
|
+
expect(installCommandAt(commandPath, moved)).toBe(true);
|
|
195
|
+
expect(readFileSync(commandPath, "utf-8")).toContain(
|
|
196
|
+
"/opt/homebrew/bin/bun",
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("replaces a stale symlink", () => {
|
|
201
|
+
const commandPath = join(root, "assistant");
|
|
202
|
+
symlinkSync("/nonexistent/old-target", commandPath);
|
|
203
|
+
|
|
204
|
+
expect(installCommandAt(commandPath, target)).toBe(true);
|
|
205
|
+
expect(lstatSync(commandPath).isFile()).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("never clobbers a file it does not own", () => {
|
|
209
|
+
const commandPath = join(root, "assistant");
|
|
210
|
+
writeFileSync(commandPath, "#!/bin/sh\n# a developer's own build\n");
|
|
211
|
+
|
|
212
|
+
expect(installCommandAt(commandPath, target)).toBe(false);
|
|
213
|
+
expect(readFileSync(commandPath, "utf-8")).toContain("developer's own");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("reports failure instead of throwing on an unusable path", () => {
|
|
217
|
+
const commandPath = join(root, "assistant");
|
|
218
|
+
mkdirSync(commandPath);
|
|
219
|
+
|
|
220
|
+
expect(installCommandAt(commandPath, target)).toBe(false);
|
|
221
|
+
expect(existsSync(commandPath)).toBe(true);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("symlinks a compiled binary target", () => {
|
|
225
|
+
const binary = join(root, "vellum-assistant");
|
|
226
|
+
writeFileSync(binary, "");
|
|
227
|
+
const commandPath = join(root, "bin", "assistant");
|
|
228
|
+
|
|
229
|
+
expect(installCommandAt(commandPath, { kind: "binary", binary })).toBe(
|
|
230
|
+
true,
|
|
231
|
+
);
|
|
232
|
+
expect(lstatSync(commandPath).isSymbolicLink()).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -7,7 +7,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
7
7
|
|
|
8
8
|
import { makeMockLogger } from "../../__tests__/helpers/mock-logger.js";
|
|
9
9
|
import { setConfig } from "../../__tests__/helpers/set-config.js";
|
|
10
|
-
import type { InflightContentWriter } from "../inflight-message-content.js";
|
|
11
10
|
|
|
12
11
|
// The finalize module's import graph reaches the memory indexer; keep it inert
|
|
13
12
|
// so no embedding backend is touched.
|
|
@@ -78,17 +77,16 @@ async function runTail(overrides: {
|
|
|
78
77
|
replyDeliveredInAppOnly?: boolean;
|
|
79
78
|
}): Promise<void> {
|
|
80
79
|
await runDeferredTurnTail({
|
|
81
|
-
|
|
80
|
+
conversationId: CONVERSATION_ID,
|
|
82
81
|
state: {
|
|
83
82
|
deferredFinalizeEffects: overrides.deferredFinalizeEffects ?? [],
|
|
84
83
|
lastAssistantMessageId:
|
|
85
84
|
"lastAssistantMessageId" in overrides
|
|
86
85
|
? overrides.lastAssistantMessageId
|
|
87
86
|
: ASSISTANT_MESSAGE_ID,
|
|
88
|
-
inflightWriters: new Map<string, InflightContentWriter>(),
|
|
89
87
|
},
|
|
90
88
|
rlog,
|
|
91
|
-
|
|
89
|
+
criticalSectionMs: 0,
|
|
92
90
|
turnCompleted: overrides.turnCompleted,
|
|
93
91
|
userMessageId:
|
|
94
92
|
"userMessageId" in overrides ? overrides.userMessageId : USER_MESSAGE_ID,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
3
|
-
* conversation
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* `settleTurnContent` runs after the terminal SSE, so the user can delete the
|
|
3
|
+
* conversation before its content-settling steps run. These tests pin that the
|
|
4
|
+
* two filesystem steps (tool-result spooling and the JSONL disk mirror) read the
|
|
5
|
+
* conversation fresh and skip once it is gone, rather than rebuilding a deleted
|
|
6
|
+
* conversation's directory from in-memory history.
|
|
7
7
|
*/
|
|
8
8
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
9
9
|
|
|
@@ -19,10 +19,9 @@ setConfig("memory", { enabled: false, v2: { enabled: false } });
|
|
|
19
19
|
|
|
20
20
|
const CONVERSATION_ID = "conv-tail-delete-1";
|
|
21
21
|
const ASSISTANT_MESSAGE_ID = "msg-assistant-1";
|
|
22
|
-
const USER_MESSAGE_ID = "msg-user-1";
|
|
23
22
|
const CONVERSATION_DIR = "/tmp/vellum-test/conv-tail-delete-1";
|
|
24
23
|
|
|
25
|
-
/** Flipped by a
|
|
24
|
+
/** Flipped by a test to model a deletion that landed before the settle ran. */
|
|
26
25
|
let conversationDeleted = false;
|
|
27
26
|
let getConversationCalls = 0;
|
|
28
27
|
const resolvedDirCalls: string[] = [];
|
|
@@ -56,6 +55,7 @@ function makeConversation(): ConversationRow {
|
|
|
56
55
|
originInterface: null,
|
|
57
56
|
forkParentConversationId: null,
|
|
58
57
|
forkParentMessageId: null,
|
|
58
|
+
forkStrategy: null,
|
|
59
59
|
isAutoTitle: 0,
|
|
60
60
|
scheduleJobId: null,
|
|
61
61
|
lastMessageAt: null,
|
|
@@ -115,29 +115,22 @@ mock.module("../../persistence/conversation-disk-view.js", () => ({
|
|
|
115
115
|
},
|
|
116
116
|
}));
|
|
117
117
|
|
|
118
|
-
const {
|
|
119
|
-
await import("../conversation-turn-finalize.js");
|
|
118
|
+
const { settleTurnContent } = await import("../conversation-turn-finalize.js");
|
|
120
119
|
|
|
121
120
|
const rlog = makeMockLogger() as Parameters<
|
|
122
|
-
typeof
|
|
121
|
+
typeof settleTurnContent
|
|
123
122
|
>[0]["rlog"];
|
|
124
123
|
|
|
125
|
-
/**
|
|
126
|
-
async function
|
|
127
|
-
deferredEffect: () => Promise<void>,
|
|
128
|
-
): Promise<Message[]> {
|
|
124
|
+
/** Settles one turn's content and hands back the history it left behind. */
|
|
125
|
+
async function runSettle(): Promise<Message[]> {
|
|
129
126
|
const ctx = { conversationId: CONVERSATION_ID, messages: [] as Message[] };
|
|
130
|
-
await
|
|
127
|
+
await settleTurnContent({
|
|
131
128
|
ctx,
|
|
132
129
|
state: {
|
|
133
|
-
deferredFinalizeEffects: [deferredEffect],
|
|
134
130
|
lastAssistantMessageId: ASSISTANT_MESSAGE_ID,
|
|
135
131
|
inflightWriters: new Map<string, InflightContentWriter>(),
|
|
136
132
|
},
|
|
137
133
|
rlog,
|
|
138
|
-
generationCompletedAt: Date.now(),
|
|
139
|
-
turnCompleted: true,
|
|
140
|
-
userMessageId: USER_MESSAGE_ID,
|
|
141
134
|
});
|
|
142
135
|
return ctx.messages;
|
|
143
136
|
}
|
|
@@ -150,11 +143,11 @@ beforeEach(() => {
|
|
|
150
143
|
diskSyncCalls.length = 0;
|
|
151
144
|
});
|
|
152
145
|
|
|
153
|
-
describe("
|
|
146
|
+
describe("settleTurnContent conversation deleted after the terminal SSE", () => {
|
|
154
147
|
test("skips the filesystem steps when the conversation is gone", async () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
conversationDeleted = true;
|
|
149
|
+
|
|
150
|
+
const messages = await runSettle();
|
|
158
151
|
|
|
159
152
|
expect(resolvedDirCalls).toEqual([]);
|
|
160
153
|
expect(truncateCalls).toEqual([]);
|
|
@@ -162,16 +155,14 @@ describe("runDeferredTurnTail conversation deleted mid-tail", () => {
|
|
|
162
155
|
expect(messages).toEqual([]);
|
|
163
156
|
});
|
|
164
157
|
|
|
165
|
-
test("reads the conversation
|
|
166
|
-
await
|
|
167
|
-
conversationDeleted = true;
|
|
168
|
-
});
|
|
158
|
+
test("reads the conversation itself rather than trusting an earlier read", async () => {
|
|
159
|
+
await runSettle();
|
|
169
160
|
|
|
170
|
-
expect(getConversationCalls).toBe(
|
|
161
|
+
expect(getConversationCalls).toBe(1);
|
|
171
162
|
});
|
|
172
163
|
|
|
173
164
|
test("runs the filesystem steps when the conversation survives", async () => {
|
|
174
|
-
const messages = await
|
|
165
|
+
const messages = await runSettle();
|
|
175
166
|
|
|
176
167
|
expect(resolvedDirCalls).toEqual([CONVERSATION_ID]);
|
|
177
168
|
expect(truncateCalls).toEqual([CONVERSATION_DIR]);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimal capability view {@link conversationSupportsDynamicUi} reads. The live
|
|
3
|
-
* `Conversation` (whose fields are the richer `ChannelCapabilities`)
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* `Conversation` (whose fields are the richer `ChannelCapabilities`) and
|
|
4
|
+
* partial test doubles both satisfy it structurally, so the helper stays a
|
|
5
|
+
* dependency-free leaf callable from any layer without importing
|
|
6
|
+
* `Conversation`.
|
|
7
7
|
*/
|
|
8
8
|
export interface DynamicUiCapabilityView {
|
|
9
9
|
readonly currentTurnChannelCapabilities?: {
|
|
@@ -11,6 +11,7 @@ import type pino from "pino";
|
|
|
11
11
|
import { v4 as uuid } from "uuid";
|
|
12
12
|
|
|
13
13
|
import type { AgentEvent } from "../agent/loop.js";
|
|
14
|
+
import type { AnsweredQuestion } from "../api/events/question-answered.js";
|
|
14
15
|
import type { AssistantEvent } from "../api/index.js";
|
|
15
16
|
import type {
|
|
16
17
|
TurnChannelContext,
|
|
@@ -334,6 +335,12 @@ export interface EventHandlerState {
|
|
|
334
335
|
* tools (in handleToolResult) and native server tools (server_tool_complete).
|
|
335
336
|
*/
|
|
336
337
|
readonly toolActivityMetadata: Map<string, ToolActivityMetadata>;
|
|
338
|
+
/**
|
|
339
|
+
* Answered `ask_question` records keyed by tool_use_id, captured when the
|
|
340
|
+
* result lands so the questions and the user's answers are persisted on the
|
|
341
|
+
* tool's content block and the answered card survives a history reopen.
|
|
342
|
+
*/
|
|
343
|
+
readonly toolAnsweredQuestions: Map<string, AnsweredQuestion>;
|
|
337
344
|
/** tool_use_ids emitted in the current turn (populated in handleToolUse, cleared after annotation). */
|
|
338
345
|
currentTurnToolUseIds: string[];
|
|
339
346
|
/** Wall-clock time (ms since epoch) when the agent loop turn started, used as the display timestamp for assistant messages. */
|
|
@@ -602,6 +609,7 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
602
609
|
toolConfirmationOutcomes: new Map(),
|
|
603
610
|
toolRiskOutcomes: new Map(),
|
|
604
611
|
toolActivityMetadata: new Map(),
|
|
612
|
+
toolAnsweredQuestions: new Map(),
|
|
605
613
|
currentTurnToolUseIds: [],
|
|
606
614
|
turnStartedAt: Date.now(),
|
|
607
615
|
serverToolStartedAt: new Map(),
|
|
@@ -837,6 +845,12 @@ export function buildPersistedAssistantContent(
|
|
|
837
845
|
display: surface.display,
|
|
838
846
|
...(surface.persistent ? { persistent: true } : {}),
|
|
839
847
|
...(surface.toolCallId ? { toolCallId: surface.toolCallId } : {}),
|
|
848
|
+
// A surface answered before this write lands owns no persisted block for
|
|
849
|
+
// `markSurfaceCompleted` to patch, so its completion rides the snapshot.
|
|
850
|
+
...(surface.completed ? { completed: true } : {}),
|
|
851
|
+
...(surface.completionSummary
|
|
852
|
+
? { completionSummary: surface.completionSummary }
|
|
853
|
+
: {}),
|
|
840
854
|
} as unknown as ContentBlock);
|
|
841
855
|
}
|
|
842
856
|
return withSurfaces.map((block) => {
|
|
@@ -2005,7 +2019,7 @@ export async function finalizePendingToolResultRow(
|
|
|
2005
2019
|
);
|
|
2006
2020
|
const contentJson = JSON.stringify(
|
|
2007
2021
|
conv != null
|
|
2008
|
-
? referenceMediaBlocksForPersist(
|
|
2022
|
+
? await referenceMediaBlocksForPersist(
|
|
2009
2023
|
conversationId,
|
|
2010
2024
|
conv.createdAt,
|
|
2011
2025
|
rowId,
|
|
@@ -2277,6 +2291,20 @@ export async function handleToolResult(
|
|
|
2277
2291
|
state.toolActivityMetadata.set(event.toolUseId, event.activityMetadata);
|
|
2278
2292
|
}
|
|
2279
2293
|
|
|
2294
|
+
// Capture the answered `ask_question` record and stamp it on the durable
|
|
2295
|
+
// tool_use block right away. The end-of-turn annotation re-stamps it, but
|
|
2296
|
+
// that only runs once every tool in the turn has finished: a user who
|
|
2297
|
+
// switches conversations while a sibling tool is still running would
|
|
2298
|
+
// otherwise reload into history that has lost their answer.
|
|
2299
|
+
if (event.answeredQuestion) {
|
|
2300
|
+
state.toolAnsweredQuestions.set(event.toolUseId, event.answeredQuestion);
|
|
2301
|
+
recordAnsweredQuestionOnPersistedMessage(
|
|
2302
|
+
state,
|
|
2303
|
+
event.toolUseId,
|
|
2304
|
+
event.answeredQuestion,
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2280
2308
|
const toolName = state.toolUseIdToName.get(event.toolUseId);
|
|
2281
2309
|
if (toolName === "file_write" || toolName === "bash") {
|
|
2282
2310
|
deps.ctx.markWorkspaceTopLevelDirty();
|
|
@@ -2360,6 +2388,7 @@ export async function handleToolResult(
|
|
|
2360
2388
|
approvalReason: event.approvalReason,
|
|
2361
2389
|
riskThreshold: event.riskThreshold,
|
|
2362
2390
|
activityMetadata: event.activityMetadata,
|
|
2391
|
+
answeredQuestion: event.answeredQuestion,
|
|
2363
2392
|
errorCode: event.errorCode,
|
|
2364
2393
|
completedAt,
|
|
2365
2394
|
});
|
|
@@ -2380,18 +2409,23 @@ export async function handleToolResult(
|
|
|
2380
2409
|
}
|
|
2381
2410
|
|
|
2382
2411
|
/**
|
|
2383
|
-
* Stamp
|
|
2384
|
-
* assistant message
|
|
2385
|
-
* (message_complete precedes tool events), so without
|
|
2386
|
-
* snapshot fetched mid-
|
|
2387
|
-
* render a
|
|
2388
|
-
*
|
|
2389
|
-
* `
|
|
2412
|
+
* Stamp vellum-internal metadata onto an in-flight tool_use block in the
|
|
2413
|
+
* persisted assistant message, ahead of the turn's end-of-turn annotation. The
|
|
2414
|
+
* block is already durable (message_complete precedes tool events), so without
|
|
2415
|
+
* an early stamp a `/messages` snapshot fetched mid-turn carries none of it and
|
|
2416
|
+
* clients render a degraded row until every tool in the turn has finished.
|
|
2417
|
+
*
|
|
2418
|
+
* `apply` mutates the block record and returns false when the value is already
|
|
2419
|
+
* stamped, which skips the write. The write itself is best-effort:
|
|
2420
|
+
* `annotatePersistedAssistantMessage` re-stamps from the same state maps once
|
|
2421
|
+
* the turn's tools complete, so a transient `SQLITE_BUSY` here must not abort
|
|
2422
|
+
* the turn. `what` names the field for the failure log.
|
|
2390
2423
|
*/
|
|
2391
|
-
function
|
|
2424
|
+
function stampToolUseBlockEarly(
|
|
2392
2425
|
state: EventHandlerState,
|
|
2393
2426
|
toolUseId: string,
|
|
2394
|
-
|
|
2427
|
+
what: string,
|
|
2428
|
+
apply: (block: Record<string, unknown>) => boolean,
|
|
2395
2429
|
): void {
|
|
2396
2430
|
const messageId = state.lastAssistantMessageId;
|
|
2397
2431
|
if (!messageId) {
|
|
@@ -2413,19 +2447,15 @@ function recordToolStartOnPersistedMessage(
|
|
|
2413
2447
|
if (rec.id !== toolUseId) {
|
|
2414
2448
|
continue;
|
|
2415
2449
|
}
|
|
2416
|
-
if (rec
|
|
2450
|
+
if (!apply(rec)) {
|
|
2417
2451
|
return;
|
|
2418
2452
|
}
|
|
2419
|
-
rec._startedAt = startedAt;
|
|
2420
|
-
// Best-effort early stamp: `annotatePersistedAssistantMessage` re-stamps
|
|
2421
|
-
// once every tool in the turn completes, so a transient `SQLITE_BUSY` here
|
|
2422
|
-
// must not abort the turn — the end-of-turn write recovers it.
|
|
2423
2453
|
try {
|
|
2424
2454
|
updateMessageContent(messageId, JSON.stringify(content));
|
|
2425
2455
|
} catch (err) {
|
|
2426
2456
|
log.error(
|
|
2427
2457
|
{ err, messageId },
|
|
2428
|
-
|
|
2458
|
+
`stamping ${what} failed; end-of-turn annotation will recover`,
|
|
2429
2459
|
);
|
|
2430
2460
|
}
|
|
2431
2461
|
return;
|
|
@@ -2433,57 +2463,73 @@ function recordToolStartOnPersistedMessage(
|
|
|
2433
2463
|
}
|
|
2434
2464
|
|
|
2435
2465
|
/**
|
|
2436
|
-
* Stamp `
|
|
2437
|
-
*
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2466
|
+
* Stamp `_startedAt` the moment the tool begins, so a mid-tool `/messages`
|
|
2467
|
+
* snapshot can render a running elapsed-time counter.
|
|
2468
|
+
*/
|
|
2469
|
+
function recordToolStartOnPersistedMessage(
|
|
2470
|
+
state: EventHandlerState,
|
|
2471
|
+
toolUseId: string,
|
|
2472
|
+
startedAt: number,
|
|
2473
|
+
): void {
|
|
2474
|
+
stampToolUseBlockEarly(state, toolUseId, "tool start time", (rec) => {
|
|
2475
|
+
if (rec._startedAt === startedAt) {
|
|
2476
|
+
return false;
|
|
2477
|
+
}
|
|
2478
|
+
rec._startedAt = startedAt;
|
|
2479
|
+
return true;
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
/**
|
|
2484
|
+
* Stamp `_previewStartedAt` (the first-byte timestamp). Called from
|
|
2485
|
+
* `handleToolUse` rather than `handleToolUsePreviewStart`: the block only
|
|
2486
|
+
* exists once message_complete has written it, which happens after the preview
|
|
2487
|
+
* event but before the tool event. Without it a mid-tool `/messages` snapshot
|
|
2488
|
+
* loses the perceived-start anchor and clients fall back to execution start,
|
|
2489
|
+
* hiding the input-streaming gap the user actually waited through.
|
|
2444
2490
|
*/
|
|
2445
2491
|
function recordToolPreviewStartOnPersistedMessage(
|
|
2446
2492
|
state: EventHandlerState,
|
|
2447
2493
|
toolUseId: string,
|
|
2448
2494
|
previewStartedAt: number,
|
|
2449
2495
|
): void {
|
|
2450
|
-
|
|
2451
|
-
if (!messageId) {
|
|
2452
|
-
return;
|
|
2453
|
-
}
|
|
2454
|
-
|
|
2455
|
-
const row = getMessageById(messageId);
|
|
2456
|
-
if (!row) {
|
|
2457
|
-
return;
|
|
2458
|
-
}
|
|
2459
|
-
|
|
2460
|
-
const content: ContentBlock[] = row.content;
|
|
2461
|
-
|
|
2462
|
-
for (const block of content) {
|
|
2463
|
-
if (block.type !== "tool_use") {
|
|
2464
|
-
continue;
|
|
2465
|
-
}
|
|
2466
|
-
const rec = block as unknown as Record<string, unknown>;
|
|
2467
|
-
if (rec.id !== toolUseId) {
|
|
2468
|
-
continue;
|
|
2469
|
-
}
|
|
2496
|
+
stampToolUseBlockEarly(state, toolUseId, "tool preview-start time", (rec) => {
|
|
2470
2497
|
if (rec._previewStartedAt === previewStartedAt) {
|
|
2471
|
-
return;
|
|
2498
|
+
return false;
|
|
2472
2499
|
}
|
|
2473
2500
|
rec._previewStartedAt = previewStartedAt;
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2501
|
+
return true;
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
/**
|
|
2506
|
+
* Stamp `_answeredQuestion` the moment an `ask_question` prompt settles, so a
|
|
2507
|
+
* user who leaves the conversation while a sibling tool is still running comes
|
|
2508
|
+
* back to their answer rather than to a question that lost its response.
|
|
2509
|
+
*/
|
|
2510
|
+
function recordAnsweredQuestionOnPersistedMessage(
|
|
2511
|
+
state: EventHandlerState,
|
|
2512
|
+
toolUseId: string,
|
|
2513
|
+
answeredQuestion: AnsweredQuestion,
|
|
2514
|
+
): void {
|
|
2515
|
+
stampToolUseBlockEarly(state, toolUseId, "answered question", (rec) => {
|
|
2516
|
+
// Narrow the persisted marker rather than casting it: the row is data read
|
|
2517
|
+
// back from the database, so its shape is an assumption until checked. Any
|
|
2518
|
+
// value that is not a record with a string `requestId` is treated as absent
|
|
2519
|
+
// and overwritten, which is the safe direction for a dedup check.
|
|
2520
|
+
const existing: unknown = rec._answeredQuestion;
|
|
2521
|
+
const existingRequestId =
|
|
2522
|
+
typeof existing === "object" &&
|
|
2523
|
+
existing !== null &&
|
|
2524
|
+
typeof (existing as { requestId?: unknown }).requestId === "string"
|
|
2525
|
+
? (existing as { requestId: string }).requestId
|
|
2526
|
+
: undefined;
|
|
2527
|
+
if (existingRequestId === answeredQuestion.requestId) {
|
|
2528
|
+
return false;
|
|
2484
2529
|
}
|
|
2485
|
-
|
|
2486
|
-
|
|
2530
|
+
rec._answeredQuestion = answeredQuestion;
|
|
2531
|
+
return true;
|
|
2532
|
+
});
|
|
2487
2533
|
}
|
|
2488
2534
|
|
|
2489
2535
|
/**
|
|
@@ -2583,6 +2629,11 @@ function annotatePersistedAssistantMessage(
|
|
|
2583
2629
|
rec._activityMetadata = activity;
|
|
2584
2630
|
modified = true;
|
|
2585
2631
|
}
|
|
2632
|
+
const answeredQuestion = state.toolAnsweredQuestions.get(id);
|
|
2633
|
+
if (answeredQuestion) {
|
|
2634
|
+
rec._answeredQuestion = answeredQuestion;
|
|
2635
|
+
modified = true;
|
|
2636
|
+
}
|
|
2586
2637
|
}
|
|
2587
2638
|
}
|
|
2588
2639
|
|
|
@@ -2608,6 +2659,12 @@ function annotatePersistedAssistantMessage(
|
|
|
2608
2659
|
...(surface.activationMoment
|
|
2609
2660
|
? { activationMoment: surface.activationMoment }
|
|
2610
2661
|
: {}),
|
|
2662
|
+
// A surface answered before this write lands owns no persisted block for
|
|
2663
|
+
// `markSurfaceCompleted` to patch, so its completion rides the snapshot.
|
|
2664
|
+
...(surface.completed ? { completed: true } : {}),
|
|
2665
|
+
...(surface.completionSummary
|
|
2666
|
+
? { completionSummary: surface.completionSummary }
|
|
2667
|
+
: {}),
|
|
2611
2668
|
} as unknown as ContentBlock);
|
|
2612
2669
|
}
|
|
2613
2670
|
modified = true;
|
|
@@ -2874,10 +2931,9 @@ export async function handleMessageComplete(
|
|
|
2874
2931
|
// The row was reserved at `llm_call_started` (with channel metadata
|
|
2875
2932
|
// stamped at that point) and `state.lastAssistantMessageId` carries its
|
|
2876
2933
|
// id. Flush the final content via `updateContent` instead of inserting a
|
|
2877
|
-
// new row. No `syncToDisk` flag here
|
|
2878
|
-
//
|
|
2879
|
-
//
|
|
2880
|
-
// `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
|
|
2934
|
+
// new row. No `syncToDisk` flag here: the orchestrator separately invokes
|
|
2935
|
+
// `syncMessageToDisk` on `state.lastAssistantMessageId` after the loop
|
|
2936
|
+
// completes (see `conversation-turn-finalize.ts::settleTurnContent`).
|
|
2881
2937
|
const assistantMessageId = state.lastAssistantMessageId;
|
|
2882
2938
|
if (!assistantMessageId) {
|
|
2883
2939
|
throw new Error(
|