@vellumai/assistant 0.11.2 → 0.11.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register and tear down client subscribers on an assistant event hub.
|
|
3
|
+
*
|
|
4
|
+
* The caller supplies the hub, so this helper holds no runtime import into
|
|
5
|
+
* `src/` and stays safe for the test preload's import graph.
|
|
6
|
+
*/
|
|
7
|
+
import type { HostProxyCapability, InterfaceId } from "../../channels/types.js";
|
|
8
|
+
import type {
|
|
9
|
+
AssistantEventHub,
|
|
10
|
+
DesktopPresenceState,
|
|
11
|
+
} from "../../runtime/assistant-event-hub.js";
|
|
12
|
+
|
|
13
|
+
export interface RegisterHubClientArgs {
|
|
14
|
+
hub: AssistantEventHub;
|
|
15
|
+
clientId: string;
|
|
16
|
+
interfaceId?: InterfaceId;
|
|
17
|
+
capabilities?: HostProxyCapability[];
|
|
18
|
+
actorPrincipalId?: string;
|
|
19
|
+
/** Reported immediately after subscribing, when supplied. */
|
|
20
|
+
presence?: DesktopPresenceState;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function registerHubClient(args: RegisterHubClientArgs): void {
|
|
24
|
+
const { hub } = args;
|
|
25
|
+
hub.subscribe({
|
|
26
|
+
type: "client",
|
|
27
|
+
clientId: args.clientId,
|
|
28
|
+
interfaceId: args.interfaceId ?? "macos",
|
|
29
|
+
capabilities: args.capabilities ?? [],
|
|
30
|
+
actorPrincipalId: args.actorPrincipalId,
|
|
31
|
+
callback: () => {},
|
|
32
|
+
});
|
|
33
|
+
if (args.presence) {
|
|
34
|
+
hub.setClientPresence(args.clientId, args.presence);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function clearHubClients(hub: AssistantEventHub): void {
|
|
39
|
+
for (const client of hub.listClients()) {
|
|
40
|
+
hub.disposeClient(client.clientId);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a stand-in `Conversation` for tests that exercise functions taking the
|
|
3
|
+
* live conversation (surface helpers, the tool executor, post-execution
|
|
4
|
+
* hooks).
|
|
5
|
+
*
|
|
6
|
+
* Those functions read a handful of fields off a `Conversation` that has ~150
|
|
7
|
+
* members, so a test double supplies only what the function under test
|
|
8
|
+
* touches. `Partial<Conversation>` keeps the literal contextually typed —
|
|
9
|
+
* field types and callback parameter types are still checked against the real
|
|
10
|
+
* class, and a renamed or retyped member still breaks the build — while the
|
|
11
|
+
* single assertion here confines the unavoidable widening to one place
|
|
12
|
+
* instead of one `as unknown as` per test file.
|
|
13
|
+
*
|
|
14
|
+
* The `Conversation` import is type-only, so this helper contributes nothing
|
|
15
|
+
* to the runtime import graph.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
19
|
+
import type { ChannelCapabilities } from "../../daemon/conversation-runtime-assembly.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `TExtra` carries test-only fields a double hangs off the same object
|
|
23
|
+
* (recorded calls, captured messages) through to the return type, so a caller
|
|
24
|
+
* can still read `ctx.processMessageCalls` off the result.
|
|
25
|
+
*/
|
|
26
|
+
export function asConversation<TExtra extends object = object>(
|
|
27
|
+
mock: Partial<Conversation> & TExtra,
|
|
28
|
+
): Conversation & TExtra {
|
|
29
|
+
return mock as unknown as Conversation & TExtra;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fill a partial capability set out to a full `ChannelCapabilities`.
|
|
34
|
+
*
|
|
35
|
+
* Surface tests care about `channel` and `supportsDynamicUi`; the remaining
|
|
36
|
+
* required fields are noise at the call site but must be present for the
|
|
37
|
+
* value to be a real `ChannelCapabilities`. Defaults are the conservative
|
|
38
|
+
* ones (no dashboard, no voice), so a test that forgets to opt in gets the
|
|
39
|
+
* restrictive branch rather than a silently permissive one.
|
|
40
|
+
*/
|
|
41
|
+
export function mockChannelCapabilities(
|
|
42
|
+
caps: Pick<ChannelCapabilities, "channel" | "supportsDynamicUi"> &
|
|
43
|
+
Partial<ChannelCapabilities>,
|
|
44
|
+
): ChannelCapabilities {
|
|
45
|
+
return { dashboardCapable: false, supportsVoiceInput: false, ...caps };
|
|
46
|
+
}
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
|
+
bindsSameIdentity,
|
|
26
|
+
boundIdentity,
|
|
25
27
|
hashVerificationSecret,
|
|
26
28
|
VERIFICATION_SESSIONS_IPC_METHODS,
|
|
27
29
|
type VerificationSessionWire,
|
|
@@ -62,10 +64,29 @@ function isInterceptable(s: VerificationSessionWire): boolean {
|
|
|
62
64
|
return (INTERCEPTABLE_STATUSES as readonly string[]).includes(s.status);
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
const OUTBOUND_LIVE_STATUSES = ["pending_bootstrap", "awaiting_response"];
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Mirrors the gateway store: an outbound mint supersedes only sessions bound
|
|
71
|
+
* to the same identity, leaving other actors and inbound challenges alone.
|
|
72
|
+
* The identity rule itself comes from the shared contract, so this cannot
|
|
73
|
+
* drift from what the gateway does.
|
|
74
|
+
*/
|
|
75
|
+
function revokeSameActorOutbound(
|
|
76
|
+
channel: string,
|
|
77
|
+
params: SimCreateOutboundParams,
|
|
78
|
+
): void {
|
|
79
|
+
const identity = boundIdentity(params);
|
|
80
|
+
if (identity === null) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
66
83
|
const now = Date.now();
|
|
67
84
|
for (const s of sessions.values()) {
|
|
68
|
-
if (
|
|
85
|
+
if (
|
|
86
|
+
s.channel === channel &&
|
|
87
|
+
OUTBOUND_LIVE_STATUSES.includes(s.status) &&
|
|
88
|
+
bindsSameIdentity(boundIdentity(s), identity)
|
|
89
|
+
) {
|
|
69
90
|
s.status = "revoked";
|
|
70
91
|
s.updatedAt = now;
|
|
71
92
|
}
|
|
@@ -164,7 +185,7 @@ export interface SimCreateOutboundResult {
|
|
|
164
185
|
export function createOutboundSession(
|
|
165
186
|
params: SimCreateOutboundParams,
|
|
166
187
|
): SimCreateOutboundResult {
|
|
167
|
-
|
|
188
|
+
revokeSameActorOutbound(params.channel, params);
|
|
168
189
|
|
|
169
190
|
const isUnbound = params.identityBindingStatus === "pending_bootstrap";
|
|
170
191
|
const secret = isUnbound
|
|
@@ -220,17 +241,30 @@ export type SimGuardedCreateOutboundResult =
|
|
|
220
241
|
export function createOutboundSessionGuarded(
|
|
221
242
|
params: SimCreateOutboundParams & {
|
|
222
243
|
requireSourceSessionPending?: string;
|
|
223
|
-
ifNoneActive?: boolean;
|
|
224
244
|
ifNoneActiveForExternalUserId?: string;
|
|
225
245
|
},
|
|
226
246
|
): SimGuardedCreateOutboundResult {
|
|
227
247
|
const {
|
|
228
248
|
requireSourceSessionPending,
|
|
229
|
-
ifNoneActive,
|
|
230
249
|
ifNoneActiveForExternalUserId,
|
|
231
250
|
...createParams
|
|
232
251
|
} = params;
|
|
233
252
|
|
|
253
|
+
if (ifNoneActiveForExternalUserId !== undefined) {
|
|
254
|
+
// Scoped, like the gateway. Reading the channel's latest and comparing
|
|
255
|
+
// misses this sender's session whenever somebody else started later.
|
|
256
|
+
const active = findActiveSession(params.channel, {
|
|
257
|
+
expectedExternalUserId: ifNoneActiveForExternalUserId,
|
|
258
|
+
});
|
|
259
|
+
if (active !== null) {
|
|
260
|
+
return { conflict: true, reason: "active_session_exists" };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Claim the named source row. Winning the claim IS the guard, so a second
|
|
265
|
+
// claim of the same deep-link token conflicts. The identity-scoped revoke
|
|
266
|
+
// cannot do this: a bootstrap row carries whichever identity was bound onto
|
|
267
|
+
// it last.
|
|
234
268
|
if (requireSourceSessionPending !== undefined) {
|
|
235
269
|
const source = sessions.get(requireSourceSessionPending);
|
|
236
270
|
if (
|
|
@@ -240,20 +274,8 @@ export function createOutboundSessionGuarded(
|
|
|
240
274
|
) {
|
|
241
275
|
return { conflict: true, reason: "source_session_not_pending" };
|
|
242
276
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (ifNoneActive && findActiveSession(params.channel) !== null) {
|
|
246
|
-
return { conflict: true, reason: "active_session_exists" };
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (ifNoneActiveForExternalUserId !== undefined) {
|
|
250
|
-
const active = findActiveSession(params.channel);
|
|
251
|
-
if (
|
|
252
|
-
active !== null &&
|
|
253
|
-
active.expectedExternalUserId === ifNoneActiveForExternalUserId
|
|
254
|
-
) {
|
|
255
|
-
return { conflict: true, reason: "active_session_exists" };
|
|
256
|
-
}
|
|
277
|
+
source.status = "revoked";
|
|
278
|
+
source.updatedAt = Date.now();
|
|
257
279
|
}
|
|
258
280
|
|
|
259
281
|
return createOutboundSession(createParams);
|
|
@@ -309,6 +331,10 @@ export function getPendingSession(
|
|
|
309
331
|
|
|
310
332
|
export function findActiveSession(
|
|
311
333
|
channel: string,
|
|
334
|
+
filter: {
|
|
335
|
+
expectedExternalUserId?: string;
|
|
336
|
+
verificationPurpose?: "guardian" | "trusted_contact";
|
|
337
|
+
} = {},
|
|
312
338
|
): VerificationSessionWire | null {
|
|
313
339
|
const now = Date.now();
|
|
314
340
|
return (
|
|
@@ -318,7 +344,11 @@ export function findActiveSession(
|
|
|
318
344
|
s.channel === channel &&
|
|
319
345
|
(s.status === "pending_bootstrap" ||
|
|
320
346
|
s.status === "awaiting_response") &&
|
|
321
|
-
s.expiresAt > now
|
|
347
|
+
s.expiresAt > now &&
|
|
348
|
+
(!filter.expectedExternalUserId ||
|
|
349
|
+
s.expectedExternalUserId === filter.expectedExternalUserId) &&
|
|
350
|
+
(!filter.verificationPurpose ||
|
|
351
|
+
s.verificationPurpose === filter.verificationPurpose),
|
|
322
352
|
)
|
|
323
353
|
.sort(newestFirst)[0] ?? null
|
|
324
354
|
);
|
|
@@ -475,50 +505,24 @@ function recordInvalidAttempt(key: string): void {
|
|
|
475
505
|
rateLimits.set(key, entry);
|
|
476
506
|
}
|
|
477
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Mirrors the gateway consume path. Both sides read the shared
|
|
510
|
+
* `boundIdentity`, so the sim cannot accept a code the real service would
|
|
511
|
+
* refuse. A session bound to no identity, or not yet finally bound
|
|
512
|
+
* (`pending_bootstrap`), bypasses the check as it does at the gateway.
|
|
513
|
+
*/
|
|
478
514
|
function checkIdentityMatch(
|
|
479
515
|
session: VerificationSessionWire,
|
|
480
516
|
actorExternalUserId: string,
|
|
481
517
|
actorChatId: string,
|
|
482
518
|
): boolean {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
session.expectedChatId != null ||
|
|
486
|
-
session.expectedPhoneE164 != null;
|
|
487
|
-
// pending_bootstrap (and unbound inbound) sessions bypass the check.
|
|
488
|
-
if (!hasExpectedIdentity || session.identityBindingStatus !== "bound") {
|
|
519
|
+
const identity = boundIdentity(session);
|
|
520
|
+
if (identity === null || session.identityBindingStatus !== "bound") {
|
|
489
521
|
return true;
|
|
490
522
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
(actorExternalUserId === session.expectedPhoneE164 ||
|
|
495
|
-
actorExternalUserId === session.expectedExternalUserId)
|
|
496
|
-
) {
|
|
497
|
-
return true;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Shared-chatId caveat: when both expected fields are set, require the
|
|
501
|
-
// externalUserId match — chat IDs can be shared.
|
|
502
|
-
if (session.expectedChatId != null) {
|
|
503
|
-
if (session.expectedExternalUserId != null) {
|
|
504
|
-
if (actorExternalUserId === session.expectedExternalUserId) {
|
|
505
|
-
return true;
|
|
506
|
-
}
|
|
507
|
-
} else if (actorChatId === session.expectedChatId) {
|
|
508
|
-
return true;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
if (
|
|
513
|
-
session.expectedPhoneE164 == null &&
|
|
514
|
-
session.expectedChatId == null &&
|
|
515
|
-
session.expectedExternalUserId != null &&
|
|
516
|
-
actorExternalUserId === session.expectedExternalUserId
|
|
517
|
-
) {
|
|
518
|
-
return true;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return false;
|
|
523
|
+
return identity.field === "chatId"
|
|
524
|
+
? actorChatId === identity.value
|
|
525
|
+
: actorExternalUserId === identity.value;
|
|
522
526
|
}
|
|
523
527
|
|
|
524
528
|
export function validateAndConsumeVerification(
|
|
@@ -572,8 +572,10 @@ describe("repairHistory", () => {
|
|
|
572
572
|
).toBe(true);
|
|
573
573
|
});
|
|
574
574
|
|
|
575
|
-
test("trailing server_tool_use
|
|
576
|
-
//
|
|
575
|
+
test("trailing server_tool_use is preserved as a deferred execution", () => {
|
|
576
|
+
// An unanswered server_tool_use at the tail is a deferred search the
|
|
577
|
+
// provider executes on the next request; repairing it would cancel the
|
|
578
|
+
// search.
|
|
577
579
|
const messages: Message[] = [
|
|
578
580
|
{ role: "user", content: [{ type: "text", text: "Go" }] },
|
|
579
581
|
{
|
|
@@ -591,21 +593,107 @@ describe("repairHistory", () => {
|
|
|
591
593
|
|
|
592
594
|
const { messages: repaired, stats } = repairHistory(messages);
|
|
593
595
|
|
|
594
|
-
expect(stats.missingToolResultsInserted).toBe(
|
|
595
|
-
// Result is in the assistant message
|
|
596
|
+
expect(stats.missingToolResultsInserted).toBe(0);
|
|
596
597
|
expect(repaired).toHaveLength(2);
|
|
597
598
|
expect(repaired[1].role).toBe("assistant");
|
|
598
|
-
expect(repaired[1].content).toHaveLength(
|
|
599
|
-
expect(repaired[1].content[
|
|
600
|
-
type: "
|
|
601
|
-
|
|
602
|
-
content: {
|
|
603
|
-
type: "web_search_tool_result_error",
|
|
604
|
-
error_code: "unavailable",
|
|
605
|
-
},
|
|
599
|
+
expect(repaired[1].content).toHaveLength(1);
|
|
600
|
+
expect(repaired[1].content[0]).toMatchObject({
|
|
601
|
+
type: "server_tool_use",
|
|
602
|
+
id: "stu_1",
|
|
606
603
|
});
|
|
607
604
|
});
|
|
608
605
|
|
|
606
|
+
test("deferred mixed tail (tool_use + server_tool_use, then tool_result) survives a reload untouched", () => {
|
|
607
|
+
// Persisted mid-deferral shape: the model called a client tool and a
|
|
608
|
+
// search in one parallel group, the client result came back, and the
|
|
609
|
+
// daemon reloaded before the next model call ran the search.
|
|
610
|
+
const messages: Message[] = [
|
|
611
|
+
{ role: "user", content: [{ type: "text", text: "Check both" }] },
|
|
612
|
+
{
|
|
613
|
+
role: "assistant",
|
|
614
|
+
content: [
|
|
615
|
+
{ type: "tool_use", id: "tu_a", name: "file_read", input: {} },
|
|
616
|
+
{
|
|
617
|
+
type: "server_tool_use",
|
|
618
|
+
id: "stu_deferred",
|
|
619
|
+
name: "web_search",
|
|
620
|
+
input: { query: "news" },
|
|
621
|
+
},
|
|
622
|
+
],
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
role: "user",
|
|
626
|
+
content: [
|
|
627
|
+
{ type: "tool_result", tool_use_id: "tu_a", content: "file" },
|
|
628
|
+
],
|
|
629
|
+
},
|
|
630
|
+
];
|
|
631
|
+
|
|
632
|
+
const { messages: repaired, stats } = repairHistory(messages);
|
|
633
|
+
|
|
634
|
+
expect(stats.missingToolResultsInserted).toBe(0);
|
|
635
|
+
expect(stats.orphanToolResultsDowngraded).toBe(0);
|
|
636
|
+
expect(repaired).toHaveLength(3);
|
|
637
|
+
expect(repaired[1].content.map((b) => b.type)).toEqual([
|
|
638
|
+
"tool_use",
|
|
639
|
+
"server_tool_use",
|
|
640
|
+
]);
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test("cross-message server tool pair from a completed deferred execution survives a reload untouched", () => {
|
|
644
|
+
const messages: Message[] = [
|
|
645
|
+
{ role: "user", content: [{ type: "text", text: "Check both" }] },
|
|
646
|
+
{
|
|
647
|
+
role: "assistant",
|
|
648
|
+
content: [
|
|
649
|
+
{ type: "tool_use", id: "tu_a", name: "file_read", input: {} },
|
|
650
|
+
{
|
|
651
|
+
type: "server_tool_use",
|
|
652
|
+
id: "stu_split",
|
|
653
|
+
name: "web_search",
|
|
654
|
+
input: { query: "news" },
|
|
655
|
+
},
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
role: "user",
|
|
660
|
+
content: [
|
|
661
|
+
{ type: "tool_result", tool_use_id: "tu_a", content: "file" },
|
|
662
|
+
],
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
role: "assistant",
|
|
666
|
+
content: [
|
|
667
|
+
{
|
|
668
|
+
type: "web_search_tool_result",
|
|
669
|
+
tool_use_id: "stu_split",
|
|
670
|
+
content: [
|
|
671
|
+
{
|
|
672
|
+
type: "web_search_result",
|
|
673
|
+
url: "https://example.com",
|
|
674
|
+
title: "Example",
|
|
675
|
+
},
|
|
676
|
+
],
|
|
677
|
+
},
|
|
678
|
+
{ type: "text", text: "Found it." },
|
|
679
|
+
],
|
|
680
|
+
},
|
|
681
|
+
];
|
|
682
|
+
|
|
683
|
+
const { messages: repaired, stats } = repairHistory(messages);
|
|
684
|
+
|
|
685
|
+
expect(stats.missingToolResultsInserted).toBe(0);
|
|
686
|
+
expect(stats.orphanToolResultsDowngraded).toBe(0);
|
|
687
|
+
expect(repaired[1].content.map((b) => b.type)).toEqual([
|
|
688
|
+
"tool_use",
|
|
689
|
+
"server_tool_use",
|
|
690
|
+
]);
|
|
691
|
+
expect(repaired[3].content.map((b) => b.type)).toEqual([
|
|
692
|
+
"web_search_tool_result",
|
|
693
|
+
"text",
|
|
694
|
+
]);
|
|
695
|
+
});
|
|
696
|
+
|
|
609
697
|
test("synthetic web_search_tool_result is placed immediately after its server_tool_use, not at end", () => {
|
|
610
698
|
// Regression: synthetic results appended to the end of the content array
|
|
611
699
|
// get separated from their server_tool_use by ensureToolPairing's split
|
|
@@ -648,6 +736,12 @@ describe("repairHistory", () => {
|
|
|
648
736
|
},
|
|
649
737
|
],
|
|
650
738
|
},
|
|
739
|
+
// A later assistant message closes the deferral window: the searches
|
|
740
|
+
// never executed, so they are genuine orphans.
|
|
741
|
+
{
|
|
742
|
+
role: "assistant",
|
|
743
|
+
content: [{ type: "text", text: "Skill ready." }],
|
|
744
|
+
},
|
|
651
745
|
];
|
|
652
746
|
|
|
653
747
|
const { messages: repaired, stats } = repairHistory(messages);
|
|
@@ -866,6 +960,12 @@ describe("repairHistory", () => {
|
|
|
866
960
|
},
|
|
867
961
|
],
|
|
868
962
|
},
|
|
963
|
+
// A later exchange closes the deferral window for stu_missing_result.
|
|
964
|
+
{ role: "user", content: [{ type: "text", text: "and?" }] },
|
|
965
|
+
{
|
|
966
|
+
role: "assistant",
|
|
967
|
+
content: [{ type: "text", text: "done" }],
|
|
968
|
+
},
|
|
869
969
|
];
|
|
870
970
|
|
|
871
971
|
const { messages: repaired, stats } = repairHistory(messages);
|
|
@@ -742,8 +742,11 @@ describe("HostBashProxy", () => {
|
|
|
742
742
|
});
|
|
743
743
|
|
|
744
744
|
describe("same-user binding (sourceActorPrincipalId)", () => {
|
|
745
|
-
|
|
746
|
-
|
|
745
|
+
// The proxy path names which comparison failed, so each rejection asserts
|
|
746
|
+
// its own reason — a turn with no actor, a client registered without one,
|
|
747
|
+
// and two genuinely different users are three different problems.
|
|
748
|
+
const CROSS_USER_REJECTION =
|
|
749
|
+
"Submitting actor does not match the target client's actor for this request. The target client is signed in as a different user — run `assistant clients list` to see which connected clients you own.";
|
|
747
750
|
|
|
748
751
|
test("same-user targeted request succeeds", async () => {
|
|
749
752
|
setup();
|
|
@@ -784,7 +787,7 @@ describe("HostBashProxy", () => {
|
|
|
784
787
|
);
|
|
785
788
|
|
|
786
789
|
expect(result.isError).toBe(true);
|
|
787
|
-
expect(result.content).toBe(
|
|
790
|
+
expect(result.content).toBe(CROSS_USER_REJECTION);
|
|
788
791
|
// No broadcast and no pending registration
|
|
789
792
|
expect(sentMessages).toHaveLength(0);
|
|
790
793
|
});
|
|
@@ -807,7 +810,9 @@ describe("HostBashProxy", () => {
|
|
|
807
810
|
);
|
|
808
811
|
|
|
809
812
|
expect(result.isError).toBe(true);
|
|
810
|
-
expect(result.content).
|
|
813
|
+
expect(result.content).toContain(
|
|
814
|
+
"registered without an authenticated user",
|
|
815
|
+
);
|
|
811
816
|
expect(sentMessages).toHaveLength(0);
|
|
812
817
|
});
|
|
813
818
|
|
|
@@ -823,7 +828,7 @@ describe("HostBashProxy", () => {
|
|
|
823
828
|
);
|
|
824
829
|
|
|
825
830
|
expect(result.isError).toBe(true);
|
|
826
|
-
expect(result.content).
|
|
831
|
+
expect(result.content).toContain("no authenticated actor");
|
|
827
832
|
expect(sentMessages).toHaveLength(0);
|
|
828
833
|
});
|
|
829
834
|
|
|
@@ -312,6 +312,73 @@ describe("handleHostBashResult", () => {
|
|
|
312
312
|
});
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
+
// ── Fill-if-missing: persisted target healed after registration ────
|
|
316
|
+
//
|
|
317
|
+
// A request registered while the target's SSE record had no principal
|
|
318
|
+
// persists `targetActorPrincipalId: undefined`. Once the SSE self-heal
|
|
319
|
+
// fills the hub record, the result route re-reads the live record,
|
|
320
|
+
// but ONLY when the persisted value is missing.
|
|
321
|
+
|
|
322
|
+
describe("targeted request - missing persisted target principal fills from the live hub record", () => {
|
|
323
|
+
test("accepts a matching submitter when the hub record was healed after registration", async () => {
|
|
324
|
+
const requestId = "req-healed-target";
|
|
325
|
+
// Registered pre-heal: hub had no principal, so nothing was persisted.
|
|
326
|
+
registerPending(requestId, { targetClientId: "client-abc" });
|
|
327
|
+
// SSE self-heal fills the hub record afterwards.
|
|
328
|
+
clientActorPrincipals.set("client-abc", "principal-shared");
|
|
329
|
+
|
|
330
|
+
const result = await handleHostBashResult({
|
|
331
|
+
body: bashBody(requestId),
|
|
332
|
+
headers: {
|
|
333
|
+
"x-vellum-client-id": "client-abc",
|
|
334
|
+
"x-vellum-actor-principal-id": "principal-shared",
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
expect(result).toEqual({ accepted: true });
|
|
339
|
+
expect(resolvedIds).toContain(requestId);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test("still throws ForbiddenError (403) for a submitter with a different principal than the healed target", () => {
|
|
343
|
+
const requestId = "req-healed-target-mismatch";
|
|
344
|
+
registerPending(requestId, { targetClientId: "client-abc" });
|
|
345
|
+
clientActorPrincipals.set("client-abc", "principal-victim");
|
|
346
|
+
|
|
347
|
+
expect(() =>
|
|
348
|
+
handleHostBashResult({
|
|
349
|
+
body: bashBody(requestId),
|
|
350
|
+
headers: {
|
|
351
|
+
"x-vellum-client-id": "client-abc",
|
|
352
|
+
"x-vellum-actor-principal-id": "principal-attacker",
|
|
353
|
+
},
|
|
354
|
+
}),
|
|
355
|
+
).toThrow(ForbiddenError);
|
|
356
|
+
expect(pendingStore.has(requestId)).toBe(true);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test("a present persisted principal always wins over the live hub record", () => {
|
|
360
|
+
// The fill is missing-only: a persisted value captured at registration
|
|
361
|
+
// is never overridden, so a submitter matching only the (different)
|
|
362
|
+
// live record is still rejected.
|
|
363
|
+
const requestId = "req-persisted-wins";
|
|
364
|
+
registerPending(requestId, {
|
|
365
|
+
targetClientId: "client-abc",
|
|
366
|
+
targetActorPrincipalId: "principal-registration",
|
|
367
|
+
});
|
|
368
|
+
clientActorPrincipals.set("client-abc", "principal-live");
|
|
369
|
+
|
|
370
|
+
expect(() =>
|
|
371
|
+
handleHostBashResult({
|
|
372
|
+
body: bashBody(requestId),
|
|
373
|
+
headers: {
|
|
374
|
+
"x-vellum-client-id": "client-abc",
|
|
375
|
+
"x-vellum-actor-principal-id": "principal-live",
|
|
376
|
+
},
|
|
377
|
+
}),
|
|
378
|
+
).toThrow(ForbiddenError);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
315
382
|
// ── Untargeted-request behavior (regression for new check) ─────────
|
|
316
383
|
|
|
317
384
|
describe("untargeted request — actor principal check is skipped", () => {
|
|
@@ -867,7 +867,7 @@ describe("HostBrowserProxy", () => {
|
|
|
867
867
|
);
|
|
868
868
|
|
|
869
869
|
expect(result.isError).toBe(true);
|
|
870
|
-
expect(result.content).toContain("
|
|
870
|
+
expect(result.content).toContain("signed in as a different user");
|
|
871
871
|
expect(getPublishedMessages()).toHaveLength(0);
|
|
872
872
|
});
|
|
873
873
|
|
|
@@ -1054,7 +1054,7 @@ describe("HostBrowserProxy", () => {
|
|
|
1054
1054
|
);
|
|
1055
1055
|
|
|
1056
1056
|
expect(result.isError).toBe(true);
|
|
1057
|
-
expect(result.content).toContain("
|
|
1057
|
+
expect(result.content).toContain("signed in as a different user");
|
|
1058
1058
|
expect(result.content).not.toContain("extension_required");
|
|
1059
1059
|
expect(getPublishedMessages()).toHaveLength(0);
|
|
1060
1060
|
});
|
|
@@ -1416,9 +1416,7 @@ describe("HostCuProxy", () => {
|
|
|
1416
1416
|
);
|
|
1417
1417
|
|
|
1418
1418
|
expect(result.isError).toBe(true);
|
|
1419
|
-
expect(result.content).toContain(
|
|
1420
|
-
"Submitting actor does not match the target client's actor",
|
|
1421
|
-
);
|
|
1419
|
+
expect(result.content).toContain("signed in as a different user");
|
|
1422
1420
|
expect(sentMessages).toHaveLength(0);
|
|
1423
1421
|
});
|
|
1424
1422
|
|
|
@@ -1444,9 +1442,7 @@ describe("HostCuProxy", () => {
|
|
|
1444
1442
|
);
|
|
1445
1443
|
|
|
1446
1444
|
expect(result.isError).toBe(true);
|
|
1447
|
-
expect(result.content).toContain(
|
|
1448
|
-
"Submitting actor does not match the target client's actor",
|
|
1449
|
-
);
|
|
1445
|
+
expect(result.content).toContain("no authenticated actor");
|
|
1450
1446
|
expect(sentMessages).toHaveLength(0);
|
|
1451
1447
|
});
|
|
1452
1448
|
|
|
@@ -1473,7 +1469,7 @@ describe("HostCuProxy", () => {
|
|
|
1473
1469
|
|
|
1474
1470
|
expect(result.isError).toBe(true);
|
|
1475
1471
|
expect(result.content).toContain(
|
|
1476
|
-
"
|
|
1472
|
+
"registered without an authenticated user",
|
|
1477
1473
|
);
|
|
1478
1474
|
expect(sentMessages).toHaveLength(0);
|
|
1479
1475
|
});
|
|
@@ -693,9 +693,7 @@ describe("HostFileProxy", () => {
|
|
|
693
693
|
);
|
|
694
694
|
|
|
695
695
|
expect(result.isError).toBe(true);
|
|
696
|
-
expect(result.content).toContain(
|
|
697
|
-
"Submitting actor does not match the target client's actor",
|
|
698
|
-
);
|
|
696
|
+
expect(result.content).toContain("signed in as a different user");
|
|
699
697
|
// No host_file_request was broadcast.
|
|
700
698
|
expect(sentMessages).toHaveLength(0);
|
|
701
699
|
});
|
|
@@ -720,7 +718,7 @@ describe("HostFileProxy", () => {
|
|
|
720
718
|
|
|
721
719
|
expect(result.isError).toBe(true);
|
|
722
720
|
expect(result.content).toContain(
|
|
723
|
-
"
|
|
721
|
+
"registered without an authenticated user",
|
|
724
722
|
);
|
|
725
723
|
expect(sentMessages).toHaveLength(0);
|
|
726
724
|
});
|
|
@@ -744,9 +742,7 @@ describe("HostFileProxy", () => {
|
|
|
744
742
|
);
|
|
745
743
|
|
|
746
744
|
expect(result.isError).toBe(true);
|
|
747
|
-
expect(result.content).toContain(
|
|
748
|
-
"Submitting actor does not match the target client's actor",
|
|
749
|
-
);
|
|
745
|
+
expect(result.content).toContain("no authenticated actor");
|
|
750
746
|
expect(sentMessages).toHaveLength(0);
|
|
751
747
|
});
|
|
752
748
|
|
|
@@ -27,6 +27,7 @@ mock.module("../daemon/host-file-proxy.js", () => ({
|
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
29
|
import { hostFileReadTool } from "../tools/host-filesystem/read.js";
|
|
30
|
+
import { DEFAULT_READ_LINE_LIMIT } from "../tools/shared/filesystem/file-ops-service.js";
|
|
30
31
|
import type { ToolContext } from "../tools/types.js";
|
|
31
32
|
|
|
32
33
|
const testDirs: string[] = [];
|
|
@@ -226,13 +227,16 @@ describe("host_file_read image support", () => {
|
|
|
226
227
|
|
|
227
228
|
expect(result.isError).toBe(false);
|
|
228
229
|
expect(result.contentBlocks).toHaveLength(1);
|
|
230
|
+
// The proxied request carries the resolved default window, so a host read
|
|
231
|
+
// is bounded by the same limit as a local one rather than streaming a
|
|
232
|
+
// whole file across the bridge.
|
|
229
233
|
expect(requests).toEqual([
|
|
230
234
|
{
|
|
231
235
|
input: {
|
|
232
236
|
operation: "read",
|
|
233
237
|
path: "/host/screenshot.png",
|
|
234
238
|
offset: undefined,
|
|
235
|
-
limit:
|
|
239
|
+
limit: DEFAULT_READ_LINE_LIMIT,
|
|
236
240
|
},
|
|
237
241
|
conversationId: "test-conversation",
|
|
238
242
|
signal: undefined,
|