pi-subagents-lite 1.0.0 → 1.0.1
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/package.json +1 -1
- package/src/agent-manager.ts +3 -0
- package/src/agent-runner.ts +6 -3
- package/src/config-io.ts +1 -1
- package/src/menus.ts +29 -2
- package/src/model-precedence.ts +4 -2
- package/src/tool-execution.ts +2 -1
package/package.json
CHANGED
package/src/agent-manager.ts
CHANGED
|
@@ -115,6 +115,8 @@ export interface SpawnOptions {
|
|
|
115
115
|
onAssistantUsage?: (usage: LifetimeUsage) => void;
|
|
116
116
|
/** Called when the session successfully compacts. */
|
|
117
117
|
onCompaction?: (info: CompactionInfo) => void;
|
|
118
|
+
/** Grace turns: extra turns allowed after hitting maxTurns. */
|
|
119
|
+
graceTurns?: number;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
export class AgentManager {
|
|
@@ -304,6 +306,7 @@ export class AgentManager {
|
|
|
304
306
|
model: options.model,
|
|
305
307
|
maxTurns: options.maxTurns,
|
|
306
308
|
thinkingLevel: options.thinkingLevel,
|
|
309
|
+
graceTurns: options.graceTurns,
|
|
307
310
|
signal: record.abortController!.signal,
|
|
308
311
|
...this.createRecordCallbacks(record, options),
|
|
309
312
|
onTurnEnd: (turnCount) => {
|
package/src/agent-runner.ts
CHANGED
|
@@ -29,8 +29,8 @@ import { type CompactionInfo, type EnvInfo, SHORT_ID_LENGTH, type SubagentType,
|
|
|
29
29
|
/** Names of tools registered by this extension that subagents must NOT inherit. */
|
|
30
30
|
const EXCLUDED_TOOL_NAMES = ["Agent"];
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
const
|
|
32
|
+
/** Default grace turns when not specified in config. */
|
|
33
|
+
const DEFAULT_GRACE_TURNS = 6;
|
|
34
34
|
|
|
35
35
|
/** Timeout for quick git commands (branch detection, repo check). */
|
|
36
36
|
const GIT_EXEC_TIMEOUT_MS = 5000;
|
|
@@ -76,6 +76,8 @@ interface RunOptions {
|
|
|
76
76
|
* pre-compaction context size estimate. Aborted compactions don't fire.
|
|
77
77
|
*/
|
|
78
78
|
onCompaction?: (info: CompactionInfo) => void;
|
|
79
|
+
/** Grace turns: extra turns allowed after hitting maxTurns. Defaults to 6. */
|
|
80
|
+
graceTurns?: number;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
interface RunResult {
|
|
@@ -558,6 +560,7 @@ export async function runAgent(
|
|
|
558
560
|
const maxTurns = normalizeMaxTurns(options.maxTurns ?? agentConfig?.maxTurns);
|
|
559
561
|
let softLimitReached = false;
|
|
560
562
|
let aborted = false;
|
|
563
|
+
const graceTurns = options.graceTurns ?? DEFAULT_GRACE_TURNS;
|
|
561
564
|
|
|
562
565
|
const unsubEvents = subscribeToSessionEvents(session, options);
|
|
563
566
|
|
|
@@ -569,7 +572,7 @@ export async function runAgent(
|
|
|
569
572
|
if (!softLimitReached && turnCount >= maxTurns) {
|
|
570
573
|
softLimitReached = true;
|
|
571
574
|
session.steer("You have reached your turn limit. Wrap up immediately — provide your final answer now.");
|
|
572
|
-
} else if (softLimitReached && turnCount >= maxTurns +
|
|
575
|
+
} else if (softLimitReached && turnCount >= maxTurns + graceTurns) {
|
|
573
576
|
aborted = true;
|
|
574
577
|
session.abort();
|
|
575
578
|
}
|
package/src/config-io.ts
CHANGED
|
@@ -14,7 +14,7 @@ const CONFIG_PATH = path.join(CONFIG_DIR, "subagents-lite.json");
|
|
|
14
14
|
|
|
15
15
|
/** Default configuration — used when config file doesn't exist or is invalid. */
|
|
16
16
|
export const DEFAULT_CONFIG: SubagentsConfig = {
|
|
17
|
-
agent: { default: null, forceBackground: false },
|
|
17
|
+
agent: { default: null, forceBackground: false, graceTurns: 6 },
|
|
18
18
|
concurrency: { default: 4 },
|
|
19
19
|
};
|
|
20
20
|
|
package/src/menus.ts
CHANGED
|
@@ -301,6 +301,26 @@ export async function showModelSettingsMenu(
|
|
|
301
301
|
);
|
|
302
302
|
});
|
|
303
303
|
|
|
304
|
+
// Grace turns setting
|
|
305
|
+
const graceTurns = __config.agent.graceTurns ?? 6;
|
|
306
|
+
items.push(`Grace turns · ${graceTurns}`);
|
|
307
|
+
actions.push(async () => {
|
|
308
|
+
const input = await ctx.ui.input("Grace turns (≥ 0)", String(graceTurns));
|
|
309
|
+
if (input === undefined) return;
|
|
310
|
+
const parsed = parseInt(input.trim(), 10);
|
|
311
|
+
if (isNaN(parsed)) {
|
|
312
|
+
ctx.ui.notify("Invalid value — must be a number", "error");
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (parsed < 0) {
|
|
316
|
+
ctx.ui.notify("Invalid value — must be ≥ 0", "error");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
__config.agent.graceTurns = parsed;
|
|
320
|
+
saveConfigAtomic(__config);
|
|
321
|
+
ctx.ui.notify(`Grace turns set to ${parsed}`, "info");
|
|
322
|
+
});
|
|
323
|
+
|
|
304
324
|
items.push("");
|
|
305
325
|
actions.push(async () => {});
|
|
306
326
|
items.push("─── per-type overrides ───");
|
|
@@ -375,13 +395,20 @@ export async function showModelSettingsMenu(
|
|
|
375
395
|
items.push("Clear all overrides");
|
|
376
396
|
actions.push(async () => {
|
|
377
397
|
const hasOverrides = Object.entries(__config.agent).some(
|
|
378
|
-
([k, v]) => k !== "default" && k !== "forceBackground" && v != null,
|
|
398
|
+
([k, v]) => k !== "default" && k !== "forceBackground" && k !== "graceTurns" && v != null,
|
|
379
399
|
);
|
|
380
400
|
if (!hasOverrides && __config.agent.default === null) {
|
|
381
401
|
ctx.ui.notify("No overrides to clear", "info");
|
|
382
402
|
return;
|
|
383
403
|
}
|
|
384
|
-
|
|
404
|
+
const preserved: Record<string, unknown> = {
|
|
405
|
+
default: __config.agent.default,
|
|
406
|
+
forceBackground: __config.agent.forceBackground,
|
|
407
|
+
};
|
|
408
|
+
if (__config.agent.graceTurns != null) {
|
|
409
|
+
preserved.graceTurns = __config.agent.graceTurns;
|
|
410
|
+
}
|
|
411
|
+
__config.agent = preserved as typeof __config.agent;
|
|
385
412
|
saveConfigAtomic(__config);
|
|
386
413
|
ctx.ui.notify("All model overrides cleared", "info");
|
|
387
414
|
});
|
package/src/model-precedence.ts
CHANGED
|
@@ -17,7 +17,8 @@ export interface SubagentsConfig {
|
|
|
17
17
|
agent: {
|
|
18
18
|
default: string | null;
|
|
19
19
|
forceBackground: boolean;
|
|
20
|
-
|
|
20
|
+
graceTurns?: number;
|
|
21
|
+
[agentType: string]: string | null | undefined | boolean | number;
|
|
21
22
|
};
|
|
22
23
|
concurrency: {
|
|
23
24
|
default: number;
|
|
@@ -60,10 +61,11 @@ export function resolveModel(options: ResolveModelOptions): string {
|
|
|
60
61
|
const { subagentType, agentConfig, config, parentModelId, sessionOverrides } = options;
|
|
61
62
|
|
|
62
63
|
// Precedence chain: session > config > frontmatter > parent
|
|
64
|
+
// Cast agent values: index signature includes number (graceTurns), but models are always strings
|
|
63
65
|
const candidates: Array<string | boolean | null | undefined> = [
|
|
64
66
|
sessionOverrides?.[subagentType],
|
|
65
67
|
sessionOverrides?.["default"],
|
|
66
|
-
config.agent[subagentType],
|
|
68
|
+
config.agent[subagentType] as string | null | undefined,
|
|
67
69
|
config.agent["default"],
|
|
68
70
|
agentConfig?.model,
|
|
69
71
|
parentModelId, // final fallback (always a valid string)
|
package/src/tool-execution.ts
CHANGED
|
@@ -208,6 +208,7 @@ export async function executeAgentTool(
|
|
|
208
208
|
thinkingLevel,
|
|
209
209
|
modelKey,
|
|
210
210
|
invocation: modelName ? { modelName } : undefined,
|
|
211
|
+
graceTurns: __config.agent.graceTurns,
|
|
211
212
|
};
|
|
212
213
|
|
|
213
214
|
if (runInBackground || __config.agent.forceBackground) {
|
|
@@ -239,7 +240,7 @@ async function executeSpawnBackground(
|
|
|
239
240
|
|
|
240
241
|
const record = manager.getRecord(agentId)!;
|
|
241
242
|
const details: Record<string, unknown> = { type: resolvedType, description: spawnOptions.description };
|
|
242
|
-
const suffix = `A notification will arrive when done - User asks you not to poll or duplicate the delegated work.\n\nAgent ID: ${agentId}`;
|
|
243
|
+
const suffix = `A notification will arrive when done - User asks you not to poll, check status or duplicate the delegated work.\n\nAgent ID: ${agentId}`;
|
|
243
244
|
const label = record.status === "queued" ? "Agent queued" : "Agent running";
|
|
244
245
|
|
|
245
246
|
return successResult(`[${label}] ${suffix}`, details);
|