@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
|
@@ -35,6 +35,26 @@ export function isDeniedBasename(path: string): boolean {
|
|
|
35
35
|
return DENIED_BASENAMES.has(basename(path));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* `/proc/<pid>/environ` for any pid, including the `self` and `thread-self`
|
|
40
|
+
* aliases. Reading one yields the target process's full environment.
|
|
41
|
+
*/
|
|
42
|
+
const PROC_ENVIRON_PATTERN = /^\/proc\/(?:\d+|self|thread-self)\/environ$/;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Whether a path exposes a process environment block.
|
|
46
|
+
*
|
|
47
|
+
* The daemon's own environment carries credential material the file tools
|
|
48
|
+
* must never hand back: the actor token signing key, the CES service token,
|
|
49
|
+
* the guardian bootstrap secret, and any provider API keys forwarded in at
|
|
50
|
+
* launch. The bash tool strips those from the child processes it spawns via
|
|
51
|
+
* the `SAFE_ENV_VARS` allowlist, so denying them here keeps the file tools
|
|
52
|
+
* from becoming the looser path to the same secrets.
|
|
53
|
+
*/
|
|
54
|
+
export function isProcessEnvironPath(path: string): boolean {
|
|
55
|
+
return PROC_ENVIRON_PATTERN.test(path);
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
export type PathResult =
|
|
39
59
|
| { ok: true; resolved: string }
|
|
40
60
|
| { ok: false; reason: PathFailureReason; error: string };
|
|
@@ -186,6 +206,16 @@ function deniedFailure(target: SandboxTarget): PathResult | null {
|
|
|
186
206
|
error: `Access to "${basename(target.resolved)}" is denied`,
|
|
187
207
|
};
|
|
188
208
|
}
|
|
209
|
+
if (
|
|
210
|
+
isProcessEnvironPath(target.resolved) ||
|
|
211
|
+
isProcessEnvironPath(target.realResolved)
|
|
212
|
+
) {
|
|
213
|
+
return {
|
|
214
|
+
ok: false,
|
|
215
|
+
reason: "denied",
|
|
216
|
+
error: "Access to process environment blocks is denied",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
189
219
|
return null;
|
|
190
220
|
}
|
|
191
221
|
|
|
@@ -336,8 +366,8 @@ export function sandboxPolicy(
|
|
|
336
366
|
}
|
|
337
367
|
|
|
338
368
|
/**
|
|
339
|
-
*
|
|
340
|
-
* installs.
|
|
369
|
+
* Write-side sandbox policy: permits out-of-workspace targets on
|
|
370
|
+
* non-containerized installs.
|
|
341
371
|
*
|
|
342
372
|
* Identical to {@link sandboxPolicy} for in-bounds targets. A target that
|
|
343
373
|
* escapes the boundary is allowed with host-style validation: the basename
|
|
@@ -348,9 +378,9 @@ export function sandboxPolicy(
|
|
|
348
378
|
* FileRiskClassifier), so an escape reaching this policy has already been
|
|
349
379
|
* threshold-approved or user-approved.
|
|
350
380
|
*
|
|
351
|
-
* In containerized mode the boundary stays hard: the container
|
|
352
|
-
*
|
|
353
|
-
* guardian's device.
|
|
381
|
+
* In containerized mode the boundary stays hard for writes: the container
|
|
382
|
+
* filesystem is the install tree the assistant runs from, and the
|
|
383
|
+
* host_file_* proxy tools are the escape hatch for the guardian's device.
|
|
354
384
|
*/
|
|
355
385
|
export function sandboxPolicyWithHostFallback(
|
|
356
386
|
rawPath: string,
|
|
@@ -365,6 +395,41 @@ export function sandboxPolicyWithHostFallback(
|
|
|
365
395
|
);
|
|
366
396
|
}
|
|
367
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Read-side sandbox policy: the working directory bounds where the assistant
|
|
400
|
+
* *writes*, not what it may look at.
|
|
401
|
+
*
|
|
402
|
+
* Everything the process can open, it may read. A containerized install owns
|
|
403
|
+
* its whole filesystem (the workspace, the install tree it runs from, `/tmp`),
|
|
404
|
+
* and `bash cat` already reads all of it at Low risk, so denying the file
|
|
405
|
+
* tools the same reach only pushes reads through a shell. A bare-metal install
|
|
406
|
+
* reaches the host filesystem, which the permission lane classifies as
|
|
407
|
+
* elevated risk before execution (see the gateway FileRiskClassifier). Either
|
|
408
|
+
* way the boundary is not what protects secrets.
|
|
409
|
+
*
|
|
410
|
+
* The denials are what protect secrets, and they apply to every read: the
|
|
411
|
+
* service security directories (gateway trust material, CES credential keys,
|
|
412
|
+
* the daemon dotenv), the basename denylist, and process environment blocks
|
|
413
|
+
* (see {@link isProcessEnvironPath}), each checked on both the logical and
|
|
414
|
+
* the symlink-resolved path. When that deny set cannot be mirrored faithfully
|
|
415
|
+
* (see {@link securityDirConfigMirrorable}), reads fail closed to the hard
|
|
416
|
+
* boundary rather than escape it unprotected.
|
|
417
|
+
*
|
|
418
|
+
* Write-side policies do not take this allowance.
|
|
419
|
+
*/
|
|
420
|
+
export function sandboxReadPolicy(
|
|
421
|
+
rawPath: string,
|
|
422
|
+
boundaryDir: string,
|
|
423
|
+
options?: { mustExist?: boolean },
|
|
424
|
+
): PathResult {
|
|
425
|
+
return evaluateSandboxPolicy(
|
|
426
|
+
rawPath,
|
|
427
|
+
boundaryDir,
|
|
428
|
+
options,
|
|
429
|
+
securityDirConfigMirrorable(),
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
368
433
|
// ---------------------------------------------------------------------------
|
|
369
434
|
// Host policy
|
|
370
435
|
// ---------------------------------------------------------------------------
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
2
|
|
|
3
3
|
/** Default maximum file size: 100 MB */
|
|
4
4
|
export const MAX_FILE_SIZE_BYTES = 100 * 1024 * 1024;
|
|
@@ -17,13 +17,13 @@ function formatBytes(bytes: number): string {
|
|
|
17
17
|
* Check whether a file on disk exceeds the size limit.
|
|
18
18
|
* Returns an error string if the file is too large, or undefined if OK.
|
|
19
19
|
*/
|
|
20
|
-
export function checkFileSizeOnDisk(
|
|
20
|
+
export async function checkFileSizeOnDisk(
|
|
21
21
|
filePath: string,
|
|
22
22
|
limit: number = MAX_FILE_SIZE_BYTES,
|
|
23
|
-
): string | undefined {
|
|
24
|
-
const
|
|
25
|
-
if (
|
|
26
|
-
return `File size (${formatBytes(
|
|
23
|
+
): Promise<string | undefined> {
|
|
24
|
+
const fileStat = await stat(filePath);
|
|
25
|
+
if (fileStat.size > limit) {
|
|
26
|
+
return `File size (${formatBytes(fileStat.size)}) exceeds the ${formatBytes(
|
|
27
27
|
limit,
|
|
28
28
|
)} limit: ${filePath}`;
|
|
29
29
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Targeted guidance for tool calls whose parameter names reveal that the
|
|
3
|
+
* caller wanted a different tool, or a different spelling of a parameter this
|
|
4
|
+
* tool does accept.
|
|
5
|
+
*
|
|
6
|
+
* `validateInputAgainstSchema` rejects any key a tool's `TOOLS.json`
|
|
7
|
+
* `properties` block does not declare, and its generic `Unknown parameter
|
|
8
|
+
* "path". Supported: ...` error lists the accepted keys without naming the
|
|
9
|
+
* tool the caller actually wants. A tool listed here replaces that error with
|
|
10
|
+
* a redirect the caller can act on in a single retry. Declaring these keys in
|
|
11
|
+
* `properties` instead would advertise parameters the tool does not accept.
|
|
12
|
+
*
|
|
13
|
+
* Rules describe the first-party tools that ship in `bundled-skills/`, and tool
|
|
14
|
+
* names are not reserved: a managed, workspace, extra, or plugin skill may
|
|
15
|
+
* define its own `subagent_read` with an entirely different contract. The
|
|
16
|
+
* `bundled` prefix on the exports below is the reminder that callers must
|
|
17
|
+
* establish bundled provenance before consulting the table.
|
|
18
|
+
*
|
|
19
|
+
* Pure data plus a lookup, with no imports from tool executors, so both the
|
|
20
|
+
* skill-tool factory (`createSkillTool`, which validates before it reaches an
|
|
21
|
+
* executor) and the executors themselves can consult it.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
interface ToolInputMisuseRule {
|
|
25
|
+
/** Input keys that trigger this rule. Rules are matched in array order. */
|
|
26
|
+
keys: readonly string[];
|
|
27
|
+
/** Guidance returned in place of the generic validation error. */
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const MISUSE_RULES: Readonly<Record<string, readonly ToolInputMisuseRule[]>> = {
|
|
32
|
+
subagent_read: [
|
|
33
|
+
{
|
|
34
|
+
keys: ["path", "file", "filename"],
|
|
35
|
+
message:
|
|
36
|
+
"subagent_read returns a subagent's output, it does not read files. Use file_read for files. Pass subagent_id or label here.",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
keys: ["subagentId", "agent_id"],
|
|
40
|
+
message: "Unknown parameter. Use subagent_id (snake_case) or label.",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Return the redirect for a misused parameter shape on a bundled tool, or
|
|
47
|
+
* `undefined` when the tool has no rule for the keys present (the caller then
|
|
48
|
+
* falls back to its own error message).
|
|
49
|
+
*
|
|
50
|
+
* Only call this for a tool that came from a bundled skill. `toolName` alone
|
|
51
|
+
* does not establish that.
|
|
52
|
+
*/
|
|
53
|
+
export function bundledToolInputMisuseMessage(
|
|
54
|
+
toolName: string,
|
|
55
|
+
input: Record<string, unknown>,
|
|
56
|
+
): string | undefined {
|
|
57
|
+
const rules = MISUSE_RULES[toolName];
|
|
58
|
+
if (!rules) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
for (const rule of rules) {
|
|
62
|
+
if (rule.keys.some((key) => key in input)) {
|
|
63
|
+
return rule.message;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Every key that carries a redirect for bundled `toolName`, for drift guards. */
|
|
70
|
+
export function bundledToolInputMisuseKeys(toolName: string): string[] {
|
|
71
|
+
return (MISUSE_RULES[toolName] ?? []).flatMap((rule) => [...rule.keys]);
|
|
72
|
+
}
|
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import type { SkillSource } from "../../config/skills.js";
|
|
5
5
|
import { loadSkillCatalog } from "../../config/skills.js";
|
|
6
6
|
import { refreshSkillCapabilityMemories } from "../../daemon/skill-memory-refresh.js";
|
|
7
|
+
import { emitNotificationSignal } from "../../notifications/emit-signal.js";
|
|
7
8
|
import { getConversation } from "../../persistence/conversation-crud.js";
|
|
8
9
|
import { upsertSkillCardInsertJob } from "../../persistence/jobs-store.js";
|
|
9
10
|
import { MEMORY_RETROSPECTIVE_ORIGIN } from "../../plugins/defaults/memory/memory-retrospective-constants.js";
|
|
@@ -66,6 +67,72 @@ function normalizeOptionalStringArray(
|
|
|
66
67
|
return { value: normalized.length > 0 ? normalized : undefined };
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Tell the user that a background pass changed a skill they already have.
|
|
72
|
+
*
|
|
73
|
+
* A newly authored skill announces itself in the conversation through the
|
|
74
|
+
* `skill_card` surface; an update announces itself here instead. The pass
|
|
75
|
+
* runs in a background fork and rewrites the body of a skill the user may be
|
|
76
|
+
* relying on, and `createManagedSkill` writes through an atomic rename
|
|
77
|
+
* keeping no prior version, so the notification pipeline is what puts the
|
|
78
|
+
* change in the background feed alongside the other unattended work (sweeps,
|
|
79
|
+
* scheduled jobs, heartbeat), where a user already looks to see what the
|
|
80
|
+
* assistant did on its own.
|
|
81
|
+
*
|
|
82
|
+
* `sourceContextId` is a conversation id so the feed item's "Go to Convo"
|
|
83
|
+
* target resolves (see `home-feed-side-effect.ts`, which looks it up via
|
|
84
|
+
* `getConversation`): the source conversation when lineage resolved, else the
|
|
85
|
+
* run's own conversation. Deduped per skill per day, so a pass that refines
|
|
86
|
+
* the same skill repeatedly cannot flood the feed. Best-effort and
|
|
87
|
+
* non-blocking: the skill is already written, and a notification failure must
|
|
88
|
+
* never turn that into a tool error.
|
|
89
|
+
*/
|
|
90
|
+
function notifyBackgroundSkillUpdate(args: {
|
|
91
|
+
skillId: string;
|
|
92
|
+
name: string;
|
|
93
|
+
conversationId: string;
|
|
94
|
+
}): void {
|
|
95
|
+
const day = new Date().toISOString().slice(0, 10);
|
|
96
|
+
void emitNotificationSignal({
|
|
97
|
+
// This emit is a tool executor's, not the scheduler's. The channel is
|
|
98
|
+
// provenance the pipeline reads: `home-feed-side-effect` derives
|
|
99
|
+
// `fromAssistant` from it, so labelling this "scheduler" would drop the
|
|
100
|
+
// item from the feed's assistant-initiated filter despite being exactly
|
|
101
|
+
// that.
|
|
102
|
+
sourceChannel: "assistant_tool",
|
|
103
|
+
sourceContextId: args.conversationId,
|
|
104
|
+
sourceEventName: "activity.complete",
|
|
105
|
+
dedupeKey: `skill-updated:${args.skillId}:${day}`,
|
|
106
|
+
contextPayload: {
|
|
107
|
+
// `summary` feeds the copy composer; `title`/`body` are the home feed's
|
|
108
|
+
// fallback when no channel copy was rendered. Without them a fully
|
|
109
|
+
// suppressed delivery (the intended shape for this signal: low urgency,
|
|
110
|
+
// background, no interruption) leaves the feed writer with no summary
|
|
111
|
+
// and it skips the item entirely, so the quiet case would surface
|
|
112
|
+
// nothing at all.
|
|
113
|
+
summary: `Updated the skill "${args.name}" from something learned in an earlier conversation.`,
|
|
114
|
+
// Named, not just "Skill updated": the feed sits several rows deep and
|
|
115
|
+
// a generic title is unscannable next to entries that name their
|
|
116
|
+
// subject (`Background job failed: memory.v2.sweep`). The word "Skill"
|
|
117
|
+
// stays because a bare skill name does not always read as one.
|
|
118
|
+
title: `Skill updated: ${args.name}`,
|
|
119
|
+
body: `Updated the skill "${args.name}" from something learned in an earlier conversation.`,
|
|
120
|
+
skillId: args.skillId,
|
|
121
|
+
},
|
|
122
|
+
attentionHints: {
|
|
123
|
+
requiresAction: false,
|
|
124
|
+
urgency: "low",
|
|
125
|
+
isAsyncBackground: true,
|
|
126
|
+
visibleInSourceNow: false,
|
|
127
|
+
},
|
|
128
|
+
}).catch((err: unknown) => {
|
|
129
|
+
log.warn(
|
|
130
|
+
{ err, skillId: args.skillId },
|
|
131
|
+
"skill update notification failed; the skill write stands",
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
69
136
|
/**
|
|
70
137
|
* Core execution logic for scaffold_managed_skill.
|
|
71
138
|
* Exported so bundled-skill executors and tests can call it directly.
|
|
@@ -355,6 +422,21 @@ export async function executeScaffoldManagedSkill(
|
|
|
355
422
|
}
|
|
356
423
|
}
|
|
357
424
|
|
|
425
|
+
// A background pass changed a skill that already existed. Creates announce
|
|
426
|
+
// themselves through the skill card below; updates announce themselves in
|
|
427
|
+
// the background activity feed. Covers an explicit `overwrite: true`
|
|
428
|
+
// refinement as well as any other background write onto a pre-existing
|
|
429
|
+
// skill.
|
|
430
|
+
const notifyConversationId =
|
|
431
|
+
sourceConversationId ?? retrospectiveConversationId;
|
|
432
|
+
if (fromRetrospective && managedSkillExistedBefore && notifyConversationId) {
|
|
433
|
+
notifyBackgroundSkillUpdate({
|
|
434
|
+
skillId: id,
|
|
435
|
+
name: normalizedName,
|
|
436
|
+
conversationId: notifyConversationId,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
358
440
|
// Surface a genuine retrospective CREATE to the user as a skill card on the
|
|
359
441
|
// source conversation, via the durable `skill_card_insert` delivery job
|
|
360
442
|
// (memory-retrospective-skill-card.ts). The creation site is the one place
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
coerceStringNumbers,
|
|
6
6
|
validateInputAgainstSchema,
|
|
7
7
|
} from "../../skills/validate-input.js";
|
|
8
|
+
import { bundledToolInputMisuseMessage } from "../shared/input-misuse.js";
|
|
8
9
|
import type { ExecutionTarget } from "../tool-types.js";
|
|
9
10
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
10
11
|
import { runSkillToolScript } from "./skill-script-runner.js";
|
|
@@ -53,8 +54,20 @@ export function createSkillTool(
|
|
|
53
54
|
schema,
|
|
54
55
|
);
|
|
55
56
|
if (!validation.ok) {
|
|
57
|
+
// A parameter shape with its own redirect (e.g. a file path passed to
|
|
58
|
+
// `subagent_read`) answers with that redirect: the generic "Unknown
|
|
59
|
+
// parameter" list names the accepted keys but not the tool the caller
|
|
60
|
+
// is actually reaching for. Redirects describe first-party tools, so
|
|
61
|
+
// only bundled skills consult them. A managed, workspace, extra, or
|
|
62
|
+
// plugin skill that reuses a bundled tool name keeps the generic error,
|
|
63
|
+
// which is the one that matches its own manifest.
|
|
64
|
+
const misuse = bundled
|
|
65
|
+
? bundledToolInputMisuseMessage(entry.name, coercedInput)
|
|
66
|
+
: undefined;
|
|
56
67
|
return {
|
|
57
|
-
content:
|
|
68
|
+
content:
|
|
69
|
+
misuse ??
|
|
70
|
+
`Invalid input for tool "${entry.name}": ${validation.errors.join("; ")}. Fix the arguments and retry.`,
|
|
58
71
|
isError: true,
|
|
59
72
|
};
|
|
60
73
|
}
|
|
@@ -2,19 +2,24 @@
|
|
|
2
2
|
* A progress-aware deadline for the synchronous advisor consult.
|
|
3
3
|
*
|
|
4
4
|
* A reasoning advisor profile spends most of its window *thinking*, streaming
|
|
5
|
-
* reasoning tokens the whole time
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* reasoning tokens the whole time, and a consult that opens a file goes silent
|
|
6
|
+
* for the whole read. A fixed wall-clock ceiling would cut either one off
|
|
7
|
+
* mid-work, so this aborts only after the consult goes `idleMs` with no sign of
|
|
8
|
+
* progress at all, meaning neither a streamed token (thinking or text) nor tool
|
|
9
|
+
* activity, with an absolute `maxMs` backstop so a runaway or looping stream
|
|
10
|
+
* can't block the parent forever.
|
|
11
|
+
*
|
|
12
|
+
* The idle window is the caller's liveness check, not its budget: because tool
|
|
13
|
+
* activity re-arms it, a consult that keeps reading is bounded by `maxMs` and
|
|
14
|
+
* by whatever ceiling the caller puts on tool rounds, not by `idleMs`.
|
|
10
15
|
*
|
|
11
16
|
* Usage: combine `signal` with the caller's own signal, call `recordProgress()`
|
|
12
|
-
* on every
|
|
17
|
+
* on every sign of forward progress, and `dispose()` once the consult settles.
|
|
13
18
|
*/
|
|
14
19
|
export interface ConsultDeadline {
|
|
15
20
|
/** Aborts when the idle window lapses or the absolute max elapses. */
|
|
16
21
|
readonly signal: AbortSignal;
|
|
17
|
-
/** Reset the idle window
|
|
22
|
+
/** Reset the idle window: call on every streamed chunk and tool event. */
|
|
18
23
|
recordProgress(): void;
|
|
19
24
|
/** Clear both timers; call once the consult settles (success or failure). */
|
|
20
25
|
dispose(): void;
|
|
@@ -49,7 +49,9 @@ export async function executeSubagentMessage(
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const result = await manager.sendMessage(subagentId, content
|
|
52
|
+
const result = await manager.sendMessage(subagentId, content, {
|
|
53
|
+
cronRunId: context.cronRunId ?? null,
|
|
54
|
+
});
|
|
53
55
|
|
|
54
56
|
if (result === "empty") {
|
|
55
57
|
return {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { getMessages } from "../../persistence/conversation-crud.js";
|
|
2
2
|
import { extractTextFromStoredMessageContent } from "../../persistence/message-content.js";
|
|
3
|
-
import { TERMINAL_STATUSES } from "../../subagent/index.js";
|
|
3
|
+
import { getSubagentManager, TERMINAL_STATUSES } from "../../subagent/index.js";
|
|
4
|
+
import {
|
|
5
|
+
formatSubagentToolStats,
|
|
6
|
+
SUBAGENT_READ_STILL_PROCESSING,
|
|
7
|
+
SUBAGENT_STATS_UNAVAILABLE,
|
|
8
|
+
} from "../../subagent/types.js";
|
|
9
|
+
import { bundledToolInputMisuseMessage } from "../shared/input-misuse.js";
|
|
4
10
|
import { invalidToolInputResult } from "../shared/zod-tool-schema.js";
|
|
5
11
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
6
12
|
import {
|
|
@@ -9,6 +15,34 @@ import {
|
|
|
9
15
|
subagentRefInputSchema,
|
|
10
16
|
} from "./resolve.js";
|
|
11
17
|
|
|
18
|
+
/**
|
|
19
|
+
* The machine truth envelope appended to a read: what the subagent actually
|
|
20
|
+
* ran, so the parent can check the output above against it.
|
|
21
|
+
*
|
|
22
|
+
* The counters are re-read first, because a child that was sent guidance keeps
|
|
23
|
+
* running after the harvest its own run took. `settled` is false when that
|
|
24
|
+
* guidance is still being processed, which makes both the transcript above and
|
|
25
|
+
* these counts an interim reading, so the footer says so.
|
|
26
|
+
*
|
|
27
|
+
* The manager owns the whole answer, including why there are no counters: they
|
|
28
|
+
* live in memory only, so a subagent rebuilt from its durable row says they are
|
|
29
|
+
* unavailable rather than reporting zero calls, which would read as "this
|
|
30
|
+
* subagent did nothing", while a live run that never reached its harvest has
|
|
31
|
+
* nothing measured to report and claims nothing.
|
|
32
|
+
*/
|
|
33
|
+
function statsFooter(subagentId: string, settled: boolean): string {
|
|
34
|
+
const note = settled ? "" : `\n\n${SUBAGENT_READ_STILL_PROCESSING}`;
|
|
35
|
+
const reading = getSubagentManager().currentToolStats(subagentId);
|
|
36
|
+
switch (reading.kind) {
|
|
37
|
+
case "counted":
|
|
38
|
+
return `${note}\n\n${formatSubagentToolStats(reading.stats)}`;
|
|
39
|
+
case "unrecoverable":
|
|
40
|
+
return `${note}\n\n${SUBAGENT_STATS_UNAVAILABLE}`;
|
|
41
|
+
default:
|
|
42
|
+
return note;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
12
46
|
// `last_n` is deliberately UNDECLARED (loose passthrough): the executor's
|
|
13
47
|
// typeof-guarded read below ignores it when malformed — including non-integer
|
|
14
48
|
// numbers the advertised `integer` type wouldn't admit.
|
|
@@ -18,6 +52,16 @@ export async function executeSubagentRead(
|
|
|
18
52
|
input: Record<string, unknown>,
|
|
19
53
|
context: ToolContext,
|
|
20
54
|
): Promise<ToolExecutionResult> {
|
|
55
|
+
// File-reader keys and misspellings of `subagent_id` name a wrong-tool or
|
|
56
|
+
// wrong-parameter call, so they get the redirect rather than the generic
|
|
57
|
+
// '"subagent_id" or "label" is required'. `createSkillTool` runs the same
|
|
58
|
+
// check for calls the manifest validator rejects before they reach here.
|
|
59
|
+
// This executor backs the bundled subagent skill, so the bundled table is
|
|
60
|
+
// the right one to consult.
|
|
61
|
+
const misuse = bundledToolInputMisuseMessage("subagent_read", input);
|
|
62
|
+
if (misuse) {
|
|
63
|
+
return { content: misuse, isError: true };
|
|
64
|
+
}
|
|
21
65
|
const parsedInput = subagentReadInputSchema.safeParse(input);
|
|
22
66
|
if (!parsedInput.success) {
|
|
23
67
|
return invalidToolInputResult("subagent_read", parsedInput.error);
|
|
@@ -54,12 +98,25 @@ export async function executeSubagentRead(
|
|
|
54
98
|
}
|
|
55
99
|
|
|
56
100
|
if (!TERMINAL_STATUSES.has(state.status)) {
|
|
101
|
+
// A premature read is often the only result a parent ever captures, so the
|
|
102
|
+
// message has to close the loop itself: the completion notification is
|
|
103
|
+
// already coming, and re-reading only burns another turn.
|
|
57
104
|
return {
|
|
58
|
-
content: `Subagent "${state.config.label}" is still ${state.status}.
|
|
105
|
+
content: `Subagent "${state.config.label}" is still ${state.status}. Do not poll: you will be notified automatically when it completes, and that notification tells you whether the result is inlined or waiting behind a read.`,
|
|
59
106
|
isError: false,
|
|
60
107
|
};
|
|
61
108
|
}
|
|
62
109
|
|
|
110
|
+
// A terminal subagent can still have a follow-up turn in flight: guidance
|
|
111
|
+
// queued during its run drains after the run itself returns, which is what
|
|
112
|
+
// the completion notification's "queued follow-up guidance is still being
|
|
113
|
+
// processed, read for the latest output" points at. Reading straight through
|
|
114
|
+
// would answer that pointer with the transcript from before the guidance
|
|
115
|
+
// landed, so wait for the queued turn. The wait is bounded and its result
|
|
116
|
+
// reported either way: a subagent still working at the deadline is read as
|
|
117
|
+
// it stands, labelled as unfinished rather than presented as the result.
|
|
118
|
+
const settled = await getSubagentManager().settleQueuedTurns(subagentId);
|
|
119
|
+
|
|
63
120
|
// Read the subagent's conversation messages from DB.
|
|
64
121
|
const dbMessages = getMessages(state.conversationId);
|
|
65
122
|
if (!dbMessages || dbMessages.length === 0) {
|
|
@@ -96,8 +153,13 @@ export async function executeSubagentRead(
|
|
|
96
153
|
}
|
|
97
154
|
}
|
|
98
155
|
|
|
156
|
+
const footer = statsFooter(subagentId, settled);
|
|
157
|
+
|
|
99
158
|
if (messageTexts.length === 0) {
|
|
100
|
-
return {
|
|
159
|
+
return {
|
|
160
|
+
content: `Subagent produced no text output.${footer}`,
|
|
161
|
+
isError: false,
|
|
162
|
+
};
|
|
101
163
|
}
|
|
102
164
|
|
|
103
165
|
const lastN =
|
|
@@ -107,7 +169,7 @@ export async function executeSubagentRead(
|
|
|
107
169
|
const sliced = lastN ? messageTexts.slice(-lastN) : messageTexts;
|
|
108
170
|
|
|
109
171
|
return {
|
|
110
|
-
content: sliced.join("\n\n")
|
|
172
|
+
content: `${sliced.join("\n\n")}${footer}`,
|
|
111
173
|
isError: false,
|
|
112
174
|
};
|
|
113
175
|
}
|