@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
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { InterfaceId } from "../channels/types.js";
|
|
7
|
-
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
8
|
-
import type { SurfaceConversationContext } from "./conversation-surfaces.js";
|
|
9
|
-
import type { TrustContext } from "./trust-context-types.js";
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* How a subagent/wake tool allowlist is enforced.
|
|
@@ -24,6 +21,25 @@ import type { TrustContext } from "./trust-context-types.js";
|
|
|
24
21
|
*/
|
|
25
22
|
export type SubagentToolGateMode = "wire" | "execution";
|
|
26
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Live tool-call counters for a subagent child, recorded by the tool executor
|
|
26
|
+
* and harvested by the SubagentManager when the run ends.
|
|
27
|
+
*
|
|
28
|
+
* This is the machine half of a subagent's result: the parent reads the child's
|
|
29
|
+
* own prose narrative, and these counts say what the child actually ran, so a
|
|
30
|
+
* claim of executed work that never touched a tool is visible rather than
|
|
31
|
+
* taken on trust. Ephemeral (in-memory only, never persisted) and only ever
|
|
32
|
+
* written for subagent conversations.
|
|
33
|
+
*/
|
|
34
|
+
export interface SubagentToolStats {
|
|
35
|
+
/** Tool calls dispatched, including ones that returned an error. */
|
|
36
|
+
calls: number;
|
|
37
|
+
/** Of those, the calls whose result was not an error. */
|
|
38
|
+
succeeded: number;
|
|
39
|
+
/** Distinct paths successfully passed to `file_write` / `file_edit`. */
|
|
40
|
+
filesWritten: Set<string>;
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
/**
|
|
28
44
|
* Client-context inputs frozen for tool-DEFINITION resolution during a wake
|
|
29
45
|
* that runs with `subagentToolGateMode: "execution"`.
|
|
@@ -64,122 +80,3 @@ export interface WakeToolContextPin {
|
|
|
64
80
|
*/
|
|
65
81
|
requestOrigin?: string;
|
|
66
82
|
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Subset of Conversation state that the tool executor callback reads at
|
|
70
|
-
* call time (not construction time). These are captured by the
|
|
71
|
-
* returned closure, so they must be live references.
|
|
72
|
-
*/
|
|
73
|
-
export interface ToolSetupContext extends SurfaceConversationContext {
|
|
74
|
-
readonly conversationId: string;
|
|
75
|
-
assistantId?: string;
|
|
76
|
-
currentRequestId?: string;
|
|
77
|
-
workingDir: string;
|
|
78
|
-
abortController: AbortController | null;
|
|
79
|
-
/** When set, only tools in this set may execute during the current turn. */
|
|
80
|
-
allowedToolNames?: Set<string>;
|
|
81
|
-
/** When set, the subagent/wake tool allowlist (see {@link subagentToolGateMode}). */
|
|
82
|
-
subagentAllowedTools?: Set<string>;
|
|
83
|
-
/**
|
|
84
|
-
* When true, side-effecting tools are refused for this subagent regardless of
|
|
85
|
-
* trust class (the read-only background continuation): kept off the wire tool
|
|
86
|
-
* surface and rejected in the executor gate. Independent of the allowlist.
|
|
87
|
-
*/
|
|
88
|
-
subagentDenySideEffects?: boolean;
|
|
89
|
-
/**
|
|
90
|
-
* Collects tool names the subagent attempted but that
|
|
91
|
-
* {@link subagentAllowedTools} denied, for parent-visible reporting. The
|
|
92
|
-
* executor records into this Set (shared by reference with the Conversation).
|
|
93
|
-
*/
|
|
94
|
-
subagentDeniedToolNames?: Set<string>;
|
|
95
|
-
/**
|
|
96
|
-
* How {@link subagentAllowedTools} is enforced. Absent or `"wire"` keeps
|
|
97
|
-
* the historical behavior (definitions filtered before the provider
|
|
98
|
-
* request); `"execution"` keeps the full tool surface on the wire and
|
|
99
|
-
* rejects non-allowlisted calls in the executor callback instead.
|
|
100
|
-
*/
|
|
101
|
-
subagentToolGateMode?: SubagentToolGateMode;
|
|
102
|
-
/** Turn-scoped disk-pressure cleanup mode flag. */
|
|
103
|
-
diskPressureCleanupModeActive?: boolean;
|
|
104
|
-
/** True when the conversation has no connected client (HTTP-only path). */
|
|
105
|
-
hasNoClient?: boolean;
|
|
106
|
-
/** When true, the conversation is executing a task run and must not become interactive. */
|
|
107
|
-
headlessLock?: boolean;
|
|
108
|
-
/** When set, this conversation is executing a task run. Used to retrieve ephemeral permission rules. */
|
|
109
|
-
taskRunId?: string;
|
|
110
|
-
/** Guardian runtime context for the conversation — trustClass is propagated into ToolContext for control-plane policy enforcement. */
|
|
111
|
-
trustContext?: TrustContext;
|
|
112
|
-
/** Per-turn trust snapshot, captured at turn start. Preferred over the live
|
|
113
|
-
* `trustContext` for mid-turn trust decisions (tool approval, control-plane
|
|
114
|
-
* policy) so a concurrent mutation cannot elevate the in-flight turn. */
|
|
115
|
-
currentTurnTrustContext?: TrustContext;
|
|
116
|
-
/** Voice/call session ID, if the conversation originates from a call. Propagated into ToolContext for scoped grant consumption. */
|
|
117
|
-
callSessionId?: string;
|
|
118
|
-
/** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */
|
|
119
|
-
readonly transportInterface?: InterfaceId;
|
|
120
|
-
/**
|
|
121
|
-
* Per-turn snapshot of the channel's UI capabilities, captured at turn start
|
|
122
|
-
* (mirrors {@link Conversation.currentTurnChannelCapabilities}). Read per tool
|
|
123
|
-
* call — together with the structural {@link SurfaceConversationContext.channelCapabilities}
|
|
124
|
-
* fallback — to derive `ToolContext.supportsDynamicUi`, so UI-dependent tools
|
|
125
|
-
* (e.g. `ask_question`) can degrade to text on channels that can't render
|
|
126
|
-
* dynamic surfaces.
|
|
127
|
-
*/
|
|
128
|
-
readonly currentTurnChannelCapabilities?: {
|
|
129
|
-
readonly channel: string;
|
|
130
|
-
readonly supportsDynamicUi: boolean;
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* The conversation's per-chat plugin scope (mirrors
|
|
134
|
-
* {@link Conversation.enabledPlugins}). `null`/absent means no per-chat
|
|
135
|
-
* restriction. Read per tool call to derive the effective enabled-plugin set
|
|
136
|
-
* (via `getEffectiveEnabledPluginSet`) for the `ToolContext.enabledPluginSet`
|
|
137
|
-
* field and the `skill_execute` dispatch guard.
|
|
138
|
-
*/
|
|
139
|
-
readonly enabledPlugins?: string[] | null;
|
|
140
|
-
|
|
141
|
-
/** Turn-scoped flag: true when any tool call in the current turn received explicit user approval via interactive prompt. Cleared at turn end. */
|
|
142
|
-
approvedViaPromptThisTurn?: boolean;
|
|
143
|
-
/**
|
|
144
|
-
* When true, side-effect tools must prompt for confirmation even if a
|
|
145
|
-
* trust/allow rule would auto-allow them. Set by callers without an
|
|
146
|
-
* interactive approval UI (e.g. non-guardian phone voice turns) to force
|
|
147
|
-
* a `confirmation_request` event that the caller's auto-deny / scoped-grant
|
|
148
|
-
* handler can intercept. Provides a second layer of defense against broad
|
|
149
|
-
* trust rules auto-executing side-effect tools in non-interactive contexts.
|
|
150
|
-
*/
|
|
151
|
-
forcePromptSideEffects?: boolean;
|
|
152
|
-
/**
|
|
153
|
-
* The LLM call site driving the current turn, set by `runAgentLoopImpl`
|
|
154
|
-
* (`options.callSite ?? "mainAgent"`). Non-main turns (voice `callAgent`,
|
|
155
|
-
* `filingAgent`, …) resolve different provider/model/profile config, so
|
|
156
|
-
* tool telemetry attribution must use this rather than assuming
|
|
157
|
-
* `mainAgent`. Absent before the first turn starts.
|
|
158
|
-
*/
|
|
159
|
-
currentCallSite?: LLMCallSite;
|
|
160
|
-
/**
|
|
161
|
-
* Per-turn snapshot of the resolved inference-profile override, set by
|
|
162
|
-
* `runAgentLoopImpl`. Propagated into `ToolContext.overrideProfile` so
|
|
163
|
-
* tools that spawn nested invocations (e.g. `subagent_spawn`) can forward
|
|
164
|
-
* the override without round-tripping through a row read that would
|
|
165
|
-
* return `undefined` for the in-flight (background) subagent.
|
|
166
|
-
*/
|
|
167
|
-
currentTurnOverrideProfile?: string;
|
|
168
|
-
/**
|
|
169
|
-
* Whether the current turn has no human present to answer clarification
|
|
170
|
-
* prompts. Resolved once per turn by the agent loop — honoring an explicit
|
|
171
|
-
* per-run `isInteractive` option (e.g. scheduled/background turns) over the
|
|
172
|
-
* live client state — so tool execution sees turn-level interactivity rather
|
|
173
|
-
* than re-deriving it from `hasNoClient`/`headlessLock`, which would read a
|
|
174
|
-
* scheduled turn running on a client-attached conversation as interactive.
|
|
175
|
-
*/
|
|
176
|
-
currentTurnIsNonInteractive?: boolean;
|
|
177
|
-
/**
|
|
178
|
-
* Origin tag of the current turn (the conversation's `TitleOrigin`, e.g.
|
|
179
|
-
* "memory_consolidation"), set by `runAgentLoop` from its `requestOrigin`
|
|
180
|
-
* option. Propagated into `ToolContext.requestOrigin` so the permission
|
|
181
|
-
* checker can scope narrow non-interactive auto-grants to a specific
|
|
182
|
-
* internal background origin. Absent for normal interactive turns.
|
|
183
|
-
*/
|
|
184
|
-
currentTurnRequestOrigin?: string;
|
|
185
|
-
}
|
|
@@ -9,32 +9,34 @@
|
|
|
9
9
|
|
|
10
10
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
11
11
|
|
|
12
|
+
import { DOCUMENT_MUTATION_TOOL_NAMES } from "../api/constants/document-tools.js";
|
|
12
13
|
import type { AssistantEvent } from "../api/index.js";
|
|
13
14
|
import { getApp, linkAppToConversationLineage } from "../apps/app-store.js";
|
|
14
|
-
import { findActiveSession } from "../channels/gateway-verification-sessions.js";
|
|
15
15
|
import { getConfig } from "../config/loader.js";
|
|
16
16
|
import { generateAppIcon } from "../media/app-icon-generator.js";
|
|
17
17
|
import { invalidateEdgeIndex } from "../plugins/defaults/memory/substrate/edge-index.js";
|
|
18
18
|
import { invalidatePageIndex } from "../plugins/defaults/memory/substrate/page-index.js";
|
|
19
19
|
import { getConceptsDir } from "../plugins/defaults/memory/substrate/page-store.js";
|
|
20
20
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
21
|
-
import {
|
|
22
|
-
|
|
21
|
+
import {
|
|
22
|
+
publishAppsChanged,
|
|
23
|
+
publishDocumentsChanged,
|
|
24
|
+
} from "../runtime/sync/resource-sync-events.js";
|
|
23
25
|
import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
|
|
24
26
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
25
27
|
import { getLogger } from "../util/logger.js";
|
|
26
28
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
27
29
|
import { ensureAppSourceWatcher } from "./app-source-watcher.js";
|
|
30
|
+
import type { Conversation } from "./conversation.js";
|
|
28
31
|
import { refreshSurfacesForApp } from "./conversation-surfaces.js";
|
|
29
32
|
import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
|
|
30
|
-
import type { ToolSetupContext } from "./tool-setup-types.js";
|
|
31
33
|
|
|
32
34
|
const log = getLogger("tool-side-effects");
|
|
33
35
|
|
|
34
36
|
// ── Types ────────────────────────────────────────────────────────────
|
|
35
37
|
|
|
36
38
|
export interface SideEffectContext {
|
|
37
|
-
ctx:
|
|
39
|
+
ctx: Conversation;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export type PostExecutionHook = (
|
|
@@ -57,7 +59,7 @@ export type PostExecutionHook = (
|
|
|
57
59
|
* and would race with the executor's own output (LUM-1153).
|
|
58
60
|
*/
|
|
59
61
|
function notifyAppChanged(
|
|
60
|
-
ctx:
|
|
62
|
+
ctx: Conversation,
|
|
61
63
|
appId: string,
|
|
62
64
|
opts?: { fileChange?: boolean; status?: string },
|
|
63
65
|
): void {
|
|
@@ -179,6 +181,15 @@ function registerAppSurfaceRefreshHook(toolName: string): void {
|
|
|
179
181
|
registerAppSurfaceRefreshHook("app_refresh");
|
|
180
182
|
registerAppSurfaceRefreshHook("app_update");
|
|
181
183
|
|
|
184
|
+
// The mutating document tools carry no list-level change signal of their own,
|
|
185
|
+
// so the conversation assets pill and the Library keep serving a cached list
|
|
186
|
+
// after an edit, and a deleted document lingers as a ghost row. `skill_execute`
|
|
187
|
+
// calls reach the runner already unwrapped to the inner tool name, so the
|
|
188
|
+
// bundled document-editor skill needs no separate registration.
|
|
189
|
+
registerHook([...DOCUMENT_MUTATION_TOOL_NAMES], () => {
|
|
190
|
+
publishDocumentsChanged();
|
|
191
|
+
});
|
|
192
|
+
|
|
182
193
|
registerHook("voice_config_update", (_name, input) => {
|
|
183
194
|
const setting = input.setting as string | undefined;
|
|
184
195
|
if (!setting) {
|
|
@@ -229,94 +240,6 @@ registerHook("voice_config_update", (_name, input) => {
|
|
|
229
240
|
} as unknown as AssistantEvent);
|
|
230
241
|
});
|
|
231
242
|
|
|
232
|
-
// Dispatch pending Slack DM delivery when a CLI verification command
|
|
233
|
-
// completes. The CLI subprocess is sandboxed and cannot reach the
|
|
234
|
-
// gateway, so it includes a `_pendingSlackDm` field in its JSON output.
|
|
235
|
-
// This hook runs in the unsandboxed daemon process and delivers the DM.
|
|
236
|
-
registerHook("bash", async (_name, input, result) => {
|
|
237
|
-
const command = (input.command ?? "") as string;
|
|
238
|
-
if (!command.includes("channel-verification-sessions")) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (!result.content.includes("_pendingSlackDm")) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
type PendingDm = { userId: string; text: string; assistantId: string };
|
|
246
|
-
type Parsed = { _pendingSlackDm?: PendingDm };
|
|
247
|
-
|
|
248
|
-
// Returns "delivered" when DM was sent, "rejected" when _pendingSlackDm
|
|
249
|
-
// was found but failed validation, or null when the field was absent.
|
|
250
|
-
const dispatch = async (
|
|
251
|
-
parsed: Parsed,
|
|
252
|
-
): Promise<"delivered" | "rejected" | null> => {
|
|
253
|
-
if (parsed._pendingSlackDm) {
|
|
254
|
-
const { userId, text, assistantId } = parsed._pendingSlackDm;
|
|
255
|
-
|
|
256
|
-
// Validate that an active Slack verification session exists and
|
|
257
|
-
// that the destination matches the userId in the parsed payload.
|
|
258
|
-
// Fail closed: an unverifiable DM (gateway unreachable) is not sent.
|
|
259
|
-
let session;
|
|
260
|
-
try {
|
|
261
|
-
session = await findActiveSession("slack");
|
|
262
|
-
} catch (err) {
|
|
263
|
-
log.warn(
|
|
264
|
-
{ err, userId, assistantId },
|
|
265
|
-
"Bash hook: gateway session lookup failed — ignoring _pendingSlackDm",
|
|
266
|
-
);
|
|
267
|
-
return "rejected";
|
|
268
|
-
}
|
|
269
|
-
if (!session) {
|
|
270
|
-
log.warn(
|
|
271
|
-
{ userId, assistantId },
|
|
272
|
-
"Bash hook: no active Slack verification session — ignoring _pendingSlackDm",
|
|
273
|
-
);
|
|
274
|
-
return "rejected";
|
|
275
|
-
}
|
|
276
|
-
if (session.destinationAddress !== userId) {
|
|
277
|
-
log.warn(
|
|
278
|
-
{ userId, expected: session.destinationAddress, assistantId },
|
|
279
|
-
"Bash hook: Slack DM userId does not match active session destination — ignoring",
|
|
280
|
-
);
|
|
281
|
-
return "rejected";
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
deliverVerificationSlack(userId, text, assistantId);
|
|
285
|
-
return "delivered";
|
|
286
|
-
}
|
|
287
|
-
return null;
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// Try full content first (handles pretty-printed single-object JSON)
|
|
291
|
-
let singleObject: Parsed | undefined;
|
|
292
|
-
try {
|
|
293
|
-
singleObject = JSON.parse(result.content.trim()) as Parsed;
|
|
294
|
-
} catch {
|
|
295
|
-
// Not a single JSON object — fall back to line-by-line for
|
|
296
|
-
// multi-object output (e.g. cancel + create chained with &&).
|
|
297
|
-
}
|
|
298
|
-
if (singleObject !== undefined) {
|
|
299
|
-
if ((await dispatch(singleObject)) !== null) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
for (const line of result.content.split("\n")) {
|
|
304
|
-
const trimmed = line.trim();
|
|
305
|
-
if (!trimmed.startsWith("{")) {
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
let parsed: Parsed;
|
|
309
|
-
try {
|
|
310
|
-
parsed = JSON.parse(trimmed) as Parsed;
|
|
311
|
-
} catch {
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if ((await dispatch(parsed)) === "delivered") {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
243
|
// Invalidate the in-memory v2 edge index and page index when the LLM writes
|
|
321
244
|
// or edits a file under `memory/concepts/`. The page-store invalidates on
|
|
322
245
|
// programmatic writes; this hook covers consolidation, where the LLM edits
|
|
@@ -67,3 +67,42 @@ export interface TrustContext {
|
|
|
67
67
|
*/
|
|
68
68
|
requesterInteractionCount?: number;
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Whether two trust contexts describe the same acting identity at the same
|
|
73
|
+
* privilege, for callers that may only run work under one of them (batched
|
|
74
|
+
* turns being the case that matters).
|
|
75
|
+
*
|
|
76
|
+
* Compares the privilege (`trustClass`), the channel a grant is scoped to
|
|
77
|
+
* (`sourceChannel`), and every field that can carry who the actor is. The
|
|
78
|
+
* identity fields are covered exhaustively rather than by picking the usual
|
|
79
|
+
* ones: an ingress that populates only `requesterIdentifier` or
|
|
80
|
+
* `requesterContactId` would otherwise leave two distinct senders comparing
|
|
81
|
+
* equal on a pair of undefineds, which is the exact case this guards.
|
|
82
|
+
*
|
|
83
|
+
* Deliberately conservative: an absent field never matches a present one, so
|
|
84
|
+
* unknown identities are treated as distinct. Answering "different" when they
|
|
85
|
+
* match only costs a batching opportunity; answering "same" when they differ
|
|
86
|
+
* runs one actor's work under another's privileges.
|
|
87
|
+
*/
|
|
88
|
+
export function sameTrustIdentity(
|
|
89
|
+
a: TrustContext | undefined,
|
|
90
|
+
b: TrustContext | undefined,
|
|
91
|
+
): boolean {
|
|
92
|
+
if (a === b) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (!a || !b) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return (
|
|
99
|
+
a.trustClass === b.trustClass &&
|
|
100
|
+
a.sourceChannel === b.sourceChannel &&
|
|
101
|
+
a.requesterExternalUserId === b.requesterExternalUserId &&
|
|
102
|
+
a.requesterChatId === b.requesterChatId &&
|
|
103
|
+
a.requesterIdentifier === b.requesterIdentifier &&
|
|
104
|
+
a.requesterContactId === b.requesterContactId &&
|
|
105
|
+
a.guardianExternalUserId === b.guardianExternalUserId &&
|
|
106
|
+
a.guardianPrincipalId === b.guardianPrincipalId
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -87,12 +87,16 @@ export function isPersonalMemoryAllowed(
|
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* Map a channel-native chat type (Telegram `private`/`group`/`supergroup`,
|
|
90
|
-
* Slack `im`/`mpim`/`channel`) onto the
|
|
91
|
-
* axis. Slack
|
|
92
|
-
* without distinguishing public from private, so
|
|
93
|
-
* undefined
|
|
94
|
-
* private channels. The channel-type tier starts matching for
|
|
95
|
-
* once the gateway forwards the distinct type.
|
|
90
|
+
* Slack `im`/`mpim`/`channel`, Discord `dm`/`channel`) onto the
|
|
91
|
+
* permission-matrix conversation-type axis. Slack and Discord both forward
|
|
92
|
+
* every non-DM as `"channel"` without distinguishing public from private, so
|
|
93
|
+
* `"channel"` maps to undefined: a permissive public-channel cell must not
|
|
94
|
+
* silently govern private channels. The channel-type tier starts matching for
|
|
95
|
+
* their non-DMs once the gateway forwards the distinct type.
|
|
96
|
+
*
|
|
97
|
+
* Every DM-capable channel must have an arm here. A missing one is silent:
|
|
98
|
+
* the cell stays settable, because the adapter validates, and simply never
|
|
99
|
+
* matches, so the guardian sets a rule for DMs and it does nothing.
|
|
96
100
|
*/
|
|
97
101
|
export function mapChatTypeToConversationType(
|
|
98
102
|
chatType?: string,
|
|
@@ -100,6 +104,10 @@ export function mapChatTypeToConversationType(
|
|
|
100
104
|
switch (chatType) {
|
|
101
105
|
case "im": // Slack DM
|
|
102
106
|
case "private": // Telegram DM
|
|
107
|
+
// Discord has no string vocabulary for this: its API distinguishes a DM by
|
|
108
|
+
// a numeric channel type, and the absence of a guild. The normalizer names
|
|
109
|
+
// it for the axis rather than inventing a native-looking word.
|
|
110
|
+
case "dm":
|
|
103
111
|
return "dm";
|
|
104
112
|
// "mpim" is Slack's multi-party DM. The gateway normalizer currently
|
|
105
113
|
// collapses mpim into "channel", so this arm matches nothing from Slack
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-conversation serialization for the detached end-of-turn tails the agent
|
|
3
|
+
* loop schedules after releasing the processing lock.
|
|
4
|
+
*
|
|
5
|
+
* The chain is keyed by conversation id and held at module scope rather than
|
|
6
|
+
* on the `Conversation` instance. A tail runs while the conversation reads
|
|
7
|
+
* idle, which is exactly the window in which `evictConversationsForReload` and
|
|
8
|
+
* the stale-instance rebuild in `conversation-store.ts` drop the live instance:
|
|
9
|
+
* an instance-scoped chain would let the rebuilt instance start an empty chain
|
|
10
|
+
* whose tail overlaps the previous instance's still-running one. The state
|
|
11
|
+
* those tails advance (memory segments, the conversation attention cursor) is
|
|
12
|
+
* per conversation, not per instance, so the serialization has to be too.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { getLogger } from "../util/logger.js";
|
|
16
|
+
|
|
17
|
+
const log = getLogger("turn-tail-chain");
|
|
18
|
+
|
|
19
|
+
/** Tail promise per conversation id. Entries exist only while a tail is live. */
|
|
20
|
+
const chains = new Map<string, Promise<void>>();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Queue `tail` behind any tail already running for this conversation.
|
|
24
|
+
*
|
|
25
|
+
* Returns immediately: the tail is detached by design, so its failure is
|
|
26
|
+
* logged rather than surfaced. The chain is `.catch`-terminated at every link,
|
|
27
|
+
* so a rejected tail can neither become an unhandled rejection nor poison the
|
|
28
|
+
* tails queued after it.
|
|
29
|
+
*/
|
|
30
|
+
export function chainTurnTail(
|
|
31
|
+
conversationId: string,
|
|
32
|
+
tail: () => Promise<void>,
|
|
33
|
+
): void {
|
|
34
|
+
const previous = chains.get(conversationId) ?? Promise.resolve();
|
|
35
|
+
const next: Promise<void> = previous
|
|
36
|
+
.then(tail)
|
|
37
|
+
.catch((err: unknown) => {
|
|
38
|
+
log.warn(
|
|
39
|
+
{ err, conversationId },
|
|
40
|
+
"Deferred turn tail failed (non-fatal)",
|
|
41
|
+
);
|
|
42
|
+
})
|
|
43
|
+
.then(() => {
|
|
44
|
+
// Drop the entry only when nothing chained onto this link while it ran,
|
|
45
|
+
// so the map holds an entry per conversation with a live tail rather
|
|
46
|
+
// than one per conversation the daemon has ever served.
|
|
47
|
+
if (chains.get(conversationId) === next) {
|
|
48
|
+
chains.delete(conversationId);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
chains.set(conversationId, next);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve once every tail currently queued for this conversation has settled.
|
|
56
|
+
*
|
|
57
|
+
* Tests use this to await work the agent loop deliberately detached. Callers
|
|
58
|
+
* that chain a new tail after awaiting get a fresh promise, so this is a
|
|
59
|
+
* point-in-time barrier, not a permanent quiesce.
|
|
60
|
+
*/
|
|
61
|
+
export function settleTurnTail(conversationId: string): Promise<void> {
|
|
62
|
+
return chains.get(conversationId) ?? Promise.resolve();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Number of conversations with a live tail. Lets tests assert the map is
|
|
67
|
+
* released rather than growing per conversation.
|
|
68
|
+
*
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
export function __turnTailChainSizeForTests(): number {
|
|
72
|
+
return chains.size;
|
|
73
|
+
}
|
|
@@ -20,18 +20,27 @@ export interface StripResult {
|
|
|
20
20
|
/**
|
|
21
21
|
* Replaces every `web_search_tool_result` block in the message list with a
|
|
22
22
|
* plain `text` summary of its results, and drops the paired `server_tool_use`
|
|
23
|
-
* that produced it.
|
|
23
|
+
* that produced it, wherever that use lives. The pair usually shares one
|
|
24
|
+
* assistant message, but a deferred execution (the API runs the search on the
|
|
25
|
+
* request after a mixed server/client parallel tool group) places the result
|
|
26
|
+
* at the head of the following assistant message, so pairing is resolved
|
|
27
|
+
* across the whole list. Dropping both sides together keeps the history free
|
|
28
|
+
* of unpaired server-tool blocks, which the provider layer would otherwise
|
|
29
|
+
* repair with a synthetic error result.
|
|
30
|
+
*
|
|
31
|
+
* A `server_tool_use` with no result anywhere in the list is left untouched:
|
|
32
|
+
* either the search is still pending (deferred tail, executed by the provider
|
|
33
|
+
* on this request) or it is a genuine orphan the provider layer repairs.
|
|
24
34
|
*
|
|
25
35
|
* Anthropic's `encrypted_content` tokens attached to each `web_search_result`
|
|
26
36
|
* are opaque server tokens with bounded validity (they expire and/or are
|
|
27
37
|
* route-scoped). Replaying a stale token produces
|
|
28
38
|
* `messages.N.content.M: Invalid encrypted_content in search_result block`.
|
|
29
39
|
* For historical turns the model does not need the opaque token to re-read
|
|
30
|
-
* the body
|
|
40
|
+
* the body: a title+url summary is sufficient to preserve context.
|
|
31
41
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* definition from a prior turn.
|
|
42
|
+
* Runs on the outbound message list before each model call; every executed
|
|
43
|
+
* search in the list is summarized regardless of which turn produced it.
|
|
35
44
|
*/
|
|
36
45
|
export function stripHistoricalWebSearchResults(
|
|
37
46
|
messages: Message[],
|
|
@@ -42,42 +51,45 @@ export function stripHistoricalWebSearchResults(
|
|
|
42
51
|
messagesModified: 0,
|
|
43
52
|
};
|
|
44
53
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const transformed: ContentBlock[] = [];
|
|
48
|
-
|
|
54
|
+
const strippedToolUseIds = new Set<string>();
|
|
55
|
+
for (const msg of messages) {
|
|
49
56
|
for (const block of msg.content) {
|
|
50
|
-
if (block.type
|
|
51
|
-
|
|
57
|
+
if (block.type === "web_search_tool_result") {
|
|
58
|
+
strippedToolUseIds.add(
|
|
59
|
+
(block as WebSearchToolResultContent).tool_use_id,
|
|
60
|
+
);
|
|
52
61
|
}
|
|
53
|
-
const wsr = block as WebSearchToolResultContent;
|
|
54
|
-
const query = findQueryForToolUseId(msg.content, wsr.tool_use_id);
|
|
55
|
-
transformed.push(formatAsText(wsr, query));
|
|
56
|
-
droppedServerToolUseIds.add(wsr.tool_use_id);
|
|
57
|
-
stats.blocksStripped++;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (droppedServerToolUseIds.size === 0) {
|
|
61
|
-
return msg;
|
|
62
62
|
}
|
|
63
|
+
}
|
|
63
64
|
|
|
65
|
+
const next: Message[] = messages.map((msg) => {
|
|
66
|
+
let modified = false;
|
|
64
67
|
const rewritten: ContentBlock[] = [];
|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
for (const block of msg.content) {
|
|
67
70
|
if (block.type === "server_tool_use") {
|
|
68
71
|
const stu = block as ServerToolUseContent;
|
|
69
|
-
if (
|
|
72
|
+
if (strippedToolUseIds.has(stu.id)) {
|
|
70
73
|
stats.serverToolUsesDropped++;
|
|
74
|
+
modified = true;
|
|
71
75
|
continue;
|
|
72
76
|
}
|
|
73
77
|
rewritten.push(block);
|
|
74
78
|
} else if (block.type === "web_search_tool_result") {
|
|
75
|
-
|
|
79
|
+
const wsr = block as WebSearchToolResultContent;
|
|
80
|
+
rewritten.push(
|
|
81
|
+
formatAsText(wsr, findQueryForToolUseId(messages, wsr.tool_use_id)),
|
|
82
|
+
);
|
|
83
|
+
stats.blocksStripped++;
|
|
84
|
+
modified = true;
|
|
76
85
|
} else {
|
|
77
86
|
rewritten.push(block);
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
|
|
90
|
+
if (!modified) {
|
|
91
|
+
return msg;
|
|
92
|
+
}
|
|
81
93
|
stats.messagesModified++;
|
|
82
94
|
return { ...msg, content: rewritten };
|
|
83
95
|
});
|
|
@@ -86,19 +98,21 @@ export function stripHistoricalWebSearchResults(
|
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
function findQueryForToolUseId(
|
|
89
|
-
|
|
101
|
+
messages: Message[],
|
|
90
102
|
toolUseId: string,
|
|
91
103
|
): string | null {
|
|
92
|
-
for (const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
for (const msg of messages) {
|
|
105
|
+
for (const b of msg.content) {
|
|
106
|
+
if (b.type !== "server_tool_use") {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const stu = b as ServerToolUseContent;
|
|
110
|
+
if (stu.id !== toolUseId) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const q = stu.input?.query;
|
|
114
|
+
return typeof q === "string" ? q : null;
|
|
99
115
|
}
|
|
100
|
-
const q = stu.input?.query;
|
|
101
|
-
return typeof q === "string" ? q : null;
|
|
102
116
|
}
|
|
103
117
|
return null;
|
|
104
118
|
}
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import type { HeartbeatAlertEvent } from "../api/events/heartbeat-alert.js";
|
|
5
5
|
import { getConfig } from "../config/loader.js";
|
|
6
6
|
import type { HeartbeatConfig } from "../config/schemas/heartbeat.js";
|
|
7
|
-
import {
|
|
7
|
+
import { warmGuardianBindings } from "../contacts/guardian-delivery-reader.js";
|
|
8
8
|
import {
|
|
9
9
|
checkDiskPressureBackgroundGate,
|
|
10
10
|
diskPressureBackgroundSkipLogFields,
|
|
@@ -815,10 +815,11 @@ export class HeartbeatService {
|
|
|
815
815
|
|
|
816
816
|
const checklist = this.readChecklist();
|
|
817
817
|
const completedRunCount = countCompletedHeartbeatRuns();
|
|
818
|
-
// Warm
|
|
819
|
-
// persona read (isShallowProfile →
|
|
820
|
-
//
|
|
821
|
-
|
|
818
|
+
// Warm both guardian-delivery cache keys (vellum + unfiltered) so
|
|
819
|
+
// buildPrompt's sync guardian persona read (isShallowProfile →
|
|
820
|
+
// resolveGuardianPersona), including its any-channel fallback, hits fresh
|
|
821
|
+
// keys instead of falling back to default.md on a cold/TTL-expired cache.
|
|
822
|
+
await warmGuardianBindings();
|
|
822
823
|
const { prompt, includedReengagement } = this.buildPrompt(
|
|
823
824
|
checklist,
|
|
824
825
|
unhealthyProviders,
|
|
@@ -848,7 +849,6 @@ export class HeartbeatService {
|
|
|
848
849
|
callSite: "heartbeatAgent",
|
|
849
850
|
timeoutMs: getConfig().timeouts.backgroundTurnTimeoutSec * 1000,
|
|
850
851
|
origin: "heartbeat",
|
|
851
|
-
deferNotifications: true,
|
|
852
852
|
onConversationCreated: (newConversationId) => {
|
|
853
853
|
conversationId = newConversationId;
|
|
854
854
|
broadcastMessage({
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createServer } from "node:net";
|
|
1
2
|
import { tmpdir } from "node:os";
|
|
2
3
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
3
4
|
|
|
5
|
+
import { ensureSocketPathFree } from "../socket-cleanup.js";
|
|
4
6
|
import { resolveIpcSocketPath } from "../socket-path.js";
|
|
5
7
|
|
|
6
8
|
let savedWorkspaceDir: string | undefined;
|
|
@@ -77,4 +79,23 @@ describe("resolveIpcSocketPath", () => {
|
|
|
77
79
|
|
|
78
80
|
delete process.env.EXAMPLE_SERVICE_IPC_SOCKET_DIR;
|
|
79
81
|
});
|
|
82
|
+
|
|
83
|
+
test.skipIf(process.platform !== "win32")(
|
|
84
|
+
"rejects an occupied named pipe",
|
|
85
|
+
async () => {
|
|
86
|
+
const pipe = `\\\\.\\pipe\\vellum-ipc-test-${process.pid}`;
|
|
87
|
+
const server = createServer();
|
|
88
|
+
await new Promise<void>((resolve, reject) => {
|
|
89
|
+
server.once("error", reject);
|
|
90
|
+
server.listen(pipe, resolve);
|
|
91
|
+
});
|
|
92
|
+
try {
|
|
93
|
+
await expect(ensureSocketPathFree(pipe)).rejects.toMatchObject({
|
|
94
|
+
code: "EADDRINUSE",
|
|
95
|
+
});
|
|
96
|
+
} finally {
|
|
97
|
+
server.close();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
);
|
|
80
101
|
});
|