@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +1 -1
- package/Dockerfile +8 -0
- package/docs/activation-funnel-telemetry.md +13 -7
- 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__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -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__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/openapi.yaml +530 -107
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/activation-early-marking.test.ts +6 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
- package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
- package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
- package/src/__tests__/app-bundler.test.ts +4 -12
- package/src/__tests__/app-executors.test.ts +2 -49
- package/src/__tests__/app-routes-csp.test.ts +114 -146
- package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
- package/src/__tests__/build-persisted-content.test.ts +96 -0
- package/src/__tests__/bundle-scanner.test.ts +27 -1
- package/src/__tests__/call-controller.test.ts +291 -0
- package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
- package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
- package/src/__tests__/config-loader-backfill.test.ts +9 -4
- package/src/__tests__/config-schema-cmd.test.ts +10 -11
- package/src/__tests__/config-schema.test.ts +190 -257
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
- package/src/__tests__/conversation-agent-loop.test.ts +22 -9
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
- package/src/__tests__/conversation-process-callsite.test.ts +12 -19
- package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
- package/src/__tests__/conversation-summarize-route.test.ts +36 -44
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
- package/src/__tests__/conversation-usage.test.ts +4 -12
- package/src/__tests__/credential-routes.test.ts +250 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/db-migration-rollback.test.ts +22 -0
- package/src/__tests__/empty-response-hook.test.ts +186 -1
- package/src/__tests__/external-plugin-loader.test.ts +11 -5
- package/src/__tests__/heartbeat-service.test.ts +0 -28
- package/src/__tests__/host-shell-tool.test.ts +2 -0
- package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
- package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -16
- package/src/__tests__/list-all-apps.test.ts +0 -4
- package/src/__tests__/llm-context-resolution.test.ts +32 -56
- package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
- package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
- package/src/__tests__/llm-resolver.test.ts +342 -602
- package/src/__tests__/llm-schema.test.ts +79 -37
- package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
- package/src/__tests__/media-stream-output.test.ts +259 -3
- package/src/__tests__/media-stream-server-integration.test.ts +22 -1
- package/src/__tests__/media-stream-stt-session.test.ts +47 -0
- package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
- package/src/__tests__/memory-recall-log-store.test.ts +47 -13
- package/src/__tests__/mock-gateway-ipc.ts +46 -1
- package/src/__tests__/mtime-cache.test.ts +61 -0
- package/src/__tests__/navigate-settings-tab.test.ts +2 -0
- package/src/__tests__/normalize-onboarding.test.ts +33 -0
- package/src/__tests__/onboarding-persona-write.test.ts +26 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
- package/src/__tests__/provider-connections-backfill.test.ts +138 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
- package/src/__tests__/provider-registry-ollama.test.ts +8 -18
- package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
- package/src/__tests__/provider-usage-tracking.test.ts +9 -19
- package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
- package/src/__tests__/published-app-updater.test.ts +22 -16
- package/src/__tests__/registry.test.ts +5 -16
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
- package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
- package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
- package/src/__tests__/reveal-success-registry.test.ts +123 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
- package/src/__tests__/secret-fixtures.ts +9 -0
- package/src/__tests__/server-history-render.test.ts +28 -0
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/slack-share-routes.test.ts +0 -1
- package/src/__tests__/stt-stream-session.test.ts +6 -5
- package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
- package/src/__tests__/subagent-disposal.test.ts +2 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +37 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
- package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
- package/src/__tests__/telemetry-routes.test.ts +99 -19
- package/src/__tests__/tool-audit.test.ts +34 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-profiler.test.ts +72 -1
- package/src/__tests__/tool-result-spool.test.ts +49 -4
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
- package/src/__tests__/ui-channel-variants.test.ts +108 -0
- package/src/__tests__/ui-shape-teaching.test.ts +255 -0
- package/src/__tests__/usage-attribution.test.ts +18 -41
- package/src/__tests__/user-plugin-loader.test.ts +4 -4
- package/src/__tests__/voice-config-update.test.ts +46 -0
- package/src/__tests__/voice-session-bridge.test.ts +216 -84
- package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
- package/src/agent/loop.ts +4 -3
- package/src/api/events/open-conversation.test.ts +64 -0
- package/src/api/events/open-conversation.ts +33 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +25 -35
- package/src/bundler/app-bundler.ts +34 -48
- package/src/bundler/app-compiler.ts +39 -4
- package/src/bundler/bundle-scanner.ts +13 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
- package/src/calls/call-constants.ts +5 -0
- package/src/calls/call-controller.ts +100 -32
- package/src/calls/call-transport.ts +9 -0
- package/src/calls/media-stream-output.ts +107 -4
- package/src/calls/media-stream-server.ts +29 -9
- package/src/calls/media-stream-stt-session.ts +7 -1
- package/src/calls/media-turn-detector.ts +11 -1
- package/src/calls/voice-session-bridge.ts +84 -63
- package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/config.help.ts +6 -6
- package/src/cli/commands/credentials.help.ts +13 -0
- package/src/cli/commands/credentials.ts +6 -1
- package/src/cli/commands/email.help.ts +7 -0
- package/src/cli/commands/email.ts +35 -1
- package/src/cli/commands/inference-providers.ts +168 -107
- package/src/cli/commands/inference.help.ts +118 -46
- package/src/cli/commands/memory/index.help.ts +23 -0
- package/src/cli/commands/memory/nodes.ts +146 -0
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/commands/plugins.help.ts +13 -2
- package/src/cli/commands/plugins.ts +61 -7
- package/src/cli/commands/telemetry.help.ts +13 -0
- package/src/cli/commands/telemetry.ts +45 -5
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
- package/src/cli/lib/bundled-marketplace.json +93 -36
- package/src/cli/lib/inspect-plugin.ts +5 -1
- package/src/cli/lib/install-from-github.ts +68 -4
- package/src/cli/lib/plugin-catalog-local.ts +6 -2
- package/src/cli/lib/plugin-fingerprint.ts +3 -3
- package/src/cli/lib/upgrade-plugin.ts +236 -35
- package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
- package/src/config/__tests__/profile-materialization.test.ts +1 -88
- package/src/config/bundled-skills/AGENTS.md +3 -30
- package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
- package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
- package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/call-site-defaults.ts +3 -3
- package/src/config/feature-flag-registry.json +24 -39
- package/src/config/llm-resolver.ts +88 -475
- package/src/config/profile-materialization.ts +11 -11
- package/src/config/schema.ts +93 -127
- package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
- package/src/config/schemas/__tests__/stt.test.ts +31 -3
- package/src/config/schemas/live-voice.ts +10 -4
- package/src/config/schemas/llm.ts +52 -15
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +8 -0
- package/src/config/schemas/memory-v2.ts +2 -2
- package/src/config/schemas/memory-v3.ts +1 -1
- package/src/config/schemas/services.ts +6 -3
- package/src/config/schemas/stt.ts +38 -21
- package/src/config/schemas/tts.ts +13 -18
- package/src/config/skills.ts +31 -21
- package/src/context/compactor.ts +44 -7
- package/src/context/post-turn-tool-result-truncation.ts +4 -2
- package/src/context/tool-result-spool.ts +26 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
- package/src/conversations/message-consolidation.ts +22 -2
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
- package/src/daemon/app-source-watcher.ts +17 -23
- package/src/daemon/chat-credential-redaction.ts +1365 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
- package/src/daemon/conversation-agent-loop.ts +71 -31
- package/src/daemon/conversation-error.ts +36 -14
- package/src/daemon/conversation-process.ts +22 -0
- package/src/daemon/conversation-store.ts +35 -0
- package/src/daemon/conversation-surfaces.ts +25 -25
- package/src/daemon/conversation-tool-setup.ts +33 -7
- package/src/daemon/conversation.ts +55 -5
- package/src/daemon/handlers/shared.ts +33 -2
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/message-types/conversations.ts +6 -17
- package/src/daemon/providers-setup.ts +8 -0
- package/src/daemon/tool-setup-types.ts +7 -1
- package/src/daemon/wake-conversation-ops.ts +10 -1
- package/src/hooks/types.ts +9 -0
- package/src/ipc/__tests__/email-ipc.test.ts +90 -0
- package/src/ipc/gateway-client.test.ts +59 -0
- package/src/ipc/gateway-client.ts +70 -27
- package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
- package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
- package/src/live-voice/__tests__/protocol.test.ts +122 -0
- package/src/live-voice/live-voice-session.ts +443 -40
- package/src/live-voice/protocol.ts +143 -1
- package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
- package/src/monitoring/plugin-source-watch.ts +3 -62
- package/src/notifications/README.md +1 -1
- package/src/permissions/checker.ts +8 -4
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
- package/src/persistence/conversation-crud.ts +104 -2
- package/src/persistence/db-init.ts +14 -3
- package/src/persistence/job-handlers/cleanup.ts +15 -7
- package/src/persistence/llm-request-log-store.ts +88 -52
- package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
- package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
- package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
- package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
- package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
- package/src/persistence/migrations/helpers/relocation.ts +44 -1
- package/src/persistence/migrations/run-migrations.ts +25 -1
- package/src/persistence/schema/infrastructure.ts +9 -0
- package/src/persistence/schema/memory-core.ts +3 -0
- package/src/persistence/schema/memory-injection.ts +2 -0
- package/src/persistence/steps.ts +36 -0
- package/src/platform/client.test.ts +1 -44
- package/src/platform/client.ts +10 -20
- package/src/platform/consent-cache.test.ts +89 -23
- package/src/platform/consent-cache.ts +71 -33
- package/src/plugin-api/constants.ts +12 -0
- package/src/plugin-api/conversation-turn.ts +37 -14
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/resolve-credential.ts +75 -0
- package/src/plugin-api/vision-support.test.ts +8 -19
- package/src/plugin-api/vision-support.ts +26 -17
- package/src/plugins/collect-source-versions.ts +77 -0
- package/src/plugins/defaults/compaction/compact.ts +6 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
- package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
- package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
- package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
- package/src/plugins/defaults/index.ts +8 -1
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
- package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
- package/src/plugins/defaults/memory/graph/store.ts +114 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
- package/src/plugins/defaults/memory/graph/tools.ts +47 -13
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
- package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
- package/src/plugins/defaults/memory/memory-db.ts +3 -2
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
- package/src/plugins/defaults/memory/path-containment.ts +21 -0
- package/src/plugins/defaults/memory/prompt-override.ts +51 -13
- package/src/plugins/defaults/memory/tools.test.ts +34 -0
- package/src/plugins/defaults/memory/tools.ts +12 -2
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
- package/src/plugins/defaults/memory/v2/migration.ts +46 -16
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
- package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
- package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
- package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
- package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
- package/src/plugins/defaults/memory/v3/prune.ts +17 -11
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
- package/src/plugins/external-plugin-loader.ts +15 -15
- package/src/plugins/mtime-cache.ts +47 -0
- package/src/plugins/pipeline.ts +9 -1
- package/src/plugins/plugin-execution-context.ts +44 -0
- package/src/plugins/plugin-tree-walk.ts +31 -24
- package/src/plugins/source-fingerprint.ts +3 -4
- package/src/prompts/normalize-onboarding.ts +12 -0
- package/src/prompts/persona-resolver.ts +8 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
- package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
- package/src/providers/__tests__/retry-callsite.test.ts +235 -215
- package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
- package/src/providers/atlascloud/client.ts +10 -49
- package/src/providers/baseten/client.ts +43 -0
- package/src/providers/call-site-routing.ts +26 -13
- package/src/providers/connection-resolution.ts +9 -11
- package/src/providers/fetch-provider-catalog.ts +4 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
- package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
- package/src/providers/inference/adapter-factory.ts +27 -6
- package/src/providers/inference/auth.ts +29 -1
- package/src/providers/inference/backfill.ts +61 -10
- package/src/providers/inference/connection-availability.ts +3 -2
- package/src/providers/inference/resolve-auth.ts +9 -1
- package/src/providers/model-catalog.ts +37 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
- package/src/providers/openai/api-key-validation.ts +70 -0
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +11 -4
- package/src/providers/vellum-model-routing.test.ts +26 -0
- package/src/providers/vellum-model-routing.ts +30 -0
- package/src/providers/voice-error-copy.ts +47 -0
- package/src/runtime/agent-wake.ts +40 -24
- package/src/runtime/for-chat-mint-registry.ts +118 -0
- package/src/runtime/reveal-nonce.ts +49 -0
- package/src/runtime/reveal-success-registry.ts +306 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
- package/src/runtime/routes/app-management-routes.ts +152 -45
- package/src/runtime/routes/app-routes.ts +16 -77
- package/src/runtime/routes/canned-message-complete.ts +16 -16
- package/src/runtime/routes/conversation-management-routes.ts +17 -14
- package/src/runtime/routes/conversation-query-routes.ts +54 -6
- package/src/runtime/routes/conversation-routes.ts +48 -2
- package/src/runtime/routes/credential-routes.ts +116 -3
- package/src/runtime/routes/email-routes.ts +17 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
- package/src/runtime/routes/inference-send-routes.ts +1 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
- package/src/runtime/routes/plugins-routes.ts +37 -6
- package/src/runtime/routes/publish-routes.ts +15 -18
- package/src/runtime/routes/schedule-worker-routes.ts +9 -0
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/telemetry-routes.ts +149 -45
- package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
- package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
- package/src/schedule/schedule-store.ts +12 -1
- package/src/schedule/schedule-timezone.ts +63 -0
- package/src/schedule/scheduler.ts +100 -6
- package/src/schedule/worker-control.ts +19 -0
- package/src/security/auth-fallback-events-store.ts +7 -6
- package/src/security/secret-scanner.ts +26 -1
- package/src/services/published-app-updater.ts +6 -11
- package/src/stt/stt-stream-session.ts +36 -16
- package/src/subagent/manager.ts +34 -8
- package/src/telemetry/AGENTS.md +30 -1
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
- package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
- package/src/telemetry/config-setting-snapshot.ts +44 -10
- package/src/telemetry/telemetry-event-sources.test.ts +124 -30
- package/src/telemetry/telemetry-event-sources.ts +137 -83
- package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
- package/src/telemetry/telemetry-events-outbox.ts +60 -9
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire-validation.ts +39 -2
- package/src/telemetry/telemetry-wire.generated.ts +8 -0
- package/src/telemetry/tool-audit.ts +15 -9
- package/src/telemetry/tool-executed-events-store.test.ts +1 -1
- package/src/telemetry/turn-events-store.ts +20 -0
- package/src/telemetry/types.ts +45 -12
- package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
- package/src/telemetry/usage-telemetry-reporter.ts +117 -18
- package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
- package/src/telemetry/watchdog-direct-emit.ts +11 -6
- package/src/tools/apps/executors.ts +11 -36
- package/src/tools/executor.ts +14 -1
- package/src/tools/host-terminal/host-shell.ts +6 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
- package/src/tools/network/web-fetch.ts +6 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/subagent/spawn.ts +7 -11
- package/src/tools/terminal/shell.ts +5 -2
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/tool-profiler.ts +37 -6
- package/src/tools/ui-surface/channel-variants.ts +101 -0
- package/src/tools/ui-surface/definitions.ts +23 -67
- package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
- package/src/tts/__tests__/provider-adapters.test.ts +18 -0
- package/src/tts/provider-catalog.ts +2 -4
- package/src/tts/providers/deepgram-provider.ts +10 -1
- package/src/types/onboarding-context.ts +8 -0
- package/src/usage/attribution.ts +18 -112
- package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
- package/src/util/provider-error-patterns.ts +7 -1
- package/src/util/worker-process.ts +105 -0
- package/src/watcher/__tests__/telemetry.test.ts +17 -4
- package/src/watcher/telemetry.ts +5 -5
- package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/provider-commit-message-generator.ts +6 -4
- package/src/__tests__/app-open-proxy.test.ts +0 -67
- package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
- package/src/onboarding/onboarding-research-events-store.ts +0 -104
- package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
- package/src/tools/apps/definitions.ts +0 -73
- package/src/tools/apps/open-proxy.ts +0 -43
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Regression test for the subagent provider routing fix.
|
|
3
3
|
*
|
|
4
4
|
* Before the fix, `SubagentManager.spawn()` constructed the Conversation with
|
|
5
|
-
* `getProvider(
|
|
6
|
-
* `llm.callSites.subagentSpawn.provider` overrides only changed the
|
|
7
|
-
* *metadata* the downstream client saw — the actual HTTP transport
|
|
8
|
-
* belonged to
|
|
9
|
-
* in `CallSiteRoutingProvider`, which consults the resolver per call
|
|
10
|
-
* routes to the resolved provider's transport when it differs from the
|
|
5
|
+
* a `getProvider()` lookup of the default provider directly, which meant
|
|
6
|
+
* per-call `llm.callSites.subagentSpawn.provider` overrides only changed the
|
|
7
|
+
* request *metadata* the downstream client saw — the actual HTTP transport
|
|
8
|
+
* still belonged to the default provider. After the fix, the provider is
|
|
9
|
+
* wrapped in `CallSiteRoutingProvider`, which consults the resolver per call
|
|
10
|
+
* and routes to the resolved provider's transport when it differs from the
|
|
11
11
|
* default.
|
|
12
12
|
*
|
|
13
13
|
* This test stubs the `Conversation` constructor and the provider registry
|
|
@@ -15,19 +15,11 @@
|
|
|
15
15
|
* `Conversation`, then verify it's a `CallSiteRoutingProvider` that selects
|
|
16
16
|
* the right transport for the `subagentSpawn` callSite.
|
|
17
17
|
*/
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
|
|
21
|
-
import { setConfig } from "./helpers/set-config.js";
|
|
22
|
-
|
|
23
|
-
// Legacy-shaped fixtures (llm.default-centric resolution): pinned to the
|
|
24
|
-
// flag-off cascade. Override-or-default (flag-on) semantics are pinned by
|
|
25
|
-
// llm-resolver-override-or-default.test.ts and its companion suites.
|
|
26
|
-
beforeAll(() => {
|
|
27
|
-
setOverridesForTesting({ "override-or-default-resolution": false });
|
|
28
|
-
});
|
|
18
|
+
import { afterAll, describe, expect, mock, test } from "bun:test";
|
|
29
19
|
|
|
30
20
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
21
|
+
import { getProvider as getProviderImport } from "../providers/registry.js";
|
|
22
|
+
import { setConfig } from "./helpers/set-config.js";
|
|
31
23
|
|
|
32
24
|
// Capture the provider passed to Conversation.
|
|
33
25
|
let capturedProvider: unknown = undefined;
|
|
@@ -126,15 +118,27 @@ mock.module("../prompts/system-prompt.js", () => ({
|
|
|
126
118
|
}));
|
|
127
119
|
|
|
128
120
|
// Provider registry + connection resolver — routing goes through
|
|
129
|
-
// `provider_connection` exclusively. `getProvider`
|
|
130
|
-
//
|
|
131
|
-
//
|
|
121
|
+
// `provider_connection` exclusively. `getProvider` throws while this file's
|
|
122
|
+
// tests run (the production code under test must not call it), and delegates
|
|
123
|
+
// to the real registry afterwards: `mock.module` patches persist for the rest
|
|
124
|
+
// of the `bun test` process, and later test files (e.g. the platform-proxy
|
|
125
|
+
// integration suite) call the real `getProvider`. The real function is
|
|
126
|
+
// snapshotted before `mock.module` rebinds the import.
|
|
132
127
|
const anthropicStub = { name: "anthropic" };
|
|
133
128
|
const openaiStub = { name: "openai" };
|
|
134
129
|
|
|
130
|
+
const realGetProvider = getProviderImport;
|
|
131
|
+
let legacyGetProviderGuardArmed = true;
|
|
132
|
+
afterAll(() => {
|
|
133
|
+
legacyGetProviderGuardArmed = false;
|
|
134
|
+
});
|
|
135
|
+
|
|
135
136
|
mock.module("../providers/registry.js", () => ({
|
|
136
137
|
getProvider: (name: string) => {
|
|
137
|
-
|
|
138
|
+
if (legacyGetProviderGuardArmed) {
|
|
139
|
+
throw new Error(`legacy getProvider should not be called: ${name}`);
|
|
140
|
+
}
|
|
141
|
+
return realGetProvider(name);
|
|
138
142
|
},
|
|
139
143
|
resolveProviderFromConnection: async (connection: { name: string }) => {
|
|
140
144
|
if (connection.name === "anthropic-conn") {
|
|
@@ -189,19 +193,36 @@ function setLlmConfig(raw: unknown): void {
|
|
|
189
193
|
setConfig("llm", raw);
|
|
190
194
|
}
|
|
191
195
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Base LLM fixture: the workspace's default identity is a complete
|
|
198
|
+
* (provider + model) active profile carrying the `provider_connection` —
|
|
199
|
+
* `activeProfile` wins mainAgent resolution, and connections can only be
|
|
200
|
+
* declared on profiles (see the note on the second test below).
|
|
201
|
+
*/
|
|
202
|
+
function makeLlmFixture(
|
|
203
|
+
extras: {
|
|
204
|
+
profiles?: Record<string, unknown>;
|
|
205
|
+
callSites?: Record<string, unknown>;
|
|
206
|
+
} = {},
|
|
207
|
+
): Record<string, unknown> {
|
|
208
|
+
return {
|
|
209
|
+
profiles: {
|
|
210
|
+
primary: {
|
|
211
|
+
source: "user",
|
|
196
212
|
provider: "anthropic",
|
|
197
213
|
provider_connection: "anthropic-conn",
|
|
198
214
|
model: "claude-opus-4-7",
|
|
199
215
|
},
|
|
200
|
-
profiles
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
216
|
+
...extras.profiles,
|
|
217
|
+
},
|
|
218
|
+
activeProfile: "primary",
|
|
219
|
+
...(extras.callSites ? { callSites: extras.callSites } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
describe("SubagentManager — provider call-site routing", () => {
|
|
224
|
+
test("wraps the default provider in CallSiteRoutingProvider", async () => {
|
|
225
|
+
setLlmConfig(makeLlmFixture());
|
|
205
226
|
|
|
206
227
|
capturedProvider = undefined;
|
|
207
228
|
const manager = new SubagentManager();
|
|
@@ -224,25 +245,20 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
224
245
|
// entry would be silently stripped by Zod. The correct shape for an
|
|
225
246
|
// alternate-provider call-site override is a profile reference, defined
|
|
226
247
|
// here as `altOpenai`.
|
|
227
|
-
setLlmConfig(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
balanced: { source: "managed", status: "disabled" },
|
|
236
|
-
altOpenai: {
|
|
237
|
-
provider: "openai",
|
|
238
|
-
provider_connection: "openai-conn",
|
|
239
|
-
model: "gpt-5.4",
|
|
248
|
+
setLlmConfig(
|
|
249
|
+
makeLlmFixture({
|
|
250
|
+
profiles: {
|
|
251
|
+
altOpenai: {
|
|
252
|
+
provider: "openai",
|
|
253
|
+
provider_connection: "openai-conn",
|
|
254
|
+
model: "gpt-5.4",
|
|
255
|
+
},
|
|
240
256
|
},
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
},
|
|
245
|
-
|
|
257
|
+
callSites: {
|
|
258
|
+
subagentSpawn: { profile: "altOpenai" },
|
|
259
|
+
},
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
246
262
|
|
|
247
263
|
capturedProvider = undefined;
|
|
248
264
|
const manager = new SubagentManager();
|
|
@@ -266,18 +282,8 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
266
282
|
});
|
|
267
283
|
|
|
268
284
|
test("falls back to default provider when subagentSpawn callSite is absent", async () => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
provider: "anthropic",
|
|
272
|
-
provider_connection: "anthropic-conn",
|
|
273
|
-
model: "claude-opus-4-7",
|
|
274
|
-
},
|
|
275
|
-
profiles: {
|
|
276
|
-
// Disable the catalog default so resolution lands on llm.default.
|
|
277
|
-
balanced: { source: "managed", status: "disabled" },
|
|
278
|
-
},
|
|
279
|
-
// No subagentSpawn override.
|
|
280
|
-
});
|
|
285
|
+
// No subagentSpawn override.
|
|
286
|
+
setLlmConfig(makeLlmFixture());
|
|
281
287
|
|
|
282
288
|
capturedProvider = undefined;
|
|
283
289
|
const manager = new SubagentManager();
|
|
@@ -296,17 +302,7 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
296
302
|
});
|
|
297
303
|
|
|
298
304
|
test("copies parent guardian and auth context into spawned conversation", async () => {
|
|
299
|
-
setLlmConfig(
|
|
300
|
-
default: {
|
|
301
|
-
provider: "anthropic",
|
|
302
|
-
provider_connection: "anthropic-conn",
|
|
303
|
-
model: "claude-opus-4-7",
|
|
304
|
-
},
|
|
305
|
-
profiles: {
|
|
306
|
-
// Disable the catalog default so resolution lands on llm.default.
|
|
307
|
-
balanced: { source: "managed", status: "disabled" },
|
|
308
|
-
},
|
|
309
|
-
});
|
|
305
|
+
setLlmConfig(makeLlmFixture());
|
|
310
306
|
|
|
311
307
|
const parentTrustContext = {
|
|
312
308
|
sourceChannel: "vellum",
|
|
@@ -351,17 +347,7 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
351
347
|
});
|
|
352
348
|
|
|
353
349
|
test("copies the parent's plugin scope into the spawned conversation (by value)", async () => {
|
|
354
|
-
setLlmConfig(
|
|
355
|
-
default: {
|
|
356
|
-
provider: "anthropic",
|
|
357
|
-
provider_connection: "anthropic-conn",
|
|
358
|
-
model: "claude-opus-4-7",
|
|
359
|
-
},
|
|
360
|
-
profiles: {
|
|
361
|
-
// Disable the catalog default so resolution lands on llm.default.
|
|
362
|
-
balanced: { source: "managed", status: "disabled" },
|
|
363
|
-
},
|
|
364
|
-
});
|
|
350
|
+
setLlmConfig(makeLlmFixture());
|
|
365
351
|
|
|
366
352
|
const parentScope = ["caveman", "data"];
|
|
367
353
|
|
|
@@ -392,17 +378,7 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
392
378
|
});
|
|
393
379
|
|
|
394
380
|
test("propagates a null (unrestricted) parent scope unchanged", async () => {
|
|
395
|
-
setLlmConfig(
|
|
396
|
-
default: {
|
|
397
|
-
provider: "anthropic",
|
|
398
|
-
provider_connection: "anthropic-conn",
|
|
399
|
-
model: "claude-opus-4-7",
|
|
400
|
-
},
|
|
401
|
-
profiles: {
|
|
402
|
-
// Disable the catalog default so resolution lands on llm.default.
|
|
403
|
-
balanced: { source: "managed", status: "disabled" },
|
|
404
|
-
},
|
|
405
|
-
});
|
|
381
|
+
setLlmConfig(makeLlmFixture());
|
|
406
382
|
|
|
407
383
|
capturedConversations.length = 0;
|
|
408
384
|
clearConversations();
|
|
@@ -431,7 +407,6 @@ describe("SubagentManager — provider call-site routing", () => {
|
|
|
431
407
|
describe("CallSiteRoutingProvider — selectProvider behavior", () => {
|
|
432
408
|
test("routes to the resolved provider when callSite resolves to a profile with provider_connection", async () => {
|
|
433
409
|
setLlmConfig({
|
|
434
|
-
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
435
410
|
profiles: {
|
|
436
411
|
altOpenai: {
|
|
437
412
|
provider: "openai",
|
|
@@ -492,7 +467,6 @@ describe("CallSiteRoutingProvider — selectProvider behavior", () => {
|
|
|
492
467
|
|
|
493
468
|
test("routes to default when no callSite provided", async () => {
|
|
494
469
|
setLlmConfig({
|
|
495
|
-
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
496
470
|
callSites: {
|
|
497
471
|
subagentSpawn: { provider: "openai", model: "gpt-5.4" },
|
|
498
472
|
},
|
|
@@ -22,6 +22,7 @@ interface FakeManagedSubagent {
|
|
|
22
22
|
outputTokens: number;
|
|
23
23
|
estimatedCost: number;
|
|
24
24
|
};
|
|
25
|
+
subagentDeniedToolNames: Set<string>;
|
|
25
26
|
} | null;
|
|
26
27
|
state: SubagentState;
|
|
27
28
|
parentSendToClient: (msg: ServerMessage) => void;
|
|
@@ -51,6 +52,7 @@ function makeFakeConversation(): NonNullable<
|
|
|
51
52
|
messages: [],
|
|
52
53
|
sendToClient: () => {},
|
|
53
54
|
usageStats: { inputTokens: 100, outputTokens: 50, estimatedCost: 0.005 },
|
|
55
|
+
subagentDeniedToolNames: new Set<string>(),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -51,6 +51,7 @@ interface FakeManagedSubagent {
|
|
|
51
51
|
outputTokens: number;
|
|
52
52
|
estimatedCost: number;
|
|
53
53
|
};
|
|
54
|
+
subagentDeniedToolNames: Set<string>;
|
|
54
55
|
} | null;
|
|
55
56
|
state: SubagentState;
|
|
56
57
|
parentSendToClient: (msg: ServerMessage) => void;
|
|
@@ -80,6 +81,7 @@ function injectFakeSubagent(
|
|
|
80
81
|
messages: [],
|
|
81
82
|
sendToClient: () => {},
|
|
82
83
|
usageStats: { inputTokens: 100, outputTokens: 50, estimatedCost: 0.005 },
|
|
84
|
+
subagentDeniedToolNames: new Set<string>(),
|
|
83
85
|
};
|
|
84
86
|
|
|
85
87
|
const internals = asInternals(manager);
|
|
@@ -28,6 +28,7 @@ interface FakeManagedSubagent {
|
|
|
28
28
|
outputTokens: number;
|
|
29
29
|
estimatedCost: number;
|
|
30
30
|
};
|
|
31
|
+
subagentDeniedToolNames: Set<string>;
|
|
31
32
|
} | null;
|
|
32
33
|
state: SubagentState;
|
|
33
34
|
parentSendToClient: (msg: ServerMessage) => void;
|
|
@@ -57,6 +58,7 @@ function makeFakeConversation(): NonNullable<
|
|
|
57
58
|
messages: [],
|
|
58
59
|
sendToClient: () => {},
|
|
59
60
|
usageStats: { inputTokens: 100, outputTokens: 50, estimatedCost: 0.005 },
|
|
61
|
+
subagentDeniedToolNames: new Set<string>(),
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -51,6 +51,7 @@ interface FakeManagedSubagent {
|
|
|
51
51
|
outputTokens: number;
|
|
52
52
|
estimatedCost: number;
|
|
53
53
|
};
|
|
54
|
+
subagentDeniedToolNames: Set<string>;
|
|
54
55
|
} | null;
|
|
55
56
|
state: SubagentState;
|
|
56
57
|
parentSendToClient: (msg: ServerMessage) => void;
|
|
@@ -84,6 +85,7 @@ function injectFakeSubagent(
|
|
|
84
85
|
messages: [],
|
|
85
86
|
sendToClient: () => {},
|
|
86
87
|
usageStats: { inputTokens: 100, outputTokens: 50, estimatedCost: 0.005 },
|
|
88
|
+
subagentDeniedToolNames: new Set<string>(),
|
|
87
89
|
};
|
|
88
90
|
|
|
89
91
|
const internals = asInternals(manager);
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
SUBAGENT_ROLE_REGISTRY,
|
|
6
6
|
type SubagentRole,
|
|
7
7
|
} from "../subagent/index.js";
|
|
8
|
+
import { buildSubagentSystemPrompt } from "../subagent/manager.js";
|
|
9
|
+
import type { SubagentConfig } from "../subagent/types.js";
|
|
8
10
|
|
|
9
11
|
/** All roles defined in the SubagentRole union. */
|
|
10
12
|
const ALL_ROLES: SubagentRole[] = [
|
|
@@ -127,6 +129,41 @@ describe("SUBAGENT_ROLE_REGISTRY", () => {
|
|
|
127
129
|
});
|
|
128
130
|
});
|
|
129
131
|
|
|
132
|
+
describe("buildSubagentSystemPrompt — blocked-signal constraint", () => {
|
|
133
|
+
const cfg = (objective: string): SubagentConfig => ({
|
|
134
|
+
id: "sub-1",
|
|
135
|
+
parentConversationId: "conv-1",
|
|
136
|
+
label: "task",
|
|
137
|
+
objective,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("every role's constructed prompt tells it to signal blocked instead of fabricating a result", () => {
|
|
141
|
+
for (const role of ALL_ROLES) {
|
|
142
|
+
const prompt = buildSubagentSystemPrompt(
|
|
143
|
+
cfg("write the results to a CSV file"),
|
|
144
|
+
role,
|
|
145
|
+
);
|
|
146
|
+
expect(prompt).toContain("notify_parent");
|
|
147
|
+
expect(prompt).toContain('urgency "blocked"');
|
|
148
|
+
expect(prompt).toContain("do NOT fabricate");
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("the blocked-signal guidance is shared (Constraints), not baked into per-role preambles", () => {
|
|
153
|
+
// A read-only role and a write-capable role both receive it (role-agnostic).
|
|
154
|
+
expect(
|
|
155
|
+
buildSubagentSystemPrompt(cfg("save output"), "researcher"),
|
|
156
|
+
).toContain("do NOT fabricate");
|
|
157
|
+
expect(buildSubagentSystemPrompt(cfg("save output"), "coder")).toContain(
|
|
158
|
+
"do NOT fabricate",
|
|
159
|
+
);
|
|
160
|
+
// It is NOT duplicated into the researcher role's own preamble.
|
|
161
|
+
expect(
|
|
162
|
+
SUBAGENT_ROLE_REGISTRY.researcher.systemPromptPreamble,
|
|
163
|
+
).not.toContain("do NOT fabricate");
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
130
167
|
describe("mergeSkillIds", () => {
|
|
131
168
|
test("removes duplicates between role and config skill IDs", () => {
|
|
132
169
|
expect(mergeSkillIds(["a", "b"], ["b", "c"])).toEqual(["a", "b", "c"]);
|
|
@@ -56,6 +56,7 @@ let lastPersistedUserMessage: string | undefined;
|
|
|
56
56
|
class FakeConversation {
|
|
57
57
|
messages: Message[];
|
|
58
58
|
usageStats = { inputTokens: 10, outputTokens: 5, estimatedCost: 0.001 };
|
|
59
|
+
subagentDeniedToolNames = new Set<string>();
|
|
59
60
|
conversationType = "background";
|
|
60
61
|
hasSystemPromptOverride = false;
|
|
61
62
|
|
|
@@ -96,4 +96,54 @@ describe("buildSubagentTerminalMessage", () => {
|
|
|
96
96
|
expect(msg).toContain("Error: boom");
|
|
97
97
|
expect(msg).toContain("Do NOT re-spawn or retry");
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
test("appends a denied-tools note to an inlined completion", () => {
|
|
101
|
+
const msg = buildSubagentTerminalMessage({
|
|
102
|
+
label: "write-report",
|
|
103
|
+
subagentId: "sa-7",
|
|
104
|
+
isFork: false,
|
|
105
|
+
outcome: "completed",
|
|
106
|
+
silent: false,
|
|
107
|
+
finalText: "Here is what I found.",
|
|
108
|
+
deniedTools: ["file_write"],
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(msg).toContain("Here is what I found.");
|
|
112
|
+
expect(msg).toContain("attempted file_write");
|
|
113
|
+
expect(msg).toContain("does not permit it");
|
|
114
|
+
expect(msg).toContain("re-spawn with a role that includes it");
|
|
115
|
+
expect(msg).toContain("coder");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("appends a pluralized denied-tools note to a read-pointer completion", () => {
|
|
119
|
+
const msg = buildSubagentTerminalMessage({
|
|
120
|
+
label: "empty-write",
|
|
121
|
+
subagentId: "sa-8",
|
|
122
|
+
isFork: false,
|
|
123
|
+
outcome: "completed",
|
|
124
|
+
silent: false,
|
|
125
|
+
finalText: " ",
|
|
126
|
+
deniedTools: ["file_write", "file_edit"],
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(msg).toContain('subagent_read with subagent_id "sa-8"');
|
|
130
|
+
expect(msg).toContain("attempted file_write, file_edit");
|
|
131
|
+
expect(msg).toContain("does not permit them");
|
|
132
|
+
expect(msg).toContain("re-spawn with a role that includes them");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("omits the denied-tools note when none were denied", () => {
|
|
136
|
+
const msg = buildSubagentTerminalMessage({
|
|
137
|
+
label: "clean",
|
|
138
|
+
subagentId: "sa-9",
|
|
139
|
+
isFork: false,
|
|
140
|
+
outcome: "completed",
|
|
141
|
+
silent: false,
|
|
142
|
+
finalText: "All done.",
|
|
143
|
+
deniedTools: [],
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
expect(msg).not.toContain("does not permit");
|
|
147
|
+
expect(msg).not.toContain("re-spawn");
|
|
148
|
+
});
|
|
99
149
|
});
|
|
@@ -52,7 +52,6 @@ mock.module("../tools/browser/browser-screencast.js", () => ({
|
|
|
52
52
|
mock.module("../apps/app-store.js", () => ({
|
|
53
53
|
getApp: mock(() => null),
|
|
54
54
|
getAppDirPath: mock(() => "/tmp/test-apps/dummy"),
|
|
55
|
-
isMultifileApp: mock(() => false),
|
|
56
55
|
getAppsDir: mock(() => "/tmp/test-apps"),
|
|
57
56
|
resolveAppIdByDirName: mock(() => null),
|
|
58
57
|
resolveAppIdFromPath: mock(() => null),
|
|
@@ -225,13 +224,13 @@ describe("createResolveToolsCallback — subagentToolGateMode", () => {
|
|
|
225
224
|
|
|
226
225
|
describe("createResolveToolsCallback — toolContextPin", () => {
|
|
227
226
|
// Core defs spanning each client-gated family: host proxy (host_bash),
|
|
228
|
-
// dynamic UI (ui_show), connected-client (
|
|
227
|
+
// dynamic UI (ui_show), connected-client (ask_question), client-platform
|
|
229
228
|
// (request_system_permission), plus the always-on remember.
|
|
230
229
|
const CLIENT_GATED_DEFS = [
|
|
231
230
|
makeToolDef("remember"),
|
|
232
231
|
makeToolDef("host_bash"),
|
|
233
232
|
makeToolDef("ui_show"),
|
|
234
|
-
makeToolDef("
|
|
233
|
+
makeToolDef("ask_question"),
|
|
235
234
|
makeToolDef("request_system_permission"),
|
|
236
235
|
];
|
|
237
236
|
|
|
@@ -271,8 +270,9 @@ describe("createResolveToolsCallback — toolContextPin", () => {
|
|
|
271
270
|
.sort();
|
|
272
271
|
// request_system_permission stays out: it keys on
|
|
273
272
|
// channelCapabilities.clientOS, which desktop HTTP live turns never set
|
|
274
|
-
// either — exclusion IS parity there.
|
|
275
|
-
|
|
273
|
+
// either — exclusion IS parity there. ask_question stays IN: its
|
|
274
|
+
// macOS-specific hide also keys on clientOS, which the pin leaves unset.
|
|
275
|
+
expect(names).toEqual(["ask_question", "host_bash", "remember", "ui_show"]);
|
|
276
276
|
});
|
|
277
277
|
|
|
278
278
|
test("the pin REPLACES the live context — absent pin fields do not fall through", () => {
|
|
@@ -365,6 +365,79 @@ describe("createToolExecutor — execution-layer allowlist gate", () => {
|
|
|
365
365
|
expect(calls[0]!.name).toBe("remember");
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
+
test("execution mode: a denied call is recorded on subagentDeniedToolNames", async () => {
|
|
369
|
+
const denied = new Set<string>();
|
|
370
|
+
const { executor } = makeCapturingExecutor();
|
|
371
|
+
const toolFn = makeToolFn(
|
|
372
|
+
executor,
|
|
373
|
+
makeSetupCtx({
|
|
374
|
+
subagentAllowedTools: new Set(["remember"]),
|
|
375
|
+
subagentToolGateMode: "execution",
|
|
376
|
+
subagentDeniedToolNames: denied,
|
|
377
|
+
}),
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
await toolFn("bash", { command: "echo hi" });
|
|
381
|
+
|
|
382
|
+
expect([...denied]).toEqual(["bash"]);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("skill_execute records the resolved inner tool, not the wrapper", async () => {
|
|
386
|
+
const denied = new Set<string>();
|
|
387
|
+
const { executor } = makeCapturingExecutor();
|
|
388
|
+
const toolFn = makeToolFn(
|
|
389
|
+
executor,
|
|
390
|
+
makeSetupCtx({
|
|
391
|
+
subagentAllowedTools: new Set(["remember"]),
|
|
392
|
+
subagentToolGateMode: "execution",
|
|
393
|
+
subagentDeniedToolNames: denied,
|
|
394
|
+
}),
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
await toolFn("skill_execute", {
|
|
398
|
+
tool: "bash",
|
|
399
|
+
input: { command: "echo hi" },
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
expect(denied.has("bash")).toBe(true);
|
|
403
|
+
expect(denied.has("skill_execute")).toBe(false);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
test("records a non-allowlisted attempt even in wire gate mode (observation only)", async () => {
|
|
407
|
+
const denied = new Set<string>();
|
|
408
|
+
const { executor } = makeCapturingExecutor();
|
|
409
|
+
const toolFn = makeToolFn(
|
|
410
|
+
executor,
|
|
411
|
+
// No subagentToolGateMode → "wire": the executor does not reject here, but
|
|
412
|
+
// the out-of-allowlist attempt is still recorded for parent reporting.
|
|
413
|
+
makeSetupCtx({
|
|
414
|
+
subagentAllowedTools: new Set(["remember"]),
|
|
415
|
+
subagentDeniedToolNames: denied,
|
|
416
|
+
}),
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
await toolFn("bash", { command: "echo hi" });
|
|
420
|
+
|
|
421
|
+
expect(denied.has("bash")).toBe(true);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test("an allowlisted call records nothing", async () => {
|
|
425
|
+
const denied = new Set<string>();
|
|
426
|
+
const { executor } = makeCapturingExecutor();
|
|
427
|
+
const toolFn = makeToolFn(
|
|
428
|
+
executor,
|
|
429
|
+
makeSetupCtx({
|
|
430
|
+
subagentAllowedTools: new Set(["remember"]),
|
|
431
|
+
subagentToolGateMode: "execution",
|
|
432
|
+
subagentDeniedToolNames: denied,
|
|
433
|
+
}),
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
await toolFn("remember", { content: "a fact" });
|
|
437
|
+
|
|
438
|
+
expect([...denied]).toEqual([]);
|
|
439
|
+
});
|
|
440
|
+
|
|
368
441
|
test("execution mode: skill_execute gates the resolved inner tool, executor never invoked", async () => {
|
|
369
442
|
const { executor, calls } = makeCapturingExecutor();
|
|
370
443
|
const toolFn = makeToolFn(
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
24
24
|
|
|
25
|
+
import { INTERNAL_NUDGE_OUTPUT_SUPPRESSION } from "../plugin-api/constants.js";
|
|
25
26
|
import type {
|
|
26
27
|
PluginLogger,
|
|
27
28
|
PostModelCallContext,
|
|
@@ -152,6 +153,24 @@ beforeEach(() => {
|
|
|
152
153
|
|
|
153
154
|
// ─── Nudges when a progress surface is left open ──────────────────────────────
|
|
154
155
|
|
|
156
|
+
describe("surface-completion-nudge — internal-notice suppression", () => {
|
|
157
|
+
test("appends the shared suppression clause inside the notice wrapper", () => {
|
|
158
|
+
expect(SURFACE_COMPLETION_NUDGE_TEXT).toContain(
|
|
159
|
+
INTERNAL_NUDGE_OUTPUT_SUPPRESSION,
|
|
160
|
+
);
|
|
161
|
+
expect(SURFACE_COMPLETION_NUDGE_TEXT.startsWith("<system_notice>")).toBe(
|
|
162
|
+
true,
|
|
163
|
+
);
|
|
164
|
+
expect(SURFACE_COMPLETION_NUDGE_TEXT.endsWith("</system_notice>")).toBe(
|
|
165
|
+
true,
|
|
166
|
+
);
|
|
167
|
+
// The surface-advance + final-reply instruction still leads.
|
|
168
|
+
expect(SURFACE_COMPLETION_NUDGE_TEXT).toContain(
|
|
169
|
+
"Then give your final reply",
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
155
174
|
describe("surface-completion-nudge — nudges on a dangling progress surface", () => {
|
|
156
175
|
test("task_progress card shown and never completed → continue with nudge", async () => {
|
|
157
176
|
const shown = showSurface(taskProgressShow("in_progress"));
|