@stigmer/runner 3.32.0 → 3.34.0
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/dist/.build-fingerprint +1 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +13 -6
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +21 -5
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
- package/dist/activities/execute-deep-agent/deepagents-profiles.d.ts +21 -7
- package/dist/activities/execute-deep-agent/deepagents-profiles.js +24 -9
- package/dist/activities/execute-deep-agent/deepagents-profiles.js.map +1 -1
- package/dist/activities/execute-deep-agent/platform-route.d.ts +75 -0
- package/dist/activities/execute-deep-agent/platform-route.js +107 -0
- package/dist/activities/execute-deep-agent/platform-route.js.map +1 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +2 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -5
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +5 -7
- package/dist/activities/execute-deep-agent/subagent-wiring.js +5 -7
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/execute-deep-agent/translator.d.ts +6 -2
- package/dist/activities/execute-deep-agent/translator.js +6 -2
- package/dist/activities/execute-deep-agent/translator.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-setup.js +14 -3
- package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -1
- package/dist/middleware/index.d.ts +7 -3
- package/dist/middleware/index.js +7 -3
- package/dist/middleware/index.js.map +1 -1
- package/dist/shared/workspace/stigmer-link.d.ts +15 -3
- package/dist/shared/workspace/stigmer-link.js +22 -3
- package/dist/shared/workspace/stigmer-link.js.map +1 -1
- package/dist/shared/workspace/types.d.ts +4 -3
- package/package.json +15 -9
- package/src/activities/execute-deep-agent/__tests__/builtin-tool-surface.test.ts +107 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +14 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/fixtures/paused-session.deepagents-1.10.2.json +592 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +2 -2
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -1
- package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +10 -13
- package/src/activities/execute-deep-agent/__tests__/hermetic/resume-across-engine-upgrade.test.ts +374 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +7 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +6 -0
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +16 -8
- package/src/activities/execute-deep-agent/__tests__/platform-route.test.ts +148 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +24 -0
- package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +16 -9
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +25 -6
- package/src/activities/execute-deep-agent/deepagents-profiles.ts +25 -9
- package/src/activities/execute-deep-agent/platform-route.ts +134 -0
- package/src/activities/execute-deep-agent/subagent-transformer.ts +40 -6
- package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -7
- package/src/activities/execute-deep-agent/translator.ts +6 -2
- package/src/activities/execute-deep-agent/turn-setup.ts +17 -3
- package/src/middleware/index.ts +7 -3
- package/src/shared/workspace/__tests__/stigmer-link.test.ts +41 -18
- package/src/shared/workspace/stigmer-link.ts +22 -3
- package/src/shared/workspace/types.ts +4 -3
|
@@ -40,6 +40,7 @@ import type { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
|
|
|
40
40
|
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
41
41
|
import type { Command } from "@langchain/langgraph";
|
|
42
42
|
import { createDeepAgent } from "deepagents";
|
|
43
|
+
import { todoListMiddleware } from "langchain";
|
|
43
44
|
import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
44
45
|
|
|
45
46
|
import type { Config } from "../../config.js";
|
|
@@ -71,6 +72,7 @@ import { resolveRecursionLimit, UNBOUNDED_ADVISORY_RECURSION_LIMIT } from "../..
|
|
|
71
72
|
import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
|
|
72
73
|
import { CasCaptureObserver } from "./cas-capture-observer.js";
|
|
73
74
|
import { createCasCaptureBackend } from "./cas-capture-backend.js";
|
|
75
|
+
import { mountPlatformRoute } from "./platform-route.js";
|
|
74
76
|
import { resolveResumeInput, type GraphStateSnapshot } from "./hitl.js";
|
|
75
77
|
import { buildEnhancedSystemPrompt, composeUserMessage, renderSkillsSection } from "./prompt-builder.js";
|
|
76
78
|
import { buildShellEnv } from "./shell-env.js";
|
|
@@ -454,8 +456,14 @@ export async function buildEngine(
|
|
|
454
456
|
// File capture point: the CAS-observing backend — git-tracked edits flow to
|
|
455
457
|
// disk (the boundary's git diff is authoritative) and the shared observer
|
|
456
458
|
// records the pre-turn bytes of every CAS-owned path. Gate-independent, so
|
|
457
|
-
// it holds even under the global bypass.
|
|
458
|
-
|
|
459
|
+
// it holds even under the global bypass. Platform content (skills, inputs,
|
|
460
|
+
// the approved plan) is mounted over it read-only at `.stigmer/`
|
|
461
|
+
// (`platform-route.ts`): the virtual-rooted backend refuses to follow the
|
|
462
|
+
// workspace link out of the root.
|
|
463
|
+
const fileBackend = await mountPlatformRoute(
|
|
464
|
+
await createCasCaptureBackend({ rootDir: primaryDir, observer: workspace.casObserver, shellEnv }),
|
|
465
|
+
{ workspaceDir: primaryDir, platformDir: workspace.backend.platformDir },
|
|
466
|
+
);
|
|
459
467
|
const graph = await createDeepAgent({
|
|
460
468
|
model,
|
|
461
469
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -463,8 +471,14 @@ export async function buildEngine(
|
|
|
463
471
|
backend: fileBackend,
|
|
464
472
|
systemPrompt,
|
|
465
473
|
tools: graphTools,
|
|
474
|
+
// The to-do list rides ahead of Stigmer's stack: deepagents stopped
|
|
475
|
+
// installing it by default (1.12), and the product reads it — the parent's
|
|
476
|
+
// `write_todos` is what `status.todos` projects and what plan mode's
|
|
477
|
+
// build progress is instructed through (`shared/implement-plan-prompt.ts`).
|
|
478
|
+
// The framework's own middleware, with its default texts. Parent only: a
|
|
479
|
+
// sub-agent's list never reaches the execution (`harness/transcript/builder.ts`).
|
|
466
480
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
467
|
-
middleware: middleware as any,
|
|
481
|
+
middleware: [todoListMiddleware(), ...middleware] as any,
|
|
468
482
|
subagents: compiledSubagents ?? undefined,
|
|
469
483
|
...(responseFormat ? { responseFormat } : {}),
|
|
470
484
|
...(planModePermissions ? { permissions: planModePermissions } : {}),
|
package/src/middleware/index.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Assembles the ordered middleware array from a MiddlewareStackConfig. The
|
|
5
5
|
* order is load-bearing and reads top to bottom:
|
|
6
6
|
*
|
|
7
|
-
* 0. Path normalization (
|
|
8
|
-
*
|
|
9
|
-
* workspace-absolute paths)
|
|
7
|
+
* 0. Path normalization (whenever configured, which every graph does
|
|
8
|
+
* since issue #754 — FIRST, so every downstream middleware observes
|
|
9
|
+
* canonical workspace-absolute paths)
|
|
10
10
|
* 1. Loop detection (always)
|
|
11
11
|
* 2. Execution budget (always — advises at ~80% of the tool-round budget
|
|
12
12
|
* that LangGraph's `recursionLimit` enforces)
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
* graceful-stop middleware and the cost cap's tool block were second stops
|
|
26
26
|
* inside the graph that the runtime could not see).
|
|
27
27
|
*
|
|
28
|
+
* Ahead of this stack the parent graph adds the framework's to-do list
|
|
29
|
+
* middleware (`execute-deep-agent/turn-setup.ts`): it is langchain's, not
|
|
30
|
+
* Stigmer's, and only the parent carries it.
|
|
31
|
+
*
|
|
28
32
|
* The sub-agent stack is `execute-deep-agent/subagent-wiring.ts`'s: the same
|
|
29
33
|
* order over the parent's shared instances where one exists (the advisory's
|
|
30
34
|
* running total), fresh ones otherwise.
|
|
@@ -2,25 +2,29 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
|
2
2
|
import { mkdtemp, mkdir, rm, writeFile, readFile, lstat, readlink } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import { FilesystemBackend } from "deepagents";
|
|
6
5
|
|
|
7
6
|
import {
|
|
8
7
|
ensureStigmerSymlink,
|
|
9
8
|
removeStigmerSymlink,
|
|
9
|
+
stigmerSymlinkPointsAt,
|
|
10
10
|
STIGMER_LOCAL_STATE_DIR,
|
|
11
11
|
} from "../stigmer-link.js";
|
|
12
12
|
import { LocalWorkspaceBackend } from "../local-backend.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* The `.stigmer` symlink is the bridge that makes platform-mounted content
|
|
16
|
-
* (approved plan, skills, attachment inputs) readable
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* the platform-routing LocalWorkspaceBackend
|
|
21
|
-
* `.stigmer/…` path
|
|
22
|
-
*
|
|
23
|
-
*
|
|
16
|
+
* (approved plan, skills, attachment inputs) readable at `.stigmer/…` by
|
|
17
|
+
* whatever reads from the workspace: the Cursor SDK and shell commands on
|
|
18
|
+
* both harnesses. The lifecycle tests pin the ownership contract (ensure
|
|
19
|
+
* replaces, remove is symlink-only); the convergence tests pin the physics:
|
|
20
|
+
* content written through the platform-routing LocalWorkspaceBackend is
|
|
21
|
+
* readable at the same `.stigmer/…` path from inside the workspace once the
|
|
22
|
+
* link exists, and not before (the "plan file doesn't exist" bug).
|
|
23
|
+
*
|
|
24
|
+
* The native harness's FILE tools do not read through the link — their
|
|
25
|
+
* virtual-rooted backend refuses a path whose real location leaves the
|
|
26
|
+
* workspace — so their side of the convergence is pinned on the production
|
|
27
|
+
* backends in `activities/execute-deep-agent/__tests__/platform-route.test.ts`.
|
|
24
28
|
*/
|
|
25
29
|
describe("stigmer-link", () => {
|
|
26
30
|
let workspaceDir: string;
|
|
@@ -104,16 +108,35 @@ describe("stigmer-link", () => {
|
|
|
104
108
|
});
|
|
105
109
|
});
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
describe("stigmerSymlinkPointsAt", () => {
|
|
112
|
+
it("is true only while the link points at this platform dir", async () => {
|
|
113
|
+
expect(await stigmerSymlinkPointsAt(workspaceDir, platformDir), "no link yet").toBe(false);
|
|
114
|
+
await ensureStigmerSymlink(workspaceDir, platformDir);
|
|
115
|
+
expect(await stigmerSymlinkPointsAt(workspaceDir, platformDir)).toBe(true);
|
|
116
|
+
expect(await stigmerSymlinkPointsAt(workspaceDir, join(platformDir, "elsewhere")), "another dir").toBe(false);
|
|
117
|
+
await removeStigmerSymlink(workspaceDir);
|
|
118
|
+
expect(await stigmerSymlinkPointsAt(workspaceDir, platformDir), "removed at turn end").toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("is false for a real .stigmer directory", async () => {
|
|
122
|
+
await mkdir(linkPath());
|
|
123
|
+
expect(await stigmerSymlinkPointsAt(workspaceDir, platformDir)).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ── Write/read convergence (the link, pinned) ─────────
|
|
108
128
|
|
|
109
129
|
describe("platform write / agent read convergence", () => {
|
|
110
|
-
/** Read
|
|
111
|
-
function agentRead(path: string): Promise<{ content?: string; error?: string }> {
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
/** Read the way a process in the workspace does (the shell, the Cursor SDK): a path relative to its CWD. */
|
|
131
|
+
async function agentRead(path: string): Promise<{ content?: string; error?: string }> {
|
|
132
|
+
try {
|
|
133
|
+
return { content: await readFile(join(workspaceDir, path), "utf8") };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
136
|
+
}
|
|
114
137
|
}
|
|
115
138
|
|
|
116
|
-
it("an approved plan mounted under .stigmer/inputs is readable
|
|
139
|
+
it("an approved plan mounted under .stigmer/inputs is readable from the workspace once the link exists", async () => {
|
|
117
140
|
const planFileName = "notes_ab12cd34.plan.md";
|
|
118
141
|
const planText = "# The Approved Plan\n\nStep 1: do the thing.\n";
|
|
119
142
|
|
|
@@ -125,9 +148,9 @@ describe("stigmer-link", () => {
|
|
|
125
148
|
const workspaceBackend = new LocalWorkspaceBackend(workspaceDir, platformDir);
|
|
126
149
|
await workspaceBackend.writeFile(`.stigmer/inputs/${planFileName}`, planText);
|
|
127
150
|
|
|
128
|
-
// Without the symlink the
|
|
129
|
-
// module fixes
|
|
130
|
-
//
|
|
151
|
+
// Without the symlink nothing in the workspace can see the plan — the
|
|
152
|
+
// bug this module fixes. Pinned so the link stays load-bearing in
|
|
153
|
+
// reviewers' and agents' mental models.
|
|
131
154
|
const before = await agentRead(`.stigmer/inputs/${planFileName}`);
|
|
132
155
|
expect(before.content ?? "").not.toContain("The Approved Plan");
|
|
133
156
|
|
|
@@ -7,10 +7,14 @@
|
|
|
7
7
|
* physically lives in the platform dir, outside the workspace, so a real repo
|
|
8
8
|
* is never polluted with Stigmer files (issue #173). But the agent reads from
|
|
9
9
|
* the workspace: the Cursor SDK resolves paths against the workspace CWD, and
|
|
10
|
-
*
|
|
11
|
-
* `FilesystemBackend` rooted at the workspace. The symlink is what makes the
|
|
10
|
+
* shell commands on both harnesses run there. The symlink is what makes the
|
|
12
11
|
* `.stigmer/…` paths those agents are prompted with (skill locations,
|
|
13
|
-
* `.stigmer/inputs/…` attachments) actually resolve.
|
|
12
|
+
* `.stigmer/inputs/…` attachments) actually resolve. The native harness's
|
|
13
|
+
* FILE tools are the exception: their virtual-rooted backend refuses a path
|
|
14
|
+
* whose real location leaves the workspace, so they read the platform dir
|
|
15
|
+
* through a read-only `.stigmer/` route instead
|
|
16
|
+
* (`activities/execute-deep-agent/platform-route.ts`), mounted on exactly
|
|
17
|
+
* the turns this link exists ({@link stigmerSymlinkPointsAt}).
|
|
14
18
|
*
|
|
15
19
|
* Lifecycle contract (same for both harnesses):
|
|
16
20
|
* - Created per turn, under the workspace turn lock — the link is a
|
|
@@ -70,6 +74,21 @@ export async function ensureStigmerSymlink(
|
|
|
70
74
|
await symlink(platformDir, linkPath, "dir");
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Whether the workspace's `.stigmer` is, right now, the link
|
|
79
|
+
* {@link ensureStigmerSymlink} makes to `platformDir`. A turn that mounts no
|
|
80
|
+
* skill and no attachment creates no link, so this is also "does this turn
|
|
81
|
+
* expose platform content at all" — the native harness mounts its read-only
|
|
82
|
+
* `.stigmer/` route on exactly the turns where the link would resolve.
|
|
83
|
+
*/
|
|
84
|
+
export async function stigmerSymlinkPointsAt(workspaceDir: string, platformDir: string): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
return (await readlink(join(workspaceDir, STIGMER_LOCAL_STATE_DIR))) === platformDir;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
/**
|
|
74
93
|
* Remove the workspace `.stigmer` symlink created by
|
|
75
94
|
* {@link ensureStigmerSymlink}.
|
|
@@ -54,9 +54,10 @@ export class WorkspaceProvisionError extends Error {
|
|
|
54
54
|
* routed to the platform directory instead of the workspace root, keeping
|
|
55
55
|
* platform files (skills, inputs) physically separate from the user's
|
|
56
56
|
* workspace. The routing covers the RUNNER's own reads/writes through
|
|
57
|
-
* this interface; the agent
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* this interface; the agent sees the same files through the per-turn
|
|
58
|
+
* `.stigmer` symlink (see stigmer-link.ts), and the native file tools
|
|
59
|
+
* through their read-only `.stigmer/` route over the same dir
|
|
60
|
+
* (`activities/execute-deep-agent/platform-route.ts`).
|
|
60
61
|
*/
|
|
61
62
|
export interface WorkspaceBackend {
|
|
62
63
|
readonly rootDir: string;
|