@stigmer/runner 3.1.13 → 3.1.15
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 +35 -15
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +40 -12
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
- package/dist/activities/execute-deep-agent/deepagents-profiles.d.ts +16 -0
- package/dist/activities/execute-deep-agent/deepagents-profiles.js +31 -0
- package/dist/activities/execute-deep-agent/deepagents-profiles.js.map +1 -0
- package/dist/activities/execute-deep-agent/setup.js +12 -3
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/shell-env.d.ts +16 -0
- package/dist/activities/execute-deep-agent/shell-env.js +36 -0
- package/dist/activities/execute-deep-agent/shell-env.js.map +1 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +29 -6
- package/dist/activities/execute-deep-agent/subagent-transformer.js +73 -19
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/runner-manager.js +2 -0
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +2 -0
- package/dist/runner.js.map +1 -1
- package/package.json +3 -3
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +134 -1
- package/src/activities/execute-deep-agent/__tests__/shell-env.test.ts +46 -0
- package/src/activities/execute-deep-agent/__tests__/shell-execute-gate.test.ts +291 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +7 -4
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +69 -15
- package/src/activities/execute-deep-agent/deepagents-profiles.ts +35 -0
- package/src/activities/execute-deep-agent/setup.ts +12 -6
- package/src/activities/execute-deep-agent/shell-env.ts +42 -0
- package/src/activities/execute-deep-agent/subagent-transformer.ts +93 -20
- package/src/runner-manager.ts +5 -0
- package/src/runner.ts +5 -0
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
* - Filter parent MCP tools: no reconnection overhead, stateless servers are the norm
|
|
12
12
|
* - Prompt injection for skills: FilesystemBackend incompatible with native skills field
|
|
13
13
|
* - Built-in explore/shell subagents use prompt-based tool restriction
|
|
14
|
+
* - Built-in general-purpose replaces deepagents' auto-injected one (which carries
|
|
15
|
+
* no approval gate — see deepagents-profiles.ts for the suppression half)
|
|
16
|
+
* - Sub-agent backends are shell-capable outside plan mode (issue #248), mirroring
|
|
17
|
+
* the parent's backend selection in setup.ts
|
|
14
18
|
* - Invalid configurations are logged and skipped (graceful degradation)
|
|
15
19
|
* - Empty subagent list returns null (no subagents configured)
|
|
16
20
|
*/
|
|
17
21
|
|
|
18
|
-
import { createDeepAgent, FilesystemBackend } from "deepagents";
|
|
22
|
+
import { createDeepAgent, FilesystemBackend, LocalShellBackend, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT } from "deepagents";
|
|
19
23
|
import type { CompiledSubAgent } from "deepagents";
|
|
20
24
|
import type { StructuredTool } from "@langchain/core/tools";
|
|
21
25
|
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
@@ -26,7 +30,7 @@ import type { SubAgent, McpServerUsage } from "@stigmer/protos/ai/stigmer/agenti
|
|
|
26
30
|
import type { WorkspaceBackend } from "../../shared/workspace/types.js";
|
|
27
31
|
import type { StigmerClient } from "../../client/stigmer-client.js";
|
|
28
32
|
import type { ApprovalGateConfig } from "../../middleware/approval-gate.js";
|
|
29
|
-
import {
|
|
33
|
+
import { createCasCaptureBackend } from "./cas-capture-backend.js";
|
|
30
34
|
import type { CasCaptureObserver } from "./cas-capture-observer.js";
|
|
31
35
|
import type { CostCapMiddleware, StigmerMiddleware } from "../../middleware/index.js";
|
|
32
36
|
import { createThinkTool } from "../../middleware/index.js";
|
|
@@ -44,7 +48,11 @@ import {
|
|
|
44
48
|
// Built-in subagent types and prompts
|
|
45
49
|
// =========================================================================
|
|
46
50
|
|
|
47
|
-
export const BUILTIN_SUBAGENT_TYPES: ReadonlySet<string> = new Set([
|
|
51
|
+
export const BUILTIN_SUBAGENT_TYPES: ReadonlySet<string> = new Set([
|
|
52
|
+
"explore",
|
|
53
|
+
"shell",
|
|
54
|
+
"general-purpose",
|
|
55
|
+
]);
|
|
48
56
|
|
|
49
57
|
const EXPLORE_SYSTEM_PROMPT = `\
|
|
50
58
|
You are an exploration specialist. Your ONLY job is to explore codebases \
|
|
@@ -159,6 +167,13 @@ export interface SubagentTransformOptions {
|
|
|
159
167
|
* model name string is passed to deepagents directly.
|
|
160
168
|
*/
|
|
161
169
|
readonly modelFactory?: (modelName: string) => Promise<BaseChatModel>;
|
|
170
|
+
/**
|
|
171
|
+
* Per-execution env for the sub-agent `execute` tool, snapshotted in setup
|
|
172
|
+
* (see shell-env.ts). Presence is the single switch for shell capability:
|
|
173
|
+
* undefined (plan mode) compiles sub-agents onto non-shell filesystem
|
|
174
|
+
* backends, exactly like the parent's backend selection.
|
|
175
|
+
*/
|
|
176
|
+
readonly shellEnv?: Record<string, string>;
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
// =========================================================================
|
|
@@ -166,18 +181,28 @@ export interface SubagentTransformOptions {
|
|
|
166
181
|
// =========================================================================
|
|
167
182
|
|
|
168
183
|
/**
|
|
169
|
-
* Create built-in explore and
|
|
184
|
+
* Create built-in explore, shell, and general-purpose subagent specifications.
|
|
170
185
|
*
|
|
171
|
-
*
|
|
172
|
-
* - The full deepagents built-in tool set
|
|
186
|
+
* explore and shell receive:
|
|
187
|
+
* - The full deepagents built-in tool set restricted via prompt
|
|
173
188
|
* - Purpose-built system prompts with explicit scope boundaries
|
|
174
189
|
* - No skills, no MCP tools, no parent prompt inheritance
|
|
175
190
|
*
|
|
191
|
+
* general-purpose is the gated replacement for the sub-agent deepagents would
|
|
192
|
+
* otherwise auto-inject WITHOUT our approval gate (suppressed process-wide in
|
|
193
|
+
* deepagents-profiles.ts; supplying our own under the same name is the
|
|
194
|
+
* documented override path). It uses deepagents' own description/prompt so the
|
|
195
|
+
* model's delegation behavior is unchanged, and receives the parent's MCP tools
|
|
196
|
+
* for capability parity with the injected original. Conscious simplification:
|
|
197
|
+
* the parent's skills prompt is NOT inherited — a sub-agent needing skills
|
|
198
|
+
* should be declared explicitly in the Agent spec.
|
|
199
|
+
*
|
|
176
200
|
* Returns an empty array if no workspace is configured (subagents need
|
|
177
201
|
* workspace tools to be useful).
|
|
178
202
|
*/
|
|
179
203
|
export function createBuiltinSubagents(
|
|
180
204
|
hasWorkspace: boolean,
|
|
205
|
+
parentMcpTools: readonly StructuredTool[] = [],
|
|
181
206
|
): TransformedSubagent[] {
|
|
182
207
|
if (!hasWorkspace) {
|
|
183
208
|
return [];
|
|
@@ -185,7 +210,17 @@ export function createBuiltinSubagents(
|
|
|
185
210
|
|
|
186
211
|
const result: TransformedSubagent[] = [];
|
|
187
212
|
|
|
188
|
-
for (const subagentType of ["explore", "shell"] as const) {
|
|
213
|
+
for (const subagentType of ["explore", "shell", "general-purpose"] as const) {
|
|
214
|
+
if (subagentType === "general-purpose") {
|
|
215
|
+
result.push({
|
|
216
|
+
name: "general-purpose",
|
|
217
|
+
description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,
|
|
218
|
+
systemPrompt: DEFAULT_SUBAGENT_PROMPT + RESPONSE_RULES,
|
|
219
|
+
tools: [...parentMcpTools],
|
|
220
|
+
});
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
189
224
|
const prompt = BUILTIN_PROMPTS.get(subagentType);
|
|
190
225
|
const description = BUILTIN_DESCRIPTIONS.get(subagentType);
|
|
191
226
|
if (!prompt || !description) continue;
|
|
@@ -408,11 +443,51 @@ export function resolveSubagentSkillPrompt(
|
|
|
408
443
|
// Compilation pipeline
|
|
409
444
|
// =========================================================================
|
|
410
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Select a sub-agent's deepagents backend, mirroring the parent's selection in
|
|
448
|
+
* setup.ts along two independent axes:
|
|
449
|
+
*
|
|
450
|
+
* - CAS observation (capture mode): when a shared observer is supplied, the
|
|
451
|
+
* backend records pre-turn bytes of CAS-owned paths so the sub-agent's
|
|
452
|
+
* gitignored writes fold into the parent turn's change set (DD-19). Without
|
|
453
|
+
* one, writes stay on the classic gitignored deny-gate.
|
|
454
|
+
* - Shell capability (issue #248): when `shellEnv` is present the backend
|
|
455
|
+
* implements deepagents' sandbox protocol so the `execute` tool exists
|
|
456
|
+
* (approval-gated by the sub-agent's own middleware). Absent (plan mode),
|
|
457
|
+
* the backend is filesystem-only — read-only by construction, matching the
|
|
458
|
+
* parent.
|
|
459
|
+
*/
|
|
460
|
+
async function buildSubagentBackend(opts: {
|
|
461
|
+
readonly workspaceRootDir: string;
|
|
462
|
+
readonly casObserver?: CasCaptureObserver;
|
|
463
|
+
readonly shellEnv?: Record<string, string>;
|
|
464
|
+
}): Promise<FilesystemBackend> {
|
|
465
|
+
if (opts.casObserver) {
|
|
466
|
+
return createCasCaptureBackend({
|
|
467
|
+
rootDir: opts.workspaceRootDir,
|
|
468
|
+
observer: opts.casObserver,
|
|
469
|
+
shellEnv: opts.shellEnv,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (opts.shellEnv === undefined) {
|
|
474
|
+
return new FilesystemBackend({ rootDir: opts.workspaceRootDir });
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const shellBackend = new LocalShellBackend({
|
|
478
|
+
rootDir: opts.workspaceRootDir,
|
|
479
|
+
env: opts.shellEnv,
|
|
480
|
+
});
|
|
481
|
+
await shellBackend.initialize();
|
|
482
|
+
return shellBackend;
|
|
483
|
+
}
|
|
484
|
+
|
|
411
485
|
/**
|
|
412
486
|
* Compile transformed subagent specifications into CompiledSubAgent instances.
|
|
413
487
|
*
|
|
414
488
|
* Each subagent gets:
|
|
415
|
-
* - Its own agent graph
|
|
489
|
+
* - Its own agent graph sharing the parent's workspace root (shell-capable
|
|
490
|
+
* outside plan mode; see {@link buildSubagentBackend})
|
|
416
491
|
* - Per-subagent middleware (loop detection, budget, truncation, cost cap view)
|
|
417
492
|
* - Concurrency gating via shared SubAgentGate
|
|
418
493
|
*/
|
|
@@ -426,6 +501,8 @@ export async function compileSubagents(
|
|
|
426
501
|
/** Shared CAS observer (capture mode only); see {@link SubagentTransformOptions.casObserver}. */
|
|
427
502
|
readonly casObserver?: CasCaptureObserver;
|
|
428
503
|
readonly modelFactory?: (modelName: string) => Promise<BaseChatModel>;
|
|
504
|
+
/** Shell env for `execute`; see {@link SubagentTransformOptions.shellEnv}. */
|
|
505
|
+
readonly shellEnv?: Record<string, string>;
|
|
429
506
|
},
|
|
430
507
|
): Promise<CompiledSubAgent[]> {
|
|
431
508
|
if (transformed.length === 0) return [];
|
|
@@ -453,15 +530,7 @@ export async function compileSubagents(
|
|
|
453
530
|
// no-proxy paths).
|
|
454
531
|
const model = opts.modelFactory ? await opts.modelFactory(modelName) : modelName;
|
|
455
532
|
|
|
456
|
-
|
|
457
|
-
// the sub-agent's gitignored writes are captured (same class the parent
|
|
458
|
-
// uses). Otherwise the plain backend + classic gitignored deny-gate.
|
|
459
|
-
const backend = opts.casObserver
|
|
460
|
-
? new CasCaptureFilesystemBackend(
|
|
461
|
-
{ rootDir: opts.workspaceRootDir },
|
|
462
|
-
{ observer: opts.casObserver },
|
|
463
|
-
)
|
|
464
|
-
: new FilesystemBackend({ rootDir: opts.workspaceRootDir });
|
|
533
|
+
const backend = await buildSubagentBackend(opts);
|
|
465
534
|
|
|
466
535
|
const agentGraph = await createDeepAgent({
|
|
467
536
|
model,
|
|
@@ -469,7 +538,6 @@ export async function compileSubagents(
|
|
|
469
538
|
tools: spec.tools.length > 0 ? spec.tools : undefined,
|
|
470
539
|
middleware: middleware as unknown[],
|
|
471
540
|
backend,
|
|
472
|
-
generalPurposeAgent: false,
|
|
473
541
|
} as Parameters<typeof createDeepAgent>[0]);
|
|
474
542
|
|
|
475
543
|
const gatedRunnable = gate.wrapRunnable(
|
|
@@ -507,7 +575,7 @@ export async function compileSubagents(
|
|
|
507
575
|
* Transform proto SubAgents and compile into CompiledSubAgent instances.
|
|
508
576
|
*
|
|
509
577
|
* This is the main entry point called from setup.ts. It orchestrates:
|
|
510
|
-
* 1. Built-in subagent creation (explore
|
|
578
|
+
* 1. Built-in subagent creation (explore, shell, general-purpose)
|
|
511
579
|
* 2. Per-subagent transformation (proto → TransformedSubagent)
|
|
512
580
|
* 3. MCP tool filtering per subagent
|
|
513
581
|
* 4. Skill resolution and prompt injection (Session 2)
|
|
@@ -531,6 +599,7 @@ export async function transformAndCompileSubagents(
|
|
|
531
599
|
parentHasNativeThinking,
|
|
532
600
|
costCap,
|
|
533
601
|
modelFactory,
|
|
602
|
+
shellEnv,
|
|
534
603
|
} = options;
|
|
535
604
|
|
|
536
605
|
if (subAgents.length === 0 && !workspaceBackend.rootDir) {
|
|
@@ -543,7 +612,10 @@ export async function transformAndCompileSubagents(
|
|
|
543
612
|
);
|
|
544
613
|
|
|
545
614
|
// Step 1: Create built-in subagents
|
|
546
|
-
const builtins = createBuiltinSubagents(
|
|
615
|
+
const builtins = createBuiltinSubagents(
|
|
616
|
+
!!workspaceBackend.rootDir,
|
|
617
|
+
parentMcpTools,
|
|
618
|
+
);
|
|
547
619
|
|
|
548
620
|
// Step 1b: Batch fetch all skills referenced by subagents
|
|
549
621
|
const allSkillRefs = collectAllSkillRefs(subAgents);
|
|
@@ -645,6 +717,7 @@ export async function transformAndCompileSubagents(
|
|
|
645
717
|
workspaceRootDir: workspaceBackend.rootDir,
|
|
646
718
|
casObserver,
|
|
647
719
|
modelFactory,
|
|
720
|
+
shellEnv,
|
|
648
721
|
});
|
|
649
722
|
|
|
650
723
|
if (compiled.length === 0) {
|
package/src/runner-manager.ts
CHANGED
|
@@ -195,6 +195,11 @@ export async function createStigmerRunnerManager(
|
|
|
195
195
|
): Promise<StigmerRunnerManager> {
|
|
196
196
|
validateManagerOptions(options);
|
|
197
197
|
|
|
198
|
+
const { registerStigmerDeepagentsProfiles } = await import(
|
|
199
|
+
"./activities/execute-deep-agent/deepagents-profiles.js"
|
|
200
|
+
);
|
|
201
|
+
registerStigmerDeepagentsProfiles();
|
|
202
|
+
|
|
198
203
|
// `tokenRef` holds the control-plane token (the host's durable credential,
|
|
199
204
|
// e.g. the desktop's Auth0 token) and is shared with activity clients via
|
|
200
205
|
// config.stigmerTokenRef. The proxy credential (x-stigmer-auth) is managed
|
package/src/runner.ts
CHANGED
|
@@ -136,6 +136,11 @@ export async function createStigmerRunner(
|
|
|
136
136
|
): Promise<StigmerRunner> {
|
|
137
137
|
validateOptions(options);
|
|
138
138
|
|
|
139
|
+
const { registerStigmerDeepagentsProfiles } = await import(
|
|
140
|
+
"./activities/execute-deep-agent/deepagents-profiles.js"
|
|
141
|
+
);
|
|
142
|
+
registerStigmerDeepagentsProfiles();
|
|
143
|
+
|
|
139
144
|
const baseConfig = mapOptionsToConfig(options);
|
|
140
145
|
|
|
141
146
|
// Install the Cursor SDK interceptors BEFORE resolving Temporal coordinates.
|