@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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - `ingress.publicBaseUrl` → set to `""`
|
|
7
7
|
* - `ingress.enabled` → deleted
|
|
8
8
|
* - `ingress.publicBaseUrlManagedBy` → deleted
|
|
9
|
+
* - `telegram.registeredWebhookUrl` → deleted
|
|
9
10
|
* - `daemon` → deleted entirely
|
|
10
11
|
* - `skills.load.extraDirs` → set to `[]`
|
|
11
12
|
* - `hostBrowser.cdpInspect.desktopAuto` → deleted **only when the source
|
|
@@ -45,6 +46,16 @@ export function sanitizeConfigForTransfer(configJson: string): string {
|
|
|
45
46
|
delete ingress.publicBaseUrlManagedBy;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// Strip the recorded Telegram webhook URL. It records where *this*
|
|
50
|
+
// deployment pointed Telegram, so carrying it across a teleport would have
|
|
51
|
+
// the destination compare its own registration against the source's address
|
|
52
|
+
// and report a mismatch on a channel that is fine. Absent, the health sweep
|
|
53
|
+
// reports unverified until the destination reconciles and records its own.
|
|
54
|
+
if (config.telegram && typeof config.telegram === "object") {
|
|
55
|
+
const telegram = config.telegram as Record<string, unknown>;
|
|
56
|
+
delete telegram.registeredWebhookUrl;
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
// Strip daemon entirely
|
|
49
60
|
delete config.daemon;
|
|
50
61
|
|
package/src/config/schema.ts
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
PlatformConfigSchema,
|
|
51
51
|
UiConfigSchema,
|
|
52
52
|
} from "./schemas/platform.js";
|
|
53
|
+
import { PluginUpdatesConfigSchema } from "./schemas/plugin-updates.js";
|
|
53
54
|
import { SecretDetectionConfigSchema } from "./schemas/security.js";
|
|
54
55
|
import { ServicesSchema } from "./schemas/services.js";
|
|
55
56
|
import { SkillsConfigSchema } from "./schemas/skills.js";
|
|
@@ -142,6 +143,9 @@ export const AssistantConfigSchema = z.object({
|
|
|
142
143
|
.describe(
|
|
143
144
|
"Per-plugin configuration keyed by plugin name. Validated downstream by each plugin's manifest.config validator at bootstrap.",
|
|
144
145
|
),
|
|
146
|
+
pluginUpdates: PluginUpdatesConfigSchema.default(
|
|
147
|
+
PluginUpdatesConfigSchema.parse({}),
|
|
148
|
+
),
|
|
145
149
|
legacyTelemetryOptOut: z
|
|
146
150
|
.boolean()
|
|
147
151
|
.optional()
|
|
@@ -66,11 +66,22 @@ describe("SttServiceSchema", () => {
|
|
|
66
66
|
);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
test("language
|
|
70
|
-
//
|
|
71
|
-
//
|
|
69
|
+
test("language defaults to multilingual rather than staying absent", () => {
|
|
70
|
+
// Every config carries a real language, so nothing downstream has to
|
|
71
|
+
// infer one from an absent key. Omitting the param entirely is not a
|
|
72
|
+
// neutral state on Deepgram and the managed relay: it decodes as
|
|
73
|
+
// English, which is what this default exists to stop.
|
|
72
74
|
const parsed = SttServiceSchema.parse({ provider: "vellum" });
|
|
73
|
-
expect(parsed.language).
|
|
75
|
+
expect(parsed.language).toBe("multi");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("a chosen language is never replaced by the default", () => {
|
|
79
|
+
expect(
|
|
80
|
+
SttServiceSchema.parse({ provider: "deepgram", language: "ta" }).language,
|
|
81
|
+
).toBe("ta");
|
|
82
|
+
expect(
|
|
83
|
+
SttServiceSchema.parse({ provider: "deepgram", language: "en" }).language,
|
|
84
|
+
).toBe("en");
|
|
74
85
|
});
|
|
75
86
|
|
|
76
87
|
test("language round-trips a code and the multi code-switching mode", () => {
|
|
@@ -107,6 +118,10 @@ describe("managed provider", () => {
|
|
|
107
118
|
mode: "managed",
|
|
108
119
|
provider: "vellum",
|
|
109
120
|
});
|
|
110
|
-
expect(parsed).toEqual({
|
|
121
|
+
expect(parsed).toEqual({
|
|
122
|
+
provider: "vellum",
|
|
123
|
+
language: "multi",
|
|
124
|
+
providers: {},
|
|
125
|
+
});
|
|
111
126
|
});
|
|
112
127
|
});
|
|
@@ -68,6 +68,19 @@ export const TelegramConfigSchema = z
|
|
|
68
68
|
.string({ error: "telegram.apiBaseUrl must be a string" })
|
|
69
69
|
.default("https://api.telegram.org")
|
|
70
70
|
.describe("Base URL for the Telegram Bot API"),
|
|
71
|
+
// Written by the gateway reconciler, read by the health sweep. Deployment
|
|
72
|
+
// state rather than user configuration: it records where this deployment
|
|
73
|
+
// last pointed Telegram, so the sweep can tell our own registration from a
|
|
74
|
+
// stale tunnel address or another deployment's callback. Unset until a
|
|
75
|
+
// reconciliation succeeds, which the sweep reports as unverified rather
|
|
76
|
+
// than healthy. Stripped by sanitize-for-transfer, like
|
|
77
|
+
// ingress.publicBaseUrlManagedBy, because it does not travel between hosts.
|
|
78
|
+
registeredWebhookUrl: z
|
|
79
|
+
.string({ error: "telegram.registeredWebhookUrl must be a string" })
|
|
80
|
+
.optional()
|
|
81
|
+
.describe(
|
|
82
|
+
"Webhook URL this deployment last registered with Telegram (managed by the gateway)",
|
|
83
|
+
),
|
|
71
84
|
deliverAuthBypass: z
|
|
72
85
|
.boolean({ error: "telegram.deliverAuthBypass must be a boolean" })
|
|
73
86
|
.default(false)
|
|
@@ -2,6 +2,28 @@ import { z } from "zod";
|
|
|
2
2
|
|
|
3
3
|
export const MemoryRetrospectiveConfigSchema = z
|
|
4
4
|
.object({
|
|
5
|
+
// This kill switch exists only because conversation forking is expensive:
|
|
6
|
+
// a fork full-copies the source conversation (messages + attachments), so
|
|
7
|
+
// on a large conversation the retrospective's write burst can lock the
|
|
8
|
+
// SQLite table against other writers. Until forking is referential, an
|
|
9
|
+
// operator needs a way to stop retrospectives without turning off memory.
|
|
10
|
+
enabled: z
|
|
11
|
+
.boolean({ error: "memory.retrospective.enabled must be a boolean" })
|
|
12
|
+
.default(true)
|
|
13
|
+
.describe(
|
|
14
|
+
"Whether the memory-retrospective background pass runs. When false, no retrospective is enqueued by any trigger (interval, message count, pre-compaction, scheduled sweep), the scheduled sweep job stops being queued, and any row already queued completes as a no-op. The rest of the memory system (extraction, retrieval, embeddings, `<memory>` injection) is unaffected. Use `memory.enabled` to disable memory as a whole.",
|
|
15
|
+
),
|
|
16
|
+
|
|
17
|
+
forkStrategy: z
|
|
18
|
+
.enum(["cloning", "reference"], {
|
|
19
|
+
error:
|
|
20
|
+
"memory.retrospective.forkStrategy must be 'cloning' or 'reference'",
|
|
21
|
+
})
|
|
22
|
+
.default("cloning")
|
|
23
|
+
.describe(
|
|
24
|
+
"How a retrospective's fork of the source conversation is materialized. `cloning` (default) full-copies the source conversation's messages and attachments into the fork. `reference` makes the fork referential: it holds only its own messages and reads the source's through `fork_parent_message_id`, so a fork costs a single row instead of a full copy of the conversation.",
|
|
25
|
+
),
|
|
26
|
+
|
|
5
27
|
timeThresholdMs: z
|
|
6
28
|
.number({
|
|
7
29
|
error: "memory.retrospective.timeThresholdMs must be a number",
|
|
@@ -108,3 +130,6 @@ export const MemoryRetrospectiveConfigSchema = z
|
|
|
108
130
|
export type MemoryRetrospectiveConfig = z.infer<
|
|
109
131
|
typeof MemoryRetrospectiveConfigSchema
|
|
110
132
|
>;
|
|
133
|
+
|
|
134
|
+
/** How a retrospective materializes its fork of the source conversation. */
|
|
135
|
+
export type MemoryForkStrategy = MemoryRetrospectiveConfig["forkStrategy"];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unattended plugin upgrade configuration.
|
|
5
|
+
*
|
|
6
|
+
* The resource monitor process runs a periodic sweep (see
|
|
7
|
+
* `monitoring/plugin-auto-update.ts`) that moves every installed, enabled
|
|
8
|
+
* plugin to its source's current revision. The sweep is off by default:
|
|
9
|
+
* `mode: "manual"` means nothing upgrades unless a human runs
|
|
10
|
+
* `assistant plugins upgrade <name>` (or the equivalent route), which is the
|
|
11
|
+
* behavior every workspace had before this block existed. Setting
|
|
12
|
+
* `mode: "auto"` opts the workspace into the hourly sweep.
|
|
13
|
+
*/
|
|
14
|
+
export const PluginUpdatesConfigSchema = z
|
|
15
|
+
.object({
|
|
16
|
+
mode: z
|
|
17
|
+
.enum(["manual", "auto"], {
|
|
18
|
+
error: 'pluginUpdates.mode must be "manual" or "auto"',
|
|
19
|
+
})
|
|
20
|
+
.default("manual")
|
|
21
|
+
.describe(
|
|
22
|
+
'How installed plugins move to newer revisions. "manual" (default) never upgrades on its own — upgrades happen only when a human asks for one. "auto" lets the resource monitor upgrade every installed, enabled plugin on the `checkIntervalMs` cadence.',
|
|
23
|
+
),
|
|
24
|
+
strategy: z
|
|
25
|
+
// Deliberately narrower than the full `PluginUpgradeStrategy` union: the
|
|
26
|
+
// `assistant` strategy resolves conflicts by writing git conflict
|
|
27
|
+
// markers into the plugin's files and expecting someone to resolve
|
|
28
|
+
// them. Unattended, that would leave a syntactically broken plugin on
|
|
29
|
+
// disk with nobody in the loop, so it is not selectable here. It stays
|
|
30
|
+
// available for interactive `assistant plugins upgrade --strategy
|
|
31
|
+
// assistant`.
|
|
32
|
+
.enum(["theirs", "ours", "overwrite"], {
|
|
33
|
+
error:
|
|
34
|
+
'pluginUpdates.strategy must be "theirs", "ours", or "overwrite"',
|
|
35
|
+
})
|
|
36
|
+
.default("theirs")
|
|
37
|
+
.describe(
|
|
38
|
+
'How an automatic upgrade reconciles local edits to a plugin with the incoming revision. "theirs" (default) three-way merges and resolves conflicting hunks toward the incoming revision, keeping non-conflicting local edits; "ours" merges the same way but resolves conflicts toward the local edit; "overwrite" discards local edits and re-installs the revision wholesale. Only consulted when `mode` is "auto".',
|
|
39
|
+
),
|
|
40
|
+
checkIntervalMs: z
|
|
41
|
+
.number({ error: "pluginUpdates.checkIntervalMs must be a number" })
|
|
42
|
+
.int("pluginUpdates.checkIntervalMs must be an integer")
|
|
43
|
+
.min(300_000, "pluginUpdates.checkIntervalMs must be at least 300000ms")
|
|
44
|
+
.max(
|
|
45
|
+
604_800_000,
|
|
46
|
+
"pluginUpdates.checkIntervalMs must be <= 604800000ms (7 days)",
|
|
47
|
+
)
|
|
48
|
+
.default(3_600_000)
|
|
49
|
+
.describe(
|
|
50
|
+
'Minimum interval between automatic upgrade sweeps, in milliseconds (default 1 hour). The last sweep is stamped on disk, so restarting the daemon does not re-run a sweep that already ran within the interval. Only consulted when `mode` is "auto".',
|
|
51
|
+
),
|
|
52
|
+
})
|
|
53
|
+
.describe("Unattended plugin upgrade configuration");
|
|
54
|
+
|
|
55
|
+
export type PluginUpdatesConfig = z.infer<typeof PluginUpdatesConfigSchema>;
|
|
@@ -139,10 +139,14 @@ export const ServicesSchema = z.object({
|
|
|
139
139
|
WebSearchServiceSchema.parse({}),
|
|
140
140
|
),
|
|
141
141
|
"web-fetch": WebFetchServiceSchema.default(WebFetchServiceSchema.parse({})),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
// Parsed rather than handed a literal, like every sibling here: a literal
|
|
143
|
+
// default short-circuits the inner parse, so field-level defaults inside
|
|
144
|
+
// the block (the multilingual `language`) would never materialize for a
|
|
145
|
+
// config that omits `services.stt` entirely, which is every fresh
|
|
146
|
+
// workspace.
|
|
147
|
+
stt: SttServiceSchema.default(
|
|
148
|
+
SttServiceSchema.parse({ provider: "deepgram", providers: {} }),
|
|
149
|
+
),
|
|
146
150
|
tts: TtsServiceSchema.default(TtsServiceSchema.parse({})),
|
|
147
151
|
"google-oauth": GoogleOAuthServiceSchema.default(
|
|
148
152
|
GoogleOAuthServiceSchema.parse({}),
|
|
@@ -67,22 +67,34 @@ export const SttServiceSchema = z
|
|
|
67
67
|
.describe("Active STT provider used for speech-to-text transcription"),
|
|
68
68
|
/**
|
|
69
69
|
* Spoken-language selection, forwarded to providers whose adapters accept
|
|
70
|
-
* a language (Deepgram, xAI, and the managed relay).
|
|
71
|
-
* provider applies its own default, which for Deepgram (and therefore
|
|
72
|
-
* for the managed relay) is English, NOT auto-detection.
|
|
70
|
+
* a language (Deepgram, xAI, and the managed relay).
|
|
73
71
|
*
|
|
74
72
|
* `"multi"` selects Deepgram's nova-3 code-switching mode, which follows
|
|
75
73
|
* a speaker moving between languages inside a single utterance (e.g.
|
|
76
74
|
* Hinglish). Providers that auto-detect natively and take no language
|
|
77
75
|
* option (Gemini, Whisper) ignore this field.
|
|
76
|
+
*
|
|
77
|
+
* Defaults to `"multi"` rather than staying unset, so there is no state
|
|
78
|
+
* where the answer to "what language is this assistant listening for"
|
|
79
|
+
* has to be inferred. Every config carries the answer, and the settings
|
|
80
|
+
* surfaces render a real selection rather than a sentinel standing in
|
|
81
|
+
* for one.
|
|
82
|
+
*
|
|
83
|
+
* The default applies on load, not just at creation, so an existing
|
|
84
|
+
* config that never set a language materializes `"multi"` on its next
|
|
85
|
+
* start. That changes no behavior: `effectiveSttLanguage` already
|
|
86
|
+
* resolved unset to `"multi"` on Deepgram and the managed relay, and the
|
|
87
|
+
* providers that detect natively ignore the field either way. It only
|
|
88
|
+
* makes the value explicit. An assistant that has chosen a language
|
|
89
|
+
* keeps it, since a default fills nothing that is already set.
|
|
78
90
|
*/
|
|
79
91
|
language: z
|
|
80
92
|
.string({ error: "services.stt.language must be a string" })
|
|
81
93
|
.trim()
|
|
82
94
|
.min(1, { error: "services.stt.language must not be empty" })
|
|
83
|
-
.
|
|
95
|
+
.default("multi")
|
|
84
96
|
.describe(
|
|
85
|
-
"BCP-47 language code (e.g. 'en-US', 'hi') or 'multi' for code-switching across languages.
|
|
97
|
+
"BCP-47 language code (e.g. 'en-US', 'hi') or 'multi' for code-switching across languages. Defaults to 'multi'; providers that detect natively ignore it",
|
|
86
98
|
),
|
|
87
99
|
providers: SttProvidersSchema.default({}),
|
|
88
100
|
})
|
|
@@ -26,7 +26,7 @@ export const TimeoutConfigSchema = z
|
|
|
26
26
|
.positive("timeouts.permissionTimeoutSec must be a positive number")
|
|
27
27
|
.default(300)
|
|
28
28
|
.describe(
|
|
29
|
-
"How long to wait for
|
|
29
|
+
"How long to wait for a human to approve a tool call before timing out (seconds). Spent by both approval paths: the interactive permission prompt, and the inline wait when a contact's sensitive tool call is escalated to the guardian.",
|
|
30
30
|
),
|
|
31
31
|
questionResponseTimeoutSec: z
|
|
32
32
|
.number({ error: "timeouts.questionResponseTimeoutSec must be a number" })
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
getGuardianDeliveryFresh,
|
|
45
45
|
guardianForChannel,
|
|
46
46
|
invalidateGuardianDeliveryCache,
|
|
47
|
+
warmGuardianBindings,
|
|
47
48
|
} from "../guardian-delivery-reader.js";
|
|
48
49
|
|
|
49
50
|
const METHOD = "resolve_guardian_delivery";
|
|
@@ -299,3 +300,18 @@ describe("selectors", () => {
|
|
|
299
300
|
expect(anyGuardian([])).toBeUndefined();
|
|
300
301
|
});
|
|
301
302
|
});
|
|
303
|
+
|
|
304
|
+
describe("warmGuardianBindings", () => {
|
|
305
|
+
test("warms both the vellum-channel key and the unfiltered fallback key", async () => {
|
|
306
|
+
const keys: string[] = [];
|
|
307
|
+
await warmGuardianBindings(async (input) => {
|
|
308
|
+
keys.push(input?.channelTypes?.join(",") ?? "ALL");
|
|
309
|
+
return null;
|
|
310
|
+
});
|
|
311
|
+
// Both keys the sync persona resolvers read — peekGuardianForChannel
|
|
312
|
+
// ("vellum") and the peekAnyGuardian() fallback — must be warmed;
|
|
313
|
+
// warming only the channel key leaves the any-channel fallback cold for
|
|
314
|
+
// guardians bound on non-vellum channels.
|
|
315
|
+
expect(keys.sort()).toEqual(["ALL", "vellum"]);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
@@ -151,8 +151,8 @@ export async function getGuardianDelivery(input?: {
|
|
|
151
151
|
* Returns the fresh cached list for the given channel filter, or `undefined`
|
|
152
152
|
* when the cache is cold or expired. Used by sync hot paths (SSE subscribe)
|
|
153
153
|
* that cannot await {@link getGuardianDelivery} but must resolve the SAME
|
|
154
|
-
* gateway-owned principal the async paths land on.
|
|
155
|
-
*
|
|
154
|
+
* gateway-owned principal the async paths land on. There is no fallback
|
|
155
|
+
* fetch: on a cold/expired cache the caller proceeds without a principal.
|
|
156
156
|
*/
|
|
157
157
|
export function peekCachedGuardianDelivery(input?: {
|
|
158
158
|
channelTypes?: string[];
|
|
@@ -181,6 +181,33 @@ export async function getGuardianDeliveryFresh(input?: {
|
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
type GuardianDeliveryFetch = (input?: {
|
|
185
|
+
channelTypes?: string[];
|
|
186
|
+
}) => Promise<unknown>;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Warm both guardian-binding cache keys the sync persona resolvers read: the
|
|
190
|
+
* `"vellum"`-channel key for `peekGuardianForChannel("vellum")` and the
|
|
191
|
+
* unfiltered key for the `peekAnyGuardian()` fallback. Warming only one key
|
|
192
|
+
* still resolves `users/default.md` when the guardian lives on a non-vellum
|
|
193
|
+
* channel (phone / Telegram).
|
|
194
|
+
*
|
|
195
|
+
* Uses the FRESH reader so warmup bypasses a stale/empty cached entry: a
|
|
196
|
+
* gateway-side binding write (onboarding, rebind) does not invalidate the
|
|
197
|
+
* daemon cache, so a non-fresh read could return an empty binding cached
|
|
198
|
+
* before the guardian existed and freeze `users/default.md` until the TTL
|
|
199
|
+
* expires. The fresh reads repopulate the cache the sync `peek*` resolvers
|
|
200
|
+
* then read. Best-effort: the reader swallows failures.
|
|
201
|
+
*/
|
|
202
|
+
export async function warmGuardianBindings(
|
|
203
|
+
fetchDelivery: GuardianDeliveryFetch = getGuardianDeliveryFresh,
|
|
204
|
+
): Promise<void> {
|
|
205
|
+
await Promise.all([
|
|
206
|
+
fetchDelivery({ channelTypes: ["vellum"] }),
|
|
207
|
+
fetchDelivery(),
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
|
|
184
211
|
/**
|
|
185
212
|
* Clear ALL cached guardian deliveries so contact mutations refetch on the next
|
|
186
213
|
* read. Called by {@link notifyContactsChanged} after a contact write, and
|
package/src/context/compactor.ts
CHANGED
|
@@ -865,10 +865,10 @@ function resolveTailFloorIndex(messages: Message[], tailIndex: number): number {
|
|
|
865
865
|
// Retained-image hydration
|
|
866
866
|
// ---------------------------------------------------------------------------
|
|
867
867
|
|
|
868
|
-
function buildRetainedImageBlocks(
|
|
868
|
+
async function buildRetainedImageBlocks(
|
|
869
869
|
filenames: string[],
|
|
870
870
|
manifest: ManifestEntry[],
|
|
871
|
-
): { blocks: ImageContent[]; resolved: string[]; missing: string[] } {
|
|
871
|
+
): Promise<{ blocks: ImageContent[]; resolved: string[]; missing: string[] }> {
|
|
872
872
|
const blocks: ImageContent[] = [];
|
|
873
873
|
const resolved: string[] = [];
|
|
874
874
|
const missing: string[] = [];
|
|
@@ -887,7 +887,7 @@ function buildRetainedImageBlocks(
|
|
|
887
887
|
// Run the same downscale pass the agent uses when first sending an
|
|
888
888
|
// image. Without this, attachments that exceed the provider's per-image
|
|
889
889
|
// byte limit (Anthropic: 5 MB) crash the next turn after compaction.
|
|
890
|
-
const optimized = optimizeImageForTransport(
|
|
890
|
+
const optimized = await optimizeImageForTransport(
|
|
891
891
|
content.toString("base64"),
|
|
892
892
|
sourceMime,
|
|
893
893
|
);
|
|
@@ -1393,7 +1393,7 @@ export async function runAssistantDrivenCompaction(
|
|
|
1393
1393
|
blocks: retainedImageBlocks,
|
|
1394
1394
|
resolved,
|
|
1395
1395
|
missing,
|
|
1396
|
-
} = buildRetainedImageBlocks(parsed.retainedImageFilenames, manifest);
|
|
1396
|
+
} = await buildRetainedImageBlocks(parsed.retainedImageFilenames, manifest);
|
|
1397
1397
|
if (missing.length > 0) {
|
|
1398
1398
|
log.warn(
|
|
1399
1399
|
{ missing },
|
|
@@ -37,20 +37,43 @@ export const TRUNCATION_MARKER = "\u2014 full result:";
|
|
|
37
37
|
export const TRUNCATION_EXEMPT_TOOLS = new Set<string>(["skill_load"]);
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* File-read tools that page spooled `.tool-results/` content back into
|
|
41
|
-
* `file_read` reads inside the workspace; `host_file_read` reads
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* paged back at all — and (b) recognized by {@link derefToolResultReReads}, so a
|
|
45
|
-
* re-read of a spooled file collapses to a stub instead of duplicating content
|
|
46
|
-
* already in context. Sharing one set keeps the two passes from drifting if a
|
|
47
|
-
* new file-read tool is added.
|
|
40
|
+
* File-read tools that can page spooled `.tool-results/` content back into
|
|
41
|
+
* context. `file_read` reads inside the workspace; `host_file_read` reads
|
|
42
|
+
* anywhere on the host. A new file-read tool belongs here so
|
|
43
|
+
* {@link isSpooledToolResultRead} recognizes it.
|
|
48
44
|
*/
|
|
49
45
|
export const FILE_READ_TOOL_NAMES = new Set<string>([
|
|
50
46
|
"file_read",
|
|
51
47
|
"host_file_read",
|
|
52
48
|
]);
|
|
53
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Whether a tool call is a file read aimed at a spooled `.tool-results/` file.
|
|
52
|
+
*
|
|
53
|
+
* Such a read is the model paging content back in, so both passes treat it
|
|
54
|
+
* specially: the result-time spool pass leaves it alone (re-stubbing it would
|
|
55
|
+
* write a fresh copy and hand back another stub, putting the content out of
|
|
56
|
+
* reach for good), and {@link derefToolResultReReads} collapses it at turn end
|
|
57
|
+
* (its prefix and suffix are already in context above). A file read aimed
|
|
58
|
+
* anywhere else is ordinary tool output and gets no such treatment.
|
|
59
|
+
*/
|
|
60
|
+
export function isSpooledToolResultRead(
|
|
61
|
+
toolName: string | undefined,
|
|
62
|
+
input: Record<string, unknown> | undefined,
|
|
63
|
+
): boolean {
|
|
64
|
+
if (toolName === undefined || !FILE_READ_TOOL_NAMES.has(toolName)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const filePath = input?.path ?? input?.file_path;
|
|
68
|
+
if (typeof filePath !== "string") {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// The path in the stub comes from `join`, so it is backslash-separated on
|
|
72
|
+
// Windows. Compare on a normalized form: a missed match would let the spool
|
|
73
|
+
// pass stub this read and put the saved content permanently out of reach.
|
|
74
|
+
return filePath.replace(/\\/g, "/").includes(`/${TOOL_RESULT_DIR}/`);
|
|
75
|
+
}
|
|
76
|
+
|
|
54
77
|
/**
|
|
55
78
|
* Build a map of tool_use_id -> originating tool name by walking the tool_use
|
|
56
79
|
* blocks in assistant messages. A tool_result only carries `tool_use_id`, so
|
|
@@ -329,14 +352,7 @@ export function derefToolResultReReads(messages: Message[]): {
|
|
|
329
352
|
continue;
|
|
330
353
|
}
|
|
331
354
|
const tu = block as ToolUseContent;
|
|
332
|
-
if (
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
const filePath = tu.input.path ?? tu.input.file_path;
|
|
336
|
-
if (typeof filePath !== "string") {
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
if (filePath.includes(`/${TOOL_RESULT_DIR}/`)) {
|
|
355
|
+
if (isSpooledToolResultRead(tu.name, tu.input)) {
|
|
340
356
|
reReadToolUseIds.add(tu.id);
|
|
341
357
|
}
|
|
342
358
|
}
|
|
@@ -136,6 +136,48 @@ export function stripSpotlightInjections(messages: Message[]): Message[] {
|
|
|
136
136
|
return stripUserTextBlocksByPrefix(messages, [MEMORY_SPOTLIGHT_MATCHER]);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Whether the TURN-STARTING user message carries a memory-v3
|
|
141
|
+
* `<memory_spotlight>` block.
|
|
142
|
+
*
|
|
143
|
+
* The spotlight is the only injected block that is strip-and-replaced from
|
|
144
|
+
* every user message each turn, so its presence is exactly what makes that
|
|
145
|
+
* message volatile across turns. Every other injected block (turn context,
|
|
146
|
+
* workspace, `<info>`, `<memory>` cards, NOW.md) is frozen into history and
|
|
147
|
+
* re-renders byte-identically, so a message without a spotlight is a stable
|
|
148
|
+
* cache anchor. Providers consume this through the `mutableLatestUserMessage`
|
|
149
|
+
* config field when placing cache breakpoints.
|
|
150
|
+
*
|
|
151
|
+
* The turn start is the most recent user message carrying TEXT content, which
|
|
152
|
+
* is the same message the Anthropic client anchors on. Tool-result messages
|
|
153
|
+
* are skipped: they are user-role but carry no injected blocks, and letting
|
|
154
|
+
* them answer this question would flip the signal to `false` partway through a
|
|
155
|
+
* tool loop. The provider would then mark the very same turn-start block at a
|
|
156
|
+
* different TTL than it did on the turn's first request, billing a second
|
|
157
|
+
* write for one reusable prefix. Anchoring on the turn start keeps the signal
|
|
158
|
+
* constant for every request in the turn.
|
|
159
|
+
*
|
|
160
|
+
* Detection uses {@link MEMORY_SPOTLIGHT_MATCHER}, the same full-wrapper
|
|
161
|
+
* matcher {@link stripSpotlightInjections} strips with, so the two can never
|
|
162
|
+
* disagree about which blocks are ephemeral.
|
|
163
|
+
*/
|
|
164
|
+
export function turnStartUserMessageHasSpotlight(messages: Message[]): boolean {
|
|
165
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
166
|
+
const message = messages[i];
|
|
167
|
+
if (message.role !== "user") {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const textBlocks = message.content.filter((block) => block.type === "text");
|
|
171
|
+
if (textBlocks.length === 0) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
return textBlocks.some((block) =>
|
|
175
|
+
textBlockMatchesInjection(block.text, [MEMORY_SPOTLIGHT_MATCHER]),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
139
181
|
/** `<NOW.md>` scratchpad prefixes (current tag, pre-line-limit variant, legacy `<now_scratchpad>`) — shared with `stripNowScratchpad` so the two strip paths can't drift. */
|
|
140
182
|
export const NOW_SCRATCHPAD_STRIP_PREFIXES: InjectionMatcher[] = [
|
|
141
183
|
"<NOW.md Always keep this up to date",
|
|
@@ -4,8 +4,8 @@ import { join } from "node:path";
|
|
|
4
4
|
import type { ContentBlock, ToolResultContent } from "../providers/types.js";
|
|
5
5
|
import {
|
|
6
6
|
buildTruncatedContent,
|
|
7
|
-
FILE_READ_TOOL_NAMES,
|
|
8
7
|
getToolResultFilePath,
|
|
8
|
+
isSpooledToolResultRead,
|
|
9
9
|
isTruncationEligible,
|
|
10
10
|
TOOL_RESULT_DIR,
|
|
11
11
|
} from "./post-turn-tool-result-truncation.js";
|
|
@@ -32,27 +32,32 @@ export const RESULT_TIME_SPOOL_EXEMPT_TOOLS = new Set<string>(["web_fetch"]);
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Whether a tool result is eligible for the result-time spool/stub pass: the
|
|
35
|
-
* post-turn pass's shared rules plus the AX-tree exemption, minus
|
|
36
|
-
*
|
|
37
|
-
* ({@link RESULT_TIME_SPOOL_EXEMPT_TOOLS}).
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
35
|
+
* post-turn pass's shared rules plus the AX-tree exemption, minus reads of
|
|
36
|
+
* already-spooled `.tool-results/` files ({@link isSpooledToolResultRead}) and
|
|
37
|
+
* the explicit self-sized reads ({@link RESULT_TIME_SPOOL_EXEMPT_TOOLS}).
|
|
38
|
+
*
|
|
39
|
+
* The spooled-read exemption is what keeps paging possible: a file read is the
|
|
40
|
+
* model's only way to pull spooled content back into context, so stubbing a
|
|
41
|
+
* read of a `.tool-results/` file would write a fresh copy and hand back
|
|
42
|
+
* another stub, putting that content out of reach for good. It is scoped by
|
|
43
|
+
* target path rather than by tool name, because a file read aimed anywhere
|
|
44
|
+
* else is ordinary oversized output with no such circularity, and exempting it
|
|
45
|
+
* keeps a whole file inline on every LLM call for the rest of the turn.
|
|
46
|
+
* Explicit self-sized reads are honored in full; the post-turn pass still
|
|
47
|
+
* truncates them at turn end, after the model has consumed the content.
|
|
43
48
|
*/
|
|
44
49
|
function isSpoolEligible(
|
|
45
50
|
tr: ToolResultContent,
|
|
46
51
|
toolName: string | undefined,
|
|
52
|
+
toolInput: Record<string, unknown> | undefined,
|
|
47
53
|
): boolean {
|
|
48
54
|
if (!isTruncationEligible(tr, toolName)) {
|
|
49
55
|
return false;
|
|
50
56
|
}
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
) {
|
|
57
|
+
if (isSpooledToolResultRead(toolName, toolInput)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (toolName !== undefined && RESULT_TIME_SPOOL_EXEMPT_TOOLS.has(toolName)) {
|
|
56
61
|
return false;
|
|
57
62
|
}
|
|
58
63
|
if (tr.content.includes(AX_TREE_TAG)) {
|
|
@@ -72,8 +77,8 @@ function isSpoolEligible(
|
|
|
72
77
|
* rewriting an earlier message between calls would invalidate the cache from
|
|
73
78
|
* that point on every iteration. The model still gets the head/tail preview
|
|
74
79
|
* plus the on-disk path, so it can page the full content back in with
|
|
75
|
-
* `file_read` or `host_file_read` (
|
|
76
|
-
* when it actually needs it.
|
|
80
|
+
* `file_read` or `host_file_read` (a read of a `.tool-results/` path is exempt
|
|
81
|
+
* from this pass) when it actually needs it.
|
|
77
82
|
*
|
|
78
83
|
* Uses the same file paths, stub bytes, and eligibility rules as
|
|
79
84
|
* `postTurnTruncateToolResults`, whose `TRUNCATION_MARKER` guard then skips
|
|
@@ -89,7 +94,15 @@ export function spoolAndStubOversizedToolResults(
|
|
|
89
94
|
blocks: ContentBlock[],
|
|
90
95
|
options: {
|
|
91
96
|
conversationDir: string;
|
|
92
|
-
|
|
97
|
+
/**
|
|
98
|
+
* The originating call for a `tool_use_id`. A `tool_result` carries only
|
|
99
|
+
* the id, and eligibility turns on both the tool's name and the path it
|
|
100
|
+
* was pointed at, so the two travel together rather than as separate
|
|
101
|
+
* lookups that could disagree.
|
|
102
|
+
*/
|
|
103
|
+
toolCallById: (
|
|
104
|
+
toolUseId: string,
|
|
105
|
+
) => { name: string; input: Record<string, unknown> } | undefined;
|
|
93
106
|
},
|
|
94
107
|
): number {
|
|
95
108
|
let stubbedCount = 0;
|
|
@@ -98,7 +111,8 @@ export function spoolAndStubOversizedToolResults(
|
|
|
98
111
|
if (block.type !== "tool_result") {
|
|
99
112
|
continue;
|
|
100
113
|
}
|
|
101
|
-
|
|
114
|
+
const toolCall = options.toolCallById(block.tool_use_id);
|
|
115
|
+
if (!isSpoolEligible(block, toolCall?.name, toolCall?.input)) {
|
|
102
116
|
continue;
|
|
103
117
|
}
|
|
104
118
|
|
|
@@ -176,6 +176,9 @@ export async function startCes(config: AssistantConfig): Promise<void> {
|
|
|
176
176
|
},
|
|
177
177
|
});
|
|
178
178
|
if (client) {
|
|
179
|
+
log.info(
|
|
180
|
+
"CES client injected into credential resolver at startup; credential reads route through CES RPC",
|
|
181
|
+
);
|
|
179
182
|
setCesClient(client);
|
|
180
183
|
} else {
|
|
181
184
|
// The handshake lost the startup race, so provider init proceeds on the
|
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
* delegated to the shared package.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
type CesRpcClient,
|
|
14
|
+
type CesRpcClientConfig,
|
|
15
|
+
type CesTransport,
|
|
16
|
+
createCesRpcClient,
|
|
17
|
+
} from "@vellumai/ces-client/rpc-client";
|
|
18
|
+
|
|
19
|
+
import { getLogger } from "../util/logger.js";
|
|
20
|
+
|
|
12
21
|
export {
|
|
13
22
|
type CesRpcClient as CesClient,
|
|
14
23
|
type CesRpcClientConfig as CesClientConfig,
|
|
@@ -17,5 +26,17 @@ export {
|
|
|
17
26
|
CesHandshakeError,
|
|
18
27
|
type CesTransport,
|
|
19
28
|
CesTransportError,
|
|
20
|
-
createCesRpcClient as createCesClient,
|
|
21
29
|
} from "@vellumai/ces-client/rpc-client";
|
|
30
|
+
|
|
31
|
+
const log = getLogger("ces-rpc-client");
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Construct a CES RPC client wired to the assistant logger so handshake-ready
|
|
35
|
+
* and close transitions are visible in the daemon logs.
|
|
36
|
+
*/
|
|
37
|
+
export function createCesClient(
|
|
38
|
+
transport: CesTransport,
|
|
39
|
+
config?: CesRpcClientConfig,
|
|
40
|
+
): CesRpcClient {
|
|
41
|
+
return createCesRpcClient(transport, { logger: log, ...config });
|
|
42
|
+
}
|