@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
|
@@ -104,6 +104,7 @@ function makeContext(): Conversation {
|
|
|
104
104
|
conversationId: CONVERSATION_ID,
|
|
105
105
|
trustContext: { trustClass: "guardian", sourceChannel: "vellum" },
|
|
106
106
|
sendToClient: () => {},
|
|
107
|
+
emit: () => {},
|
|
107
108
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
108
109
|
lastSurfaceAction: new Map(),
|
|
109
110
|
surfaceState: new Map(),
|
|
@@ -93,7 +93,7 @@ mock.module("../skills/version-hash.js", () => ({
|
|
|
93
93
|
// In CI there's no gateway, so we return a sensible default.
|
|
94
94
|
mock.module("../ipc/gateway-client.js", () => ({
|
|
95
95
|
ipcClassifyRisk: async (): Promise<
|
|
96
|
-
import("
|
|
96
|
+
import("@vellumai/gateway-client").ClassifyRiskIpcResponse
|
|
97
97
|
> => ({
|
|
98
98
|
risk: "low",
|
|
99
99
|
reason: "mock",
|
|
@@ -6,9 +6,11 @@ import type { UsageAttributionSnapshot } from "../usage/attribution.js";
|
|
|
6
6
|
let checkerDecision: "allow" | "prompt" | "deny" = "allow";
|
|
7
7
|
let checkerReason = "allowed";
|
|
8
8
|
let checkerRisk = "low";
|
|
9
|
+
let classifyThrow: Error | null = null;
|
|
9
10
|
let promptDecision: "allow" | "deny" = "allow";
|
|
10
11
|
let fakeToolResult: ToolExecutionResult = { content: "ok", isError: false };
|
|
11
12
|
let toolThrow: Error | null = null;
|
|
13
|
+
let grantConsumeOk = false;
|
|
12
14
|
|
|
13
15
|
// ── audit-terminal captures ───────────────────────────────
|
|
14
16
|
// The executor and its permission/approval collaborators no longer emit
|
|
@@ -86,13 +88,38 @@ mock.module("../platform/consent-cache.js", () => ({
|
|
|
86
88
|
|
|
87
89
|
mock.module("../permissions/checker.js", () => ({
|
|
88
90
|
isDynamicSkillLoadInvocation: () => false,
|
|
89
|
-
|
|
91
|
+
// Mirrors the real classifier's two failure modes: it throws on an aborted
|
|
92
|
+
// signal before doing anything, and it throws when the gateway is
|
|
93
|
+
// unreachable.
|
|
94
|
+
classifyRisk: async (
|
|
95
|
+
_name: string,
|
|
96
|
+
_input: Record<string, unknown>,
|
|
97
|
+
_workingDir?: string,
|
|
98
|
+
_preParsed?: unknown,
|
|
99
|
+
_manifestOverride?: unknown,
|
|
100
|
+
signal?: AbortSignal,
|
|
101
|
+
) => {
|
|
102
|
+
signal?.throwIfAborted();
|
|
103
|
+
if (classifyThrow) {
|
|
104
|
+
throw classifyThrow;
|
|
105
|
+
}
|
|
106
|
+
return { level: checkerRisk };
|
|
107
|
+
},
|
|
90
108
|
check: async () => ({ decision: checkerDecision, reason: checkerReason }),
|
|
91
|
-
generateAllowlistOptions: () => [
|
|
92
|
-
{ label: "exact", description: "exact", pattern: "exact" },
|
|
93
|
-
],
|
|
94
109
|
generateScopeOptions: () => [{ label: "/tmp", scope: "/tmp" }],
|
|
95
|
-
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
// The scoped-grant consume the gate performs for a sensitive tool invoked by
|
|
113
|
+
// an unknown actor. `mintGrantFromDecision` is stubbed only so the module's
|
|
114
|
+
// other importer links; nothing here mints.
|
|
115
|
+
mock.module("../approvals/approval-primitive.js", () => ({
|
|
116
|
+
consumeGrantForInvocation: async () =>
|
|
117
|
+
grantConsumeOk
|
|
118
|
+
? { ok: true, grant: { id: "grant-1" } }
|
|
119
|
+
: { ok: false, reason: "no_match" },
|
|
120
|
+
mintGrantFromDecision: async () => {
|
|
121
|
+
throw new Error("mintGrantFromDecision should not be called");
|
|
122
|
+
},
|
|
96
123
|
}));
|
|
97
124
|
|
|
98
125
|
mock.module("../persistence/conversation-crud.js", () => ({
|
|
@@ -255,9 +282,11 @@ describe("ToolExecutor audit terminals", () => {
|
|
|
255
282
|
checkerDecision = "allow";
|
|
256
283
|
checkerReason = "allowed";
|
|
257
284
|
checkerRisk = "low";
|
|
285
|
+
classifyThrow = null;
|
|
258
286
|
promptDecision = "allow";
|
|
259
287
|
fakeToolResult = { content: "ok", isError: false };
|
|
260
288
|
toolThrow = null;
|
|
289
|
+
grantConsumeOk = false;
|
|
261
290
|
executedCaptures.length = 0;
|
|
262
291
|
errorCaptures.length = 0;
|
|
263
292
|
deniedCaptures.length = 0;
|
|
@@ -786,4 +815,102 @@ describe("ToolExecutor audit terminals", () => {
|
|
|
786
815
|
expect(executedCaptures).toHaveLength(1);
|
|
787
816
|
expect(executedCaptures[0].toolName).toBe("file_edit");
|
|
788
817
|
});
|
|
818
|
+
|
|
819
|
+
// ── audit riskLevel on rows the permission check never produces ─────────
|
|
820
|
+
// The classifier runs before the pre-execution gates, so a gate denial, a
|
|
821
|
+
// gate error, and a grant-consumed execution all record the call's real
|
|
822
|
+
// risk rather than a placeholder (LUM-3159).
|
|
823
|
+
|
|
824
|
+
test("a gate-denied call records the classified risk, not a placeholder", async () => {
|
|
825
|
+
checkerRisk = "high";
|
|
826
|
+
const executor = new ToolExecutor(makePrompter());
|
|
827
|
+
|
|
828
|
+
// Verification control-plane paths are guardian-only; an unknown actor is
|
|
829
|
+
// denied by the gate before any permission check.
|
|
830
|
+
const result = await executor.execute(
|
|
831
|
+
"bash",
|
|
832
|
+
{ command: "curl http://host/v1/channel-verification-sessions" },
|
|
833
|
+
makeContext({ trustClass: "unknown" }),
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
expect(result.isError).toBe(true);
|
|
837
|
+
expect(deniedCaptures).toHaveLength(1);
|
|
838
|
+
expect(deniedCaptures[0].riskLevel).toBe("high");
|
|
839
|
+
expect(deniedCaptures[0].wasPrompted).toBe(false);
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
test("a gate-errored call records the classified risk", async () => {
|
|
843
|
+
checkerRisk = "medium";
|
|
844
|
+
const executor = new ToolExecutor(makePrompter());
|
|
845
|
+
|
|
846
|
+
await executor.execute("unknown_tool", { test: true }, makeContext());
|
|
847
|
+
|
|
848
|
+
expect(errorCaptures).toHaveLength(1);
|
|
849
|
+
expect(errorCaptures[0].errorMessage).toContain("Unknown tool");
|
|
850
|
+
expect(errorCaptures[0].riskLevel).toBe("medium");
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
test("a grant-consumed execution records the classified risk", async () => {
|
|
854
|
+
checkerRisk = "high";
|
|
855
|
+
grantConsumeOk = true;
|
|
856
|
+
const executor = new ToolExecutor(makePrompter());
|
|
857
|
+
|
|
858
|
+
// A sensitive tool from an unknown actor routes through the scoped-grant
|
|
859
|
+
// consume; a consumed grant skips the permission check entirely, so this
|
|
860
|
+
// is the one executed row whose risk the permission check never supplies.
|
|
861
|
+
const result = await executor.execute(
|
|
862
|
+
"file_write",
|
|
863
|
+
{ path: "/tmp/project/out.txt", content: "x" },
|
|
864
|
+
makeContext({ trustClass: "unknown" }),
|
|
865
|
+
);
|
|
866
|
+
|
|
867
|
+
expect(result).toMatchObject({
|
|
868
|
+
isError: false,
|
|
869
|
+
approvalReason: "grant_scoped_consumed",
|
|
870
|
+
});
|
|
871
|
+
expect(executedCaptures).toHaveLength(1);
|
|
872
|
+
expect(executedCaptures[0].decision).toBe("allow");
|
|
873
|
+
expect(executedCaptures[0].riskLevel).toBe("high");
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
test("a call whose classification never completes records 'unclassified', not 'low'", async () => {
|
|
877
|
+
classifyThrow = new Error("gateway unreachable");
|
|
878
|
+
const executor = new ToolExecutor(makePrompter());
|
|
879
|
+
|
|
880
|
+
// Gate error path: the row says the risk was never assessed.
|
|
881
|
+
await executor.execute("unknown_tool", { test: true }, makeContext());
|
|
882
|
+
expect(errorCaptures).toHaveLength(1);
|
|
883
|
+
expect(errorCaptures[0].riskLevel).toBe("unclassified");
|
|
884
|
+
|
|
885
|
+
// Past the gates, the permission check still requires a classification
|
|
886
|
+
// and fails closed; that error row is likewise honest about the risk.
|
|
887
|
+
errorCaptures.length = 0;
|
|
888
|
+
const result = await executor.execute(
|
|
889
|
+
"file_read",
|
|
890
|
+
{ path: "README.md" },
|
|
891
|
+
makeContext(),
|
|
892
|
+
);
|
|
893
|
+
expect(result.isError).toBe(true);
|
|
894
|
+
expect(executedCaptures).toHaveLength(0);
|
|
895
|
+
expect(errorCaptures).toHaveLength(1);
|
|
896
|
+
expect(errorCaptures[0].errorMessage).toContain("gateway unreachable");
|
|
897
|
+
expect(errorCaptures[0].riskLevel).toBe("unclassified");
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
test("a call aborted before it starts records 'unclassified' on its cancelled row", async () => {
|
|
901
|
+
checkerRisk = "high";
|
|
902
|
+
const executor = new ToolExecutor(makePrompter());
|
|
903
|
+
const controller = new AbortController();
|
|
904
|
+
controller.abort();
|
|
905
|
+
|
|
906
|
+
const result = await executor.execute(
|
|
907
|
+
"bash",
|
|
908
|
+
{ command: "rm -rf /tmp" },
|
|
909
|
+
makeContext({ signal: controller.signal }),
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
expect(result).toEqual({ content: "Cancelled", isError: true });
|
|
913
|
+
expect(errorCaptures).toHaveLength(1);
|
|
914
|
+
expect(errorCaptures[0].riskLevel).toBe("unclassified");
|
|
915
|
+
});
|
|
789
916
|
});
|
|
@@ -43,8 +43,11 @@ let checkFnOverride:
|
|
|
43
43
|
/** Override for generateScopeOptions — when set, returns this value instead of the default. */
|
|
44
44
|
let scopeOptionsOverride: ScopeOption[] | undefined;
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Override for the classification `classifyRisk` returns; when unset the
|
|
48
|
+
* classifier answers low with no reason and no options.
|
|
49
|
+
*/
|
|
50
|
+
let classificationOverride:
|
|
48
51
|
| {
|
|
49
52
|
riskLevel: string;
|
|
50
53
|
reason: string;
|
|
@@ -61,7 +64,14 @@ let cachedAssessmentOverride:
|
|
|
61
64
|
|
|
62
65
|
mock.module("../permissions/checker.js", () => ({
|
|
63
66
|
isDynamicSkillLoadInvocation: () => false,
|
|
64
|
-
classifyRisk: async () => ({
|
|
67
|
+
classifyRisk: async () => ({
|
|
68
|
+
level: classificationOverride?.riskLevel ?? "low",
|
|
69
|
+
reason: classificationOverride?.reason,
|
|
70
|
+
scopeOptions: classificationOverride?.scopeOptions ?? [],
|
|
71
|
+
allowlistOptions: classificationOverride?.allowlistOptions,
|
|
72
|
+
directoryScopeOptions: classificationOverride?.directoryScopeOptions,
|
|
73
|
+
matchType: classificationOverride?.matchType ?? "unknown",
|
|
74
|
+
}),
|
|
65
75
|
check: async (
|
|
66
76
|
toolName: string,
|
|
67
77
|
input: Record<string, unknown>,
|
|
@@ -77,12 +87,8 @@ mock.module("../permissions/checker.js", () => ({
|
|
|
77
87
|
}
|
|
78
88
|
return { decision: "allow", reason: "allowed" };
|
|
79
89
|
},
|
|
80
|
-
generateAllowlistOptions: () => [
|
|
81
|
-
{ label: "exact", description: "exact", pattern: "exact" },
|
|
82
|
-
],
|
|
83
90
|
generateScopeOptions: () =>
|
|
84
91
|
scopeOptionsOverride ?? [{ label: "/tmp", scope: "/tmp" }],
|
|
85
|
-
getCachedAssessment: () => cachedAssessmentOverride,
|
|
86
92
|
}));
|
|
87
93
|
|
|
88
94
|
// Mock every export so downstream test files that dynamically import modules
|
|
@@ -167,7 +173,7 @@ describe("ToolExecutor allowedToolNames gating", () => {
|
|
|
167
173
|
getAllToolsOverride = undefined;
|
|
168
174
|
checkResultOverride = undefined;
|
|
169
175
|
checkFnOverride = undefined;
|
|
170
|
-
|
|
176
|
+
classificationOverride = undefined;
|
|
171
177
|
});
|
|
172
178
|
|
|
173
179
|
test("executes normally when allowedToolNames is not set", async () => {
|
|
@@ -385,7 +391,7 @@ describe("ToolExecutor policy context plumbing", () => {
|
|
|
385
391
|
getToolOverride = undefined;
|
|
386
392
|
checkResultOverride = undefined;
|
|
387
393
|
checkFnOverride = undefined;
|
|
388
|
-
|
|
394
|
+
classificationOverride = undefined;
|
|
389
395
|
});
|
|
390
396
|
|
|
391
397
|
test("passes PolicyContext with executionTarget for skill-origin tools", async () => {
|
|
@@ -604,7 +610,7 @@ describe("ToolExecutor forcePromptSideEffects enforcement", () => {
|
|
|
604
610
|
getToolOverride = undefined;
|
|
605
611
|
checkResultOverride = undefined;
|
|
606
612
|
checkFnOverride = undefined;
|
|
607
|
-
|
|
613
|
+
classificationOverride = undefined;
|
|
608
614
|
promptCalled = false;
|
|
609
615
|
});
|
|
610
616
|
|
|
@@ -931,11 +937,30 @@ describe("integration regressions — prompt payload (PR 11)", () => {
|
|
|
931
937
|
getToolOverride = undefined;
|
|
932
938
|
});
|
|
933
939
|
|
|
934
|
-
test("shell command prompt payload
|
|
940
|
+
test("shell command prompt payload carries the classifier's ladder and the scope options", async () => {
|
|
935
941
|
checkResultOverride = {
|
|
936
942
|
decision: "prompt",
|
|
937
943
|
reason: "Medium risk: requires approval",
|
|
938
944
|
};
|
|
945
|
+
// The ladder is the gateway's; the daemon passes it through untouched.
|
|
946
|
+
classificationOverride = {
|
|
947
|
+
riskLevel: "medium",
|
|
948
|
+
reason: "npm install",
|
|
949
|
+
scopeOptions: [],
|
|
950
|
+
allowlistOptions: [
|
|
951
|
+
{
|
|
952
|
+
label: "npm install",
|
|
953
|
+
description: "Exact command",
|
|
954
|
+
pattern: "npm install",
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
label: "action:npm",
|
|
958
|
+
description: "Any npm command",
|
|
959
|
+
pattern: "action:npm",
|
|
960
|
+
},
|
|
961
|
+
],
|
|
962
|
+
matchType: "registry",
|
|
963
|
+
};
|
|
939
964
|
|
|
940
965
|
let capturedAllowlist: AllowlistOption[] | undefined;
|
|
941
966
|
let capturedScopes: ScopeOption[] | undefined;
|
|
@@ -963,13 +988,11 @@ describe("integration regressions — prompt payload (PR 11)", () => {
|
|
|
963
988
|
makeContext({ forcePromptSideEffects: true }),
|
|
964
989
|
);
|
|
965
990
|
|
|
966
|
-
//
|
|
967
|
-
expect(capturedAllowlist).
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
expect(capturedAllowlist![0]).toHaveProperty("label");
|
|
972
|
-
expect(capturedAllowlist![0]).toHaveProperty("description");
|
|
991
|
+
// The prompt offers exactly what the classifier produced, in order.
|
|
992
|
+
expect(capturedAllowlist?.map((o) => o.pattern)).toEqual([
|
|
993
|
+
"npm install",
|
|
994
|
+
"action:npm",
|
|
995
|
+
]);
|
|
973
996
|
|
|
974
997
|
// Verify scope options are also passed
|
|
975
998
|
expect(capturedScopes).toBeDefined();
|
|
@@ -989,11 +1012,11 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
989
1012
|
getToolOverride = undefined;
|
|
990
1013
|
checkResultOverride = undefined;
|
|
991
1014
|
checkFnOverride = undefined;
|
|
992
|
-
|
|
1015
|
+
classificationOverride = undefined;
|
|
993
1016
|
});
|
|
994
1017
|
|
|
995
1018
|
test("auto-approved tool result includes risk metadata when classifier assessment exists", async () => {
|
|
996
|
-
|
|
1019
|
+
classificationOverride = {
|
|
997
1020
|
riskLevel: "medium",
|
|
998
1021
|
reason: "Writes to a file outside the workspace",
|
|
999
1022
|
scopeOptions: [
|
|
@@ -1019,8 +1042,10 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1019
1042
|
]);
|
|
1020
1043
|
});
|
|
1021
1044
|
|
|
1022
|
-
test("tool result
|
|
1023
|
-
//
|
|
1045
|
+
test("tool result carries the classification's risk metadata even when the classifier produced no options", async () => {
|
|
1046
|
+
// classificationOverride is unset: the classifier answered low with no
|
|
1047
|
+
// reason and no options, which is what a tool with no dedicated classifier
|
|
1048
|
+
// (registry default risk) looks like.
|
|
1024
1049
|
const executor = new ToolExecutor(makePrompter());
|
|
1025
1050
|
const result = await executor.execute(
|
|
1026
1051
|
"file_read",
|
|
@@ -1029,9 +1054,9 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1029
1054
|
);
|
|
1030
1055
|
|
|
1031
1056
|
expect(result.isError).toBe(false);
|
|
1032
|
-
expect(result.riskLevel).
|
|
1033
|
-
expect(result.
|
|
1034
|
-
expect(result.
|
|
1057
|
+
expect(result.riskLevel).toBe("low");
|
|
1058
|
+
expect(result.riskScopeOptions).toEqual([]);
|
|
1059
|
+
expect(result.riskAllowlistOptions).toBeUndefined();
|
|
1035
1060
|
});
|
|
1036
1061
|
|
|
1037
1062
|
test("denied tool result includes risk metadata", async () => {
|
|
@@ -1039,7 +1064,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1039
1064
|
decision: "deny",
|
|
1040
1065
|
reason: "Blocked by deny rule",
|
|
1041
1066
|
};
|
|
1042
|
-
|
|
1067
|
+
classificationOverride = {
|
|
1043
1068
|
riskLevel: "high",
|
|
1044
1069
|
reason: "Recursive force delete",
|
|
1045
1070
|
scopeOptions: [{ pattern: "bash:rm -rf*", label: "rm -rf commands" }],
|
|
@@ -1066,7 +1091,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1066
1091
|
decision: "prompt",
|
|
1067
1092
|
reason: "Medium risk: requires approval",
|
|
1068
1093
|
};
|
|
1069
|
-
|
|
1094
|
+
classificationOverride = {
|
|
1070
1095
|
riskLevel: "medium",
|
|
1071
1096
|
reason: "Package manager installation",
|
|
1072
1097
|
scopeOptions: [
|
|
@@ -1091,7 +1116,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1091
1116
|
});
|
|
1092
1117
|
|
|
1093
1118
|
test("tool result includes riskDirectoryScopeOptions when classifier emits directoryScopeOptions", async () => {
|
|
1094
|
-
|
|
1119
|
+
classificationOverride = {
|
|
1095
1120
|
riskLevel: "medium",
|
|
1096
1121
|
reason: "Writes to file in workspace",
|
|
1097
1122
|
scopeOptions: [
|
|
@@ -1124,7 +1149,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1124
1149
|
});
|
|
1125
1150
|
|
|
1126
1151
|
test("tool result omits riskDirectoryScopeOptions when classifier does not emit directoryScopeOptions", async () => {
|
|
1127
|
-
|
|
1152
|
+
classificationOverride = {
|
|
1128
1153
|
riskLevel: "low",
|
|
1129
1154
|
reason: "Read-only operation",
|
|
1130
1155
|
scopeOptions: [],
|
|
@@ -1144,7 +1169,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1144
1169
|
});
|
|
1145
1170
|
|
|
1146
1171
|
test("riskScopeOptions and riskDirectoryScopeOptions are independent — one does not clobber the other", async () => {
|
|
1147
|
-
|
|
1172
|
+
classificationOverride = {
|
|
1148
1173
|
riskLevel: "medium",
|
|
1149
1174
|
reason: "Filesystem write",
|
|
1150
1175
|
scopeOptions: [
|
|
@@ -1170,7 +1195,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1170
1195
|
});
|
|
1171
1196
|
|
|
1172
1197
|
test("auto-approved tool result includes riskAllowlistOptions when classifier emits them (Minimatch-glob shape for save path)", async () => {
|
|
1173
|
-
|
|
1198
|
+
classificationOverride = {
|
|
1174
1199
|
riskLevel: "medium",
|
|
1175
1200
|
reason: "Reads workspace files",
|
|
1176
1201
|
// Display ladder (regex shape — not for save).
|
|
@@ -1222,7 +1247,7 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1222
1247
|
});
|
|
1223
1248
|
|
|
1224
1249
|
test("riskAllowlistOptions is undefined when classifier did not produce allowlist (e.g. web-risk classifier)", async () => {
|
|
1225
|
-
|
|
1250
|
+
classificationOverride = {
|
|
1226
1251
|
riskLevel: "low",
|
|
1227
1252
|
reason: "GET request to public URL",
|
|
1228
1253
|
scopeOptions: [
|
|
@@ -1248,8 +1273,8 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1248
1273
|
expect(result.riskAllowlistOptions).toBeUndefined();
|
|
1249
1274
|
});
|
|
1250
1275
|
|
|
1251
|
-
test("riskAllowlistOptions is undefined when
|
|
1252
|
-
//
|
|
1276
|
+
test("riskAllowlistOptions is undefined when the classifier produced none", async () => {
|
|
1277
|
+
// classificationOverride is unset: no allowlist options on the answer.
|
|
1253
1278
|
const executor = new ToolExecutor(makePrompter());
|
|
1254
1279
|
const result = await executor.execute(
|
|
1255
1280
|
"file_read",
|
|
@@ -1258,13 +1283,13 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1258
1283
|
);
|
|
1259
1284
|
|
|
1260
1285
|
expect(result.isError).toBe(false);
|
|
1261
|
-
expect(result.riskScopeOptions).
|
|
1286
|
+
expect(result.riskScopeOptions).toEqual([]);
|
|
1262
1287
|
expect(result.riskAllowlistOptions).toBeUndefined();
|
|
1263
1288
|
});
|
|
1264
1289
|
|
|
1265
1290
|
test("denied tool result still carries riskAllowlistOptions for the rule editor save path", async () => {
|
|
1266
1291
|
checkResultOverride = { decision: "deny", reason: "Blocked by deny rule" };
|
|
1267
|
-
|
|
1292
|
+
classificationOverride = {
|
|
1268
1293
|
riskLevel: "high",
|
|
1269
1294
|
reason: "Recursive force delete",
|
|
1270
1295
|
scopeOptions: [{ pattern: "^rm\\s+-rf", label: "rm -rf *" }],
|
|
@@ -1334,7 +1359,7 @@ describe("ToolExecutor thrown-value rendering", () => {
|
|
|
1334
1359
|
getAllToolsOverride = undefined;
|
|
1335
1360
|
checkResultOverride = undefined;
|
|
1336
1361
|
checkFnOverride = undefined;
|
|
1337
|
-
|
|
1362
|
+
classificationOverride = undefined;
|
|
1338
1363
|
});
|
|
1339
1364
|
|
|
1340
1365
|
function throwingTool(name: string, thrown: unknown): void {
|
|
@@ -1406,7 +1431,7 @@ describe("ToolExecutor input-schema validation gate", () => {
|
|
|
1406
1431
|
getAllToolsOverride = undefined;
|
|
1407
1432
|
checkResultOverride = undefined;
|
|
1408
1433
|
checkFnOverride = undefined;
|
|
1409
|
-
|
|
1434
|
+
classificationOverride = undefined;
|
|
1410
1435
|
});
|
|
1411
1436
|
|
|
1412
1437
|
/**
|
|
@@ -1457,7 +1482,11 @@ describe("ToolExecutor input-schema validation gate", () => {
|
|
|
1457
1482
|
const executor = new ToolExecutor(makePrompter());
|
|
1458
1483
|
const result = await executor.execute(
|
|
1459
1484
|
"file_read",
|
|
1460
|
-
{
|
|
1485
|
+
{
|
|
1486
|
+
path: "a.txt",
|
|
1487
|
+
start_index: "not-a-number",
|
|
1488
|
+
activity: "Reading a file",
|
|
1489
|
+
},
|
|
1461
1490
|
makeContext(),
|
|
1462
1491
|
);
|
|
1463
1492
|
|
|
@@ -331,3 +331,46 @@ describe("queryUnreportedTurnEvents", () => {
|
|
|
331
331
|
expect(() => stampTurnOutcome("no-such-message", "failed")).not.toThrow();
|
|
332
332
|
});
|
|
333
333
|
});
|
|
334
|
+
|
|
335
|
+
describe("unfinalized rows and turn accounting", () => {
|
|
336
|
+
test("an in-flight grouped tool-result row is not a real user turn", async () => {
|
|
337
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
338
|
+
const first = await insertUserMessageAt(conv.id, "real question", 1000);
|
|
339
|
+
// The grouped tool-result row: user-role, reserved unfinalized while
|
|
340
|
+
// tool output streams, content a { ref } that does not contain the
|
|
341
|
+
// tool_result text the content exclusions match. Without the finalized
|
|
342
|
+
// predicate it counts as a phantom user turn until the fold.
|
|
343
|
+
const inflight = await insertUserMessageAt(
|
|
344
|
+
conv.id,
|
|
345
|
+
JSON.stringify({ ref: "conversations/conv/inflight/x.jsonl" }),
|
|
346
|
+
2000,
|
|
347
|
+
);
|
|
348
|
+
getDb().run(`UPDATE messages SET finalized = 0 WHERE id = '${inflight}'`);
|
|
349
|
+
const second = await insertUserMessageAt(conv.id, "second question", 3000);
|
|
350
|
+
|
|
351
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
352
|
+
const ids = events
|
|
353
|
+
.filter((e) => e.conversationId === conv.id)
|
|
354
|
+
.map((e) => e.id);
|
|
355
|
+
|
|
356
|
+
expect(ids).toEqual([first, second]);
|
|
357
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
358
|
+
expect(byId[first].turnIndex).toBe(1);
|
|
359
|
+
expect(byId[second].turnIndex).toBe(2);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("a persisted empty-display user row still counts as a turn", async () => {
|
|
363
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
364
|
+
const real = await insertUserMessageAt(conv.id, "real question", 1000);
|
|
365
|
+
// A hidden send persists its user row with [] content (displayContent "")
|
|
366
|
+
// and still runs a turn, so [] rows must stay in turn accounting.
|
|
367
|
+
const hidden = await insertUserMessageAt(conv.id, "[]", 2000);
|
|
368
|
+
|
|
369
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
370
|
+
const ids = events
|
|
371
|
+
.filter((e) => e.conversationId === conv.id)
|
|
372
|
+
.map((e) => e.id);
|
|
373
|
+
|
|
374
|
+
expect(ids).toEqual([real, hidden]);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
@@ -22,7 +22,7 @@ import { asConversation } from "./helpers/mock-conversation.js";
|
|
|
22
22
|
function makeContext(sent: AssistantEvent[] = []): Conversation {
|
|
23
23
|
return asConversation({
|
|
24
24
|
conversationId: "session-1",
|
|
25
|
-
|
|
25
|
+
emit: (msg) => sent.push(msg),
|
|
26
26
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
27
27
|
lastSurfaceAction: new Map<
|
|
28
28
|
string,
|
|
@@ -5,6 +5,7 @@ import { uiShowTool } from "../tools/ui-surface/definitions.js";
|
|
|
5
5
|
import {
|
|
6
6
|
SURFACE_SHAPE_DOCS,
|
|
7
7
|
SURFACE_TYPE_NAMES,
|
|
8
|
+
UI_SHOW_TYPE_DOCS,
|
|
8
9
|
uiShowTeachingError,
|
|
9
10
|
} from "../tools/ui-surface/surface-shape-docs.js";
|
|
10
11
|
|
|
@@ -290,6 +291,12 @@ describe("ui_show displayable payloads proxy through", () => {
|
|
|
290
291
|
surfaceType: "channel_setup",
|
|
291
292
|
input: { surface_type: "channel_setup", data: { channel: "telegram" } },
|
|
292
293
|
},
|
|
294
|
+
{
|
|
295
|
+
// The picker reads its own voice and catalog, so an empty payload is
|
|
296
|
+
// the whole contract and there is no missing-content state to teach.
|
|
297
|
+
surfaceType: "voice_picker",
|
|
298
|
+
input: { surface_type: "voice_picker", data: {} },
|
|
299
|
+
},
|
|
293
300
|
];
|
|
294
301
|
|
|
295
302
|
for (const { surfaceType, input } of cases) {
|
|
@@ -347,4 +354,30 @@ describe("uiShowTeachingError", () => {
|
|
|
347
354
|
expect(uiShowTool.description).toContain(name);
|
|
348
355
|
}
|
|
349
356
|
});
|
|
357
|
+
|
|
358
|
+
test("voice_picker is a cold type that accepts an empty payload", () => {
|
|
359
|
+
expect(
|
|
360
|
+
uiShowTeachingError({ surface_type: "voice_picker", data: {} }),
|
|
361
|
+
).toBeNull();
|
|
362
|
+
expect(UI_SHOW_TYPE_DOCS).toContain(
|
|
363
|
+
`voice_picker (${SURFACE_SHAPE_DOCS.voice_picker!.purpose})`,
|
|
364
|
+
);
|
|
365
|
+
expect(UI_SHOW_TYPE_DOCS).not.toContain("- voice_picker:");
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("voice_picker steering reaches the model through the cold index", () => {
|
|
369
|
+
// Asserted on the built description rather than the doc entry: a cold
|
|
370
|
+
// type's `shape` reaches the model only through a teaching error, and an
|
|
371
|
+
// empty payload has no missing-content state to raise one, so steering
|
|
372
|
+
// parked there would be dead.
|
|
373
|
+
for (const directive of [
|
|
374
|
+
"change, hear, or pick a voice",
|
|
375
|
+
"rather than describing voices in prose",
|
|
376
|
+
"attach no actions and never set await_action",
|
|
377
|
+
"during a live voice call answer in speech",
|
|
378
|
+
]) {
|
|
379
|
+
expect(UI_SHOW_TYPE_DOCS).toContain(directive);
|
|
380
|
+
expect(uiShowTool.description).toContain(directive);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
350
383
|
});
|
|
@@ -32,7 +32,7 @@ const HTML = '<div style="color:var(--content-default)">Hello</div>';
|
|
|
32
32
|
function makeContext(sent: AssistantEvent[] = []): Conversation {
|
|
33
33
|
return asConversation({
|
|
34
34
|
conversationId: "session-1",
|
|
35
|
-
|
|
35
|
+
emit: (msg) => sent.push(msg),
|
|
36
36
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
37
37
|
lastSurfaceAction: new Map<
|
|
38
38
|
string,
|