@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
|
@@ -7,7 +7,6 @@ interface SteerCall {
|
|
|
7
7
|
instruction: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
// Direct steer (no connected client -> no resume fallback).
|
|
11
10
|
const steerCalls: SteerCall[] = [];
|
|
12
11
|
const defaultSteer = (acpSessionId: string, instruction: string) => {
|
|
13
12
|
steerCalls.push({ acpSessionId, instruction });
|
|
@@ -16,13 +15,6 @@ const defaultSteer = (acpSessionId: string, instruction: string) => {
|
|
|
16
15
|
let steerImpl: (acpSessionId: string, instruction: string) => Promise<void> =
|
|
17
16
|
defaultSteer;
|
|
18
17
|
|
|
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
|
-
|
|
26
18
|
// Spread the real module's exports so transitive importers that pull other
|
|
27
19
|
// names from `../../acp/index.js` still resolve at parse time. Bun's `mock.module` is
|
|
28
20
|
// process-global and returns *exactly* the keys the factory returns.
|
|
@@ -32,50 +24,35 @@ mock.module("../../acp/index.js", () => ({
|
|
|
32
24
|
getAcpSessionManager: () => ({
|
|
33
25
|
steer: (acpSessionId: string, instruction: string) =>
|
|
34
26
|
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
|
-
},
|
|
43
27
|
}),
|
|
44
28
|
}));
|
|
45
29
|
|
|
46
30
|
const { executeAcpSteer } = await import("./steer.js");
|
|
47
31
|
|
|
48
|
-
function makeContext(
|
|
32
|
+
function makeContext(): ToolContext {
|
|
49
33
|
return {
|
|
50
34
|
workingDir: "/tmp",
|
|
51
35
|
conversationId: "conv-test",
|
|
52
36
|
trustClass: "guardian",
|
|
53
|
-
|
|
54
|
-
} as ToolContext;
|
|
37
|
+
};
|
|
55
38
|
}
|
|
56
39
|
|
|
57
40
|
beforeEach(() => {
|
|
58
41
|
steerCalls.length = 0;
|
|
59
|
-
steerOrResumeCalls.length = 0;
|
|
60
42
|
steerImpl = defaultSteer;
|
|
61
|
-
steerOrResumeImpl = async () => ({ resumed: false });
|
|
62
43
|
});
|
|
63
44
|
|
|
64
45
|
describe("executeAcpSteer", () => {
|
|
65
|
-
test("happy path: returns steered status and forwards args to
|
|
46
|
+
test("happy path: returns steered status and forwards args to manager", async () => {
|
|
66
47
|
const result = await executeAcpSteer(
|
|
67
48
|
{ acp_session_id: "acp-123", instruction: "stop, do X instead" },
|
|
68
|
-
makeContext(
|
|
49
|
+
makeContext(),
|
|
69
50
|
);
|
|
70
51
|
|
|
71
52
|
expect(result.isError).toBe(false);
|
|
72
|
-
expect(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
instruction: "stop, do X instead",
|
|
76
|
-
});
|
|
77
|
-
expect(typeof steerOrResumeCalls[0]!.send).toBe("function");
|
|
78
|
-
expect(steerCalls).toEqual([]);
|
|
53
|
+
expect(steerCalls).toEqual([
|
|
54
|
+
{ acpSessionId: "acp-123", instruction: "stop, do X instead" },
|
|
55
|
+
]);
|
|
79
56
|
|
|
80
57
|
const parsed = JSON.parse(result.content as string);
|
|
81
58
|
expect(parsed).toEqual({
|
|
@@ -94,7 +71,6 @@ describe("executeAcpSteer", () => {
|
|
|
94
71
|
expect(result.isError).toBe(true);
|
|
95
72
|
expect(result.content).toContain('"instruction" is required');
|
|
96
73
|
expect(steerCalls).toEqual([]);
|
|
97
|
-
expect(steerOrResumeCalls).toEqual([]);
|
|
98
74
|
});
|
|
99
75
|
|
|
100
76
|
test("missing acp_session_id returns isError", async () => {
|
|
@@ -106,23 +82,9 @@ describe("executeAcpSteer", () => {
|
|
|
106
82
|
expect(result.isError).toBe(true);
|
|
107
83
|
expect(result.content).toContain('"acp_session_id" is required');
|
|
108
84
|
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([]);
|
|
123
85
|
});
|
|
124
86
|
|
|
125
|
-
test("'session not found'
|
|
87
|
+
test("manager.steer throwing 'session not found' surfaces the error", async () => {
|
|
126
88
|
steerImpl = () =>
|
|
127
89
|
Promise.reject(new Error('ACP session "acp-x" not found'));
|
|
128
90
|
|
|
@@ -134,64 +96,5 @@ describe("executeAcpSteer", () => {
|
|
|
134
96
|
expect(result.isError).toBe(true);
|
|
135
97
|
expect(result.content).toContain('Could not steer ACP session "acp-x"');
|
|
136
98
|
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");
|
|
196
99
|
});
|
|
197
100
|
});
|
package/src/tools/acp/steer.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { getAcpSessionManager } from "../../acp/index.js";
|
|
2
2
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
3
|
-
import { getSendToClient } from "./context.js";
|
|
4
3
|
|
|
5
4
|
export async function executeAcpSteer(
|
|
6
5
|
input: Record<string, unknown>,
|
|
7
|
-
|
|
6
|
+
_context: ToolContext,
|
|
8
7
|
): Promise<ToolExecutionResult> {
|
|
9
8
|
const acpSessionId = input.acp_session_id as string;
|
|
10
9
|
if (!acpSessionId) {
|
|
@@ -16,54 +15,24 @@ export async function executeAcpSteer(
|
|
|
16
15
|
return { content: '"instruction" is required.', isError: true };
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
const manager = getAcpSessionManager();
|
|
20
|
-
const sendToClient = getSendToClient(context);
|
|
21
|
-
|
|
22
18
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const { resumed } = await manager.steerOrResume(
|
|
36
|
-
acpSessionId,
|
|
37
|
-
instruction,
|
|
38
|
-
sendToClient,
|
|
39
|
-
);
|
|
40
|
-
return steeredResult(acpSessionId, { resumed });
|
|
19
|
+
const manager = getAcpSessionManager();
|
|
20
|
+
await manager.steer(acpSessionId, instruction);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
content: JSON.stringify({
|
|
24
|
+
acpSessionId,
|
|
25
|
+
status: "steered",
|
|
26
|
+
message:
|
|
27
|
+
"Interrupted in-flight prompt; new instruction is now running.",
|
|
28
|
+
}),
|
|
29
|
+
isError: false,
|
|
30
|
+
};
|
|
41
31
|
} catch (err) {
|
|
42
32
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43
|
-
return
|
|
33
|
+
return {
|
|
34
|
+
content: `Could not steer ACP session "${acpSessionId}": ${msg}`,
|
|
35
|
+
isError: true,
|
|
36
|
+
};
|
|
44
37
|
}
|
|
45
38
|
}
|
|
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,12 +76,14 @@ export interface AppCreateInput {
|
|
|
76
76
|
name: string;
|
|
77
77
|
description?: string;
|
|
78
78
|
schema_json?: string;
|
|
79
|
-
/**
|
|
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
|
+
*/
|
|
80
84
|
html?: unknown;
|
|
81
|
-
/** Retired single-file multi-page shortcut.
|
|
85
|
+
/** Retired single-file multi-page shortcut. */
|
|
82
86
|
pages?: unknown;
|
|
83
|
-
/** Lenient alias. Folded into preview.icon when preview.icon is absent. */
|
|
84
|
-
icon?: unknown;
|
|
85
87
|
auto_open?: boolean;
|
|
86
88
|
preview?: Record<string, unknown>;
|
|
87
89
|
source_files?: Record<string, string>;
|
|
@@ -96,14 +98,11 @@ export async function executeAppCreate(
|
|
|
96
98
|
const description = input.description;
|
|
97
99
|
const schemaJson = input.schema_json ?? "{}";
|
|
98
100
|
|
|
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.
|
|
102
101
|
if (Object.prototype.hasOwnProperty.call(input, "html")) {
|
|
103
102
|
return {
|
|
104
103
|
content: JSON.stringify({
|
|
105
104
|
error:
|
|
106
|
-
"app_create no longer accepts html.
|
|
105
|
+
"app_create no longer accepts html. Create the app scaffold, write src/index.html and src/main.tsx with file_write, then call app_refresh.",
|
|
107
106
|
}),
|
|
108
107
|
isError: true,
|
|
109
108
|
};
|
|
@@ -158,11 +157,7 @@ export async function executeAppCreate(
|
|
|
158
157
|
|
|
159
158
|
// Extract icon from preview if provided - only persist emoji-like values,
|
|
160
159
|
// not URLs which would render as raw strings in UI and bundle manifests.
|
|
161
|
-
|
|
162
|
-
const rawIcon = (preview?.icon ??
|
|
163
|
-
(typeof input.icon === "string" ? input.icon : undefined)) as
|
|
164
|
-
| string
|
|
165
|
-
| undefined;
|
|
160
|
+
const rawIcon = preview?.icon as string | undefined;
|
|
166
161
|
const icon = rawIcon && !rawIcon.startsWith("http") ? rawIcon : undefined;
|
|
167
162
|
|
|
168
163
|
const app = store.createApp({
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { join, resolve, sep } from "node:path";
|
|
2
2
|
|
|
3
|
-
import { getAppsDir } from "../../memory/app-store.js";
|
|
4
3
|
import { enqueuePkbIndexJob } from "../../memory/jobs/embed-pkb-file.js";
|
|
5
4
|
import { PKB_WORKSPACE_SCOPE } from "../../memory/pkb/types.js";
|
|
6
5
|
import { RiskLevel } from "../../permissions/types.js";
|
|
@@ -18,29 +17,6 @@ import type {
|
|
|
18
17
|
|
|
19
18
|
const logger = getLogger("file-write");
|
|
20
19
|
|
|
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
|
-
|
|
44
20
|
/**
|
|
45
21
|
* Returns `true` iff `absPath` is an absolute path that resolves strictly
|
|
46
22
|
* inside `pkbRoot`. Matches the containment semantics used elsewhere in the
|
|
@@ -106,16 +82,6 @@ export const fileWriteTool = {
|
|
|
106
82
|
};
|
|
107
83
|
}
|
|
108
84
|
|
|
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
|
-
|
|
119
85
|
const ops = new FileSystemOps((path, opts) =>
|
|
120
86
|
sandboxPolicy(path, context.workingDir, opts),
|
|
121
87
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findConversation } from "../../daemon/conversation-
|
|
1
|
+
import { findConversation } from "../../daemon/conversation-store.js";
|
|
2
2
|
import { getConversationOverrideProfile } from "../../memory/conversation-crud.js";
|
|
3
3
|
import type { Message } from "../../providers/types.js";
|
|
4
4
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
@@ -102,7 +102,9 @@ export async function executeSubagentSpawn(
|
|
|
102
102
|
...(inheritedOverrideProfile
|
|
103
103
|
? { overrideProfile: inheritedOverrideProfile }
|
|
104
104
|
: {}),
|
|
105
|
-
...(context.toolUseId
|
|
105
|
+
...(context.toolUseId
|
|
106
|
+
? { parentToolUseId: context.toolUseId }
|
|
107
|
+
: {}),
|
|
106
108
|
...forkFields,
|
|
107
109
|
},
|
|
108
110
|
sendToClient as (msg: unknown) => void,
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
|
|
21
21
|
const APP_BUILDER_ARTIFACT_RE =
|
|
22
|
-
/\b(app|apps|application|applications|website|websites|site|sites|dashboard|dashboards|game|games|calculator|calculators|tracker|trackers|visualization|visualizations|visualisation|visualisations|
|
|
22
|
+
/\b(app|apps|application|applications|website|websites|site|sites|dashboard|dashboards|game|games|calculator|calculators|tracker|trackers|visualization|visualizations|visualisation|visualisations|tool|tools|utility|utilities|counter|counters)\b/i;
|
|
23
23
|
const APP_BUILDER_BUILD_RE =
|
|
24
24
|
/\b(build|building|built|create|creating|created|make|making|made|generate|generating|generated)\b/i;
|
|
25
25
|
|
|
@@ -58,32 +58,11 @@ function isDynamicPageAppSubstitute(input: Record<string, unknown>): boolean {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const text = collectRoutingText(input).join(" ");
|
|
61
|
-
if (
|
|
62
|
-
APP_BUILDER_ARTIFACT_RE.test(text) &&
|
|
63
|
-
(APP_BUILDER_BUILD_RE.test(text) || /\b(app|application)\b/i.test(text))
|
|
64
|
-
) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Second signal: even when the model gives the surface a clean,
|
|
69
|
-
// non-app-sounding title (dodging the text regex above), substantial
|
|
70
|
-
// interactive HTML is an app being smuggled in as a transient surface.
|
|
71
|
-
// A genuinely transient page is small and static; an app has real
|
|
72
|
-
// scripted markup. Keep the bar high so simple snippets still pass.
|
|
73
|
-
return isSubstantialInteractiveHtml(input);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const INTERACTIVE_HTML_RE = /<script\b|on[a-z]+\s*=|addEventListener|new Chart\b|window\.vellum\b/i;
|
|
77
|
-
|
|
78
|
-
function isSubstantialInteractiveHtml(
|
|
79
|
-
input: Record<string, unknown>,
|
|
80
|
-
): boolean {
|
|
81
|
-
const data = asRecord(input.data);
|
|
82
|
-
const html = data?.html;
|
|
83
|
-
if (typeof html !== "string") {
|
|
61
|
+
if (!APP_BUILDER_ARTIFACT_RE.test(text)) {
|
|
84
62
|
return false;
|
|
85
63
|
}
|
|
86
|
-
|
|
64
|
+
|
|
65
|
+
return APP_BUILDER_BUILD_RE.test(text) || /\b(app|application)\b/i.test(text);
|
|
87
66
|
}
|
|
88
67
|
|
|
89
68
|
function collectRoutingText(input: Record<string, unknown>): string[] {
|
|
@@ -9,9 +9,10 @@ import type { WorkspaceMigration } from "./types.js";
|
|
|
9
9
|
* `conversationSummarization` is invoked from `ContextWindowManager.
|
|
10
10
|
* updateSummary()` during mid-loop compaction. Without a call-site entry it
|
|
11
11
|
* falls through to `llm.default` (opus + `effort: "max"` + `thinking:
|
|
12
|
-
* { enabled: true }` + `maxTokens: 64000`), which is far too expensive
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* { enabled: true }` + `maxTokens: 64000`), which is far too expensive for
|
|
13
|
+
* summarizing a ~150k-token transcript inside the agent-loop plugin
|
|
14
|
+
* pipeline's 30s budget — we were hitting `PluginTimeoutError` and hard-
|
|
15
|
+
* failing the turn.
|
|
15
16
|
*
|
|
16
17
|
* This migration seeds `effort: "low"` and `thinking: { enabled: false }`
|
|
17
18
|
* (and opus-4.7 as the model when absent) so the summary call runs cheaply
|
|
@@ -98,7 +99,7 @@ export const seedConversationSummarizationCallsiteMigration: WorkspaceMigration
|
|
|
98
99
|
},
|
|
99
100
|
down(_workspaceDir: string): void {
|
|
100
101
|
// Forward-only: removing the seeded defaults would reintroduce the
|
|
101
|
-
//
|
|
102
|
+
// 30s pipeline-budget timeout this migration fixes.
|
|
102
103
|
},
|
|
103
104
|
};
|
|
104
105
|
|
|
@@ -20,89 +20,65 @@ import type { WorkspaceMigration } from "./types.js";
|
|
|
20
20
|
// explicitly disabled. It skips profiles that:
|
|
21
21
|
// - Don't exist (no profile to patch)
|
|
22
22
|
// - Already have thinking enabled (idempotent)
|
|
23
|
-
// - Are source: "
|
|
24
|
-
// - Have a non-managed, non-absent source (unknown origin)
|
|
23
|
+
// - Are not source: "managed" (user-created profiles are untouched)
|
|
25
24
|
// - Use a non-Anthropic provider (adaptive thinking is Anthropic-specific)
|
|
26
25
|
|
|
27
26
|
const ADAPTIVE_THINKING = { enabled: true, streamThinking: true } as const;
|
|
28
27
|
const TARGET_PROFILES = ["balanced", "quality-optimized"] as const;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*
|
|
39
|
-
* The function is idempotent: profiles that already have thinking enabled are skipped.
|
|
40
|
-
*/
|
|
41
|
-
export function repairAdaptiveThinkingOnManagedProfiles(
|
|
42
|
-
workspaceDir: string,
|
|
43
|
-
): void {
|
|
44
|
-
const configPath = join(workspaceDir, "config.json");
|
|
45
|
-
if (!existsSync(configPath)) return;
|
|
29
|
+
export const enableAdaptiveThinkingManagedProfilesMigration: WorkspaceMigration =
|
|
30
|
+
{
|
|
31
|
+
id: "097-enable-adaptive-thinking-managed-profiles",
|
|
32
|
+
description:
|
|
33
|
+
"Enable adaptive thinking on managed balanced and quality-optimized profiles",
|
|
34
|
+
run(workspaceDir: string): void {
|
|
35
|
+
const configPath = join(workspaceDir, "config.json");
|
|
36
|
+
if (!existsSync(configPath)) return;
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
let config: Record<string, unknown>;
|
|
39
|
+
try {
|
|
40
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
41
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
42
|
+
config = raw as Record<string, unknown>;
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
const llm = readObject(config.llm);
|
|
48
|
+
if (llm === null) return;
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
const profiles = readObject(llm.profiles);
|
|
51
|
+
if (profiles === null) return;
|
|
61
52
|
|
|
62
|
-
|
|
53
|
+
let changed = false;
|
|
63
54
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
for (const name of TARGET_PROFILES) {
|
|
56
|
+
const profile = readObject(profiles[name]);
|
|
57
|
+
if (profile === null) continue;
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
typeof profile.provider === "string" &&
|
|
78
|
-
profile.provider !== "anthropic"
|
|
79
|
-
) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
59
|
+
// Only patch managed Anthropic profiles.
|
|
60
|
+
if (profile.source !== "managed") continue;
|
|
61
|
+
if (
|
|
62
|
+
typeof profile.provider === "string" &&
|
|
63
|
+
profile.provider !== "anthropic"
|
|
64
|
+
) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
82
67
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
// Skip if thinking is already enabled.
|
|
69
|
+
const thinking = readObject(profile.thinking);
|
|
70
|
+
if (thinking !== null && thinking.enabled === true) continue;
|
|
86
71
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
profile.thinking = { ...ADAPTIVE_THINKING };
|
|
73
|
+
profiles[name] = profile;
|
|
74
|
+
changed = true;
|
|
75
|
+
}
|
|
91
76
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export const enableAdaptiveThinkingManagedProfilesMigration: WorkspaceMigration =
|
|
100
|
-
{
|
|
101
|
-
id: "097-enable-adaptive-thinking-managed-profiles",
|
|
102
|
-
description:
|
|
103
|
-
"Enable adaptive thinking on managed balanced and quality-optimized profiles",
|
|
104
|
-
run(workspaceDir: string): void {
|
|
105
|
-
repairAdaptiveThinkingOnManagedProfiles(workspaceDir);
|
|
77
|
+
if (changed) {
|
|
78
|
+
llm.profiles = profiles;
|
|
79
|
+
config.llm = llm;
|
|
80
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
81
|
+
}
|
|
106
82
|
},
|
|
107
83
|
down(_workspaceDir: string): void {
|
|
108
84
|
// Forward-only.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `post-tool-use` hook for the echo plugin.
|
|
3
|
-
*
|
|
4
|
-
* Purely observational — logs one structured line to stderr and returns
|
|
5
|
-
* `void`, leaving the tool result untouched.
|
|
6
|
-
*
|
|
7
|
-
* Convention: the default export is the function the harness invokes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { PostToolUseContext } from "@vellumai/plugin-api";
|
|
11
|
-
|
|
12
|
-
import { emit } from "../src/emit.js";
|
|
13
|
-
|
|
14
|
-
export default async function postToolUse(
|
|
15
|
-
ctx: PostToolUseContext,
|
|
16
|
-
): Promise<void> {
|
|
17
|
-
emit("post-tool-use", ctx.conversationId);
|
|
18
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `stop` hook for the echo plugin.
|
|
3
|
-
*
|
|
4
|
-
* Purely observational — logs one structured line to stderr and returns
|
|
5
|
-
* `void`, leaving the stop decision untouched.
|
|
6
|
-
*
|
|
7
|
-
* Convention: the default export is the function the harness invokes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { StopContext } from "@vellumai/plugin-api";
|
|
11
|
-
|
|
12
|
-
import { emit } from "../src/emit.js";
|
|
13
|
-
|
|
14
|
-
export default async function stop(ctx: StopContext): Promise<void> {
|
|
15
|
-
emit("stop", ctx.conversationId);
|
|
16
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `user-prompt-submit` hook for the echo plugin.
|
|
3
|
-
*
|
|
4
|
-
* Purely observational — logs one structured line to stderr and returns
|
|
5
|
-
* `void`, leaving the threaded context (message list, injections) untouched.
|
|
6
|
-
*
|
|
7
|
-
* Convention: the default export is the function the harness invokes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { UserPromptSubmitContext } from "@vellumai/plugin-api";
|
|
11
|
-
|
|
12
|
-
import { emit } from "../src/emit.js";
|
|
13
|
-
|
|
14
|
-
export default async function userPromptSubmit(
|
|
15
|
-
ctx: UserPromptSubmitContext,
|
|
16
|
-
): Promise<void> {
|
|
17
|
-
emit("user-prompt-submit", ctx.conversationId);
|
|
18
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared stderr emitter for the echo plugin's hooks.
|
|
3
|
-
*
|
|
4
|
-
* Files under `src/` are internal helpers — the external-plugin loader does
|
|
5
|
-
* not walk this directory, so it contributes no surface of its own. The
|
|
6
|
-
* `hooks/` files import from here.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export const PLUGIN_NAME = "echo";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* One line written to stderr per hook invocation. Kept intentionally compact —
|
|
13
|
-
* pino-style JSON so operators can pipe the assistant's stderr through `jq`
|
|
14
|
-
* without reshaping.
|
|
15
|
-
*/
|
|
16
|
-
export function emit(hook: string, conversationId: string): void {
|
|
17
|
-
const record = { plugin: PLUGIN_NAME, hook, conversationId };
|
|
18
|
-
process.stderr.write(`${JSON.stringify(record)}\n`);
|
|
19
|
-
}
|