@mystilleef/pi-subagent 0.4.0 → 0.6.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/package.json +14 -12
- package/src/{agent-cache.ts → agent/agent-cache.ts} +9 -9
- package/src/{agents.ts → agent/agents.ts} +81 -63
- package/src/{process.ts → child/process.ts} +99 -43
- package/src/{prompt-contract.ts → child/prompt-contract.ts} +2 -0
- package/src/index.ts +9 -9
- package/src/{jobs-command.ts → orchestration/jobs-command.ts} +2 -3
- package/src/{run.ts → orchestration/run.ts} +2 -2
- package/src/{subagent-orchestrator.ts → orchestration/subagent-orchestrator.ts} +21 -45
- package/src/{normalize.ts → output/normalize.ts} +0 -21
- package/src/{summary.ts → output/summary.ts} +4 -2
- package/src/{ui.ts → output/ui.ts} +20 -28
- package/src/{progress-state.ts → progress/progress-state.ts} +2 -2
- package/src/{progress.ts → progress/progress.ts} +2 -2
- package/src/{result-details.ts → progress/result-details.ts} +9 -9
- package/src/shared/instance-name.ts +117 -0
- package/src/{types.ts → shared/types.ts} +3 -2
- package/src/{utils.ts → shared/utils.ts} +4 -6
- package/src/instance-name.ts +0 -164
- /package/src/{child-events.ts → child/child-events.ts} +0 -0
- /package/src/{termination.ts → child/termination.ts} +0 -0
- /package/src/{cancel-command.ts → orchestration/cancel-command.ts} +0 -0
- /package/src/{run-command.ts → orchestration/run-command.ts} +0 -0
- /package/src/{run-registry.ts → orchestration/run-registry.ts} +0 -0
|
@@ -4,23 +4,21 @@ import type {
|
|
|
4
4
|
ExtensionContext,
|
|
5
5
|
} from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { type Static, Type } from "typebox";
|
|
7
|
-
import { getCachedAgentDiscovery } from "
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "
|
|
14
|
-
import {
|
|
15
|
-
import { runSingleAgent } from "./process.js";
|
|
7
|
+
import { getCachedAgentDiscovery } from "../agent/agent-cache.js";
|
|
8
|
+
import type {
|
|
9
|
+
AgentConfig,
|
|
10
|
+
AgentScope,
|
|
11
|
+
ThinkingLevel,
|
|
12
|
+
} from "../agent/agents.js";
|
|
13
|
+
import { runSingleAgent } from "../child/process.js";
|
|
14
|
+
import { formatSubagentResultForParent } from "../output/summary.js";
|
|
16
15
|
import {
|
|
17
16
|
cancelProgressState,
|
|
18
17
|
createProgressState,
|
|
19
18
|
failProgressState,
|
|
20
19
|
finalizeProgressState,
|
|
21
|
-
formatElapsed,
|
|
22
20
|
getProgressState,
|
|
23
|
-
} from "
|
|
21
|
+
} from "../progress/progress.js";
|
|
24
22
|
import {
|
|
25
23
|
createSubagentError,
|
|
26
24
|
getFeedbackSummaryText,
|
|
@@ -28,20 +26,20 @@ import {
|
|
|
28
26
|
hasSubagentFailed,
|
|
29
27
|
patchProgressFromDetails,
|
|
30
28
|
sanitizeDetailsForDisplay,
|
|
31
|
-
} from "
|
|
29
|
+
} from "../progress/result-details.js";
|
|
30
|
+
import { generateSubagentInstanceName } from "../shared/instance-name.js";
|
|
31
|
+
import type {
|
|
32
|
+
OnUpdateCallback,
|
|
33
|
+
SingleResult,
|
|
34
|
+
SubagentDetails,
|
|
35
|
+
SubagentToolResult,
|
|
36
|
+
} from "../shared/types.js";
|
|
32
37
|
import {
|
|
33
38
|
listRunJobs,
|
|
34
39
|
type RunJob,
|
|
35
40
|
registerRunJob,
|
|
36
41
|
removeRunJob,
|
|
37
42
|
} from "./run-registry.js";
|
|
38
|
-
import { formatSubagentResultForParent } from "./summary.js";
|
|
39
|
-
import type {
|
|
40
|
-
OnUpdateCallback,
|
|
41
|
-
SingleResult,
|
|
42
|
-
SubagentDetails,
|
|
43
|
-
SubagentToolResult,
|
|
44
|
-
} from "./types.js";
|
|
45
43
|
|
|
46
44
|
const AgentScopeSchema = StringEnum(["user", "project", "both"] as const, {
|
|
47
45
|
description:
|
|
@@ -100,18 +98,15 @@ function sanitizeResultDetails(
|
|
|
100
98
|
includeDebugMessages && (options?.includeMessages ?? true);
|
|
101
99
|
const { messages, termination, progress, stderr, usage, ...core } = result;
|
|
102
100
|
const { contextWindowTokens, ...usageBase } = usage;
|
|
103
|
-
|
|
104
101
|
const sanitized: Record<string, unknown> = {
|
|
105
102
|
...core,
|
|
106
103
|
stderr: includeDebugMessages ? stderr : "",
|
|
107
104
|
usage: { ...usageBase },
|
|
108
105
|
};
|
|
109
|
-
|
|
110
106
|
if (contextWindowTokens !== undefined) {
|
|
111
107
|
(sanitized.usage as Record<string, unknown>).contextWindowTokens =
|
|
112
108
|
contextWindowTokens;
|
|
113
109
|
}
|
|
114
|
-
|
|
115
110
|
if (progress !== undefined) {
|
|
116
111
|
const { activityText, lastToolPreview, ...progBase } = progress;
|
|
117
112
|
sanitized.progress = {
|
|
@@ -123,14 +118,12 @@ function sanitizeResultDetails(
|
|
|
123
118
|
...(lastToolPreview !== undefined && { lastToolPreview }),
|
|
124
119
|
};
|
|
125
120
|
}
|
|
126
|
-
|
|
127
121
|
if (includeMessages) {
|
|
128
122
|
sanitized.messages = options?.recentMessages
|
|
129
123
|
? [...options.recentMessages]
|
|
130
124
|
: messages !== undefined
|
|
131
125
|
? [...messages]
|
|
132
126
|
: undefined;
|
|
133
|
-
|
|
134
127
|
if (includeDebugMessages && termination !== undefined) {
|
|
135
128
|
const { cancelReason, terminationSignal, fallbackCause, ...termBase } =
|
|
136
129
|
termination;
|
|
@@ -142,7 +135,6 @@ function sanitizeResultDetails(
|
|
|
142
135
|
};
|
|
143
136
|
}
|
|
144
137
|
}
|
|
145
|
-
|
|
146
138
|
return sanitized as unknown as SingleResult;
|
|
147
139
|
}
|
|
148
140
|
|
|
@@ -175,30 +167,14 @@ function sendSubagentResultMessage(
|
|
|
175
167
|
});
|
|
176
168
|
}
|
|
177
169
|
|
|
178
|
-
export function
|
|
179
|
-
ctx: ExtensionContext,
|
|
170
|
+
export function emitCompletionAlert(
|
|
180
171
|
state: ReturnType<typeof getProgressState>,
|
|
181
172
|
): void {
|
|
182
173
|
if (!state) return;
|
|
183
174
|
if (state.status === "cancelled") return;
|
|
184
|
-
if (!ctx.ui?.notify) return;
|
|
185
175
|
const tty = (process.stdout as { isTTY?: boolean }).isTTY;
|
|
186
176
|
if (!tty) return;
|
|
187
|
-
const icon = state.status === "error" ? "✗" : "✓";
|
|
188
|
-
const severity =
|
|
189
|
-
state.status === "error" ? ("error" as const) : ("info" as const);
|
|
190
|
-
const elapsed = formatElapsed(
|
|
191
|
-
state.durationMs ?? Date.now() - state.startTime,
|
|
192
|
-
);
|
|
193
|
-
const raw = state.errorText ?? state.finalOutput ?? "";
|
|
194
|
-
const preview = raw.trim().slice(0, 80);
|
|
195
|
-
const namePart = state.instanceName
|
|
196
|
-
? `${state.agent} ${state.instanceName}`
|
|
197
|
-
: state.agent;
|
|
198
|
-
const toast = `${namePart} ${icon} ${elapsed} — "${preview}"`;
|
|
199
|
-
// Terminal bell to draw attention when all jobs complete
|
|
200
177
|
process.stdout.write("\x07");
|
|
201
|
-
ctx.ui.notify(toast, severity);
|
|
202
178
|
}
|
|
203
179
|
|
|
204
180
|
async function runSubagentWorker(
|
|
@@ -289,7 +265,7 @@ async function runSubagentWorker(
|
|
|
289
265
|
if (listRunJobs().length === 0) {
|
|
290
266
|
const state = getProgressState(requestId);
|
|
291
267
|
if (state) {
|
|
292
|
-
|
|
268
|
+
emitCompletionAlert(state);
|
|
293
269
|
}
|
|
294
270
|
}
|
|
295
271
|
}
|
|
@@ -340,7 +316,7 @@ export async function startSubagentJob(
|
|
|
340
316
|
hostSignal: AbortSignal | undefined,
|
|
341
317
|
): Promise<StartJobResult> {
|
|
342
318
|
const agentScope: AgentScope = params.agentScope ?? "both";
|
|
343
|
-
const discovery = getCachedAgentDiscovery(ctx.cwd, agentScope);
|
|
319
|
+
const discovery = await getCachedAgentDiscovery(ctx.cwd, agentScope);
|
|
344
320
|
const agents = discovery.agents;
|
|
345
321
|
const debug = params.debug === true;
|
|
346
322
|
const makeDetails = createDetailsBuilder(
|
|
@@ -361,7 +337,7 @@ export async function startSubagentJob(
|
|
|
361
337
|
if (!confirmed) return { kind: "cancelled", makeDetails };
|
|
362
338
|
}
|
|
363
339
|
if (requested.source === "project") {
|
|
364
|
-
const userAgents =
|
|
340
|
+
const userAgents = await getCachedAgentDiscovery(ctx.cwd, "user");
|
|
365
341
|
const hasUserCollision = userAgents.agents.some(
|
|
366
342
|
(a) => a.name === requested.name,
|
|
367
343
|
);
|
|
@@ -32,27 +32,6 @@ export function extractSemanticToolTarget(
|
|
|
32
32
|
return "";
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function isTranscriptNoiseLine(line: string): boolean {
|
|
36
|
-
return /^(?:(?:hello|hi|hey)(?:[!,.?:;]+|\s|$)|reasoning:|raw log:|apolog(?:y|ies)|sorry\b)/i.test(
|
|
37
|
-
line,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function isFailureDiagnosticLine(line: string): boolean {
|
|
42
|
-
return /^(?:at\s+|error:|failed:|failure:|exception:|traceback\b|caused by:)/i.test(
|
|
43
|
-
line,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function filterOutputLines(output: string): string[] {
|
|
48
|
-
return output
|
|
49
|
-
.split(/\r?\n/)
|
|
50
|
-
.map((l) => l.trim())
|
|
51
|
-
.filter(
|
|
52
|
-
(l) => l && !isTranscriptNoiseLine(l) && !isFailureDiagnosticLine(l),
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
35
|
export function stripTerminalStatusPrefixes(value: string): string {
|
|
57
36
|
return value.replace(/^(?:(?:success|failure):\s*)+/i, "");
|
|
58
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { SingleResult } from "../shared/types.js";
|
|
1
2
|
import { normalizeTerminalSentence } from "./normalize.js";
|
|
2
|
-
import type { SingleResult } from "./types.js";
|
|
3
3
|
|
|
4
4
|
export const FEEDBACK_UI_SUMMARY_MAX_CHARS = 120;
|
|
5
5
|
|
|
@@ -20,7 +20,9 @@ const FEEDBACK_UI_LABEL_PATTERN =
|
|
|
20
20
|
/^\s*(outcome|project summary|result|summary|status|output|message|error|check):\s*/i;
|
|
21
21
|
|
|
22
22
|
export function formatSubagentResultForParent(result: SingleResult): string {
|
|
23
|
-
return result.
|
|
23
|
+
return result.thinkingWarning
|
|
24
|
+
? `[thinking] ${result.thinkingWarning}\n\n${result.finalOutput}`
|
|
25
|
+
: result.finalOutput;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export function summarizeFeedbackUiFinalOutput(finalOutput: string): string {
|
|
@@ -7,11 +7,7 @@ import {
|
|
|
7
7
|
type MarkdownTheme,
|
|
8
8
|
Text,
|
|
9
9
|
} from "@earendil-works/pi-tui";
|
|
10
|
-
import type { AgentScope } from "
|
|
11
|
-
import {
|
|
12
|
-
extractSemanticToolTarget,
|
|
13
|
-
normalizeSummaryValue,
|
|
14
|
-
} from "./normalize.js";
|
|
10
|
+
import type { AgentScope } from "../agent/agents.js";
|
|
15
11
|
import {
|
|
16
12
|
formatContextPercent,
|
|
17
13
|
formatElapsed,
|
|
@@ -21,9 +17,13 @@ import {
|
|
|
21
17
|
STATUS_ICON,
|
|
22
18
|
type SubagentProgressState,
|
|
23
19
|
type ThemeBg,
|
|
24
|
-
} from "
|
|
25
|
-
import { hasSubagentFailed } from "
|
|
26
|
-
import type { SubagentDetails, UsageStats } from "
|
|
20
|
+
} from "../progress/progress-state.js";
|
|
21
|
+
import { hasSubagentFailed } from "../progress/result-details.js";
|
|
22
|
+
import type { SubagentDetails, UsageStats } from "../shared/types.js";
|
|
23
|
+
import {
|
|
24
|
+
extractSemanticToolTarget,
|
|
25
|
+
normalizeSummaryValue,
|
|
26
|
+
} from "./normalize.js";
|
|
27
27
|
|
|
28
28
|
export type { ThemeBg };
|
|
29
29
|
|
|
@@ -103,32 +103,16 @@ export function formatUsageStats(
|
|
|
103
103
|
return parts.join(" · ");
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
/**
|
|
107
|
-
* Formats millisecond durations into human-readable time strings.
|
|
108
|
-
*/
|
|
109
|
-
export function formatDuration(ms: number): string {
|
|
110
|
-
if (ms < 1000) return `${Math.floor(ms)}ms`;
|
|
111
|
-
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
112
|
-
const minutes = Math.floor(ms / 60000);
|
|
113
|
-
const seconds = Math.floor((ms % 60000) / 1000);
|
|
114
|
-
return `${minutes}m ${seconds.toString().padStart(2, "0")}s`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
106
|
/**
|
|
118
107
|
* Formats the footer for subagent result cards, including model, context, turns, and cost.
|
|
119
108
|
*/
|
|
120
|
-
export function formatResultFooter(
|
|
121
|
-
usage: UsageStats,
|
|
122
|
-
model?: string,
|
|
123
|
-
durationMs?: number,
|
|
124
|
-
): string {
|
|
109
|
+
export function formatResultFooter(usage: UsageStats, model?: string): string {
|
|
125
110
|
const parts: string[] = [];
|
|
126
111
|
if (model) parts.push(model);
|
|
127
|
-
if (usage.contextTokens && usage.contextTokens > 0)
|
|
128
|
-
parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
129
112
|
if (usage.turns)
|
|
130
113
|
parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
|
|
131
|
-
if (
|
|
114
|
+
if (usage.contextTokens && usage.contextTokens > 0)
|
|
115
|
+
parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
132
116
|
if (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);
|
|
133
117
|
return parts.join(" · ");
|
|
134
118
|
}
|
|
@@ -243,12 +227,20 @@ export function renderSubagentResult(
|
|
|
243
227
|
const finalOutput = r.finalOutput ?? getFinalOutput(r.messages ?? []);
|
|
244
228
|
const title = formatSubagentTitle(r.agent, r.instanceName, theme);
|
|
245
229
|
const bodyText = stripOutcomeLineForResultUi(bodyOverride ?? finalOutput);
|
|
246
|
-
const
|
|
230
|
+
const toolCount = r.progress?.toolCalls?.length ?? 0;
|
|
231
|
+
const toolLabel = `${toolCount} ${toolCount === 1 ? "tool" : "tools"}`;
|
|
232
|
+
const ctxPercent = formatContextPercent({
|
|
233
|
+
contextTokens: r.usage.contextTokens,
|
|
234
|
+
contextWindowTokens: r.usage.contextWindowTokens,
|
|
235
|
+
} as SubagentProgressState);
|
|
236
|
+
const metadata = `${toolLabel} · ${ctxPercent} ctx · ${formatElapsed(r.durationMs ?? 0)}`;
|
|
237
|
+
const usageStr = formatResultFooter(r.usage, r.model);
|
|
247
238
|
return renderStatusCard(
|
|
248
239
|
{
|
|
249
240
|
status: resultStatus,
|
|
250
241
|
title,
|
|
251
242
|
variant: "full",
|
|
243
|
+
metadata,
|
|
252
244
|
body: bodyText,
|
|
253
245
|
footer: usageStr,
|
|
254
246
|
},
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
normalizeTerminalSentence,
|
|
8
8
|
TOOL_PREVIEW_MAX_CHARS,
|
|
9
9
|
truncateText,
|
|
10
|
-
} from "
|
|
11
|
-
import type { SubagentDetails } from "
|
|
10
|
+
} from "../output/normalize.js";
|
|
11
|
+
import type { SubagentDetails } from "../shared/types.js";
|
|
12
12
|
|
|
13
13
|
export type ThemeBg = "toolPendingBg" | "toolSuccessBg" | "toolErrorBg";
|
|
14
14
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import type { Component } from "@earendil-works/pi-tui";
|
|
20
20
|
import { Box, Text } from "@earendil-works/pi-tui";
|
|
21
|
+
import { formatSubagentTitle, type SubagentTheme } from "../output/ui.js";
|
|
21
22
|
import {
|
|
22
23
|
formatHeaderStats,
|
|
23
24
|
getProgressState,
|
|
@@ -28,9 +29,8 @@ import {
|
|
|
28
29
|
type SubagentProgressState,
|
|
29
30
|
type ThemeBg,
|
|
30
31
|
} from "./progress-state.js";
|
|
31
|
-
import { formatSubagentTitle, type SubagentTheme } from "./ui.js";
|
|
32
32
|
|
|
33
|
-
export { makeToolPreview } from "
|
|
33
|
+
export { makeToolPreview } from "../output/normalize.js";
|
|
34
34
|
export {
|
|
35
35
|
cancelProgressState,
|
|
36
36
|
clearProgressState,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { TOOL_RESULT_FAILED_MESSAGE } from "
|
|
2
|
-
import {
|
|
3
|
-
extractProgressFromDetails,
|
|
4
|
-
getProgressState,
|
|
5
|
-
patchProgressState,
|
|
6
|
-
} from "./progress.js";
|
|
1
|
+
import { TOOL_RESULT_FAILED_MESSAGE } from "../child/process.js";
|
|
7
2
|
import {
|
|
8
3
|
formatSubagentResultForParent,
|
|
9
4
|
summarizeFeedbackUiFinalOutput,
|
|
10
|
-
} from "
|
|
5
|
+
} from "../output/summary.js";
|
|
11
6
|
import type {
|
|
12
7
|
SingleResult,
|
|
13
8
|
SubagentDetails,
|
|
14
9
|
SubagentToolResult,
|
|
15
|
-
} from "
|
|
16
|
-
import { detectMessageError } from "
|
|
10
|
+
} from "../shared/types.js";
|
|
11
|
+
import { detectMessageError } from "../shared/utils.js";
|
|
12
|
+
import {
|
|
13
|
+
extractProgressFromDetails,
|
|
14
|
+
getProgressState,
|
|
15
|
+
patchProgressState,
|
|
16
|
+
} from "./progress.js";
|
|
17
17
|
|
|
18
18
|
export function hasSubagentFailed(result: SingleResult): boolean {
|
|
19
19
|
return (
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const DEFAULT_ADJECTIVES = [
|
|
2
|
+
"able",
|
|
3
|
+
"agile",
|
|
4
|
+
"alert",
|
|
5
|
+
"amber",
|
|
6
|
+
"ample",
|
|
7
|
+
"apt",
|
|
8
|
+
"arctic",
|
|
9
|
+
"avid",
|
|
10
|
+
"bold",
|
|
11
|
+
"brave",
|
|
12
|
+
"bright",
|
|
13
|
+
"brisk",
|
|
14
|
+
"calm",
|
|
15
|
+
"clever",
|
|
16
|
+
"cosmic",
|
|
17
|
+
"crisp",
|
|
18
|
+
"daring",
|
|
19
|
+
"dawn",
|
|
20
|
+
"eager",
|
|
21
|
+
"early",
|
|
22
|
+
"fair",
|
|
23
|
+
"fast",
|
|
24
|
+
"fierce",
|
|
25
|
+
"fine",
|
|
26
|
+
"fresh",
|
|
27
|
+
"gentle",
|
|
28
|
+
"golden",
|
|
29
|
+
"grand",
|
|
30
|
+
"happy",
|
|
31
|
+
"honest",
|
|
32
|
+
"jolly",
|
|
33
|
+
"keen",
|
|
34
|
+
"kind",
|
|
35
|
+
"lively",
|
|
36
|
+
"lucky",
|
|
37
|
+
"merry",
|
|
38
|
+
"mighty",
|
|
39
|
+
"nimble",
|
|
40
|
+
"noble",
|
|
41
|
+
"novel",
|
|
42
|
+
"patient",
|
|
43
|
+
"proud",
|
|
44
|
+
"quick",
|
|
45
|
+
"quiet",
|
|
46
|
+
"rapid",
|
|
47
|
+
"ready",
|
|
48
|
+
"sharp",
|
|
49
|
+
"smart",
|
|
50
|
+
"solid",
|
|
51
|
+
"steady",
|
|
52
|
+
"swift",
|
|
53
|
+
"tidy",
|
|
54
|
+
"vivid",
|
|
55
|
+
"warm",
|
|
56
|
+
"wise",
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
59
|
+
const DEFAULT_NOUNS = [
|
|
60
|
+
"badger",
|
|
61
|
+
"beacon",
|
|
62
|
+
"bison",
|
|
63
|
+
"brook",
|
|
64
|
+
"cedar",
|
|
65
|
+
"comet",
|
|
66
|
+
"coral",
|
|
67
|
+
"coyote",
|
|
68
|
+
"crane",
|
|
69
|
+
"dolphin",
|
|
70
|
+
"eagle",
|
|
71
|
+
"ember",
|
|
72
|
+
"falcon",
|
|
73
|
+
"finch",
|
|
74
|
+
"forest",
|
|
75
|
+
"fox",
|
|
76
|
+
"gecko",
|
|
77
|
+
"glade",
|
|
78
|
+
"harbor",
|
|
79
|
+
"hawk",
|
|
80
|
+
"heron",
|
|
81
|
+
"island",
|
|
82
|
+
"jaguar",
|
|
83
|
+
"koala",
|
|
84
|
+
"lagoon",
|
|
85
|
+
"lemur",
|
|
86
|
+
"lynx",
|
|
87
|
+
"maple",
|
|
88
|
+
"meadow",
|
|
89
|
+
"otter",
|
|
90
|
+
"panda",
|
|
91
|
+
"panther",
|
|
92
|
+
"pelican",
|
|
93
|
+
"phoenix",
|
|
94
|
+
"puma",
|
|
95
|
+
"raven",
|
|
96
|
+
"reef",
|
|
97
|
+
"river",
|
|
98
|
+
"salmon",
|
|
99
|
+
"sparrow",
|
|
100
|
+
"summit",
|
|
101
|
+
"tiger",
|
|
102
|
+
"valley",
|
|
103
|
+
"violet",
|
|
104
|
+
"walrus",
|
|
105
|
+
"willow",
|
|
106
|
+
"wolf",
|
|
107
|
+
"wren",
|
|
108
|
+
"yak",
|
|
109
|
+
"zephyr",
|
|
110
|
+
] as const;
|
|
111
|
+
|
|
112
|
+
export function generateSubagentInstanceName(): string {
|
|
113
|
+
const adj =
|
|
114
|
+
DEFAULT_ADJECTIVES[Math.floor(Math.random() * DEFAULT_ADJECTIVES.length)];
|
|
115
|
+
const noun = DEFAULT_NOUNS[Math.floor(Math.random() * DEFAULT_NOUNS.length)];
|
|
116
|
+
return `${adj}-${noun}`;
|
|
117
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Message } from "@earendil-works/pi-ai";
|
|
2
|
-
import type { AgentScope } from "
|
|
3
|
-
import type { TerminationMetadata } from "
|
|
2
|
+
import type { AgentScope } from "../agent/agents.js";
|
|
3
|
+
import type { TerminationMetadata } from "../child/termination.js";
|
|
4
4
|
|
|
5
5
|
export interface UsageStats {
|
|
6
6
|
input: number;
|
|
@@ -40,6 +40,7 @@ export interface SingleResult {
|
|
|
40
40
|
progress?: StreamingProgress;
|
|
41
41
|
messages?: Message[];
|
|
42
42
|
termination?: TerminationMetadata;
|
|
43
|
+
thinkingWarning?: string;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface SubagentDetails {
|
|
@@ -5,7 +5,6 @@ import type { Message } from "@earendil-works/pi-ai";
|
|
|
5
5
|
import {
|
|
6
6
|
DefaultResourceLoader,
|
|
7
7
|
getAgentDir,
|
|
8
|
-
withFileMutationQueue,
|
|
9
8
|
} from "@earendil-works/pi-coding-agent";
|
|
10
9
|
|
|
11
10
|
export const DEFAULT_MAX_OUTPUT_BYTES = 50_000;
|
|
@@ -66,11 +65,10 @@ export async function writePromptToTempFile(
|
|
|
66
65
|
);
|
|
67
66
|
const safeName = agentName.replace(/[^\w.-]+/g, "_");
|
|
68
67
|
const filePath = path.join(tmpDir, `prompt-${safeName}.md`);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
68
|
+
// mkdtemp guarantees a unique directory per call; no concurrent writer can hold this path.
|
|
69
|
+
await fs.promises.writeFile(filePath, prompt, {
|
|
70
|
+
encoding: "utf-8",
|
|
71
|
+
mode: 0o600,
|
|
74
72
|
});
|
|
75
73
|
return { dir: tmpDir, filePath };
|
|
76
74
|
}
|
package/src/instance-name.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
const DEFAULT_ADJECTIVES = [
|
|
2
|
-
"able",
|
|
3
|
-
"agile",
|
|
4
|
-
"alert",
|
|
5
|
-
"amber",
|
|
6
|
-
"ample",
|
|
7
|
-
"apt",
|
|
8
|
-
"arctic",
|
|
9
|
-
"avid",
|
|
10
|
-
"bold",
|
|
11
|
-
"brave",
|
|
12
|
-
"bright",
|
|
13
|
-
"brisk",
|
|
14
|
-
"calm",
|
|
15
|
-
"clever",
|
|
16
|
-
"cosmic",
|
|
17
|
-
"crisp",
|
|
18
|
-
"daring",
|
|
19
|
-
"dawn",
|
|
20
|
-
"eager",
|
|
21
|
-
"early",
|
|
22
|
-
"fair",
|
|
23
|
-
"fast",
|
|
24
|
-
"fierce",
|
|
25
|
-
"fine",
|
|
26
|
-
"fresh",
|
|
27
|
-
"gentle",
|
|
28
|
-
"golden",
|
|
29
|
-
"grand",
|
|
30
|
-
"happy",
|
|
31
|
-
"honest",
|
|
32
|
-
"jolly",
|
|
33
|
-
"keen",
|
|
34
|
-
"kind",
|
|
35
|
-
"lively",
|
|
36
|
-
"lucky",
|
|
37
|
-
"merry",
|
|
38
|
-
"mighty",
|
|
39
|
-
"nimble",
|
|
40
|
-
"noble",
|
|
41
|
-
"novel",
|
|
42
|
-
"patient",
|
|
43
|
-
"proud",
|
|
44
|
-
"quick",
|
|
45
|
-
"quiet",
|
|
46
|
-
"rapid",
|
|
47
|
-
"ready",
|
|
48
|
-
"sharp",
|
|
49
|
-
"smart",
|
|
50
|
-
"solid",
|
|
51
|
-
"steady",
|
|
52
|
-
"swift",
|
|
53
|
-
"tidy",
|
|
54
|
-
"vivid",
|
|
55
|
-
"warm",
|
|
56
|
-
"wise",
|
|
57
|
-
] as const;
|
|
58
|
-
|
|
59
|
-
const DEFAULT_NOUNS = [
|
|
60
|
-
"badger",
|
|
61
|
-
"beacon",
|
|
62
|
-
"bison",
|
|
63
|
-
"brook",
|
|
64
|
-
"cedar",
|
|
65
|
-
"comet",
|
|
66
|
-
"coral",
|
|
67
|
-
"coyote",
|
|
68
|
-
"crane",
|
|
69
|
-
"dolphin",
|
|
70
|
-
"eagle",
|
|
71
|
-
"ember",
|
|
72
|
-
"falcon",
|
|
73
|
-
"finch",
|
|
74
|
-
"forest",
|
|
75
|
-
"fox",
|
|
76
|
-
"gecko",
|
|
77
|
-
"glade",
|
|
78
|
-
"harbor",
|
|
79
|
-
"hawk",
|
|
80
|
-
"heron",
|
|
81
|
-
"island",
|
|
82
|
-
"jaguar",
|
|
83
|
-
"koala",
|
|
84
|
-
"lagoon",
|
|
85
|
-
"lemur",
|
|
86
|
-
"lynx",
|
|
87
|
-
"maple",
|
|
88
|
-
"meadow",
|
|
89
|
-
"otter",
|
|
90
|
-
"panda",
|
|
91
|
-
"panther",
|
|
92
|
-
"pelican",
|
|
93
|
-
"phoenix",
|
|
94
|
-
"puma",
|
|
95
|
-
"raven",
|
|
96
|
-
"reef",
|
|
97
|
-
"river",
|
|
98
|
-
"salmon",
|
|
99
|
-
"sparrow",
|
|
100
|
-
"summit",
|
|
101
|
-
"tiger",
|
|
102
|
-
"valley",
|
|
103
|
-
"violet",
|
|
104
|
-
"walrus",
|
|
105
|
-
"willow",
|
|
106
|
-
"wolf",
|
|
107
|
-
"wren",
|
|
108
|
-
"yak",
|
|
109
|
-
"zephyr",
|
|
110
|
-
] as const;
|
|
111
|
-
|
|
112
|
-
const usedInstanceNames = new Set<string>();
|
|
113
|
-
|
|
114
|
-
let adjectives: readonly string[] = DEFAULT_ADJECTIVES;
|
|
115
|
-
let nouns: readonly string[] = DEFAULT_NOUNS;
|
|
116
|
-
let randomSource: () => number = Math.random;
|
|
117
|
-
|
|
118
|
-
function normalizeRandomIndex(limit: number): number {
|
|
119
|
-
const value = randomSource();
|
|
120
|
-
if (!Number.isFinite(value)) return 0;
|
|
121
|
-
return Math.min(limit - 1, Math.max(0, Math.floor(value * limit)));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function nameAt(index: number): string {
|
|
125
|
-
const adjective = adjectives[Math.floor(index / nouns.length)];
|
|
126
|
-
const noun = nouns[index % nouns.length];
|
|
127
|
-
return `${adjective}-${noun}`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function generateSubagentInstanceName(): string {
|
|
131
|
-
const capacity = adjectives.length * nouns.length;
|
|
132
|
-
if (usedInstanceNames.size >= capacity) {
|
|
133
|
-
throw new Error(
|
|
134
|
-
"No unused subagent instance names remain for this session.",
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
const start = normalizeRandomIndex(capacity);
|
|
138
|
-
for (let offset = 0; offset < capacity; offset += 1) {
|
|
139
|
-
const candidate = nameAt((start + offset) % capacity);
|
|
140
|
-
if (!usedInstanceNames.has(candidate)) {
|
|
141
|
-
usedInstanceNames.add(candidate);
|
|
142
|
-
return candidate;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
throw new Error("No unused subagent instance names remain for this session.");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function resetSubagentInstanceNamesForTest() {
|
|
149
|
-
usedInstanceNames.clear();
|
|
150
|
-
adjectives = DEFAULT_ADJECTIVES;
|
|
151
|
-
nouns = DEFAULT_NOUNS;
|
|
152
|
-
randomSource = Math.random;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function configureSubagentInstanceNamesForTest(options: {
|
|
156
|
-
adjectives?: readonly string[];
|
|
157
|
-
nouns?: readonly string[];
|
|
158
|
-
randomSource?: () => number;
|
|
159
|
-
}) {
|
|
160
|
-
usedInstanceNames.clear();
|
|
161
|
-
adjectives = options.adjectives ?? DEFAULT_ADJECTIVES;
|
|
162
|
-
nouns = options.nouns ?? DEFAULT_NOUNS;
|
|
163
|
-
randomSource = options.randomSource ?? Math.random;
|
|
164
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|