@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- 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/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.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__/clawhub-files.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.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- 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__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- 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__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- 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__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- 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 +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -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 +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- 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/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- 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/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -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-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- 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/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.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/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- 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__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- 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 +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- 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 +104 -32
- 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 +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- 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/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- 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 +51 -45
- 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 +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- 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/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- 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 +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- 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-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- 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__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- 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/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- 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/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /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__/needle.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__/types.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}/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
|
@@ -7,6 +7,7 @@ interface SteerCall {
|
|
|
7
7
|
instruction: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
// Direct steer (no connected client -> no resume fallback).
|
|
10
11
|
const steerCalls: SteerCall[] = [];
|
|
11
12
|
const defaultSteer = (acpSessionId: string, instruction: string) => {
|
|
12
13
|
steerCalls.push({ acpSessionId, instruction });
|
|
@@ -15,6 +16,13 @@ const defaultSteer = (acpSessionId: string, instruction: string) => {
|
|
|
15
16
|
let steerImpl: (acpSessionId: string, instruction: string) => Promise<void> =
|
|
16
17
|
defaultSteer;
|
|
17
18
|
|
|
19
|
+
// steerOrResume (connected client path).
|
|
20
|
+
const steerOrResumeCalls: Array<SteerCall & { send: unknown }> = [];
|
|
21
|
+
let steerOrResumeImpl: (
|
|
22
|
+
acpSessionId: string,
|
|
23
|
+
instruction: string,
|
|
24
|
+
) => Promise<{ resumed: boolean }> = async () => ({ resumed: false });
|
|
25
|
+
|
|
18
26
|
// Spread the real module's exports so transitive importers that pull other
|
|
19
27
|
// names from `../../acp/index.js` still resolve at parse time. Bun's `mock.module` is
|
|
20
28
|
// process-global and returns *exactly* the keys the factory returns.
|
|
@@ -24,35 +32,50 @@ mock.module("../../acp/index.js", () => ({
|
|
|
24
32
|
getAcpSessionManager: () => ({
|
|
25
33
|
steer: (acpSessionId: string, instruction: string) =>
|
|
26
34
|
steerImpl(acpSessionId, instruction),
|
|
35
|
+
steerOrResume: (
|
|
36
|
+
acpSessionId: string,
|
|
37
|
+
instruction: string,
|
|
38
|
+
send: unknown,
|
|
39
|
+
) => {
|
|
40
|
+
steerOrResumeCalls.push({ acpSessionId, instruction, send });
|
|
41
|
+
return steerOrResumeImpl(acpSessionId, instruction);
|
|
42
|
+
},
|
|
27
43
|
}),
|
|
28
44
|
}));
|
|
29
45
|
|
|
30
46
|
const { executeAcpSteer } = await import("./steer.js");
|
|
31
47
|
|
|
32
|
-
function makeContext(): ToolContext {
|
|
48
|
+
function makeContext(opts?: { withClient?: boolean }): ToolContext {
|
|
33
49
|
return {
|
|
34
50
|
workingDir: "/tmp",
|
|
35
51
|
conversationId: "conv-test",
|
|
36
52
|
trustClass: "guardian",
|
|
37
|
-
|
|
53
|
+
...(opts?.withClient ? { sendToClient: () => {} } : {}),
|
|
54
|
+
} as ToolContext;
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
beforeEach(() => {
|
|
41
58
|
steerCalls.length = 0;
|
|
59
|
+
steerOrResumeCalls.length = 0;
|
|
42
60
|
steerImpl = defaultSteer;
|
|
61
|
+
steerOrResumeImpl = async () => ({ resumed: false });
|
|
43
62
|
});
|
|
44
63
|
|
|
45
64
|
describe("executeAcpSteer", () => {
|
|
46
|
-
test("happy path: returns steered status and forwards args to
|
|
65
|
+
test("happy path: returns steered status and forwards args to steerOrResume", async () => {
|
|
47
66
|
const result = await executeAcpSteer(
|
|
48
67
|
{ acp_session_id: "acp-123", instruction: "stop, do X instead" },
|
|
49
|
-
makeContext(),
|
|
68
|
+
makeContext({ withClient: true }),
|
|
50
69
|
);
|
|
51
70
|
|
|
52
71
|
expect(result.isError).toBe(false);
|
|
53
|
-
expect(
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
expect(steerOrResumeCalls).toHaveLength(1);
|
|
73
|
+
expect(steerOrResumeCalls[0]).toMatchObject({
|
|
74
|
+
acpSessionId: "acp-123",
|
|
75
|
+
instruction: "stop, do X instead",
|
|
76
|
+
});
|
|
77
|
+
expect(typeof steerOrResumeCalls[0]!.send).toBe("function");
|
|
78
|
+
expect(steerCalls).toEqual([]);
|
|
56
79
|
|
|
57
80
|
const parsed = JSON.parse(result.content as string);
|
|
58
81
|
expect(parsed).toEqual({
|
|
@@ -71,6 +94,7 @@ describe("executeAcpSteer", () => {
|
|
|
71
94
|
expect(result.isError).toBe(true);
|
|
72
95
|
expect(result.content).toContain('"instruction" is required');
|
|
73
96
|
expect(steerCalls).toEqual([]);
|
|
97
|
+
expect(steerOrResumeCalls).toEqual([]);
|
|
74
98
|
});
|
|
75
99
|
|
|
76
100
|
test("missing acp_session_id returns isError", async () => {
|
|
@@ -82,9 +106,23 @@ describe("executeAcpSteer", () => {
|
|
|
82
106
|
expect(result.isError).toBe(true);
|
|
83
107
|
expect(result.content).toContain('"acp_session_id" is required');
|
|
84
108
|
expect(steerCalls).toEqual([]);
|
|
109
|
+
expect(steerOrResumeCalls).toEqual([]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("no connected client: steers directly and never resumes", async () => {
|
|
113
|
+
const result = await executeAcpSteer(
|
|
114
|
+
{ acp_session_id: "acp-direct", instruction: "redirect" },
|
|
115
|
+
makeContext(),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(result.isError).toBe(false);
|
|
119
|
+
expect(steerCalls).toEqual([
|
|
120
|
+
{ acpSessionId: "acp-direct", instruction: "redirect" },
|
|
121
|
+
]);
|
|
122
|
+
expect(steerOrResumeCalls).toEqual([]);
|
|
85
123
|
});
|
|
86
124
|
|
|
87
|
-
test("
|
|
125
|
+
test("'session not found' without a connected client surfaces the error", async () => {
|
|
88
126
|
steerImpl = () =>
|
|
89
127
|
Promise.reject(new Error('ACP session "acp-x" not found'));
|
|
90
128
|
|
|
@@ -96,5 +134,64 @@ describe("executeAcpSteer", () => {
|
|
|
96
134
|
expect(result.isError).toBe(true);
|
|
97
135
|
expect(result.content).toContain('Could not steer ACP session "acp-x"');
|
|
98
136
|
expect(result.content).toContain("not found");
|
|
137
|
+
expect(steerOrResumeCalls).toEqual([]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("resumed session reports the resumed flag and message", async () => {
|
|
141
|
+
steerOrResumeImpl = async () => ({ resumed: true });
|
|
142
|
+
|
|
143
|
+
const result = await executeAcpSteer(
|
|
144
|
+
{ acp_session_id: "acp-gone", instruction: "keep going" },
|
|
145
|
+
makeContext({ withClient: true }),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
expect(result.isError).toBe(false);
|
|
149
|
+
expect(steerOrResumeCalls).toHaveLength(1);
|
|
150
|
+
|
|
151
|
+
const parsed = JSON.parse(result.content as string);
|
|
152
|
+
expect(parsed).toEqual({
|
|
153
|
+
acpSessionId: "acp-gone",
|
|
154
|
+
status: "steered",
|
|
155
|
+
resumed: true,
|
|
156
|
+
message:
|
|
157
|
+
"Session was resumed from history; new instruction is now running.",
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("resume failure returns its actionable error message", async () => {
|
|
162
|
+
steerOrResumeImpl = () =>
|
|
163
|
+
Promise.reject(
|
|
164
|
+
new Error(
|
|
165
|
+
'ACP session "acp-legacy" was recorded before resume support (no working directory persisted) and cannot be resumed. Spawn a new session instead.',
|
|
166
|
+
),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const result = await executeAcpSteer(
|
|
170
|
+
{ acp_session_id: "acp-legacy", instruction: "more work" },
|
|
171
|
+
makeContext({ withClient: true }),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(result.isError).toBe(true);
|
|
175
|
+
expect(result.content).toContain(
|
|
176
|
+
'Could not steer ACP session "acp-legacy"',
|
|
177
|
+
);
|
|
178
|
+
expect(result.content).toContain("recorded before resume support");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("plain steer errors surface unchanged", async () => {
|
|
182
|
+
steerOrResumeImpl = () =>
|
|
183
|
+
Promise.reject(
|
|
184
|
+
new Error(
|
|
185
|
+
'ACP session "acp-init" is not running (status: initializing)',
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const result = await executeAcpSteer(
|
|
190
|
+
{ acp_session_id: "acp-init", instruction: "redirect" },
|
|
191
|
+
makeContext({ withClient: true }),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
expect(result.isError).toBe(true);
|
|
195
|
+
expect(result.content).toContain("is not running");
|
|
99
196
|
});
|
|
100
197
|
});
|
package/src/tools/acp/steer.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getAcpSessionManager } from "../../acp/index.js";
|
|
2
2
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
3
|
+
import { getSendToClient } from "./context.js";
|
|
3
4
|
|
|
4
5
|
export async function executeAcpSteer(
|
|
5
6
|
input: Record<string, unknown>,
|
|
6
|
-
|
|
7
|
+
context: ToolContext,
|
|
7
8
|
): Promise<ToolExecutionResult> {
|
|
8
9
|
const acpSessionId = input.acp_session_id as string;
|
|
9
10
|
if (!acpSessionId) {
|
|
@@ -15,24 +16,54 @@ export async function executeAcpSteer(
|
|
|
15
16
|
return { content: '"instruction" is required.', isError: true };
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
await manager.steer(acpSessionId, instruction);
|
|
19
|
+
const manager = getAcpSessionManager();
|
|
20
|
+
const sendToClient = getSendToClient(context);
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
try {
|
|
23
|
+
if (!sendToClient) {
|
|
24
|
+
// Without a connected client there is no one to receive a resumed
|
|
25
|
+
// session's events, so skip the transparent resume fallback and
|
|
26
|
+
// steer the in-memory session only.
|
|
27
|
+
await manager.steer(acpSessionId, instruction);
|
|
28
|
+
return steeredResult(acpSessionId, { resumed: false });
|
|
29
|
+
}
|
|
30
|
+
// Sessions no longer in memory (completed, or lost to a daemon
|
|
31
|
+
// restart) are transparently resumed from persisted history and the
|
|
32
|
+
// instruction fired in the same call. Failure messages carry the
|
|
33
|
+
// actionable hint (e.g. "recorded before resume support", agent
|
|
34
|
+
// capability missing).
|
|
35
|
+
const { resumed } = await manager.steerOrResume(
|
|
36
|
+
acpSessionId,
|
|
37
|
+
instruction,
|
|
38
|
+
sendToClient,
|
|
39
|
+
);
|
|
40
|
+
return steeredResult(acpSessionId, { resumed });
|
|
31
41
|
} catch (err) {
|
|
32
42
|
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
-
return
|
|
34
|
-
content: `Could not steer ACP session "${acpSessionId}": ${msg}`,
|
|
35
|
-
isError: true,
|
|
36
|
-
};
|
|
43
|
+
return steerError(acpSessionId, msg);
|
|
37
44
|
}
|
|
38
45
|
}
|
|
46
|
+
|
|
47
|
+
function steeredResult(
|
|
48
|
+
acpSessionId: string,
|
|
49
|
+
opts: { resumed: boolean },
|
|
50
|
+
): ToolExecutionResult {
|
|
51
|
+
return {
|
|
52
|
+
content: JSON.stringify({
|
|
53
|
+
acpSessionId,
|
|
54
|
+
status: "steered",
|
|
55
|
+
...(opts.resumed ? { resumed: true } : {}),
|
|
56
|
+
message: opts.resumed
|
|
57
|
+
? "Session was resumed from history; new instruction is now running."
|
|
58
|
+
: "Interrupted in-flight prompt; new instruction is now running.",
|
|
59
|
+
}),
|
|
60
|
+
isError: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function steerError(acpSessionId: string, msg: string): ToolExecutionResult {
|
|
65
|
+
return {
|
|
66
|
+
content: `Could not steer ACP session "${acpSessionId}": ${msg}`,
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -76,14 +76,12 @@ export interface AppCreateInput {
|
|
|
76
76
|
name: string;
|
|
77
77
|
description?: string;
|
|
78
78
|
schema_json?: string;
|
|
79
|
-
/**
|
|
80
|
-
* Retired single-file shortcut. Kept in the type so legacy or stale callers
|
|
81
|
-
* get a clear tool error instead of silently creating a v2 app with stale
|
|
82
|
-
* scaffold content.
|
|
83
|
-
*/
|
|
79
|
+
/** Retired single-file shortcut. Returns a guidance error. */
|
|
84
80
|
html?: unknown;
|
|
85
|
-
/** Retired single-file multi-page shortcut. */
|
|
81
|
+
/** Retired single-file multi-page shortcut. Returns a guidance error. */
|
|
86
82
|
pages?: unknown;
|
|
83
|
+
/** Lenient alias. Folded into preview.icon when preview.icon is absent. */
|
|
84
|
+
icon?: unknown;
|
|
87
85
|
auto_open?: boolean;
|
|
88
86
|
preview?: Record<string, unknown>;
|
|
89
87
|
source_files?: Record<string, string>;
|
|
@@ -98,11 +96,14 @@ export async function executeAppCreate(
|
|
|
98
96
|
const description = input.description;
|
|
99
97
|
const schemaJson = input.schema_json ?? "{}";
|
|
100
98
|
|
|
99
|
+
// Retired shortcut: a top-level `html` is no longer accepted. Reject with a
|
|
100
|
+
// helpful message (rather than a cryptic schema error) so the model writes a
|
|
101
|
+
// multi-file TSX app under src/ instead.
|
|
101
102
|
if (Object.prototype.hasOwnProperty.call(input, "html")) {
|
|
102
103
|
return {
|
|
103
104
|
content: JSON.stringify({
|
|
104
105
|
error:
|
|
105
|
-
"app_create no longer accepts html.
|
|
106
|
+
"app_create no longer accepts html. Build a multi-file TSX app under src/ (src/index.html + src/main.tsx + src/App.tsx) instead.",
|
|
106
107
|
}),
|
|
107
108
|
isError: true,
|
|
108
109
|
};
|
|
@@ -157,7 +158,11 @@ export async function executeAppCreate(
|
|
|
157
158
|
|
|
158
159
|
// Extract icon from preview if provided - only persist emoji-like values,
|
|
159
160
|
// not URLs which would render as raw strings in UI and bundle manifests.
|
|
160
|
-
|
|
161
|
+
// Lenient alias: a top-level `icon` is folded in when preview.icon is absent.
|
|
162
|
+
const rawIcon = (preview?.icon ??
|
|
163
|
+
(typeof input.icon === "string" ? input.icon : undefined)) as
|
|
164
|
+
| string
|
|
165
|
+
| undefined;
|
|
161
166
|
const icon = rawIcon && !rawIcon.startsWith("http") ? rawIcon : undefined;
|
|
162
167
|
|
|
163
168
|
const app = store.createApp({
|
package/src/tools/executor.ts
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import { parseChannelId } from "../channels/types.js";
|
|
4
3
|
import { getConfig } from "../config/loader.js";
|
|
5
4
|
import { bridgeCesApproval } from "../credential-execution/approval-bridge.js";
|
|
6
5
|
import { isCesShellLockdownEnabled } from "../credential-execution/feature-gates.js";
|
|
7
6
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
8
7
|
import { RiskLevel } from "../permissions/types.js";
|
|
9
|
-
import { runPipeline } from "../plugins/pipeline.js";
|
|
10
|
-
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
11
|
-
import type {
|
|
12
|
-
ToolExecuteArgs,
|
|
13
|
-
ToolExecuteResult,
|
|
14
|
-
TurnContext,
|
|
15
|
-
} from "../plugins/types.js";
|
|
16
8
|
import { isUntrustedTrustClass } from "../runtime/actor-trust-resolver.js";
|
|
17
9
|
import { redactSensitiveFields } from "../security/redaction.js";
|
|
18
10
|
import { TokenExpiredError } from "../security/token-manager.js";
|
|
@@ -52,54 +44,10 @@ export class ToolExecutor {
|
|
|
52
44
|
name: string,
|
|
53
45
|
input: Record<string, unknown>,
|
|
54
46
|
context: ToolContext,
|
|
55
|
-
/**
|
|
56
|
-
* Optional per-turn context threaded in by the agent loop. Production
|
|
57
|
-
* sites propagate the orchestrator-built `TurnContext` (real
|
|
58
|
-
* `conversationId`, trust cascade, attached `contextWindowManager`) so
|
|
59
|
-
* middleware registered on the `toolExecute` pipeline sees the same
|
|
60
|
-
* context every other pipeline slot uses. When omitted (CLI/test
|
|
61
|
-
* invocations that call `ToolExecutor.execute` directly), the executor
|
|
62
|
-
* synthesizes a fallback context from the {@link ToolContext}.
|
|
63
|
-
*/
|
|
64
|
-
turnContext?: TurnContext,
|
|
65
47
|
): Promise<ToolExecutionResult> {
|
|
66
|
-
// Prefer the orchestrator-supplied `turnContext` so the pipeline sees
|
|
67
|
-
// the real conversation identity, per-turn trust, and context-window
|
|
68
|
-
// manager. When absent (CLI / test invocations that bypass the agent
|
|
69
|
-
// loop), synthesize a minimal context from the `ToolContext`.
|
|
70
|
-
const turnCtx: TurnContext = turnContext ?? {
|
|
71
|
-
requestId: context.requestId ?? "",
|
|
72
|
-
conversationId: context.conversationId,
|
|
73
|
-
turnIndex: 0,
|
|
74
|
-
trust: {
|
|
75
|
-
sourceChannel: parseChannelId(context.executionChannel) ?? "vellum",
|
|
76
|
-
trustClass: context.trustClass,
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const middlewares = getMiddlewaresFor("toolExecute");
|
|
81
48
|
const { name: executionName, input: executionInput } =
|
|
82
49
|
resolveToolInvocationAlias(name, input, context.allowedToolNames);
|
|
83
|
-
|
|
84
|
-
name: executionName,
|
|
85
|
-
input: executionInput,
|
|
86
|
-
context,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// No pipeline-level timeout: `executeInternal` already wraps the real
|
|
90
|
-
// tool invocation in `executeWithTimeout`, which is the sole enforcer
|
|
91
|
-
// of the per-tool budget. The pipeline itself runs untimed so that
|
|
92
|
-
// upstream phases (permission checks, approval waits, middleware) are
|
|
93
|
-
// not racing the tool budget — only the actual tool call is. Runaway
|
|
94
|
-
// middleware is a plugin-health concern handled by per-plugin timeouts,
|
|
95
|
-
// not here.
|
|
96
|
-
return runPipeline<ToolExecuteArgs, ToolExecuteResult>(
|
|
97
|
-
"toolExecute",
|
|
98
|
-
middlewares,
|
|
99
|
-
(args) => this.executeInternal(args.name, args.input, args.context),
|
|
100
|
-
pipelineArgs,
|
|
101
|
-
turnCtx,
|
|
102
|
-
);
|
|
50
|
+
return this.executeInternal(executionName, executionInput, context);
|
|
103
51
|
}
|
|
104
52
|
|
|
105
53
|
private async executeInternal(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { join, resolve, sep } from "node:path";
|
|
2
2
|
|
|
3
|
+
import { getAppsDir } from "../../memory/app-store.js";
|
|
3
4
|
import { enqueuePkbIndexJob } from "../../memory/jobs/embed-pkb-file.js";
|
|
4
5
|
import { PKB_WORKSPACE_SCOPE } from "../../memory/pkb/types.js";
|
|
5
6
|
import { RiskLevel } from "../../permissions/types.js";
|
|
@@ -17,6 +18,29 @@ import type {
|
|
|
17
18
|
|
|
18
19
|
const logger = getLogger("file-write");
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Detects an attempt to write a self-contained interactive HTML document —
|
|
23
|
+
* the signature of a "visualization" / "artifact" the model should be
|
|
24
|
+
* building as a real app via the app-builder skill, not dumping as a loose
|
|
25
|
+
* file. We deliberately trip ONLY on standalone docs with a substantial
|
|
26
|
+
* INLINE script (the data + rendering live in the file). app-builder's own
|
|
27
|
+
* scaffold writes a thin shell whose only script is an external module
|
|
28
|
+
* (`<script type="module" src="/src/main.tsx">`) with an empty body, so this
|
|
29
|
+
* never blocks the app-builder workflow it redirects to.
|
|
30
|
+
*/
|
|
31
|
+
const STANDALONE_HTML_RE = /<!doctype\s+html|<html[\s>]/i;
|
|
32
|
+
const INLINE_SCRIPT_RE = /<script\b(?![^>]*\bsrc=)[^>]*>[\s\S]{400,}?<\/script>/i;
|
|
33
|
+
|
|
34
|
+
function isSelfContainedArtifactHtml(path: string, content: string): boolean {
|
|
35
|
+
if (!/\.html?$/i.test(path)) return false;
|
|
36
|
+
if (content.length < 3000) return false;
|
|
37
|
+
if (!STANDALONE_HTML_RE.test(content)) return false;
|
|
38
|
+
return INLINE_SCRIPT_RE.test(content);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ARTIFACT_REDIRECT_MESSAGE =
|
|
42
|
+
'Error: This looks like a self-contained interactive visualization/artifact written as a loose HTML file. Do not build these as standalone .html files. Load the app-builder skill first with `skill_load` using `skill: "app-builder"`, then build it as a real persistent app with `app_create` (the skill loads frontend-design for the visual pass and provides chart widgets). If this genuinely needs to be a raw HTML file inside an existing code project, write it under that project folder.';
|
|
43
|
+
|
|
20
44
|
/**
|
|
21
45
|
* Returns `true` iff `absPath` is an absolute path that resolves strictly
|
|
22
46
|
* inside `pkbRoot`. Matches the containment semantics used elsewhere in the
|
|
@@ -82,6 +106,16 @@ export const fileWriteTool = {
|
|
|
82
106
|
};
|
|
83
107
|
}
|
|
84
108
|
|
|
109
|
+
// Redirect self-contained interactive HTML artifacts to app-builder.
|
|
110
|
+
// Exempt writes that land inside the apps directory (app-builder's own
|
|
111
|
+
// scaffold/iteration writes) so we never block the workflow we point to.
|
|
112
|
+
if (isSelfContainedArtifactHtml(rawPath, fileContent)) {
|
|
113
|
+
const candidate = resolve(context.workingDir, rawPath);
|
|
114
|
+
if (!isInsidePkbRoot(candidate, getAppsDir())) {
|
|
115
|
+
return { content: ARTIFACT_REDIRECT_MESSAGE, isError: true };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
const ops = new FileSystemOps((path, opts) =>
|
|
86
120
|
sandboxPolicy(path, context.workingDir, opts),
|
|
87
121
|
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { WEB_SEARCH_BACKEND_FAILURE_MESSAGE } from "../web-search-error.js";
|
|
4
|
+
|
|
3
5
|
// Mutable mock state - set per test
|
|
4
6
|
let mockWebSearchProvider: string | undefined = "perplexity";
|
|
5
7
|
let mockBraveSecureKey: string | undefined;
|
|
@@ -32,7 +34,9 @@ mock.module("../../../security/secure-keys.js", () => ({
|
|
|
32
34
|
},
|
|
33
35
|
}));
|
|
34
36
|
|
|
37
|
+
const realLogger = await import("../../../util/logger.js");
|
|
35
38
|
mock.module("../../../util/logger.js", () => ({
|
|
39
|
+
...realLogger,
|
|
36
40
|
getLogger: () =>
|
|
37
41
|
new Proxy({} as Record<string, unknown>, {
|
|
38
42
|
get: () => () => {},
|
|
@@ -169,7 +173,9 @@ describe("web_search activity metadata", () => {
|
|
|
169
173
|
expect(meta.provider).toBe("perplexity");
|
|
170
174
|
expect(meta.resultCount).toBe(0);
|
|
171
175
|
expect(meta.results).toEqual([]);
|
|
172
|
-
|
|
176
|
+
// Post-retry rate limits now surface the centralized friendly recoverable
|
|
177
|
+
// copy (ATL-727) rather than provider-specific rate-limit wording.
|
|
178
|
+
expect(meta.errorMessage).toBe(WEB_SEARCH_BACKEND_FAILURE_MESSAGE);
|
|
173
179
|
});
|
|
174
180
|
|
|
175
181
|
// ---- Tavily -------------------------------------------------------------
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { WEB_SEARCH_BACKEND_FAILURE_MESSAGE } from "../web-search-error.js";
|
|
4
|
+
|
|
3
5
|
// Mutable mock state - set per test
|
|
4
6
|
let mockWebSearchProvider: string | undefined = "perplexity";
|
|
5
7
|
let mockWebSearchMode: string | undefined = "your-own";
|
|
@@ -42,7 +44,9 @@ mock.module("../../../security/secure-keys.js", () => ({
|
|
|
42
44
|
},
|
|
43
45
|
}));
|
|
44
46
|
|
|
47
|
+
const realLogger = await import("../../../util/logger.js");
|
|
45
48
|
mock.module("../../../util/logger.js", () => ({
|
|
49
|
+
...realLogger,
|
|
46
50
|
getLogger: () =>
|
|
47
51
|
new Proxy({} as Record<string, unknown>, {
|
|
48
52
|
get: () => () => {},
|
|
@@ -201,7 +205,8 @@ describe("web_search tool", () => {
|
|
|
201
205
|
|
|
202
206
|
const result = await execute({ query: "test" });
|
|
203
207
|
expect(result.isError).toBe(true);
|
|
204
|
-
|
|
208
|
+
// Post-retry rate limits surface the friendly recoverable copy (ATL-727).
|
|
209
|
+
expect(result.content).toBe(WEB_SEARCH_BACKEND_FAILURE_MESSAGE);
|
|
205
210
|
// 1 initial + 3 retries = 4 calls
|
|
206
211
|
expect(callCount).toBe(4);
|
|
207
212
|
});
|
|
@@ -214,7 +219,9 @@ describe("web_search tool", () => {
|
|
|
214
219
|
|
|
215
220
|
const result = await execute({ query: "test" });
|
|
216
221
|
expect(result.isError).toBe(true);
|
|
217
|
-
|
|
222
|
+
// 5xx is a backend failure -> friendly recoverable copy, no raw status.
|
|
223
|
+
expect(result.content).toBe(WEB_SEARCH_BACKEND_FAILURE_MESSAGE);
|
|
224
|
+
expect(result.content).not.toContain("500");
|
|
218
225
|
});
|
|
219
226
|
|
|
220
227
|
// ---- Brave provider -----------------------------------------------------
|
|
@@ -673,7 +680,8 @@ describe("web_search tool", () => {
|
|
|
673
680
|
|
|
674
681
|
const result = await execute({ query: "test" });
|
|
675
682
|
expect(result.isError).toBe(true);
|
|
676
|
-
|
|
683
|
+
// Post-retry rate limits surface the friendly recoverable copy (ATL-727).
|
|
684
|
+
expect(result.content).toBe(WEB_SEARCH_BACKEND_FAILURE_MESSAGE);
|
|
677
685
|
expect(callCount).toBe(4);
|
|
678
686
|
});
|
|
679
687
|
|