@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2
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/AGENTS.md +9 -3
- package/ARCHITECTURE.md +32 -10
- package/docs/architecture/memory.md +43 -5
- package/docs/architecture/security.md +96 -152
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/browser-use-architecture-phase2.md +128 -56
- package/docs/flux-turn-detection-spike.md +248 -0
- package/docs/guardian-request-flow.md +35 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/knip.json +3 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +289 -113
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/scripts/write-plugin-api-shim.ts +10 -0
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/app-control-flow.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/compaction-events.test.ts +8 -10
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +32 -21
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +154 -4
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/conversation-slash-queue.test.ts +3 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/document-sync-tags.test.ts +0 -75
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -11
- package/src/__tests__/file-ops-service.test.ts +163 -30
- package/src/__tests__/filesystem-tools.test.ts +23 -24
- package/src/__tests__/gateway-only-guard.test.ts +2 -5
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/host-file-read-tool.test.ts +16 -19
- package/src/__tests__/http-user-message-parity.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/media-generate-image.test.ts +131 -21
- package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +3 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/proxy-approval-callback.test.ts +1 -0
- package/src/__tests__/qdrant-manager.test.ts +14 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
- package/src/__tests__/run-due-schedules.test.ts +21 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
- package/src/__tests__/schedule-routes.test.ts +23 -0
- package/src/__tests__/schedule-store.test.ts +17 -0
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -3
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +81 -101
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +68 -39
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-visual-surface.test.ts +1 -1
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/ui-work-result-surface.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
- package/src/__tests__/voice-session-bridge.test.ts +85 -29
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +76 -3
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/events/host-file.ts +2 -2
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +12 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
- package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +115 -41
- package/src/calls/voice-triage-escalate.ts +105 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/bundled-modules.ts +29 -0
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/db/repair.ts +4 -8
- package/src/cli/commands/domain.ts +6 -3
- package/src/cli/commands/email.ts +6 -3
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +84 -28
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/plugins.ts +85 -36
- package/src/cli/commands/schedules.ts +35 -1
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +14 -1
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/assistant-feature-flags.ts +36 -15
- package/src/config/balanced-model-experiment.ts +35 -0
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -12
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/call-site-defaults.ts +11 -5
- package/src/config/default-profile-catalog.ts +179 -16
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/feature-flag-registry.json +12 -12
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/skills.ts +9 -2
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +31 -19
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +20 -10
- package/src/daemon/conversation-process.ts +20 -6
- package/src/daemon/conversation-runtime-assembly.ts +12 -6
- package/src/daemon/conversation-store.ts +14 -4
- package/src/daemon/conversation-surfaces.ts +75 -26
- package/src/daemon/conversation-tool-setup.ts +3 -6
- package/src/daemon/conversation.ts +154 -51
- package/src/daemon/doordash-steps.ts +2 -2
- package/src/daemon/lifecycle.ts +14 -1
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +13 -26
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/trust-context.ts +12 -7
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/daemon/windows-compiled-entry.ts +4 -0
- package/src/documents/document-store.ts +143 -240
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +103 -45
- package/src/hooks/types.ts +5 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/gateway-flag-listener.ts +17 -3
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-manager.ts +16 -3
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +598 -323
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/live-voice/windows-compiled-live-voice.ts +4 -0
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/control.ts +1 -0
- package/src/monitoring/db-integrity-sample.ts +4 -5
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/approval-card-data.ts +33 -0
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -5
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +182 -52
- package/src/persistence/delivery-crud.ts +150 -36
- package/src/persistence/embeddings/qdrant-manager.ts +84 -49
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/schema/documents.ts +4 -4
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/constants.ts +8 -0
- package/src/plugin-api/conversation-turn.ts +195 -5
- package/src/plugin-api/index.ts +38 -6
- package/src/plugin-api/resolve-credential.ts +3 -2
- package/src/plugin-api/store-credential.ts +146 -0
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugin-api/webhook-url.ts +13 -11
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/main.ts +21 -7
- package/src/plugins/defaults/memory/AGENTS.md +15 -3
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/defaults/memory/v3/injector.ts +8 -0
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
- package/src/plugins/defaults/memory/worker-control.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/defaults/worker-entrypoints.ts +3 -0
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +37 -46
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/prompts/templates/system-sections.ts +0 -7
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -2
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +133 -36
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/control.ts +1 -0
- package/src/routes/route-host-client.ts +1 -0
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +48 -15
- package/src/runtime/AGENTS.md +16 -17
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +18 -15
- package/src/runtime/effective-capabilities.test.ts +43 -0
- package/src/runtime/effective-capabilities.ts +27 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +181 -23
- package/src/runtime/routes/conversation-management-routes.ts +17 -12
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/conversation-routes.ts +43 -29
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/credential-routes.ts +26 -82
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/documents-routes.ts +3 -222
- package/src/runtime/routes/inbound-message-handler.ts +21 -45
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -2
- package/src/runtime/routes/playground/reset-circuit.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +38 -8
- package/src/runtime/routes/schedule-routes.ts +94 -7
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +69 -15
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/routes/workspace-routes.ts +0 -9
- package/src/runtime/routes/workspace-utils.ts +3 -13
- package/src/runtime/services/conversation-serializer.ts +7 -2
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
- package/src/schedule/plugin-schedule-availability.ts +58 -0
- package/src/schedule/plugin-schedule-declarations.ts +23 -27
- package/src/schedule/plugin-schedule-reconciler.ts +12 -3
- package/src/schedule/schedule-store.ts +5 -1
- package/src/schedule/scheduler.ts +9 -4
- package/src/schedule/worker-control.ts +1 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
- package/src/subagent/consult-context.ts +11 -11
- package/src/subagent/consult-prompt.ts +26 -35
- package/src/subagent/manager.ts +21 -40
- package/src/subagent/notify.ts +7 -1
- package/src/subagent/types.ts +15 -12
- package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +38 -4
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/executor.ts +53 -15
- package/src/tools/filesystem/read.ts +27 -10
- package/src/tools/host-filesystem/read.ts +27 -15
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/registry.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
- package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
- package/src/tools/shared/filesystem/types.ts +5 -5
- package/src/tools/skills/scaffold-managed.ts +25 -7
- package/src/tools/subagent/spawn.ts +28 -88
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/__tests__/worker-process-command.test.ts +37 -0
- package/src/util/logger.ts +16 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/util/worker-process.ts +37 -4
- package/src/windows-compiled-cli.ts +32 -0
- package/src/windows-compiled-entry.ts +4 -0
- package/src/windows-compiled-logger.ts +6 -0
- package/src/windows-compiled-worker-entry.ts +29 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/__tests__/document-workspace-file.test.ts +0 -467
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
- package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
- package/src/subagent/consult-transcript.ts +0 -90
|
@@ -40,6 +40,18 @@ mock.module("../daemon/conversation-store.js", () => ({
|
|
|
40
40
|
},
|
|
41
41
|
}));
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Whether the daemon activated the fixture plugin. Run-now answers only for
|
|
45
|
+
* plugins this process brought up, and no route test runs the plugin loader,
|
|
46
|
+
* so the double says "activated" unless a case turns it off.
|
|
47
|
+
*/
|
|
48
|
+
let pluginActivated = true;
|
|
49
|
+
const realMtimeCache = await import("../plugins/mtime-cache.js");
|
|
50
|
+
mock.module("../plugins/mtime-cache.js", () => ({
|
|
51
|
+
...realMtimeCache,
|
|
52
|
+
isPluginDirActivated: () => pluginActivated,
|
|
53
|
+
}));
|
|
54
|
+
|
|
43
55
|
import type { AssistantEventEnvelope } from "../api/index.js";
|
|
44
56
|
import { SYNC_TAGS } from "../daemon/message-types/sync.js";
|
|
45
57
|
import {
|
|
@@ -1574,6 +1586,7 @@ describe("plugin-sourced schedules over routes", () => {
|
|
|
1574
1586
|
|
|
1575
1587
|
beforeEach(() => {
|
|
1576
1588
|
rmSync(RUN_MARKER, { force: true });
|
|
1589
|
+
pluginActivated = true;
|
|
1577
1590
|
});
|
|
1578
1591
|
|
|
1579
1592
|
function seedSourcedScript() {
|
|
@@ -1626,6 +1639,16 @@ describe("plugin-sourced schedules over routes", () => {
|
|
|
1626
1639
|
expect(existsSync(RUN_MARKER)).toBe(false);
|
|
1627
1640
|
});
|
|
1628
1641
|
|
|
1642
|
+
test("refuses a sourced row whose plugin the daemon never activated", async () => {
|
|
1643
|
+
const sourced = await seedSourcedScript();
|
|
1644
|
+
// The declaration is intact on disk, but nothing ran the plugin's
|
|
1645
|
+
// `init`, so run-now must not execute its script.
|
|
1646
|
+
pluginActivated = false;
|
|
1647
|
+
|
|
1648
|
+
await expect(runNow(sourced.id)).rejects.toThrow(BadRequestError);
|
|
1649
|
+
expect(existsSync(RUN_MARKER)).toBe(false);
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1629
1652
|
test("runs a sourced row whose plugin is healthy", async () => {
|
|
1630
1653
|
const sourced = await seedSourcedScript();
|
|
1631
1654
|
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "../persistence/conversation-crud.js";
|
|
24
24
|
import { getDb } from "../persistence/db-connection.js";
|
|
25
25
|
import { initializeDb } from "../persistence/db-init.js";
|
|
26
|
+
import { isPluginDirActivated } from "../plugins/mtime-cache.js";
|
|
26
27
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
27
28
|
import {
|
|
28
29
|
hasOwnerDeferProvenance,
|
|
@@ -1856,6 +1857,22 @@ describe("declared schedules", () => {
|
|
|
1856
1857
|
expect(result!.enabled).toBe(false);
|
|
1857
1858
|
});
|
|
1858
1859
|
|
|
1860
|
+
test("enabling a schedule re-arms it on the on-disk declaration alone", async () => {
|
|
1861
|
+
const created = await upsertDeclaredSchedule(SOURCE_KEY, makeDefinition());
|
|
1862
|
+
await setUserEnabled(created.id, false);
|
|
1863
|
+
// A schedule tool reaches this from a conversation turn, which can run in
|
|
1864
|
+
// a sidecar worker process where no plugin is activated. The probe must
|
|
1865
|
+
// therefore read the disk alone: asking about activation here would refuse
|
|
1866
|
+
// every re-enable. Whether the plugin stays armed is the reconciler's
|
|
1867
|
+
// call, and its next sweep disarms the row if it should not be.
|
|
1868
|
+
expect(isPluginDirActivated(examplePluginDir())).toBe(false);
|
|
1869
|
+
|
|
1870
|
+
const result = await setUserEnabled(created.id, true);
|
|
1871
|
+
|
|
1872
|
+
expect(result!.userEnabled).toBe(true);
|
|
1873
|
+
expect(result!.enabled).toBe(true);
|
|
1874
|
+
});
|
|
1875
|
+
|
|
1859
1876
|
test("enabling a schedule whose plugin manifest is broken records the override without re-arming", async () => {
|
|
1860
1877
|
const created = await upsertDeclaredSchedule(SOURCE_KEY, makeDefinition());
|
|
1861
1878
|
await setUserEnabled(created.id, false);
|
|
@@ -375,19 +375,24 @@ describe("scoped-approval-grants / expiry", () => {
|
|
|
375
375
|
});
|
|
376
376
|
|
|
377
377
|
test("already-consumed grants are not affected by expiry sweep", () => {
|
|
378
|
-
const
|
|
378
|
+
const expiresAt = Date.now() + 60_000;
|
|
379
379
|
createScopedApprovalGrant(
|
|
380
380
|
grantParams({
|
|
381
381
|
scopeMode: "request_id",
|
|
382
382
|
requestId: "req-consumed",
|
|
383
|
-
expiresAt
|
|
383
|
+
expiresAt,
|
|
384
384
|
}),
|
|
385
385
|
);
|
|
386
|
-
consumeScopedApprovalGrantByRequestId(
|
|
386
|
+
const consumed = consumeScopedApprovalGrantByRequestId(
|
|
387
|
+
"req-consumed",
|
|
388
|
+
"c1",
|
|
389
|
+
expiresAt - 1,
|
|
390
|
+
);
|
|
391
|
+
expect(consumed.ok).toBe(true);
|
|
387
392
|
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
const count = expireScopedApprovalGrants();
|
|
393
|
+
// Sweep after the grant's expiresAt. Status is consumed, so the active-only
|
|
394
|
+
// expiry update must leave it alone.
|
|
395
|
+
const count = expireScopedApprovalGrants(expiresAt);
|
|
391
396
|
expect(count).toBe(0);
|
|
392
397
|
});
|
|
393
398
|
});
|
|
@@ -155,7 +155,7 @@ const runAgentLoopMock = mock(async () => undefined);
|
|
|
155
155
|
function makeSendMessageDeps() {
|
|
156
156
|
const session = {
|
|
157
157
|
setTrustContext: () => {},
|
|
158
|
-
|
|
158
|
+
replayActivityState: () => {},
|
|
159
159
|
emitConfirmationStateChanged: () => {},
|
|
160
160
|
emitActivityState: () => {},
|
|
161
161
|
setTurnChannelContext: () => {},
|
|
@@ -130,7 +130,7 @@ function makeCompletingConversation(): Conversation {
|
|
|
130
130
|
setTurnInterfaceContext: () => {},
|
|
131
131
|
ensureActorScopedHistory: async () => {},
|
|
132
132
|
usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
|
|
133
|
-
|
|
133
|
+
replayActivityState: () => {},
|
|
134
134
|
setHostBrowserProxy: () => {},
|
|
135
135
|
setHostCuProxy: () => {},
|
|
136
136
|
setHostAppControlProxy: () => {},
|
|
@@ -180,7 +180,7 @@ function makeHangingConversation(): Conversation {
|
|
|
180
180
|
setTurnInterfaceContext: () => {},
|
|
181
181
|
ensureActorScopedHistory: async () => {},
|
|
182
182
|
usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
|
|
183
|
-
|
|
183
|
+
replayActivityState: () => {},
|
|
184
184
|
setHostBrowserProxy: () => {},
|
|
185
185
|
setHostCuProxy: () => {},
|
|
186
186
|
setHostAppControlProxy: () => {},
|
|
@@ -261,7 +261,7 @@ function makePendingApprovalConversation(
|
|
|
261
261
|
setTurnInterfaceContext: () => {},
|
|
262
262
|
ensureActorScopedHistory: async () => {},
|
|
263
263
|
usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
|
|
264
|
-
|
|
264
|
+
replayActivityState: () => {},
|
|
265
265
|
setHostBrowserProxy: () => {},
|
|
266
266
|
setHostCuProxy: () => {},
|
|
267
267
|
setHostAppControlProxy: () => {},
|
|
@@ -825,6 +825,38 @@ describe("always-candidate frontmatter parsing", () => {
|
|
|
825
825
|
.map(({ id, chars }) => `${id}: ${chars}`);
|
|
826
826
|
expect(overrun).toEqual([]);
|
|
827
827
|
});
|
|
828
|
+
|
|
829
|
+
test("the bundled acp skill's card fits the default budget", async () => {
|
|
830
|
+
// `acp` owns Claude Code and Codex setup, sign-in, and delegation, and the
|
|
831
|
+
// terms that route those turns to it live in this card. The card is
|
|
832
|
+
// hard-truncated at the default budget, so an overrun drops the trailing
|
|
833
|
+
// hints and the whole avoid-when list from what the selector sees.
|
|
834
|
+
const { DEFAULT_CARD_CHARS, buildSkillContent } =
|
|
835
|
+
await import("../plugins/defaults/memory/substrate/skill-content.js");
|
|
836
|
+
const acp = loadSkillCatalog().find((skill) => skill.id === "acp");
|
|
837
|
+
expect(acp).toBeDefined();
|
|
838
|
+
|
|
839
|
+
// A card that overran is cut to exactly the budget, so staying under it is
|
|
840
|
+
// what proves nothing was dropped. `avoid-when` is appended last and is
|
|
841
|
+
// therefore the first content a truncation eats.
|
|
842
|
+
const card = buildSkillContent(acp!);
|
|
843
|
+
expect(card.length).toBeLessThan(DEFAULT_CARD_CHARS);
|
|
844
|
+
expect(card).toContain("Avoid when:");
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
test("the bundled acp card carries its setup and sign-in vocabulary", async () => {
|
|
848
|
+
// A "configure Claude Code" or "let's do the auth" turn only reaches this
|
|
849
|
+
// skill if the card actually says it covers setup and authentication;
|
|
850
|
+
// delegation-only wording routes those turns to a terminal skill instead.
|
|
851
|
+
const { buildSkillContent } =
|
|
852
|
+
await import("../plugins/defaults/memory/substrate/skill-content.js");
|
|
853
|
+
const acp = loadSkillCatalog().find((skill) => skill.id === "acp");
|
|
854
|
+
const card = buildSkillContent(acp!).toLowerCase();
|
|
855
|
+
|
|
856
|
+
for (const term of ["set up", "install", "authenticate", "connect"]) {
|
|
857
|
+
expect(card).toContain(term);
|
|
858
|
+
}
|
|
859
|
+
});
|
|
828
860
|
});
|
|
829
861
|
|
|
830
862
|
describe("bundled skill categories", () => {
|
|
@@ -39,10 +39,12 @@ import {
|
|
|
39
39
|
} from "../daemon/conversation-surfaces.js";
|
|
40
40
|
import { asConversation } from "./helpers/mock-conversation.js";
|
|
41
41
|
|
|
42
|
-
function makeContext(
|
|
42
|
+
function makeContext(
|
|
43
|
+
emit: (msg: AssistantEvent) => void = () => {},
|
|
44
|
+
): Conversation {
|
|
43
45
|
return asConversation({
|
|
44
46
|
conversationId: "session-1",
|
|
45
|
-
|
|
47
|
+
emit,
|
|
46
48
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
47
49
|
lastSurfaceAction: new Map<
|
|
48
50
|
string,
|
|
@@ -131,8 +133,7 @@ describe("starter task surface actions", () => {
|
|
|
131
133
|
|
|
132
134
|
test("app_open registers dynamic_page surface as action-capable", async () => {
|
|
133
135
|
const sent: AssistantEvent[] = [];
|
|
134
|
-
const ctx = makeContext();
|
|
135
|
-
ctx.sendToClient = (msg) => sent.push(msg);
|
|
136
|
+
const ctx = makeContext((msg) => sent.push(msg));
|
|
136
137
|
|
|
137
138
|
const result = await surfaceProxyResolver(ctx, "app_open", {
|
|
138
139
|
app_id: "test-app",
|
|
@@ -184,8 +184,11 @@ import {
|
|
|
184
184
|
clearConversations,
|
|
185
185
|
setConversation,
|
|
186
186
|
} from "../daemon/conversation-registry.js";
|
|
187
|
+
import type { TrustContext } from "../daemon/trust-context-types.js";
|
|
187
188
|
import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
|
|
188
189
|
import { SubagentManager } from "../subagent/manager.js";
|
|
190
|
+
import { mockAuthContext } from "./helpers/mock-actor-context.js";
|
|
191
|
+
import { asConversation } from "./helpers/mock-conversation.js";
|
|
189
192
|
|
|
190
193
|
// Seed the workspace `llm` config per-case. The real loader schema-merges the
|
|
191
194
|
// raw fragment over defaults exactly as the code path reads it.
|
|
@@ -304,26 +307,29 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
304
307
|
test("copies parent guardian and auth context into spawned conversation", async () => {
|
|
305
308
|
setLlmConfig(makeLlmFixture());
|
|
306
309
|
|
|
307
|
-
const parentTrustContext = {
|
|
310
|
+
const parentTrustContext: TrustContext = {
|
|
308
311
|
sourceChannel: "vellum",
|
|
309
312
|
trustClass: "guardian",
|
|
310
313
|
guardianPrincipalId: "guardian-1",
|
|
311
314
|
guardianExternalUserId: "guardian-1",
|
|
312
315
|
};
|
|
313
|
-
const parentAuthContext = {
|
|
316
|
+
const parentAuthContext = mockAuthContext({
|
|
314
317
|
subject: "local:self:parent-perms",
|
|
315
318
|
actorPrincipalId: "guardian-1",
|
|
316
|
-
};
|
|
319
|
+
});
|
|
317
320
|
|
|
318
321
|
capturedConversations.length = 0;
|
|
319
322
|
clearConversations();
|
|
320
323
|
const manager = new SubagentManager();
|
|
321
|
-
setConversation(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
setConversation(
|
|
325
|
+
"parent-perms",
|
|
326
|
+
asConversation({
|
|
327
|
+
trustContext: parentTrustContext,
|
|
328
|
+
getAuthContext: () => parentAuthContext,
|
|
329
|
+
assistantId: "self",
|
|
330
|
+
getCurrentSystemPrompt: () => "parent system",
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
327
333
|
|
|
328
334
|
await manager.spawn(
|
|
329
335
|
{
|
|
@@ -354,11 +360,14 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
354
360
|
capturedConversations.length = 0;
|
|
355
361
|
clearConversations();
|
|
356
362
|
const manager = new SubagentManager();
|
|
357
|
-
setConversation(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
363
|
+
setConversation(
|
|
364
|
+
"parent-scoped",
|
|
365
|
+
asConversation({
|
|
366
|
+
enabledPlugins: parentScope,
|
|
367
|
+
getAuthContext: () => undefined,
|
|
368
|
+
getCurrentSystemPrompt: () => "parent system",
|
|
369
|
+
}),
|
|
370
|
+
);
|
|
362
371
|
|
|
363
372
|
await manager.spawn(
|
|
364
373
|
{
|
|
@@ -383,11 +392,14 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
383
392
|
capturedConversations.length = 0;
|
|
384
393
|
clearConversations();
|
|
385
394
|
const manager = new SubagentManager();
|
|
386
|
-
setConversation(
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
395
|
+
setConversation(
|
|
396
|
+
"parent-unscoped",
|
|
397
|
+
asConversation({
|
|
398
|
+
enabledPlugins: null,
|
|
399
|
+
getAuthContext: () => undefined,
|
|
400
|
+
getCurrentSystemPrompt: () => "parent system",
|
|
401
|
+
}),
|
|
402
|
+
);
|
|
391
403
|
|
|
392
404
|
await manager.spawn(
|
|
393
405
|
{
|
|
@@ -182,7 +182,7 @@ describe("SubagentManager fork — prompt source and role decoupling", () => {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
test("fork with systemPromptOverride uses that prompt and does not set hasSystemPromptOverride", async () => {
|
|
185
|
-
const overridePrompt = "You are
|
|
185
|
+
const overridePrompt = "You are a reviewer. Frame the context as review.";
|
|
186
186
|
const created = await spawnFork({ systemPromptOverride: overridePrompt });
|
|
187
187
|
|
|
188
188
|
expect(created.systemPrompt).toBe(overridePrompt);
|
|
@@ -207,6 +207,7 @@ import {
|
|
|
207
207
|
setConversation,
|
|
208
208
|
} from "../daemon/conversation-registry.js";
|
|
209
209
|
import { SubagentAbortedError, SubagentManager } from "../subagent/manager.js";
|
|
210
|
+
import { asConversation } from "./helpers/mock-conversation.js";
|
|
210
211
|
|
|
211
212
|
function makeConfig(overrides: Record<string, unknown> = {}) {
|
|
212
213
|
return {
|
|
@@ -229,16 +230,19 @@ function registerFakeParent(parentConversationId: string): {
|
|
|
229
230
|
enqueuedCount: () => number;
|
|
230
231
|
} {
|
|
231
232
|
let enqueued = 0;
|
|
232
|
-
setConversation(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
233
|
+
setConversation(
|
|
234
|
+
parentConversationId,
|
|
235
|
+
asConversation({
|
|
236
|
+
// Accessors read by setUpSubagent when copying trust/auth context.
|
|
237
|
+
trustContext: undefined,
|
|
238
|
+
getAuthContext: () => undefined,
|
|
239
|
+
assistantId: undefined,
|
|
240
|
+
enqueueMessage: () => {
|
|
241
|
+
enqueued += 1;
|
|
242
|
+
return { rejected: false, queued: true, requestId: "req-fake" };
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
242
246
|
return { enqueuedCount: () => enqueued };
|
|
243
247
|
}
|
|
244
248
|
|
|
@@ -585,20 +589,17 @@ describe("SubagentManager — first user message framing", () => {
|
|
|
585
589
|
await manager.spawnAndAwait(
|
|
586
590
|
makeConfig({
|
|
587
591
|
objective: "Please advise.",
|
|
588
|
-
fork: true,
|
|
589
592
|
role: "advisor",
|
|
593
|
+
spawnMode: "advisor_consult",
|
|
590
594
|
// The advisor always supplies its own framing; setUpSubagent uses it
|
|
591
|
-
//
|
|
595
|
+
// in place of a built subagent preamble.
|
|
592
596
|
systemPromptOverride: "You are a senior advisor.",
|
|
593
|
-
parentMessages: [
|
|
594
|
-
{ role: "user", content: [{ type: "text", text: "prior turn" }] },
|
|
595
|
-
],
|
|
596
597
|
}),
|
|
597
598
|
() => {},
|
|
598
599
|
);
|
|
599
600
|
|
|
600
|
-
// The
|
|
601
|
-
// directive would fight the advisor system prompt.
|
|
601
|
+
// The consult is a regular blocking spawn, so its user turn is the brief
|
|
602
|
+
// itself: the fork directive would fight the advisor system prompt.
|
|
602
603
|
expect(lastPersistedUserMessage).toBe("Please advise.");
|
|
603
604
|
expect(lastPersistedUserMessage).not.toContain("FORK TASK");
|
|
604
605
|
});
|
|
@@ -118,7 +118,7 @@ function makeSetupCtx(overrides: Partial<Conversation> = {}): Conversation {
|
|
|
118
118
|
workingDir: "/tmp/test",
|
|
119
119
|
getTurnActorPrincipalId: () => undefined,
|
|
120
120
|
abortController: null,
|
|
121
|
-
|
|
121
|
+
emit: mock(() => {}),
|
|
122
122
|
pendingSurfaceActions: new Map(),
|
|
123
123
|
lastSurfaceAction: new Map(),
|
|
124
124
|
surfaceState: new Map(),
|
|
@@ -1073,16 +1073,24 @@ describe("Subagent spawn repeat-loop guard", () => {
|
|
|
1073
1073
|
const objective = "Audit the advisor pipeline for drift";
|
|
1074
1074
|
seedSpawns("guard-advisor", objective, 6);
|
|
1075
1075
|
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1076
|
+
const manager = getSubagentManager();
|
|
1077
|
+
const originalAwait = manager.spawnAndAwait.bind(manager);
|
|
1078
|
+
manager.spawnAndAwait = (async () =>
|
|
1079
|
+
"guidance") as unknown as typeof manager.spawnAndAwait;
|
|
1080
|
+
try {
|
|
1081
|
+
const { result } = await spawnWithGuard({
|
|
1082
|
+
label: "Consult",
|
|
1083
|
+
objective,
|
|
1084
|
+
role: "advisor",
|
|
1085
|
+
});
|
|
1081
1086
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1087
|
+
// The advisor branch runs and returns its guidance, so the guard never
|
|
1088
|
+
// saw the repetition.
|
|
1089
|
+
expect(result.content).toBe("guidance");
|
|
1090
|
+
expect(result.content).not.toContain("confirm_repeat");
|
|
1091
|
+
} finally {
|
|
1092
|
+
manager.spawnAndAwait = originalAwait;
|
|
1093
|
+
}
|
|
1086
1094
|
});
|
|
1087
1095
|
|
|
1088
1096
|
test("copies still running trip the guard before any of them completes", async () => {
|
|
@@ -2831,19 +2839,27 @@ describe("Subagent output contract", () => {
|
|
|
2831
2839
|
});
|
|
2832
2840
|
|
|
2833
2841
|
test("a null contract reads as omitted and reaches the advisor branch", async () => {
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2842
|
+
const manager = getSubagentManager();
|
|
2843
|
+
const originalAwait = manager.spawnAndAwait.bind(manager);
|
|
2844
|
+
manager.spawnAndAwait = (async () =>
|
|
2845
|
+
"guidance") as unknown as typeof manager.spawnAndAwait;
|
|
2846
|
+
try {
|
|
2847
|
+
const result = await executeSubagentSpawn(
|
|
2848
|
+
{
|
|
2849
|
+
label: "Consult",
|
|
2850
|
+
objective: "Check the plan",
|
|
2851
|
+
role: "advisor",
|
|
2852
|
+
output_contract: null,
|
|
2853
|
+
},
|
|
2854
|
+
makeContext("sess-contract-advisor-none", { sendToClient: () => {} }),
|
|
2855
|
+
);
|
|
2856
|
+
// The advisor branch runs and returns its guidance, so the contract check
|
|
2857
|
+
// waved this spawn through.
|
|
2858
|
+
expect(result.content).toBe("guidance");
|
|
2859
|
+
expect(result.content).not.toContain("does not apply to the advisor");
|
|
2860
|
+
} finally {
|
|
2861
|
+
manager.spawnAndAwait = originalAwait;
|
|
2862
|
+
}
|
|
2847
2863
|
});
|
|
2848
2864
|
|
|
2849
2865
|
test("verdict defaults the child to the cost-optimized tier", async () => {
|
|
@@ -2998,7 +3014,6 @@ describe("Subagent output contract", () => {
|
|
|
2998
3014
|
// ── Advisor-role consult ────────────────────────────────────────────
|
|
2999
3015
|
|
|
3000
3016
|
describe("Subagent advisor-role consult", () => {
|
|
3001
|
-
type Block = { type: string; [k: string]: unknown };
|
|
3002
3017
|
type CapturedAwait = {
|
|
3003
3018
|
config: Record<string, unknown>;
|
|
3004
3019
|
opts?: {
|
|
@@ -3062,16 +3077,11 @@ describe("Subagent advisor-role consult", () => {
|
|
|
3062
3077
|
expect(result.content).toBe("Here is my advice.");
|
|
3063
3078
|
// Ran synchronously through spawnAndAwait, not fire-and-forget spawn.
|
|
3064
3079
|
expect(captured.current).toBeDefined();
|
|
3065
|
-
expect(captured.current!.config.fork).toBe(true);
|
|
3066
3080
|
expect(captured.current!.config.role).toBe("advisor");
|
|
3067
3081
|
// The advisor is a ROLE, not an `LLMCallSiteEnum` value, so its usage
|
|
3068
3082
|
// lands under `subagentSpawn` like any other subagent. The declared
|
|
3069
|
-
// spawn mode is what separates it from a plain
|
|
3083
|
+
// spawn mode is what separates it from a plain spawn in cost telemetry.
|
|
3070
3084
|
expect(captured.current!.config.spawnMode).toBe("advisor_consult");
|
|
3071
|
-
// Framing embeds the executor prompt as advisor system prompt context.
|
|
3072
|
-
expect(captured.current!.config.systemPromptOverride).toContain(
|
|
3073
|
-
"PARENT SYSTEM PROMPT",
|
|
3074
|
-
);
|
|
3075
3085
|
// The situational context pack must never ride display surfaces: the
|
|
3076
3086
|
// system prompt stays minimal and `objective` (rendered verbatim by the
|
|
3077
3087
|
// subagent detail panel) stays the concise advice request. Only the
|
|
@@ -3089,26 +3099,18 @@ describe("Subagent advisor-role consult", () => {
|
|
|
3089
3099
|
}
|
|
3090
3100
|
});
|
|
3091
3101
|
|
|
3092
|
-
test("advisor
|
|
3093
|
-
//
|
|
3094
|
-
//
|
|
3102
|
+
test("advisor carries no parent transcript or system prompt", async () => {
|
|
3103
|
+
// The consult is a regular blocking spawn: the brief is its whole input, so
|
|
3104
|
+
// nothing of the parent conversation is snapshotted into it.
|
|
3095
3105
|
mockFindConversation = () => ({
|
|
3096
3106
|
messages: [
|
|
3097
3107
|
{ role: "user", content: [{ type: "text", text: "Do the task" }] },
|
|
3098
3108
|
{
|
|
3099
3109
|
role: "assistant",
|
|
3100
|
-
content: [
|
|
3101
|
-
{ type: "thinking", thinking: "secret reasoning" },
|
|
3102
|
-
{ type: "text", text: "Working on it" },
|
|
3103
|
-
{ type: "tool_use", id: "t1", name: "bash", input: {} },
|
|
3104
|
-
],
|
|
3105
|
-
},
|
|
3106
|
-
{
|
|
3107
|
-
role: "user",
|
|
3108
|
-
content: [{ type: "tool_result", tool_use_id: "t1", content: "ok" }],
|
|
3110
|
+
content: [{ type: "text", text: "Working on it" }],
|
|
3109
3111
|
},
|
|
3110
3112
|
],
|
|
3111
|
-
getCurrentSystemPrompt: () => "
|
|
3113
|
+
getCurrentSystemPrompt: () => "PARENT SYSTEM PROMPT",
|
|
3112
3114
|
});
|
|
3113
3115
|
const { captured, restore } = stubAwait("advice");
|
|
3114
3116
|
try {
|
|
@@ -3116,77 +3118,55 @@ describe("Subagent advisor-role consult", () => {
|
|
|
3116
3118
|
{ label: "Consult", objective: "x", role: "advisor" },
|
|
3117
3119
|
makeContext("advisor-sess-2", { sendToClient: () => {} }),
|
|
3118
3120
|
);
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
expect(allBlocks.some((b) => b.type === "thinking")).toBe(false);
|
|
3126
|
-
expect(allBlocks.some((b) => b.type === "tool_use")).toBe(true);
|
|
3127
|
-
expect(allBlocks.some((b) => b.type === "tool_result")).toBe(true);
|
|
3121
|
+
expect(captured.current!.config.fork).toBeUndefined();
|
|
3122
|
+
expect(captured.current!.config.parentMessages).toBeUndefined();
|
|
3123
|
+
expect(captured.current!.config.parentSystemPrompt).toBeUndefined();
|
|
3124
|
+
expect(captured.current!.config.systemPromptOverride).not.toContain(
|
|
3125
|
+
"PARENT SYSTEM PROMPT",
|
|
3126
|
+
);
|
|
3128
3127
|
} finally {
|
|
3129
3128
|
restore();
|
|
3130
3129
|
mockFindConversation = () => undefined;
|
|
3131
3130
|
}
|
|
3132
3131
|
});
|
|
3133
3132
|
|
|
3134
|
-
test("
|
|
3135
|
-
// The
|
|
3136
|
-
//
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
});
|
|
3144
|
-
mockGetMessages = (convId: string) => {
|
|
3145
|
-
if (convId !== "advisor-sess-3") {
|
|
3146
|
-
return null;
|
|
3147
|
-
}
|
|
3148
|
-
return [
|
|
3149
|
-
{
|
|
3150
|
-
role: "user",
|
|
3151
|
-
content: [{ type: "text", text: "Plan the work" }],
|
|
3152
|
-
},
|
|
3153
|
-
{
|
|
3154
|
-
role: "assistant",
|
|
3155
|
-
content: [
|
|
3156
|
-
{ type: "text", text: "My plan: step 1, step 2." },
|
|
3157
|
-
{
|
|
3158
|
-
type: "tool_use",
|
|
3159
|
-
id: "adv-1",
|
|
3160
|
-
name: "subagent_spawn",
|
|
3161
|
-
input: {},
|
|
3162
|
-
},
|
|
3163
|
-
],
|
|
3164
|
-
},
|
|
3165
|
-
];
|
|
3166
|
-
};
|
|
3133
|
+
test("the agent's objective reaches the advisor as its brief", async () => {
|
|
3134
|
+
// The brief is the advisor's only account of the work, so it must travel
|
|
3135
|
+
// verbatim inside the request fence.
|
|
3136
|
+
const brief = [
|
|
3137
|
+
"Task: migrate the queue to the new store.",
|
|
3138
|
+
"Plan: dual-write, then cut over.",
|
|
3139
|
+
"Evidence: src/queue/store.ts already exports both writers.",
|
|
3140
|
+
"Question: is dual-write the right shape here?",
|
|
3141
|
+
].join("\n");
|
|
3167
3142
|
const { captured, restore } = stubAwait("advice");
|
|
3168
3143
|
try {
|
|
3169
3144
|
await executeSubagentSpawn(
|
|
3170
|
-
{ label: "Consult", objective:
|
|
3171
|
-
makeContext("advisor-sess-
|
|
3145
|
+
{ label: "Consult", objective: brief, role: "advisor" },
|
|
3146
|
+
makeContext("advisor-sess-brief", { sendToClient: () => {} }),
|
|
3147
|
+
);
|
|
3148
|
+
expect(captured.current!.config.requestText).toContain(
|
|
3149
|
+
`<agent_request>\n${brief}\n</agent_request>`,
|
|
3172
3150
|
);
|
|
3173
|
-
const msgs = captured.current!.config.parentMessages as Array<{
|
|
3174
|
-
role: string;
|
|
3175
|
-
content: Block[];
|
|
3176
|
-
}>;
|
|
3177
|
-
const allBlocks = msgs.flatMap((m) => m.content);
|
|
3178
|
-
// The plan text the model wrote this turn is present in the consult.
|
|
3179
|
-
expect(
|
|
3180
|
-
allBlocks.some(
|
|
3181
|
-
(b) => b.type === "text" && b.text === "My plan: step 1, step 2.",
|
|
3182
|
-
),
|
|
3183
|
-
).toBe(true);
|
|
3184
|
-
// No dangling tool_use is sent.
|
|
3185
|
-
expect(allBlocks.some((b) => b.type === "tool_use")).toBe(false);
|
|
3186
3151
|
} finally {
|
|
3187
3152
|
restore();
|
|
3188
|
-
|
|
3189
|
-
|
|
3153
|
+
}
|
|
3154
|
+
});
|
|
3155
|
+
|
|
3156
|
+
test("advisor consults still run when the parent conversation is gone", async () => {
|
|
3157
|
+
// The parent is looked up only for its warm skill catalog, so an evicted
|
|
3158
|
+
// conversation costs a section of the context pack, not the consult.
|
|
3159
|
+
mockFindConversation = () => undefined;
|
|
3160
|
+
const { captured, restore } = stubAwait("advice");
|
|
3161
|
+
try {
|
|
3162
|
+
const result = await executeSubagentSpawn(
|
|
3163
|
+
{ label: "Consult", objective: "advise me", role: "advisor" },
|
|
3164
|
+
makeContext("advisor-sess-no-parent", { sendToClient: () => {} }),
|
|
3165
|
+
);
|
|
3166
|
+
expect(result.content).toBe("advice");
|
|
3167
|
+
expect(captured.current!.config.role).toBe("advisor");
|
|
3168
|
+
} finally {
|
|
3169
|
+
restore();
|
|
3190
3170
|
}
|
|
3191
3171
|
});
|
|
3192
3172
|
|