@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8
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/bun.lock +2 -2
- package/docs/plugins.md +832 -0
- package/examples/plugins/echo/README.md +60 -61
- package/examples/plugins/echo/package.json +2 -1
- package/examples/plugins/echo/register.ts +143 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
- package/openapi.yaml +5 -15
- package/package.json +2 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -4
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
- package/src/__tests__/conversation-agent-loop.test.ts +39 -42
- package/src/__tests__/conversation-clean-command.test.ts +2 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
- package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
- package/src/__tests__/conversation-starter-routes.test.ts +6 -14
- package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
- package/src/__tests__/db-acp-history.test.ts +0 -101
- package/src/__tests__/dynamic-page-surface.test.ts +0 -31
- package/src/__tests__/file-write-tool.test.ts +0 -63
- package/src/__tests__/gateway-only-guard.test.ts +2 -12
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +0 -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__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +6 -34
- package/src/__tests__/injector-disk-pressure.test.ts +34 -77
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
- package/src/__tests__/pipeline-runner.test.ts +554 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -3
- package/src/__tests__/plugin-bootstrap.test.ts +23 -12
- package/src/__tests__/plugin-registry.test.ts +49 -3
- package/src/__tests__/plugin-types.test.ts +70 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +3 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +286 -54
- package/src/acp/__tests__/client-handler.test.ts +0 -40
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
- package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
- package/src/acp/agent-process.ts +1 -61
- package/src/acp/client-handler.ts +0 -31
- package/src/acp/prepare-agent-env.ts +29 -83
- package/src/acp/resolve-agent.test.ts +7 -320
- package/src/acp/resolve-agent.ts +18 -182
- package/src/acp/session-manager.ts +73 -495
- package/src/acp/types.ts +0 -8
- package/src/agent/compaction-circuit.ts +102 -60
- package/src/agent/loop.ts +59 -32
- package/src/api/responses/conversation-message.ts +1 -7
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +0 -1
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +31 -83
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
- package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +5 -14
- package/src/config/schemas/heartbeat.ts +0 -9
- package/src/context/strip-injections.ts +2 -8
- package/src/context/window-manager.ts +1 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
- package/src/daemon/conversation-agent-loop.ts +279 -62
- package/src/daemon/conversation-runtime-assembly.ts +69 -106
- package/src/daemon/conversation-store.ts +90 -9
- package/src/daemon/conversation-workspace.ts +0 -17
- package/src/daemon/conversation.ts +6 -0
- package/src/daemon/external-plugins-bootstrap.ts +11 -11
- package/src/daemon/handlers/conversations.ts +1 -3
- package/src/daemon/handlers/skills.ts +1 -4
- package/src/daemon/lifecycle.ts +0 -21
- package/src/daemon/server.ts +0 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
- package/src/heartbeat/heartbeat-run-store.ts +1 -23
- package/src/heartbeat/heartbeat-service.ts +0 -26
- 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 +0 -15
- package/src/ipc/skill-routes/memory.ts +2 -4
- package/src/memory/conversation-starter-checkpoints.ts +0 -1
- package/src/memory/db-init.ts +0 -2
- package/src/memory/job-handlers/conversation-starters.ts +2 -13
- package/src/memory/jobs-worker.ts +1 -1
- package/src/memory/migrations/index.ts +0 -1
- package/src/memory/schema/acp.ts +0 -4
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +4 -13
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
- package/src/plugin-api/index.ts +5 -0
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +19 -8
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/index.ts +5 -3
- package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +293 -6
- package/src/plugins/registry.ts +37 -9
- package/src/plugins/types.ts +336 -32
- package/src/plugins/user-loader.ts +127 -30
- package/src/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- package/src/prompts/__tests__/system-prompt.test.ts +0 -6
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
- package/src/runtime/__tests__/agent-wake.test.ts +5 -5
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +3 -0
- 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 +55 -283
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
- package/src/runtime/routes/acp-routes.test.ts +25 -89
- package/src/runtime/routes/acp-routes.ts +29 -81
- 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 +10 -6
- 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 +2 -15
- package/src/runtime/routes/conversation-starter-routes.ts +7 -13
- package/src/runtime/routes/conversations-import-routes.ts +7 -24
- 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 +3 -18
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/memory-v3-routes.ts +6 -16
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
- package/src/runtime/routes/work-items-routes.ts +4 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +4 -2
- package/src/subagent/manager.ts +5 -17
- package/src/tools/acp/list-agents.test.ts +1 -7
- package/src/tools/acp/spawn.test.ts +55 -158
- package/src/tools/acp/spawn.ts +72 -47
- package/src/tools/acp/steer.test.ts +8 -105
- package/src/tools/acp/steer.ts +17 -48
- package/src/tools/apps/executors.ts +8 -13
- package/src/tools/filesystem/write.ts +0 -34
- package/src/tools/subagent/spawn.ts +4 -2
- package/src/tools/ui-surface/definitions.ts +4 -25
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
- package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
- package/examples/plugins/echo/hooks/stop.ts +0 -16
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
- package/examples/plugins/echo/src/emit.ts +0 -19
- package/src/__tests__/compaction-circuit.test.ts +0 -258
- package/src/__tests__/compaction-direct.test.ts +0 -132
- package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
- package/src/acp/__tests__/agent-process.test.ts +0 -161
- package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
- package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
- package/src/acp/auto-install.test.ts +0 -196
- package/src/acp/auto-install.ts +0 -177
- package/src/acp/feature-gate.test.ts +0 -48
- package/src/acp/feature-gate.ts +0 -34
- package/src/acp/resume-hint.ts +0 -25
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
- package/src/daemon/conversation-registry.ts +0 -159
- package/src/daemon/overflow-reduction-loop.ts +0 -230
- package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
- package/src/plugins/defaults/compaction/compact.ts +0 -59
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
- package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
- package/src/tools/acp/context.ts +0 -20
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
|
@@ -1,59 +1,43 @@
|
|
|
1
1
|
# Echo plugin
|
|
2
2
|
|
|
3
|
-
Minimal example plugin. Observes
|
|
4
|
-
|
|
3
|
+
Minimal example plugin. Observes every assistant pipeline and logs one JSON
|
|
4
|
+
line per invocation to `stderr`:
|
|
5
5
|
|
|
6
6
|
```json
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
"hook": "post-tool-use",
|
|
10
|
-
"conversationId": "conv_abc123"
|
|
11
|
-
}
|
|
7
|
+
{"plugin":"echo","pipeline":"compaction","durationMs":1590,"outcome":"success"}
|
|
8
|
+
{"plugin":"echo","pipeline":"overflowReduce","durationMs":42,"outcome":"success"}
|
|
12
9
|
```
|
|
13
10
|
|
|
14
11
|
Use this as a starting point for writing your own plugin, or as a quick way
|
|
15
|
-
to eyeball which
|
|
12
|
+
to eyeball which pipelines fire during a conversation and how long they
|
|
13
|
+
take.
|
|
16
14
|
|
|
17
|
-
For the full plugin authoring guide
|
|
18
|
-
|
|
19
|
-
[`experimental/plugins/README.md`](../../../../experimental/plugins/README.md).
|
|
20
|
-
[`simple-memory`](../../../../experimental/plugins/simple-memory/) is the
|
|
21
|
-
canonical reference implementation that exercises every wired surface.
|
|
15
|
+
For the full plugin authoring guide, see
|
|
16
|
+
[`assistant/docs/plugins.md`](../../../docs/plugins.md).
|
|
22
17
|
|
|
23
18
|
## What it does
|
|
24
19
|
|
|
25
|
-
-
|
|
26
|
-
`
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
The assistant discovers a plugin by its `package.json` manifest and builds the
|
|
35
|
-
`Plugin` from the interface directories — `hooks/<name>.ts` files whose default
|
|
36
|
-
export is the hook function. Files under `src/` are internal helpers and are
|
|
37
|
-
not walked by the loader.
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
echo/
|
|
41
|
-
├── package.json # Manifest (name + @vellumai/plugin-api range)
|
|
42
|
-
├── README.md
|
|
43
|
-
├── hooks/
|
|
44
|
-
│ ├── user-prompt-submit.ts # default export = hook function
|
|
45
|
-
│ ├── post-tool-use.ts
|
|
46
|
-
│ └── stop.ts
|
|
47
|
-
└── src/
|
|
48
|
-
└── emit.ts # shared stderr emitter (not a surface)
|
|
49
|
-
```
|
|
20
|
+
- Registers one observer middleware per slot in
|
|
21
|
+
`PipelineMiddlewareMap` — `compaction`, `overflowReduce`, and
|
|
22
|
+
`circuitBreaker`.
|
|
23
|
+
- Each middleware calls `next(args)` to pass the request through unchanged,
|
|
24
|
+
measures wall-clock duration, and emits one line to `stderr` whether the
|
|
25
|
+
downstream succeeded or threw.
|
|
26
|
+
- Never modifies arguments, never rewrites results, never swallows errors.
|
|
27
|
+
It is purely observational — safe to stack alongside any other plugin.
|
|
50
28
|
|
|
51
29
|
## Install locally
|
|
52
30
|
|
|
53
31
|
The assistant scans `<workspaceDir>/plugins/*` (e.g.
|
|
54
|
-
`~/.vellum/workspace/plugins/`) for subdirectories containing a
|
|
55
|
-
and
|
|
56
|
-
directory in place is enough to
|
|
32
|
+
`~/.vellum/workspace/plugins/`) for subdirectories containing a
|
|
33
|
+
`register.{ts,js}` file and dynamic-imports each one during assistant
|
|
34
|
+
startup. Dropping (or symlinking) this directory in place is enough to
|
|
35
|
+
enable it.
|
|
36
|
+
|
|
37
|
+
The plugin reads `registerPlugin` from `globalThis.__vellumPluginRuntime`,
|
|
38
|
+
which the daemon attaches before scanning plugins. This works against both
|
|
39
|
+
the `bun --compile`-bundled daemon binary AND a daemon running from
|
|
40
|
+
source — no special install procedure required either way.
|
|
57
41
|
|
|
58
42
|
### Option 1 — symlink from the repo (simplest in-repo dev)
|
|
59
43
|
|
|
@@ -70,10 +54,23 @@ pick up changes.
|
|
|
70
54
|
### Option 2 — standalone copy
|
|
71
55
|
|
|
72
56
|
A plain `cp -R` of this directory into `~/.vellum/workspace/plugins/echo/`
|
|
73
|
-
works
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
works for the runtime imports (which go through the global bridge), but
|
|
58
|
+
the `import type` lines at the top of `register.ts` still resolve into
|
|
59
|
+
the in-repo assistant source tree. If your standalone copy lives outside
|
|
60
|
+
a vellum-assistant checkout, rewrite those `import type` paths to point
|
|
61
|
+
at an absolute path inside any checkout — they're erased at compile time
|
|
62
|
+
and have no module-identity effect at runtime:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// before (repo-local):
|
|
66
|
+
import type { VellumPluginRuntime } from "../../../src/plugins/external-api.js";
|
|
67
|
+
import type { Plugin } from "../../../src/plugins/types.js";
|
|
68
|
+
// after (standalone, edit to your checkout path):
|
|
69
|
+
import type { VellumPluginRuntime } from "/path/to/vellum-assistant/assistant/src/plugins/external-api.js";
|
|
70
|
+
import type { Plugin } from "/path/to/vellum-assistant/assistant/src/plugins/types.js";
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
No runtime-import rewriting is needed — the bridge already handles that.
|
|
77
74
|
|
|
78
75
|
### Restart the assistant
|
|
79
76
|
|
|
@@ -87,23 +84,24 @@ vellum restart
|
|
|
87
84
|
## Verify it works
|
|
88
85
|
|
|
89
86
|
With the plugin installed and the assistant restarted, send any message
|
|
90
|
-
that exercises a
|
|
91
|
-
assistant's stderr log:
|
|
87
|
+
that exercises a pipeline — a conversation turn, a tool call, a title
|
|
88
|
+
generation — and tail the assistant's stderr log:
|
|
92
89
|
|
|
93
90
|
```bash
|
|
94
91
|
tail -f ~/.vellum/daemon.log
|
|
95
92
|
```
|
|
96
93
|
|
|
97
|
-
You should see one line per
|
|
94
|
+
You should see one line per pipeline invocation, similar to:
|
|
98
95
|
|
|
99
96
|
```json
|
|
100
|
-
{
|
|
101
|
-
|
|
102
|
-
"hook": "post-tool-use",
|
|
103
|
-
"conversationId": "conv_abc123"
|
|
104
|
-
}
|
|
97
|
+
{"plugin":"echo","pipeline":"compaction","durationMs":1590,"outcome":"success"}
|
|
98
|
+
{"plugin":"echo","pipeline":"overflowReduce","durationMs":42,"outcome":"success"}
|
|
105
99
|
```
|
|
106
100
|
|
|
101
|
+
If a pipeline throws (for example, a tool that errors out), you'll see a
|
|
102
|
+
line with `"outcome":"error"` — the plugin rethrows after logging so the
|
|
103
|
+
original error still propagates.
|
|
104
|
+
|
|
107
105
|
## Uninstall
|
|
108
106
|
|
|
109
107
|
Remove the symlink (or the copied directory) and restart the assistant:
|
|
@@ -115,13 +113,14 @@ vellum restart
|
|
|
115
113
|
|
|
116
114
|
## Next steps
|
|
117
115
|
|
|
118
|
-
- Read [`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
- Read [`assistant/docs/plugins.md`](../../../docs/plugins.md) for the full
|
|
117
|
+
plugin authoring guide: manifest shape, middleware patterns
|
|
118
|
+
(observe / transform / short-circuit / veto), strict-fail semantics, the
|
|
119
|
+
per-pipeline timeout table, credential and config access, and
|
|
120
|
+
troubleshooting.
|
|
122
121
|
- Look at the first-party default plugins under
|
|
123
|
-
`assistant/src/plugins/defaults/` for examples of
|
|
124
|
-
|
|
122
|
+
`assistant/src/plugins/defaults/` for examples of non-observational
|
|
123
|
+
middleware.
|
|
125
124
|
- Build your own plugin by copying this directory, renaming the manifest
|
|
126
|
-
`name`, and replacing the observer
|
|
127
|
-
need.
|
|
125
|
+
`name`, and replacing the observer with a middleware that does whatever
|
|
126
|
+
you need.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/plugin-echo-example",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"description": "Example plugin that observes every assistant
|
|
4
|
+
"description": "Example plugin that observes every assistant pipeline and logs one structured line per invocation to stderr. Meant as an authoring reference — not shipped with the assistant runtime.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"main": "./register.ts",
|
|
8
9
|
"engines": {
|
|
9
10
|
"node": ">=20.12.0"
|
|
10
11
|
},
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Echo plugin — observes every assistant pipeline and logs one structured
|
|
3
|
+
* line per invocation to stderr.
|
|
4
|
+
*
|
|
5
|
+
* Bundled in the repository as an authoring reference. To try it locally,
|
|
6
|
+
* symlink (or copy) this directory into `<workspaceDir>/plugins/echo/` and
|
|
7
|
+
* restart the assistant. See `README.md` in this directory for the install
|
|
8
|
+
* recipe and `assistant/docs/plugins.md` for general plugin authoring docs.
|
|
9
|
+
*
|
|
10
|
+
* ## Runtime bridge
|
|
11
|
+
*
|
|
12
|
+
* The plugin reads `registerPlugin` from `globalThis.__vellumPluginRuntime`,
|
|
13
|
+
* a stable handle the daemon attaches at startup. This lets the same plugin
|
|
14
|
+
* file work whether the daemon is running from source (relative or absolute
|
|
15
|
+
* imports would resolve to the daemon's modules) or as a `bun --compile`
|
|
16
|
+
* binary (where absolute imports would load a disjoint disk copy with a
|
|
17
|
+
* separate registry instance). The bridge is documented in
|
|
18
|
+
* `assistant/src/plugins/external-api.ts`.
|
|
19
|
+
*
|
|
20
|
+
* Type imports below still come from the in-repo source tree. Types are
|
|
21
|
+
* erased at runtime, so they don't affect module identity — but they only
|
|
22
|
+
* resolve while this file lives inside the vellum-assistant checkout. For a
|
|
23
|
+
* standalone-copy install, rewrite the `import type` paths to absolute paths
|
|
24
|
+
* inside a checkout (or vendor only the types you need).
|
|
25
|
+
*
|
|
26
|
+
* ## Design
|
|
27
|
+
*
|
|
28
|
+
* - Registers an observer middleware on every slot of `PipelineMiddlewareMap`.
|
|
29
|
+
* - Each middleware records a start timestamp, calls `next(args)`, and on
|
|
30
|
+
* return — whether successful or not — emits one JSON line on `stderr` with
|
|
31
|
+
* `{ plugin, pipeline, durationMs, outcome }`. A `try { return await next(); }
|
|
32
|
+
* catch { outcome = "error"; rethrow; } finally { log(); }` pattern keeps the
|
|
33
|
+
* observation strictly non-interfering: the plugin never swallows errors
|
|
34
|
+
* and never rewrites arguments or results.
|
|
35
|
+
* - Middleware is declared as async functions with stable names so the
|
|
36
|
+
* pipeline runner's `chain` log field attributes them correctly.
|
|
37
|
+
*
|
|
38
|
+
* The file exports no named symbols at module level — it only runs
|
|
39
|
+
* `registerPlugin(echoPlugin)` as an import-time side effect, matching the
|
|
40
|
+
* user-plugin-loader contract (see `assistant/src/plugins/user-loader.ts`).
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import type { VellumPluginRuntime } from "../../../src/plugins/external-api.js";
|
|
44
|
+
import type {
|
|
45
|
+
CircuitBreakerArgs,
|
|
46
|
+
CircuitBreakerResult,
|
|
47
|
+
CompactionArgs,
|
|
48
|
+
CompactionResult,
|
|
49
|
+
OverflowReduceArgs,
|
|
50
|
+
OverflowReduceResult,
|
|
51
|
+
Plugin,
|
|
52
|
+
} from "../../../src/plugins/types.js";
|
|
53
|
+
|
|
54
|
+
const runtime = (globalThis as { __vellumPluginRuntime?: VellumPluginRuntime })
|
|
55
|
+
.__vellumPluginRuntime;
|
|
56
|
+
if (!runtime || runtime.version !== 1) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"echo plugin: globalThis.__vellumPluginRuntime is missing or has an unexpected version — install a recent assistant build",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const { registerPlugin } = runtime;
|
|
62
|
+
|
|
63
|
+
const PLUGIN_NAME = "echo";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* One line written to stderr per pipeline invocation. Kept intentionally
|
|
67
|
+
* compact — pino-style JSON so operators can pipe the assistant's stderr
|
|
68
|
+
* through `jq` without reshaping.
|
|
69
|
+
*/
|
|
70
|
+
function emit(
|
|
71
|
+
pipelineName: string,
|
|
72
|
+
startMs: number,
|
|
73
|
+
outcome: "success" | "error",
|
|
74
|
+
): void {
|
|
75
|
+
const durationMs = Math.round(performance.now() - startMs);
|
|
76
|
+
const record = {
|
|
77
|
+
plugin: PLUGIN_NAME,
|
|
78
|
+
pipeline: pipelineName,
|
|
79
|
+
durationMs,
|
|
80
|
+
outcome,
|
|
81
|
+
};
|
|
82
|
+
process.stderr.write(`${JSON.stringify(record)}\n`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Factory for a pipeline-agnostic observer middleware. The returned function
|
|
87
|
+
* carries a `name` so `runPipeline`'s `chain` log field attributes this
|
|
88
|
+
* plugin's frame correctly. Error paths rethrow — the plugin is purely
|
|
89
|
+
* observational and must never change the turn's outcome.
|
|
90
|
+
*/
|
|
91
|
+
function makeObserver<A, R>(
|
|
92
|
+
pipelineName: string,
|
|
93
|
+
): (args: A, next: (args: A) => Promise<R>, _ctx: unknown) => Promise<R> {
|
|
94
|
+
const fn = async function echoObserver(
|
|
95
|
+
args: A,
|
|
96
|
+
next: (args: A) => Promise<R>,
|
|
97
|
+
_ctx: unknown,
|
|
98
|
+
): Promise<R> {
|
|
99
|
+
const start = performance.now();
|
|
100
|
+
let outcome: "success" | "error" = "success";
|
|
101
|
+
try {
|
|
102
|
+
return await next(args);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
outcome = "error";
|
|
105
|
+
throw err;
|
|
106
|
+
} finally {
|
|
107
|
+
emit(pipelineName, start, outcome);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return fn;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The echo plugin. Declares one middleware per slot in
|
|
115
|
+
* `PipelineMiddlewareMap` — all thin observers produced by `makeObserver`.
|
|
116
|
+
*
|
|
117
|
+
* Manifest:
|
|
118
|
+
* - Host-compat range lives in `package.json` under
|
|
119
|
+
* `peerDependencies["@vellumai/plugin-api"]`. The external-plugin loader
|
|
120
|
+
* validates it against the running assistant version via
|
|
121
|
+
* `semver.satisfies()` before this file is even imported.
|
|
122
|
+
* - No `requiresCredential` or `requiresFlag` — the plugin needs no external
|
|
123
|
+
* state and runs unconditionally.
|
|
124
|
+
*/
|
|
125
|
+
const echoPlugin: Plugin = {
|
|
126
|
+
manifest: {
|
|
127
|
+
name: PLUGIN_NAME,
|
|
128
|
+
version: "0.1.0",
|
|
129
|
+
},
|
|
130
|
+
middleware: {
|
|
131
|
+
compaction: makeObserver<CompactionArgs, CompactionResult>("compaction"),
|
|
132
|
+
overflowReduce: makeObserver<OverflowReduceArgs, OverflowReduceResult>(
|
|
133
|
+
"overflowReduce",
|
|
134
|
+
),
|
|
135
|
+
circuitBreaker: makeObserver<CircuitBreakerArgs, CircuitBreakerResult>(
|
|
136
|
+
"circuitBreaker",
|
|
137
|
+
),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Side-effect registration — the user-plugin loader dynamic-imports this
|
|
142
|
+
// file and expects the registry to pick up the plugin during that import.
|
|
143
|
+
registerPlugin(echoPlugin);
|
|
@@ -194,12 +194,8 @@ export interface ProvidersFacet {
|
|
|
194
194
|
// Memory
|
|
195
195
|
// ---------------------------------------------------------------------------
|
|
196
196
|
|
|
197
|
-
/**
|
|
198
|
-
|
|
199
|
-
* UI-facing (`ConversationMessage`), so only renderable turns are accepted —
|
|
200
|
-
* agent-context `system` rows are not persisted via this facet.
|
|
201
|
-
*/
|
|
202
|
-
export type MessageRole = "user" | "assistant";
|
|
197
|
+
/** Valid message roles for `memory.addMessage`. */
|
|
198
|
+
export type MessageRole = "user" | "assistant" | "system";
|
|
203
199
|
|
|
204
200
|
/**
|
|
205
201
|
* Callable signature for `memory.addMessage`. Mirrors the daemon's
|
|
@@ -251,7 +247,10 @@ export interface Subscription {
|
|
|
251
247
|
export interface EventsFacet {
|
|
252
248
|
publish(event: AssistantEvent): Promise<void>;
|
|
253
249
|
subscribe(filter: Filter, cb: AssistantEventCallback): Subscription;
|
|
254
|
-
buildEvent(
|
|
250
|
+
buildEvent(
|
|
251
|
+
message: ServerMessage,
|
|
252
|
+
conversationId?: string,
|
|
253
|
+
): AssistantEvent;
|
|
255
254
|
}
|
|
256
255
|
|
|
257
256
|
// ---------------------------------------------------------------------------
|
package/openapi.yaml
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
openapi: 3.1.0
|
|
4
4
|
info:
|
|
5
5
|
title: Vellum Assistant API
|
|
6
|
-
version: 0.8.
|
|
6
|
+
version: 0.8.8
|
|
7
7
|
description: Auto-generated OpenAPI specification for the Vellum Assistant runtime HTTP server.
|
|
8
8
|
servers:
|
|
9
9
|
- url: http://127.0.0.1:7821
|
|
@@ -95,9 +95,7 @@ paths:
|
|
|
95
95
|
post:
|
|
96
96
|
operationId: acp_by_id_steer_post
|
|
97
97
|
summary: Steer ACP session
|
|
98
|
-
description:
|
|
99
|
-
Send a steering instruction to an ACP session. Sessions no longer in memory (completed, or lost to a daemon
|
|
100
|
-
restart) are transparently resumed from persisted history first, when the agent supports ACP session loading.
|
|
98
|
+
description: Send a steering instruction to an active ACP session.
|
|
101
99
|
tags:
|
|
102
100
|
- acp
|
|
103
101
|
responses:
|
|
@@ -112,9 +110,6 @@ paths:
|
|
|
112
110
|
type: string
|
|
113
111
|
steered:
|
|
114
112
|
type: boolean
|
|
115
|
-
resumed:
|
|
116
|
-
description: True when the session was resumed from persisted history before steering.
|
|
117
|
-
type: boolean
|
|
118
113
|
required:
|
|
119
114
|
- acpSessionId
|
|
120
115
|
- steered
|
|
@@ -141,9 +136,7 @@ paths:
|
|
|
141
136
|
delete:
|
|
142
137
|
operationId: acp_sessions_delete
|
|
143
138
|
summary: Bulk-clear terminal ACP sessions
|
|
144
|
-
description:
|
|
145
|
-
Remove every terminal-state row (completed/failed/cancelled) from the persisted acp_session_history table.
|
|
146
|
-
Rows whose session is currently active in memory (e.g. resumed) or has a resume in flight are excluded.
|
|
139
|
+
description: Remove every terminal-state row (completed/failed/cancelled) from the persisted acp_session_history table.
|
|
147
140
|
tags:
|
|
148
141
|
- acp
|
|
149
142
|
responses:
|
|
@@ -245,8 +238,8 @@ paths:
|
|
|
245
238
|
operationId: acp_sessions_by_id_delete
|
|
246
239
|
summary: Delete ACP session from history
|
|
247
240
|
description:
|
|
248
|
-
Remove a persisted ACP session row. Rejects with 409 when the session is still active in memory
|
|
249
|
-
|
|
241
|
+
Remove a persisted ACP session row. Rejects with 409 when the session is still active in memory; idempotent
|
|
242
|
+
for unknown ids.
|
|
250
243
|
tags:
|
|
251
244
|
- acp
|
|
252
245
|
responses:
|
|
@@ -16029,9 +16022,6 @@ paths:
|
|
|
16029
16022
|
type: string
|
|
16030
16023
|
role:
|
|
16031
16024
|
type: string
|
|
16032
|
-
enum:
|
|
16033
|
-
- user
|
|
16034
|
-
- assistant
|
|
16035
16025
|
content:
|
|
16036
16026
|
type: string
|
|
16037
16027
|
timestamp:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/assistant",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"prepack": "node ../scripts/prepack-bundled-deps.mjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@agentclientprotocol/sdk": "0.
|
|
36
|
+
"@agentclientprotocol/sdk": "0.16.1",
|
|
37
37
|
"@anthropic-ai/sdk": "0.78.0",
|
|
38
38
|
"@google/genai": "1.45.0",
|
|
39
39
|
"@modelcontextprotocol/sdk": "1.27.1",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Sites not exercised here (`aborted_via_error`) require deeper provider
|
|
14
14
|
* fakery and are best covered by integration tests.
|
|
15
15
|
*/
|
|
16
|
-
import { describe, expect, test } from "bun:test";
|
|
16
|
+
import { describe, expect, spyOn, test } from "bun:test";
|
|
17
17
|
|
|
18
18
|
import type {
|
|
19
19
|
AgentEvent,
|
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
} from "../agent/loop.js";
|
|
24
24
|
import { AgentLoop, isMaxTokensStopReason } from "../agent/loop.js";
|
|
25
25
|
import type { TurnContext } from "../plugins/types.js";
|
|
26
|
+
import { PluginTimeoutError } from "../plugins/types.js";
|
|
26
27
|
import type {
|
|
27
28
|
Message,
|
|
28
29
|
Provider,
|
|
@@ -101,8 +102,8 @@ const userMessage: Message = {
|
|
|
101
102
|
};
|
|
102
103
|
|
|
103
104
|
// A turn context whose `contextWindowManager.maybeCompact` returns a canned
|
|
104
|
-
// result, so the loop's compaction
|
|
105
|
-
// machinery.
|
|
105
|
+
// result, so the loop's native compaction pipeline runs without the real
|
|
106
|
+
// orchestrator machinery.
|
|
106
107
|
function fakeCompactionTurnContext(result: {
|
|
107
108
|
compacted: boolean;
|
|
108
109
|
exhausted: boolean;
|
|
@@ -118,6 +119,22 @@ function fakeCompactionTurnContext(result: {
|
|
|
118
119
|
} as unknown as TurnContext;
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
// A turn context whose compaction call times out, exercising the loop's
|
|
123
|
+
// PluginTimeoutError handling.
|
|
124
|
+
function timeoutCompactionTurnContext(): TurnContext {
|
|
125
|
+
return {
|
|
126
|
+
requestId: "req-compact",
|
|
127
|
+
conversationId: "conv-compact",
|
|
128
|
+
turnIndex: 0,
|
|
129
|
+
trust: { sourceChannel: "vellum", trustClass: "unknown" },
|
|
130
|
+
contextWindowManager: {
|
|
131
|
+
maybeCompact: async () => {
|
|
132
|
+
throw new PluginTimeoutError("compaction", "default-compaction", 1);
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
} as unknown as TurnContext;
|
|
136
|
+
}
|
|
137
|
+
|
|
121
138
|
function lastExitEvent(
|
|
122
139
|
events: AgentEvent[],
|
|
123
140
|
): Extract<AgentEvent, { type: "agent_loop_exit" }> | undefined {
|
|
@@ -399,6 +416,42 @@ describe("AgentLoop exit-reason instrumentation", () => {
|
|
|
399
416
|
expect(result.exitReason).not.toBe("budget");
|
|
400
417
|
});
|
|
401
418
|
|
|
419
|
+
test("yields 'budget' when inline compaction times out", async () => {
|
|
420
|
+
const { provider } = createMockProvider([
|
|
421
|
+
toolUseResponse("t1", "read_file", { path: "/a.txt" }),
|
|
422
|
+
textResponse("never reached"),
|
|
423
|
+
]);
|
|
424
|
+
const toolExecutor = async () => ({ content: "ok", isError: false });
|
|
425
|
+
const loop = new AgentLoop(provider, "system", {
|
|
426
|
+
tools: dummyTools,
|
|
427
|
+
toolExecutor: toolExecutor,
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const compaction: MidLoopCompaction = {
|
|
431
|
+
postCompactionHook: async () => {
|
|
432
|
+
throw new Error("postCompactionHook must not run after a timeout");
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
const recordOutcomeSpy = spyOn(loop.compactionCircuit, "recordOutcome");
|
|
436
|
+
|
|
437
|
+
// WHEN the compaction pipeline throws a PluginTimeoutError
|
|
438
|
+
const result = await loop.run([userMessage], () => {}, {
|
|
439
|
+
resolveContextWindow: () => ({
|
|
440
|
+
maxInputTokens: 10,
|
|
441
|
+
overflowRecovery: { enabled: true, safetyMarginRatio: 0 },
|
|
442
|
+
}),
|
|
443
|
+
compaction,
|
|
444
|
+
turnContext: timeoutCompactionTurnContext(),
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// THEN the loop records the timeout as a compaction failure against its
|
|
448
|
+
// own circuit breaker, and yields for budget so the orchestrator can
|
|
449
|
+
// escalate.
|
|
450
|
+
expect(recordOutcomeSpy).toHaveBeenCalledTimes(1);
|
|
451
|
+
expect(recordOutcomeSpy.mock.calls[0]?.[1]).toBe(true);
|
|
452
|
+
expect(result.exitReason).toBe("budget");
|
|
453
|
+
});
|
|
454
|
+
|
|
402
455
|
test("yields 'budget' when inline compaction reports exhausted", async () => {
|
|
403
456
|
const { provider } = createMockProvider([
|
|
404
457
|
toolUseResponse("t1", "read_file", { path: "/a.txt" }),
|
|
@@ -102,7 +102,7 @@ mock.module("@anthropic-ai/sdk", () => ({
|
|
|
102
102
|
}));
|
|
103
103
|
|
|
104
104
|
// Import after mocking
|
|
105
|
-
import { cachedTextBlock } from "../
|
|
105
|
+
import { cachedTextBlock } from "../memory/v3/provider-blocks.js";
|
|
106
106
|
import { AnthropicProvider } from "../providers/anthropic/client.js";
|
|
107
107
|
import {
|
|
108
108
|
isPlaceholderSentinelText,
|
|
@@ -103,7 +103,7 @@ const { ROUTES } = await import("../runtime/routes/host-app-control-routes.js");
|
|
|
103
103
|
const { surfaceProxyResolver } =
|
|
104
104
|
await import("../daemon/conversation-surfaces.js");
|
|
105
105
|
const { setConversation, clearConversations } =
|
|
106
|
-
await import("../daemon/conversation-
|
|
106
|
+
await import("../daemon/conversation-store.js");
|
|
107
107
|
type SurfaceConversationContext =
|
|
108
108
|
import("../daemon/conversation-surfaces.js").SurfaceConversationContext;
|
|
109
109
|
|
|
@@ -19,7 +19,6 @@ const ALLOWLIST = new Set([
|
|
|
19
19
|
"assistant/src/memory/app-store.ts", // defines getAppsDir
|
|
20
20
|
"assistant/src/memory/app-git-service.ts", // uses getAppsDir for git repo root, not per-app paths
|
|
21
21
|
"assistant/src/daemon/app-source-watcher.ts", // uses getAppsDir for recursive fs.watch root, not per-app paths
|
|
22
|
-
"assistant/src/tools/filesystem/write.ts", // uses getAppsDir as an exemption root for the artifact-HTML guard, not per-app paths
|
|
23
22
|
]);
|
|
24
23
|
|
|
25
24
|
function isTestFile(filePath: string): boolean {
|
|
@@ -119,15 +119,12 @@ mock.module("../permissions/trust-store.js", () => ({
|
|
|
119
119
|
// ---------------------------------------------------------------------------
|
|
120
120
|
let _conversationFactory: (() => Conversation) | undefined;
|
|
121
121
|
|
|
122
|
-
mock.module("../daemon/conversation-
|
|
122
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
123
123
|
findConversation: () => {
|
|
124
124
|
// Return the current test session for any conversation ID lookup.
|
|
125
125
|
if (!_conversationFactory) return undefined;
|
|
126
126
|
return _conversationFactory();
|
|
127
127
|
},
|
|
128
|
-
}));
|
|
129
|
-
|
|
130
|
-
mock.module("../daemon/conversation-store.js", () => ({
|
|
131
128
|
getOrCreateConversation: async () => {
|
|
132
129
|
if (!_conversationFactory)
|
|
133
130
|
throw new Error("_conversationFactory not set in test");
|
|
@@ -16,7 +16,7 @@ mock.module("../util/logger.js", () => ({
|
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
18
|
const _conversationMocks = new Map<string, unknown>();
|
|
19
|
-
mock.module("../daemon/conversation-
|
|
19
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
20
20
|
findConversation: (id: string) => _conversationMocks.get(id),
|
|
21
21
|
}));
|
|
22
22
|
|
|
@@ -11,7 +11,7 @@ mock.module("../util/logger.js", () => ({
|
|
|
11
11
|
|
|
12
12
|
// Map conversationId → mock session so findConversation returns the right mock.
|
|
13
13
|
const conversationMocks = new Map<string, unknown>();
|
|
14
|
-
mock.module("../daemon/conversation-
|
|
14
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
15
15
|
findConversation: (id: string) => conversationMocks.get(id),
|
|
16
16
|
}));
|
|
17
17
|
|