@vellumai/assistant 0.8.8 → 0.8.9-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -6
- package/bun.lock +2 -2
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +235 -6
- package/package.json +2 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +5 -4
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +5 -5
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/context-overflow-reducer.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +142 -218
- package/src/__tests__/conversation-agent-loop.test.ts +297 -586
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +14 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +70 -65
- package/src/__tests__/conversation-queue.test.ts +9 -9
- package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +6 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
- package/src/__tests__/conversation-speed-override.test.ts +10 -9
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
- package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -1
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +131 -26
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +12 -23
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +1 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +225 -9
- package/src/acp/resolve-agent.ts +122 -17
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +414 -248
- package/src/api/responses/conversation-message.ts +14 -1
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
- package/src/cli/lib/install-from-github.ts +464 -55
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +409 -0
- package/src/cli/lib/plugin-marketplace.ts +197 -0
- package/src/cli/lib/search-plugins.ts +195 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/bundled-skills/acp/SKILL.md +85 -33
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +15 -6
- package/src/config/schemas/call-site-catalog.ts +0 -14
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +0 -2
- package/src/context/compactor.ts +22 -4
- package/src/context/strip-injections.ts +8 -2
- package/src/context/window-manager.ts +27 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
- package/src/daemon/conversation-agent-loop.ts +175 -1055
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-process.ts +8 -136
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +293 -392
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +24 -8
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +404 -57
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +14 -19
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/server.ts +2 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +2 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +13 -4
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +6 -5
- package/src/plugin-api/types.ts +75 -0
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +7 -7
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +135 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +184 -74
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +315 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +28 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +16 -6
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +8 -2
- package/src/tools/acp/spawn.test.ts +176 -195
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +25 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/__tests__/plugin-external-api.test.ts +0 -68
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/plugins/external-api.ts +0 -104
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -34,22 +34,19 @@ describe("buildShimSource", () => {
|
|
|
34
34
|
test("emits a globalThis trampoline + one binding per export", () => {
|
|
35
35
|
const source = buildShimSource(
|
|
36
36
|
["foo", "bar"],
|
|
37
|
-
Symbol.for("vellum.plugin-api
|
|
37
|
+
Symbol.for("vellum.plugin-api"),
|
|
38
38
|
);
|
|
39
39
|
expect(source).toBe(
|
|
40
|
-
`const api = globalThis[Symbol.for("vellum.plugin-api
|
|
40
|
+
`const api = globalThis[Symbol.for("vellum.plugin-api")];\n` +
|
|
41
41
|
`export const foo = api.foo;\n` +
|
|
42
42
|
`export const bar = api.bar;\n`,
|
|
43
43
|
);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
test("handles an empty export list (today's types-only surface)", () => {
|
|
47
|
-
const source = buildShimSource(
|
|
48
|
-
[],
|
|
49
|
-
Symbol.for("vellum.plugin-api.v1"),
|
|
50
|
-
);
|
|
47
|
+
const source = buildShimSource([], Symbol.for("vellum.plugin-api"));
|
|
51
48
|
expect(source).toBe(
|
|
52
|
-
`const api = globalThis[Symbol.for("vellum.plugin-api
|
|
49
|
+
`const api = globalThis[Symbol.for("vellum.plugin-api")];\n`,
|
|
53
50
|
);
|
|
54
51
|
});
|
|
55
52
|
});
|
|
@@ -109,7 +106,7 @@ describe("ensurePluginApiShim", () => {
|
|
|
109
106
|
const pluginDir = join(workspaceDir, "plugins", "fake-plugin");
|
|
110
107
|
await mkdir(pluginDir, { recursive: true });
|
|
111
108
|
await writeFile(
|
|
112
|
-
join(pluginDir, "
|
|
109
|
+
join(pluginDir, "probe.js"),
|
|
113
110
|
`import * as api from "@vellumai/plugin-api";\nexport { api };\n`,
|
|
114
111
|
);
|
|
115
112
|
|
|
@@ -118,7 +115,7 @@ describe("ensurePluginApiShim", () => {
|
|
|
118
115
|
// → plugin-api namespace. If any link in that chain is broken, this
|
|
119
116
|
// import throws.
|
|
120
117
|
const mod: { api: Record<string, unknown> } = await import(
|
|
121
|
-
join(pluginDir, "
|
|
118
|
+
join(pluginDir, "probe.js")
|
|
122
119
|
);
|
|
123
120
|
expect(mod.api).toBeDefined();
|
|
124
121
|
});
|
|
@@ -38,13 +38,11 @@ import { RiskLevel } from "../permissions/types.js";
|
|
|
38
38
|
import { registerDefaultPlugins } from "../plugins/defaults/index.js";
|
|
39
39
|
import {
|
|
40
40
|
closeRegistration,
|
|
41
|
-
getMiddlewaresFor,
|
|
42
41
|
getRegisteredPlugins,
|
|
43
42
|
registerPlugin,
|
|
44
43
|
resetPluginRegistryForTests,
|
|
45
44
|
} from "../plugins/registry.js";
|
|
46
45
|
import {
|
|
47
|
-
type PipelineMiddlewareMap,
|
|
48
46
|
type Plugin,
|
|
49
47
|
PluginExecutionError,
|
|
50
48
|
type PluginInitContext,
|
|
@@ -485,33 +483,24 @@ describe("plugin bootstrap", () => {
|
|
|
485
483
|
expect(initFired).toBe(false);
|
|
486
484
|
});
|
|
487
485
|
|
|
488
|
-
test("requiresFlag disabled: plugin
|
|
489
|
-
// Regression:
|
|
490
|
-
//
|
|
491
|
-
// `
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
setOverridesForTesting({ "plugin-middleware-disabled": false });
|
|
495
|
-
|
|
496
|
-
const gatedMiddleware: PipelineMiddlewareMap["compaction"] = async (
|
|
497
|
-
args,
|
|
498
|
-
next,
|
|
499
|
-
) => next(args);
|
|
486
|
+
test("requiresFlag disabled: the skipped plugin is removed from the registry", async () => {
|
|
487
|
+
// Regression: a flag-gated skip must call `unregisterPlugin()` so the
|
|
488
|
+
// gated-off plugin does not linger in `registeredPlugins` with its
|
|
489
|
+
// `init()` never having fired to set up the state it depends on.
|
|
490
|
+
setOverridesForTesting({ "plugin-registry-disabled": false });
|
|
491
|
+
|
|
500
492
|
const plugin = buildPlugin(
|
|
501
|
-
"gated-
|
|
502
|
-
{
|
|
503
|
-
|
|
504
|
-
},
|
|
505
|
-
{ requiresFlag: ["plugin-middleware-disabled"] },
|
|
493
|
+
"gated-registry",
|
|
494
|
+
{},
|
|
495
|
+
{ requiresFlag: ["plugin-registry-disabled"] },
|
|
506
496
|
);
|
|
507
497
|
registerPlugin(plugin);
|
|
508
498
|
|
|
509
499
|
await bootstrapPlugins();
|
|
510
500
|
|
|
511
|
-
// The
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
expect(getMiddlewaresFor("compaction")).not.toContain(gatedMiddleware);
|
|
501
|
+
// The gated-off plugin must not survive in the registry snapshot.
|
|
502
|
+
const names = getRegisteredPlugins().map((p) => p.manifest.name);
|
|
503
|
+
expect(names).not.toContain("gated-registry");
|
|
515
504
|
});
|
|
516
505
|
|
|
517
506
|
test("requiresFlag disabled: no shutdown hook entry installed for the skipped plugin", async () => {
|
|
@@ -2,26 +2,19 @@
|
|
|
2
2
|
* Tests for the plugin registry (PR 13).
|
|
3
3
|
*
|
|
4
4
|
* Covers successful registration, required-field and duplicate-name
|
|
5
|
-
* validation, capability-version negotiation error messaging,
|
|
6
|
-
*
|
|
5
|
+
* validation, capability-version negotiation error messaging, and
|
|
6
|
+
* registration order.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
closeRegistration,
|
|
13
|
-
getMiddlewaresFor,
|
|
14
13
|
getRegisteredPlugins,
|
|
15
14
|
registerPlugin,
|
|
16
15
|
resetPluginRegistryForTests,
|
|
17
16
|
} from "../plugins/registry.js";
|
|
18
|
-
import {
|
|
19
|
-
type CompactionArgs,
|
|
20
|
-
type CompactionResult,
|
|
21
|
-
type Middleware,
|
|
22
|
-
type Plugin,
|
|
23
|
-
PluginExecutionError,
|
|
24
|
-
} from "../plugins/types.js";
|
|
17
|
+
import { type Plugin, PluginExecutionError } from "../plugins/types.js";
|
|
25
18
|
|
|
26
19
|
/** Build a minimal, valid plugin with the given name and optional extras. */
|
|
27
20
|
function buildPlugin(
|
|
@@ -147,45 +140,6 @@ describe("plugin registry", () => {
|
|
|
147
140
|
expect(() => registerPlugin(bad)).toThrow(/manifest\.version is required/);
|
|
148
141
|
});
|
|
149
142
|
|
|
150
|
-
test("getMiddlewaresFor returns middleware in registration order", () => {
|
|
151
|
-
const firstMw: Middleware<CompactionArgs, CompactionResult> = async (
|
|
152
|
-
args,
|
|
153
|
-
next,
|
|
154
|
-
) => next(args);
|
|
155
|
-
const secondMw: Middleware<CompactionArgs, CompactionResult> = async (
|
|
156
|
-
args,
|
|
157
|
-
next,
|
|
158
|
-
) => next(args);
|
|
159
|
-
|
|
160
|
-
registerPlugin(
|
|
161
|
-
buildPlugin("plugin-first", { middleware: { compaction: firstMw } }),
|
|
162
|
-
);
|
|
163
|
-
registerPlugin(
|
|
164
|
-
buildPlugin("plugin-second", { middleware: { compaction: secondMw } }),
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const middlewares = getMiddlewaresFor("compaction");
|
|
168
|
-
expect(middlewares).toHaveLength(2);
|
|
169
|
-
// Identity comparison proves the middleware instances come back in
|
|
170
|
-
// registration order — outer→inner composition semantics belong to the
|
|
171
|
-
// pipeline runner (PR 12), not the registry.
|
|
172
|
-
expect(middlewares[0]).toBe(firstMw);
|
|
173
|
-
expect(middlewares[1]).toBe(secondMw);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("getMiddlewaresFor skips plugins without a middleware for the pipeline", () => {
|
|
177
|
-
const mw: Middleware<CompactionArgs, CompactionResult> = async (
|
|
178
|
-
args,
|
|
179
|
-
next,
|
|
180
|
-
) => next(args);
|
|
181
|
-
registerPlugin(buildPlugin("bare"));
|
|
182
|
-
registerPlugin(buildPlugin("has-mw", { middleware: { compaction: mw } }));
|
|
183
|
-
|
|
184
|
-
const middlewares = getMiddlewaresFor("compaction");
|
|
185
|
-
expect(middlewares).toHaveLength(1);
|
|
186
|
-
expect(middlewares[0]).toBe(mw);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
143
|
test("getRegisteredPlugins reflects registration order", () => {
|
|
190
144
|
registerPlugin(buildPlugin("one"));
|
|
191
145
|
registerPlugin(buildPlugin("two"));
|
|
@@ -13,18 +13,10 @@ import { describe, expect, test } from "bun:test";
|
|
|
13
13
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
14
14
|
import { RiskLevel } from "../permissions/types.js";
|
|
15
15
|
import {
|
|
16
|
-
type CircuitBreakerArgs,
|
|
17
|
-
type CircuitBreakerResult,
|
|
18
|
-
type CompactionArgs,
|
|
19
|
-
type CompactionResult,
|
|
20
|
-
type Middleware,
|
|
21
|
-
type OverflowReduceArgs,
|
|
22
|
-
type OverflowReduceResult,
|
|
23
16
|
type Plugin,
|
|
24
17
|
PluginExecutionError,
|
|
25
18
|
type PluginInitContext,
|
|
26
19
|
type PluginManifest,
|
|
27
|
-
PluginTimeoutError,
|
|
28
20
|
type TurnContext,
|
|
29
21
|
} from "../plugins/types.js";
|
|
30
22
|
import type { Tool } from "../tools/types.js";
|
|
@@ -38,7 +30,6 @@ const sampleTurnContext: TurnContext = {
|
|
|
38
30
|
requestId: "req-abc",
|
|
39
31
|
conversationId: "conv-xyz",
|
|
40
32
|
turnIndex: 0,
|
|
41
|
-
pluginName: "sample-plugin",
|
|
42
33
|
trust: sampleTrust,
|
|
43
34
|
};
|
|
44
35
|
|
|
@@ -52,43 +43,6 @@ describe("plugin core types", () => {
|
|
|
52
43
|
config: { parse: (input: unknown) => input },
|
|
53
44
|
};
|
|
54
45
|
|
|
55
|
-
// `overflowReduce` has a concrete arg/result shape (PR 23). Uses a
|
|
56
|
-
// dedicated passthrough that returns a structurally-correct result so
|
|
57
|
-
// `satisfies Plugin` keeps verifying the signature.
|
|
58
|
-
const overflowReducePassthrough: Middleware<
|
|
59
|
-
OverflowReduceArgs,
|
|
60
|
-
OverflowReduceResult
|
|
61
|
-
> = async (args, _next, _ctx) => ({
|
|
62
|
-
messages: args.messages,
|
|
63
|
-
runMessages: args.runMessages,
|
|
64
|
-
injectionMode: "full",
|
|
65
|
-
reducerState: {
|
|
66
|
-
appliedTiers: [],
|
|
67
|
-
injectionMode: "full",
|
|
68
|
-
exhausted: true,
|
|
69
|
-
},
|
|
70
|
-
reducerCompacted: false,
|
|
71
|
-
attempts: 0,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Slot-specific passthrough for the `compaction` pipeline — PR 25
|
|
75
|
-
// narrowed its args/result away from the generic `{ input: unknown }`
|
|
76
|
-
// placeholder, so the generic `passthrough` no longer satisfies its
|
|
77
|
-
// middleware signature. This dedicated middleware keeps the shape-only
|
|
78
|
-
// assertion for the slot without forcing every other slot to narrow.
|
|
79
|
-
const compactionPassthrough: Middleware<
|
|
80
|
-
CompactionArgs,
|
|
81
|
-
CompactionResult
|
|
82
|
-
> = async (args, next, _ctx) => next(args);
|
|
83
|
-
|
|
84
|
-
// `circuitBreaker` carries a concrete arg shape (pipeline wrapping
|
|
85
|
-
// landed ahead of the other slots) so it needs its own passthrough
|
|
86
|
-
// rather than reusing the generic placeholder.
|
|
87
|
-
const circuitPassthrough: Middleware<
|
|
88
|
-
CircuitBreakerArgs,
|
|
89
|
-
CircuitBreakerResult
|
|
90
|
-
> = async (args, next, _ctx) => next(args);
|
|
91
|
-
|
|
92
46
|
const sampleTool: Tool = {
|
|
93
47
|
name: "sample-tool",
|
|
94
48
|
description: "Sample plugin tool",
|
|
@@ -132,34 +86,10 @@ describe("plugin core types", () => {
|
|
|
132
86
|
body: "## Sample\n\nPlugin-provided skill body.",
|
|
133
87
|
},
|
|
134
88
|
],
|
|
135
|
-
middleware: {
|
|
136
|
-
compaction: compactionPassthrough,
|
|
137
|
-
overflowReduce: overflowReducePassthrough,
|
|
138
|
-
circuitBreaker: circuitPassthrough,
|
|
139
|
-
},
|
|
140
89
|
} satisfies Plugin;
|
|
141
90
|
|
|
142
91
|
// Minimal runtime check so the test body is non-empty.
|
|
143
92
|
expect(plugin.manifest.name).toBe("sample-plugin");
|
|
144
|
-
expect(plugin.middleware.compaction).toBe(compactionPassthrough);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("PluginTimeoutError carries pipeline, plugin, and elapsed fields", () => {
|
|
148
|
-
const err = new PluginTimeoutError("compaction", "sample-plugin", 30000);
|
|
149
|
-
expect(err).toBeInstanceOf(Error);
|
|
150
|
-
expect(err.name).toBe("PluginTimeoutError");
|
|
151
|
-
expect(err.pipeline).toBe("compaction");
|
|
152
|
-
expect(err.pluginName).toBe("sample-plugin");
|
|
153
|
-
expect(err.elapsedMs).toBe(30000);
|
|
154
|
-
expect(err.message).toContain("compaction");
|
|
155
|
-
expect(err.message).toContain("30000");
|
|
156
|
-
expect(err.message).toContain("sample-plugin");
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test("PluginTimeoutError omits plugin suffix when unknown", () => {
|
|
160
|
-
const err = new PluginTimeoutError("circuitBreaker", undefined, 1234);
|
|
161
|
-
expect(err.pluginName).toBeUndefined();
|
|
162
|
-
expect(err.message).not.toContain("offending plugin");
|
|
163
93
|
});
|
|
164
94
|
|
|
165
95
|
test("PluginExecutionError carries the plugin name and message", () => {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { preModelCallSanitize } from "../agent/loop.js";
|
|
4
|
+
import type { Message } from "../providers/types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `preModelCallSanitize` is the loop's single pre-send transform: it converts
|
|
8
|
+
* historical `web_search_tool_result` blocks to text alongside the media and
|
|
9
|
+
* AX-tree strips, so every provider call — first call, post-compaction, and
|
|
10
|
+
* recovery reruns — is sanitized in one place. These tests guard that the
|
|
11
|
+
* helper actually performs the web-search conversion and is idempotent.
|
|
12
|
+
*/
|
|
13
|
+
describe("preModelCallSanitize", () => {
|
|
14
|
+
test("passes through history with nothing to sanitize", () => {
|
|
15
|
+
// GIVEN a plain conversation with no media, AX trees, or web-search blocks
|
|
16
|
+
const messages: Message[] = [
|
|
17
|
+
{ role: "user", content: [{ type: "text", text: "Hello" }] },
|
|
18
|
+
{ role: "assistant", content: [{ type: "text", text: "Hi" }] },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// WHEN the loop sanitizes the outbound history
|
|
22
|
+
const result = preModelCallSanitize(messages);
|
|
23
|
+
|
|
24
|
+
// THEN the history is returned unchanged
|
|
25
|
+
expect(result).toEqual(messages);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("converts historical web_search_tool_result blocks to text summaries", () => {
|
|
29
|
+
// GIVEN an assistant turn whose web_search_tool_result carries an opaque
|
|
30
|
+
// encrypted_content token that would be rejected if replayed
|
|
31
|
+
const messages: Message[] = [
|
|
32
|
+
{ role: "user", content: [{ type: "text", text: "Search cats" }] },
|
|
33
|
+
{
|
|
34
|
+
role: "assistant",
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "server_tool_use",
|
|
38
|
+
id: "stu_1",
|
|
39
|
+
name: "web_search",
|
|
40
|
+
input: { query: "cats" },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "web_search_tool_result",
|
|
44
|
+
tool_use_id: "stu_1",
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "web_search_result",
|
|
48
|
+
url: "https://cats.com",
|
|
49
|
+
title: "Cats!",
|
|
50
|
+
encrypted_content: "expired_token_1",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
// WHEN the loop sanitizes the outbound history
|
|
59
|
+
const result = preModelCallSanitize(messages);
|
|
60
|
+
|
|
61
|
+
// THEN the opaque block is replaced with a plaintext title+URL summary and
|
|
62
|
+
// the paired server_tool_use is dropped, so no expired token is replayed
|
|
63
|
+
const assistantMsg = result[1];
|
|
64
|
+
expect(assistantMsg.content.map((b) => b.type)).toEqual(["text"]);
|
|
65
|
+
const summary = assistantMsg.content[0];
|
|
66
|
+
expect(summary.type).toBe("text");
|
|
67
|
+
if (summary.type === "text") {
|
|
68
|
+
expect(summary.text).toContain("Cats!");
|
|
69
|
+
expect(summary.text).toContain("https://cats.com");
|
|
70
|
+
expect(summary.text).not.toContain("expired_token_1");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("is idempotent — re-sanitizing already-sanitized history is a no-op", () => {
|
|
75
|
+
// GIVEN history that has already been sanitized once
|
|
76
|
+
const messages: Message[] = [
|
|
77
|
+
{
|
|
78
|
+
role: "assistant",
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "server_tool_use",
|
|
82
|
+
id: "stu_A",
|
|
83
|
+
name: "web_search",
|
|
84
|
+
input: { query: "alpha" },
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: "web_search_tool_result",
|
|
88
|
+
tool_use_id: "stu_A",
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "web_search_result",
|
|
92
|
+
url: "https://a.example",
|
|
93
|
+
title: "A",
|
|
94
|
+
encrypted_content: "tok_A",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
const once = preModelCallSanitize(messages);
|
|
102
|
+
|
|
103
|
+
// WHEN it is sanitized a second time (every outbound call re-runs the helper)
|
|
104
|
+
const twice = preModelCallSanitize(once);
|
|
105
|
+
|
|
106
|
+
// THEN the second pass changes nothing
|
|
107
|
+
expect(twice).toEqual(once);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -27,7 +27,7 @@ mock.module("../config/env.js", () => ({
|
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
29
|
const _conversationMocks = new Map<string, unknown>();
|
|
30
|
-
mock.module("../daemon/conversation-
|
|
30
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
31
31
|
findConversation: (id: string) => _conversationMocks.get(id),
|
|
32
32
|
}));
|
|
33
33
|
|
|
@@ -91,11 +91,14 @@ mock.module("../config/loader.js", () => ({
|
|
|
91
91
|
let _conversationFactory: (() => Conversation) | undefined;
|
|
92
92
|
let _approvalGenerator: unknown;
|
|
93
93
|
|
|
94
|
-
mock.module("../daemon/conversation-
|
|
94
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
95
95
|
findConversation: () => {
|
|
96
96
|
if (!_conversationFactory) return undefined;
|
|
97
97
|
return _conversationFactory();
|
|
98
98
|
},
|
|
99
|
+
}));
|
|
100
|
+
|
|
101
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
99
102
|
getOrCreateConversation: async (..._args: unknown[]) => {
|
|
100
103
|
if (!_conversationFactory)
|
|
101
104
|
throw new Error("_conversationFactory not set in test");
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* parses it via the real frontmatter parser, and verifies that `skillFlagKey()`
|
|
6
6
|
* returns the correct key and `resolveSkillStates()` correctly gates the skill.
|
|
7
7
|
*/
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
8
10
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
11
|
|
|
10
12
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
@@ -225,3 +227,34 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
225
227
|
expect(resolvedOff.length).toBe(0);
|
|
226
228
|
});
|
|
227
229
|
});
|
|
230
|
+
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Bundled ACP skill: discoverability when ACP is disabled
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
describe("bundled acp skill discoverability", () => {
|
|
236
|
+
test("acp skill resolves with the flag off and config.acp disabled (no frontmatter flag gate)", () => {
|
|
237
|
+
// The ACP skill carries its own first-time-setup instructions, so it must
|
|
238
|
+
// stay visible even when the acp flag and config.acp.enabled are both off.
|
|
239
|
+
// Runtime enforcement happens in the ACP tools via isAcpEnabled instead.
|
|
240
|
+
const skillMdPath = fileURLToPath(
|
|
241
|
+
new URL("../config/bundled-skills/acp/SKILL.md", import.meta.url),
|
|
242
|
+
);
|
|
243
|
+
const skillMd = readFileSync(skillMdPath, "utf8");
|
|
244
|
+
|
|
245
|
+
const skill = buildSkillSummary("acp", skillMd);
|
|
246
|
+
expect(skill).not.toBeNull();
|
|
247
|
+
expect(skill!.featureFlag).toBeUndefined();
|
|
248
|
+
expect(skillFlagKey(skill!)).toBeUndefined();
|
|
249
|
+
|
|
250
|
+
// acp flag at its registry default (off) and config.acp disabled.
|
|
251
|
+
const config = makeConfig({
|
|
252
|
+
acp: { enabled: false, maxConcurrentSessions: 4, agents: {} },
|
|
253
|
+
} as Partial<AssistantConfig>);
|
|
254
|
+
|
|
255
|
+
const resolved = resolveSkillStates([skill!], config);
|
|
256
|
+
expect(resolved.length).toBe(1);
|
|
257
|
+
expect(resolved[0].summary.id).toBe("acp");
|
|
258
|
+
expect(resolved[0].state).toBe("enabled");
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -14,7 +14,7 @@ import type { Message } from "../providers/types.js";
|
|
|
14
14
|
/**
|
|
15
15
|
* Minimal reproduction of repairPendingToolUseBlocks logic for direct
|
|
16
16
|
* unit testing. The real implementation lives in conversation-process.ts.
|
|
17
|
-
* This mirrors it exactly to avoid needing the full
|
|
17
|
+
* This mirrors it exactly to avoid needing the full Conversation.
|
|
18
18
|
*/
|
|
19
19
|
function repairPendingToolUseBlocks(messages: Message[]): Message[] {
|
|
20
20
|
if (messages.length === 0) return messages;
|
|
@@ -174,7 +174,7 @@ import { LLMSchema } from "../config/schemas/llm.js";
|
|
|
174
174
|
import {
|
|
175
175
|
clearConversations,
|
|
176
176
|
setConversation,
|
|
177
|
-
} from "../daemon/conversation-
|
|
177
|
+
} from "../daemon/conversation-registry.js";
|
|
178
178
|
import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
|
|
179
179
|
import { SubagentManager } from "../subagent/manager.js";
|
|
180
180
|
|
|
@@ -18,6 +18,7 @@ function msg(role: string, content: unknown[]): MessageRow {
|
|
|
18
18
|
content: JSON.stringify(content),
|
|
19
19
|
createdAt: Date.now(),
|
|
20
20
|
metadata: null,
|
|
21
|
+
clientMessageId: null,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -26,10 +27,19 @@ describe("parseSubagentMessages", () => {
|
|
|
26
27
|
const messages = [
|
|
27
28
|
msg("user", [{ type: "text", text: "Do something" }]),
|
|
28
29
|
msg("assistant", [
|
|
29
|
-
{
|
|
30
|
+
{
|
|
31
|
+
type: "tool_use",
|
|
32
|
+
id: "t1",
|
|
33
|
+
name: "web_search",
|
|
34
|
+
input: { query: "test" },
|
|
35
|
+
},
|
|
30
36
|
]),
|
|
31
37
|
msg("user", [
|
|
32
|
-
{
|
|
38
|
+
{
|
|
39
|
+
type: "tool_result",
|
|
40
|
+
tool_use_id: "t1",
|
|
41
|
+
content: "Search results here",
|
|
42
|
+
},
|
|
33
43
|
]),
|
|
34
44
|
];
|
|
35
45
|
|
|
@@ -44,7 +54,12 @@ describe("parseSubagentMessages", () => {
|
|
|
44
54
|
const messages = [
|
|
45
55
|
msg("user", [{ type: "text", text: "Do something" }]),
|
|
46
56
|
msg("assistant", [
|
|
47
|
-
{
|
|
57
|
+
{
|
|
58
|
+
type: "tool_use",
|
|
59
|
+
id: "t2",
|
|
60
|
+
name: "file_read",
|
|
61
|
+
input: { file_path: "/tmp/test.txt" },
|
|
62
|
+
},
|
|
48
63
|
]),
|
|
49
64
|
msg("user", [
|
|
50
65
|
{
|
|
@@ -69,11 +84,14 @@ describe("parseSubagentMessages", () => {
|
|
|
69
84
|
const messages = [
|
|
70
85
|
msg("user", [{ type: "text", text: "Do something" }]),
|
|
71
86
|
msg("assistant", [
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
87
|
+
{
|
|
88
|
+
type: "tool_use",
|
|
89
|
+
id: "t3",
|
|
90
|
+
name: "bash",
|
|
91
|
+
input: { command: "echo hi" },
|
|
92
|
+
},
|
|
76
93
|
]),
|
|
94
|
+
msg("user", [{ type: "tool_result", tool_use_id: "t3", content: null }]),
|
|
77
95
|
];
|
|
78
96
|
|
|
79
97
|
const result = parseSubagentMessages("sub-1", messages);
|
|
@@ -11,7 +11,7 @@ const capturedNotifications: {
|
|
|
11
11
|
message: string;
|
|
12
12
|
}[] = [];
|
|
13
13
|
|
|
14
|
-
mock.module("../daemon/conversation-
|
|
14
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
15
15
|
findConversation: (id: string) => ({
|
|
16
16
|
enqueueMessage: (options: { content: string }) => {
|
|
17
17
|
capturedNotifications.push({
|
|
@@ -23,8 +23,6 @@ mock.module("../daemon/conversation-store.js", () => ({
|
|
|
23
23
|
persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
|
|
24
24
|
runAgentLoop: async () => {},
|
|
25
25
|
}),
|
|
26
|
-
addConversation: () => {},
|
|
27
|
-
removeConversation: () => {},
|
|
28
26
|
}));
|
|
29
27
|
|
|
30
28
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
clearConversations,
|
|
5
5
|
findConversation,
|
|
6
6
|
setConversation,
|
|
7
|
-
} from "../daemon/conversation-
|
|
7
|
+
} from "../daemon/conversation-registry.js";
|
|
8
8
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
9
9
|
import type { Message } from "../providers/types.js";
|
|
10
10
|
import { SubagentManager } from "../subagent/manager.js";
|
|
@@ -11,7 +11,7 @@ const capturedNotifications: {
|
|
|
11
11
|
message: string;
|
|
12
12
|
}[] = [];
|
|
13
13
|
|
|
14
|
-
mock.module("../daemon/conversation-
|
|
14
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
15
15
|
findConversation: (id: string) => ({
|
|
16
16
|
enqueueMessage: (options: { content: string }) => {
|
|
17
17
|
capturedNotifications.push({
|
|
@@ -23,8 +23,6 @@ mock.module("../daemon/conversation-store.js", () => ({
|
|
|
23
23
|
persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
|
|
24
24
|
runAgentLoop: async () => {},
|
|
25
25
|
}),
|
|
26
|
-
addConversation: () => {},
|
|
27
|
-
removeConversation: () => {},
|
|
28
26
|
}));
|
|
29
27
|
|
|
30
28
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
@@ -36,7 +36,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
36
36
|
*/
|
|
37
37
|
const capturedMessages: string[] = [];
|
|
38
38
|
|
|
39
|
-
mock.module("../daemon/conversation-
|
|
39
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
40
40
|
findConversation: (_id: string) => ({
|
|
41
41
|
enqueueMessage: (options: { content: string }) => {
|
|
42
42
|
capturedMessages.push(options.content);
|
|
@@ -45,8 +45,6 @@ mock.module("../daemon/conversation-store.js", () => ({
|
|
|
45
45
|
persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
|
|
46
46
|
runAgentLoop: async () => {},
|
|
47
47
|
}),
|
|
48
|
-
addConversation: () => {},
|
|
49
|
-
removeConversation: () => {},
|
|
50
48
|
}));
|
|
51
49
|
|
|
52
50
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
@@ -32,7 +32,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
32
32
|
import {
|
|
33
33
|
clearConversations,
|
|
34
34
|
setConversation,
|
|
35
|
-
} from "../daemon/conversation-
|
|
35
|
+
} from "../daemon/conversation-registry.js";
|
|
36
36
|
import type { Message } from "../providers/types.js";
|
|
37
37
|
import { getSubagentManager } from "../subagent/index.js";
|
|
38
38
|
import { executeSubagentSpawn } from "../tools/subagent/spawn.js";
|
|
@@ -51,9 +51,9 @@ import type {
|
|
|
51
51
|
StopContext,
|
|
52
52
|
UserPromptSubmitContext,
|
|
53
53
|
} from "../plugin-api/types.js";
|
|
54
|
+
import { defaultTitleGeneratePlugin } from "../plugins/defaults/index.js";
|
|
54
55
|
import stop from "../plugins/defaults/title-generate/hooks/stop.js";
|
|
55
56
|
import userPromptSubmit from "../plugins/defaults/title-generate/hooks/user-prompt-submit.js";
|
|
56
|
-
import { defaultTitleGeneratePlugin } from "../plugins/defaults/title-generate/register.js";
|
|
57
57
|
import { runHook } from "../plugins/pipeline.js";
|
|
58
58
|
import {
|
|
59
59
|
registerPlugin,
|
|
@@ -18,10 +18,10 @@ import { beforeEach, describe, expect, test } from "bun:test";
|
|
|
18
18
|
|
|
19
19
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
20
20
|
import type { PluginLogger, PostToolUseContext } from "../plugin-api/types.js";
|
|
21
|
+
import { defaultToolErrorPlugin } from "../plugins/defaults/index.js";
|
|
21
22
|
import postToolUse, {
|
|
22
23
|
TOOL_ERROR_NUDGE_TEXT,
|
|
23
24
|
} from "../plugins/defaults/tool-error/hooks/post-tool-use.js";
|
|
24
|
-
import { defaultToolErrorPlugin } from "../plugins/defaults/tool-error/register.js";
|
|
25
25
|
import { runHook } from "../plugins/pipeline.js";
|
|
26
26
|
import {
|
|
27
27
|
registerPlugin,
|
|
@@ -16,8 +16,8 @@ import { beforeEach, describe, expect, test } from "bun:test";
|
|
|
16
16
|
|
|
17
17
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
18
18
|
import type { PluginLogger, PostToolUseContext } from "../plugin-api/types.js";
|
|
19
|
+
import { defaultToolResultTruncatePlugin } from "../plugins/defaults/index.js";
|
|
19
20
|
import postToolUse from "../plugins/defaults/tool-result-truncate/hooks/post-tool-use.js";
|
|
20
|
-
import { defaultToolResultTruncatePlugin } from "../plugins/defaults/tool-result-truncate/register.js";
|
|
21
21
|
import {
|
|
22
22
|
truncateToolResult,
|
|
23
23
|
TRUNCATION_SUFFIX,
|