@narumitw/pi-subagents 0.17.2 → 0.20.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/README.md +2 -2
- package/package.json +6 -6
- package/src/agents.ts +9 -2
- package/src/config-ui.ts +27 -5
- package/src/in-process-transport.ts +79 -14
- package/src/params.ts +2 -1
- package/src/stateful.ts +2 -5
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Common controls:
|
|
|
67
67
|
|
|
68
68
|
- `cwd` — run a job from a different working directory.
|
|
69
69
|
- `timeoutMs` — set a hard subprocess timeout.
|
|
70
|
-
- `thinkingLevel` — request `off`, `minimal`, `low`, `medium`, `high`, or `
|
|
70
|
+
- `thinkingLevel` — request `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` thinking for the spawned Pi process.
|
|
71
71
|
|
|
72
72
|
## 🧭 Proactive use
|
|
73
73
|
|
|
@@ -381,7 +381,7 @@ Each subprocess has a hard timeout to avoid runaway workers.
|
|
|
381
381
|
- Set `timeoutMs` on a task, chain step, or aggregator to override it locally.
|
|
382
382
|
- If omitted, the default is `PI_SUBAGENT_TIMEOUT_MS`, or `600000` milliseconds (10 minutes) when unset.
|
|
383
383
|
|
|
384
|
-
Set `thinkingLevel` to pass Pi's `--thinking <level>` to a subprocess. Supported values are `off`, `minimal`, `low`, `medium`, `high`, and `
|
|
384
|
+
Set `thinkingLevel` to pass Pi's `--thinking <level>` to a subprocess. Supported values are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`.
|
|
385
385
|
|
|
386
386
|
Thinking-level precedence is: task/chain step/aggregator `thinkingLevel` → top-level `thinkingLevel` → agent default from config or frontmatter → Pi subprocess default. Omit `thinkingLevel` to preserve existing behavior. Pi still owns model capability clamping, so unsupported thinking levels are handled by the spawned Pi process.
|
|
387
387
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Pi extension for delegating work to specialized isolated subagents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@biomejs/biome": "2.5.3",
|
|
42
|
-
"@earendil-works/pi-agent-core": "0.80.
|
|
43
|
-
"@earendil-works/pi-ai": "0.80.
|
|
44
|
-
"@earendil-works/pi-coding-agent": "0.80.
|
|
45
|
-
"@earendil-works/pi-tui": "0.80.
|
|
46
|
-
"typescript": "
|
|
42
|
+
"@earendil-works/pi-agent-core": "0.80.10",
|
|
43
|
+
"@earendil-works/pi-ai": "0.80.10",
|
|
44
|
+
"@earendil-works/pi-coding-agent": "0.80.10",
|
|
45
|
+
"@earendil-works/pi-tui": "0.80.10",
|
|
46
|
+
"typescript": "7.0.2"
|
|
47
47
|
},
|
|
48
48
|
"repository": {
|
|
49
49
|
"type": "git",
|
package/src/agents.ts
CHANGED
|
@@ -4,10 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
8
7
|
import { getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
9
8
|
|
|
10
|
-
export const THINKING_LEVELS = [
|
|
9
|
+
export const THINKING_LEVELS = [
|
|
10
|
+
"off",
|
|
11
|
+
"minimal",
|
|
12
|
+
"low",
|
|
13
|
+
"medium",
|
|
14
|
+
"high",
|
|
15
|
+
"xhigh",
|
|
16
|
+
"max",
|
|
17
|
+
] as const;
|
|
11
18
|
|
|
12
19
|
export type SubagentThinkingLevel = (typeof THINKING_LEVELS)[number];
|
|
13
20
|
|
package/src/config-ui.ts
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
Container,
|
|
5
5
|
Key,
|
|
6
6
|
matchesKey,
|
|
7
|
-
SelectList,
|
|
8
7
|
type SelectItem,
|
|
8
|
+
SelectList,
|
|
9
9
|
Spacer,
|
|
10
10
|
Text,
|
|
11
11
|
truncateToWidth,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
uniqueToolNames,
|
|
21
21
|
} from "./settings.js";
|
|
22
22
|
|
|
23
|
-
class ToolToggleList {
|
|
23
|
+
export class ToolToggleList {
|
|
24
24
|
private items: { name: string; selected: boolean }[];
|
|
25
25
|
private cursor = 0;
|
|
26
26
|
private cachedWidth?: number;
|
|
@@ -98,6 +98,7 @@ export function registerSubagentConfigCommand(pi: ExtensionAPI) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// Loop: agent selection → tool toggle (Esc in tools returns here)
|
|
101
|
+
let selectedAgentIndex = 0;
|
|
101
102
|
while (true) {
|
|
102
103
|
// Step 1: pick an agent to configure
|
|
103
104
|
const agentItems: SelectItem[] = agents.map((a) => {
|
|
@@ -133,7 +134,20 @@ export function registerSubagentConfigCommand(pi: ExtensionAPI) {
|
|
|
133
134
|
scrollInfo: (t: string) => theme.fg("dim", t),
|
|
134
135
|
noMatch: (t: string) => theme.fg("warning", t),
|
|
135
136
|
});
|
|
136
|
-
selectList.
|
|
137
|
+
selectList.setSelectedIndex(selectedAgentIndex);
|
|
138
|
+
selectList.onSelectionChange = (item) => {
|
|
139
|
+
selectedAgentIndex = Math.max(
|
|
140
|
+
0,
|
|
141
|
+
agentItems.findIndex((candidate) => candidate.value === item.value),
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
selectList.onSelect = (item) => {
|
|
145
|
+
selectedAgentIndex = Math.max(
|
|
146
|
+
0,
|
|
147
|
+
agentItems.findIndex((candidate) => candidate.value === item.value),
|
|
148
|
+
);
|
|
149
|
+
done(item.value);
|
|
150
|
+
};
|
|
137
151
|
selectList.onCancel = () => done(null);
|
|
138
152
|
container.addChild(selectList);
|
|
139
153
|
container.addChild(
|
|
@@ -193,7 +207,11 @@ export function registerSubagentConfigCommand(pi: ExtensionAPI) {
|
|
|
193
207
|
);
|
|
194
208
|
container.addChild(new Spacer(1));
|
|
195
209
|
container.addChild(
|
|
196
|
-
new Text(
|
|
210
|
+
new Text(
|
|
211
|
+
theme.fg("muted", "Toggle tools with Enter/Space. S to save, Esc to cancel."),
|
|
212
|
+
1,
|
|
213
|
+
0,
|
|
214
|
+
),
|
|
197
215
|
);
|
|
198
216
|
container.addChild(new Spacer(1));
|
|
199
217
|
|
|
@@ -206,7 +224,11 @@ export function registerSubagentConfigCommand(pi: ExtensionAPI) {
|
|
|
206
224
|
|
|
207
225
|
container.addChild(new Spacer(1));
|
|
208
226
|
container.addChild(
|
|
209
|
-
new Text(
|
|
227
|
+
new Text(
|
|
228
|
+
theme.fg("dim", "↑↓ navigate · enter/space toggle · S save · esc cancel"),
|
|
229
|
+
1,
|
|
230
|
+
0,
|
|
231
|
+
),
|
|
210
232
|
);
|
|
211
233
|
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
212
234
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
2
3
|
import {
|
|
3
4
|
createAgentSession,
|
|
@@ -7,7 +8,12 @@ import {
|
|
|
7
8
|
SessionManager,
|
|
8
9
|
SettingsManager,
|
|
9
10
|
} from "@earendil-works/pi-coding-agent";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type AgentConfig,
|
|
13
|
+
discoverAgents,
|
|
14
|
+
isThinkingLevel,
|
|
15
|
+
type SubagentThinkingLevel,
|
|
16
|
+
} from "./agents.js";
|
|
11
17
|
import { redactPrivateText } from "./context.js";
|
|
12
18
|
import { resolveDefaultSubagentTimeoutMs } from "./execution.js";
|
|
13
19
|
import { DEFAULT_MAX_CONTEXT_BYTES, DEFAULT_MAX_OUTPUT_BYTES, truncateUtf8 } from "./limits.js";
|
|
@@ -18,6 +24,25 @@ import type { SubagentTransport } from "./transport.js";
|
|
|
18
24
|
const BUILT_IN_TOOL_NAMES = new Set(["read", "bash", "edit", "write", "grep", "find", "ls"]);
|
|
19
25
|
const DEFAULT_ABORT_GRACE_MS = 5_000;
|
|
20
26
|
|
|
27
|
+
interface ChildModelRuntime {
|
|
28
|
+
getModel(provider: string, modelId: string): Model<Api> | undefined;
|
|
29
|
+
registerProvider(provider: string, config: unknown): void;
|
|
30
|
+
registerNativeProvider?(provider: unknown): void;
|
|
31
|
+
setRuntimeApiKey(provider: string, apiKey: string): Promise<void> | void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface CodingAgentRuntimeModule {
|
|
35
|
+
ModelRuntime?: {
|
|
36
|
+
create(options?: { authPath?: string; modelsPath?: string | null }): Promise<ChildModelRuntime>;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface RegisteredProviderRegistry {
|
|
41
|
+
getRegisteredProviderConfig?(provider: string): unknown;
|
|
42
|
+
getRegisteredProviderIds?(): readonly string[];
|
|
43
|
+
getRegisteredNativeProvider?(provider: string): unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
export interface ParentRuntimeSnapshot {
|
|
22
47
|
model: Model<Api> | undefined;
|
|
23
48
|
thinkingLevel: SubagentThinkingLevel;
|
|
@@ -316,20 +341,31 @@ export async function createSdkChildSession(
|
|
|
316
341
|
options.agent.agentScope === "project" || options.agent.agentScope === "both",
|
|
317
342
|
);
|
|
318
343
|
const resolved = await resolveChildModel(options);
|
|
344
|
+
const modelRuntime = await createChildModelRuntime(
|
|
345
|
+
options.modelRegistry,
|
|
346
|
+
resolved.model,
|
|
347
|
+
agentDir,
|
|
348
|
+
);
|
|
349
|
+
const model =
|
|
350
|
+
modelRuntime?.getModel(resolved.model.provider, resolved.model.id) ?? resolved.model;
|
|
319
351
|
const sessionManager = SessionManager.inMemory(options.agent.cwd);
|
|
320
|
-
seedChildSessionManager(sessionManager, options,
|
|
321
|
-
const
|
|
352
|
+
seedChildSessionManager(sessionManager, options, model);
|
|
353
|
+
const sessionOptions: Record<string, unknown> = {
|
|
322
354
|
cwd: options.agent.cwd,
|
|
323
355
|
agentDir,
|
|
324
|
-
model
|
|
356
|
+
model,
|
|
325
357
|
thinkingLevel: resolved.thinkingLevel,
|
|
326
|
-
modelRegistry: options.modelRegistry,
|
|
327
358
|
resourceLoader,
|
|
328
359
|
settingsManager,
|
|
329
360
|
sessionManager,
|
|
330
361
|
tools: options.tools,
|
|
331
362
|
noTools: options.tools?.length === 0 ? "all" : undefined,
|
|
332
|
-
}
|
|
363
|
+
};
|
|
364
|
+
if (modelRuntime) sessionOptions.modelRuntime = modelRuntime;
|
|
365
|
+
else sessionOptions.modelRegistry = options.modelRegistry;
|
|
366
|
+
const created = await createAgentSession(
|
|
367
|
+
sessionOptions as NonNullable<Parameters<typeof createAgentSession>[0]>,
|
|
368
|
+
);
|
|
333
369
|
const session = created.session;
|
|
334
370
|
if (options.tools !== undefined) {
|
|
335
371
|
const active = session.getActiveToolNames();
|
|
@@ -359,6 +395,42 @@ export async function createSdkChildSession(
|
|
|
359
395
|
};
|
|
360
396
|
}
|
|
361
397
|
|
|
398
|
+
async function createChildModelRuntime(
|
|
399
|
+
modelRegistry: ModelRegistry,
|
|
400
|
+
model: Model<Api>,
|
|
401
|
+
agentDir: string,
|
|
402
|
+
): Promise<ChildModelRuntime | undefined> {
|
|
403
|
+
const codingAgentModule = (await import(
|
|
404
|
+
"@earendil-works/pi-coding-agent"
|
|
405
|
+
)) as unknown as CodingAgentRuntimeModule;
|
|
406
|
+
if (!codingAgentModule.ModelRuntime) return undefined;
|
|
407
|
+
|
|
408
|
+
const modelRuntime = await codingAgentModule.ModelRuntime.create({
|
|
409
|
+
authPath: join(agentDir, "auth.json"),
|
|
410
|
+
modelsPath: join(agentDir, "models.json"),
|
|
411
|
+
});
|
|
412
|
+
const registeredProviders = modelRegistry as unknown as RegisteredProviderRegistry;
|
|
413
|
+
copyRegisteredProviders(registeredProviders, modelRuntime);
|
|
414
|
+
const auth = await modelRegistry.getApiKeyAndHeaders(model);
|
|
415
|
+
if (auth.ok && auth.apiKey) await modelRuntime.setRuntimeApiKey(model.provider, auth.apiKey);
|
|
416
|
+
return modelRuntime;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export function copyRegisteredProviders(
|
|
420
|
+
registeredProviders: RegisteredProviderRegistry,
|
|
421
|
+
modelRuntime: ChildModelRuntime,
|
|
422
|
+
): void {
|
|
423
|
+
for (const provider of registeredProviders.getRegisteredProviderIds?.() ?? []) {
|
|
424
|
+
const config = registeredProviders.getRegisteredProviderConfig?.(provider);
|
|
425
|
+
if (config !== undefined) {
|
|
426
|
+
modelRuntime.registerProvider(provider, config);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
const nativeProvider = registeredProviders.getRegisteredNativeProvider?.(provider);
|
|
430
|
+
if (nativeProvider) modelRuntime.registerNativeProvider?.(nativeProvider);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
362
434
|
export async function resolveChildModel(options: ChildSessionCreateOptions): Promise<{
|
|
363
435
|
model: Model<Api>;
|
|
364
436
|
thinkingLevel: SubagentThinkingLevel;
|
|
@@ -390,14 +462,7 @@ function parseModelRequest(value: string): {
|
|
|
390
462
|
const separator = requested.lastIndexOf(":");
|
|
391
463
|
if (separator > 0) {
|
|
392
464
|
const suffix = requested.slice(separator + 1);
|
|
393
|
-
if (
|
|
394
|
-
suffix === "off" ||
|
|
395
|
-
suffix === "minimal" ||
|
|
396
|
-
suffix === "low" ||
|
|
397
|
-
suffix === "medium" ||
|
|
398
|
-
suffix === "high" ||
|
|
399
|
-
suffix === "xhigh"
|
|
400
|
-
) {
|
|
465
|
+
if (isThinkingLevel(suffix)) {
|
|
401
466
|
return { model: requested.slice(0, separator), thinkingLevel: suffix };
|
|
402
467
|
}
|
|
403
468
|
}
|
package/src/params.ts
CHANGED
|
@@ -9,7 +9,8 @@ const TimeoutMs = Type.Number({
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const ThinkingLevelSchema = StringEnum(THINKING_LEVELS, {
|
|
12
|
-
description:
|
|
12
|
+
description:
|
|
13
|
+
"Pi thinking level for the subagent process: off, minimal, low, medium, high, xhigh, or max.",
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
const TaskItem = Type.Object({
|
package/src/stateful.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
|
-
import { discoverAgents, type AgentScope } from "./agents.js";
|
|
6
|
+
import { discoverAgents, type AgentScope, isThinkingLevel } from "./agents.js";
|
|
7
7
|
import { buildContextSnapshot, type ContextMode, redactPrivateText } from "./context.js";
|
|
8
8
|
import { assertSubagentDepthAllowed } from "./execution.js";
|
|
9
9
|
import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
|
|
@@ -830,10 +830,7 @@ export function resolveStatefulTransportKind(
|
|
|
830
830
|
}
|
|
831
831
|
|
|
832
832
|
function normalizeRuntimeThinkingLevel(value: string): ParentRuntimeSnapshot["thinkingLevel"] {
|
|
833
|
-
|
|
834
|
-
return value;
|
|
835
|
-
}
|
|
836
|
-
return value === "max" ? "xhigh" : "off";
|
|
833
|
+
return isThinkingLevel(value) ? value : "off";
|
|
837
834
|
}
|
|
838
835
|
|
|
839
836
|
export {
|