@leing2021/super-pi 0.22.1 → 0.23.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.
Files changed (117) hide show
  1. package/README.md +66 -293
  2. package/extensions/ce-core/index.ts +276 -48
  3. package/extensions/ce-core/tools/parallel-subagent.ts +3 -3
  4. package/extensions/ce-core/tools/subagent.ts +2 -2
  5. package/package.json +4 -20
  6. package/rules/common/naming.md +154 -0
  7. package/skills/01-brainstorm/SKILL.md +42 -79
  8. package/skills/01-brainstorm/references/ce-brainstorm-mode.md +47 -0
  9. package/skills/02-plan/SKILL.md +43 -61
  10. package/skills/02-plan/references/solution-search.md +46 -0
  11. package/skills/03-work/SKILL.md +34 -52
  12. package/skills/03-work/references/completion-report.md +51 -0
  13. package/skills/04-review/SKILL.md +44 -51
  14. package/skills/04-review/references/solution-search.md +46 -0
  15. package/skills/06-next/SKILL.md +35 -20
  16. package/skills/06-next/references/recommendation-logic.md +47 -2
  17. package/skills/07-worktree/SKILL.md +21 -20
  18. package/skills/08-help/SKILL.md +46 -0
  19. package/skills/08-help/references/workflow-sequence.md +135 -0
  20. package/skills/references/language-detection.md +44 -0
  21. package/LICENSE +0 -21
  22. package/THIRD-PARTY-NOTICES.md +0 -35
  23. package/extensions/subagent/__tests__/async-job-tracker.test.ts +0 -21
  24. package/extensions/subagent/__tests__/execution-activity.test.ts +0 -15
  25. package/extensions/subagent/__tests__/parallel-render-stress.test.ts +0 -82
  26. package/extensions/subagent/__tests__/render-dedup.test.ts +0 -98
  27. package/extensions/subagent/__tests__/render-widget.test.ts +0 -28
  28. package/extensions/subagent/__tests__/throttle.test.ts +0 -90
  29. package/extensions/subagent/agent-management.ts +0 -596
  30. package/extensions/subagent/agent-manager-chain-detail.ts +0 -163
  31. package/extensions/subagent/agent-manager-detail.ts +0 -232
  32. package/extensions/subagent/agent-manager-edit.ts +0 -391
  33. package/extensions/subagent/agent-manager-list.ts +0 -279
  34. package/extensions/subagent/agent-manager-parallel.ts +0 -305
  35. package/extensions/subagent/agent-manager.ts +0 -706
  36. package/extensions/subagent/agent-scope.ts +0 -9
  37. package/extensions/subagent/agent-selection.ts +0 -26
  38. package/extensions/subagent/agent-serializer.ts +0 -124
  39. package/extensions/subagent/agent-templates.ts +0 -63
  40. package/extensions/subagent/agents/context-builder.md +0 -37
  41. package/extensions/subagent/agents/delegate.md +0 -9
  42. package/extensions/subagent/agents/oracle.md +0 -73
  43. package/extensions/subagent/agents/planner.md +0 -52
  44. package/extensions/subagent/agents/researcher.md +0 -50
  45. package/extensions/subagent/agents/reviewer.md +0 -38
  46. package/extensions/subagent/agents/scout.md +0 -48
  47. package/extensions/subagent/agents/worker.md +0 -52
  48. package/extensions/subagent/agents.ts +0 -762
  49. package/extensions/subagent/artifacts.ts +0 -101
  50. package/extensions/subagent/async-execution.ts +0 -521
  51. package/extensions/subagent/async-job-tracker.ts +0 -240
  52. package/extensions/subagent/async-status.ts +0 -242
  53. package/extensions/subagent/chain-clarify.ts +0 -1365
  54. package/extensions/subagent/chain-execution.ts +0 -854
  55. package/extensions/subagent/chain-serializer.ts +0 -127
  56. package/extensions/subagent/completion-dedupe.ts +0 -66
  57. package/extensions/subagent/doctor.ts +0 -201
  58. package/extensions/subagent/execution.ts +0 -748
  59. package/extensions/subagent/file-coalescer.ts +0 -43
  60. package/extensions/subagent/fork-context.ts +0 -64
  61. package/extensions/subagent/formatters.ts +0 -123
  62. package/extensions/subagent/frontmatter.ts +0 -32
  63. package/extensions/subagent/index.ts +0 -586
  64. package/extensions/subagent/intercom-bridge.ts +0 -241
  65. package/extensions/subagent/jsonl-writer.ts +0 -84
  66. package/extensions/subagent/model-fallback.ts +0 -109
  67. package/extensions/subagent/notify.ts +0 -111
  68. package/extensions/subagent/parallel-utils.ts +0 -109
  69. package/extensions/subagent/pi-args.ts +0 -139
  70. package/extensions/subagent/pi-spawn.ts +0 -101
  71. package/extensions/subagent/post-exit-stdio-guard.ts +0 -88
  72. package/extensions/subagent/prompt-template-bridge.ts +0 -400
  73. package/extensions/subagent/prompts/gather-context-and-clarify.md +0 -13
  74. package/extensions/subagent/prompts/parallel-cleanup.md +0 -42
  75. package/extensions/subagent/prompts/parallel-research.md +0 -50
  76. package/extensions/subagent/prompts/parallel-review.md +0 -40
  77. package/extensions/subagent/render-helpers.ts +0 -83
  78. package/extensions/subagent/render.ts +0 -908
  79. package/extensions/subagent/result-intercom.ts +0 -238
  80. package/extensions/subagent/result-watcher.ts +0 -172
  81. package/extensions/subagent/run-history.ts +0 -58
  82. package/extensions/subagent/run-status.ts +0 -137
  83. package/extensions/subagent/schemas.ts +0 -165
  84. package/extensions/subagent/session-tokens.ts +0 -51
  85. package/extensions/subagent/settings.ts +0 -368
  86. package/extensions/subagent/single-output.ts +0 -98
  87. package/extensions/subagent/skills.ts +0 -627
  88. package/extensions/subagent/slash-bridge.ts +0 -177
  89. package/extensions/subagent/slash-commands.ts +0 -304
  90. package/extensions/subagent/slash-live-state.ts +0 -295
  91. package/extensions/subagent/subagent-control.ts +0 -151
  92. package/extensions/subagent/subagent-executor.ts +0 -1915
  93. package/extensions/subagent/subagent-prompt-runtime.ts +0 -76
  94. package/extensions/subagent/subagent-runner.ts +0 -1471
  95. package/extensions/subagent/subagents-status.ts +0 -473
  96. package/extensions/subagent/text-editor.ts +0 -273
  97. package/extensions/subagent/throttle.ts +0 -77
  98. package/extensions/subagent/top-level-async.ts +0 -16
  99. package/extensions/subagent/types.ts +0 -624
  100. package/extensions/subagent/utils.ts +0 -457
  101. package/extensions/subagent/worktree.ts +0 -580
  102. package/extensions/super-pi-extension/agents/ce-oracle.md +0 -109
  103. package/extensions/super-pi-extension/agents/ce-planner.md +0 -116
  104. package/extensions/super-pi-extension/agents/ce-reviewer.md +0 -99
  105. package/extensions/super-pi-extension/agents/ce-scout.md +0 -80
  106. package/extensions/super-pi-extension/agents/ce-worker.md +0 -78
  107. package/extensions/super-pi-extension/chains/ce-parallel-review.chain.md +0 -34
  108. package/extensions/super-pi-extension/chains/ce-review-only.chain.md +0 -12
  109. package/extensions/super-pi-extension/chains/ce-standard.chain.md +0 -28
  110. package/extensions/super-pi-extension/index.ts +0 -129
  111. package/extensions/super-pi-extension/model-sync.ts +0 -204
  112. package/skills/08-status/SKILL.md +0 -41
  113. package/skills/08-status/references/artifact-locations.md +0 -10
  114. package/skills/09-help/SKILL.md +0 -37
  115. package/skills/09-help/references/workflow-sequence.md +0 -9
  116. package/skills/10-rules/SKILL.md +0 -76
  117. package/skills/pi-subagents/SKILL.md +0 -566
@@ -1,295 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Nico Bailon
2
- // SPDX-License-Identifier: MIT
3
- // Source: https://github.com/nicobailon/pi-subagents
4
- import type { AgentToolResult } from "@mariozechner/pi-agent-core";
5
- import type { Message } from "@mariozechner/pi-ai";
6
- import type { SubagentParamsLike } from "./subagent-executor.ts";
7
- import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
8
- import { type Details, type SingleResult, type Usage, SLASH_RESULT_TYPE } from "./types.ts";
9
-
10
- export interface SlashMessageDetails {
11
- requestId: string;
12
- result: AgentToolResult<Details>;
13
- }
14
-
15
- interface SlashSnapshot {
16
- result: AgentToolResult<Details>;
17
- version: number;
18
- }
19
-
20
- interface SequentialChainStepLike {
21
- agent: string;
22
- task?: string;
23
- }
24
-
25
- interface ParallelChainStepLike {
26
- parallel: Array<{ agent: string; task?: string }>;
27
- }
28
-
29
- type ChainStepLike = SequentialChainStepLike | ParallelChainStepLike;
30
-
31
- const liveSnapshots = new Map<string, SlashSnapshot>();
32
- const finalSnapshots = new Map<string, SlashSnapshot>();
33
- let versionCounter = 1;
34
-
35
- const EMPTY_MESSAGES: Message[] = [];
36
- const EMPTY_USAGE: Usage = {
37
- input: 0,
38
- output: 0,
39
- cacheRead: 0,
40
- cacheWrite: 0,
41
- cost: 0,
42
- turns: 0,
43
- };
44
-
45
- function nextVersion(): number {
46
- return versionCounter++;
47
- }
48
-
49
- function cloneUsage(): Usage {
50
- return { ...EMPTY_USAGE };
51
- }
52
-
53
- function createPlaceholderResult(
54
- agent: string,
55
- task: string,
56
- status: "pending" | "running",
57
- index?: number,
58
- ): SingleResult {
59
- return {
60
- agent,
61
- task,
62
- exitCode: 0,
63
- messages: EMPTY_MESSAGES,
64
- usage: cloneUsage(),
65
- progress: {
66
- ...(index !== undefined ? { index } : {}),
67
- agent,
68
- status,
69
- task,
70
- recentTools: [],
71
- recentOutput: [],
72
- toolCount: 0,
73
- tokens: 0,
74
- durationMs: 0,
75
- },
76
- };
77
- }
78
-
79
- function buildParallelInitialResult(params: SubagentParamsLike): AgentToolResult<Details> {
80
- const tasks = params.tasks ?? [];
81
- return {
82
- content: [{ type: "text", text: tasks.map((task) => `${task.agent}: ${task.task}`).join("\n\n") }],
83
- details: {
84
- mode: "parallel",
85
- ...(params.context ? { context: params.context } : {}),
86
- results: tasks.map((task, index) => createPlaceholderResult(task.agent, task.task, "running", index)),
87
- progress: tasks.map((task, index) => ({
88
- index,
89
- agent: task.agent,
90
- status: "running" as const,
91
- task: task.task,
92
- recentTools: [],
93
- recentOutput: [],
94
- toolCount: 0,
95
- tokens: 0,
96
- durationMs: 0,
97
- })),
98
- },
99
- };
100
- }
101
-
102
- function isParallelChainStep(step: ChainStepLike): step is ParallelChainStepLike {
103
- return "parallel" in step && Array.isArray(step.parallel);
104
- }
105
-
106
- function chainStepLabel(step: ChainStepLike): string {
107
- if (isParallelChainStep(step)) {
108
- return `[${step.parallel.map((entry) => entry.agent).join("+")}]`;
109
- }
110
- return step.agent;
111
- }
112
-
113
- function flattenChainResults(chain: ChainStepLike[], fallbackTask: string | undefined): SingleResult[] {
114
- const results: SingleResult[] = [];
115
- let flatIndex = 0;
116
- for (const step of chain) {
117
- if (isParallelChainStep(step)) {
118
- for (const task of step.parallel) {
119
- results.push(createPlaceholderResult(task.agent, task.task ?? fallbackTask ?? "", results.length === 0 ? "running" : "pending", flatIndex));
120
- flatIndex++;
121
- }
122
- continue;
123
- }
124
- results.push(createPlaceholderResult(step.agent, step.task ?? fallbackTask ?? "", results.length === 0 ? "running" : "pending", flatIndex));
125
- flatIndex++;
126
- }
127
- return results;
128
- }
129
-
130
- function buildChainInitialResult(params: SubagentParamsLike): AgentToolResult<Details> {
131
- const chain = (params.chain ?? []) as ChainStepLike[];
132
- const results = flattenChainResults(chain, params.task);
133
- return {
134
- content: [{
135
- type: "text",
136
- text: results.map((result, index) => `Step ${index + 1}: ${result.agent}\n${result.task}`).join("\n\n"),
137
- }],
138
- details: {
139
- mode: "chain",
140
- ...(params.context ? { context: params.context } : {}),
141
- results,
142
- progress: results.map((result, index) => ({
143
- index,
144
- agent: result.agent,
145
- status: index === 0 ? "running" as const : "pending" as const,
146
- task: result.task,
147
- recentTools: [],
148
- recentOutput: [],
149
- toolCount: 0,
150
- tokens: 0,
151
- durationMs: 0,
152
- })),
153
- chainAgents: chain.map((step) => chainStepLabel(step)),
154
- totalSteps: chain.length,
155
- currentStepIndex: 0,
156
- },
157
- };
158
- }
159
-
160
- function buildSingleInitialResult(params: SubagentParamsLike): AgentToolResult<Details> {
161
- const agent = params.agent ?? "subagent";
162
- const task = params.task ?? "";
163
- return {
164
- content: [{ type: "text", text: task }],
165
- details: {
166
- mode: "single",
167
- ...(params.context ? { context: params.context } : {}),
168
- results: [createPlaceholderResult(agent, task, "running")],
169
- progress: [{
170
- agent,
171
- status: "running",
172
- task,
173
- recentTools: [],
174
- recentOutput: [],
175
- toolCount: 0,
176
- tokens: 0,
177
- durationMs: 0,
178
- }],
179
- },
180
- };
181
- }
182
-
183
- export function buildSlashInitialResult(requestId: string, params: SubagentParamsLike): SlashMessageDetails {
184
- const result = (params.tasks?.length ?? 0) > 0
185
- ? buildParallelInitialResult(params)
186
- : (params.chain?.length ?? 0) > 0
187
- ? buildChainInitialResult(params)
188
- : buildSingleInitialResult(params);
189
- liveSnapshots.set(requestId, { result, version: nextVersion() });
190
- finalSnapshots.delete(requestId);
191
- return { requestId, result };
192
- }
193
-
194
- function cloneResultsWithProgress(
195
- results: SingleResult[],
196
- progress: NonNullable<Details["progress"]> | undefined,
197
- ): SingleResult[] {
198
- return results.map((result, index) => {
199
- const nextProgress = progress?.find((entry) => entry.index === index)
200
- ?? progress?.[index]
201
- ?? result.progress;
202
- return nextProgress ? { ...result, progress: nextProgress } : result;
203
- });
204
- }
205
-
206
- export function applySlashUpdate(requestId: string, update: SlashSubagentUpdate): void {
207
- const snapshot = liveSnapshots.get(requestId);
208
- if (!snapshot) return;
209
- const progress = update.progress;
210
- if (!progress || !snapshot.result.details) return;
211
- const currentStepIndex = progress.findIndex((entry) => entry.status === "running");
212
- const nextDetails: Details = {
213
- ...snapshot.result.details,
214
- progress,
215
- results: cloneResultsWithProgress(snapshot.result.details.results, progress),
216
- ...(snapshot.result.details.mode === "chain" && currentStepIndex >= 0 ? { currentStepIndex } : {}),
217
- };
218
- liveSnapshots.set(requestId, {
219
- result: {
220
- ...snapshot.result,
221
- details: nextDetails,
222
- },
223
- version: nextVersion(),
224
- });
225
- }
226
-
227
- export function finalizeSlashResult(response: SlashSubagentResponse): SlashMessageDetails {
228
- const snapshot = {
229
- result: response.result,
230
- version: nextVersion(),
231
- };
232
- finalSnapshots.set(response.requestId, snapshot);
233
- liveSnapshots.delete(response.requestId);
234
- return {
235
- requestId: response.requestId,
236
- result: response.result,
237
- };
238
- }
239
-
240
- export function failSlashResult(requestId: string, params: SubagentParamsLike, message: string): SlashMessageDetails {
241
- const initial = buildSlashInitialResult(requestId, params).result;
242
- const failedResults = initial.details.results.map((result) => ({
243
- ...result,
244
- exitCode: 1,
245
- error: message,
246
- progress: result.progress ? { ...result.progress, status: "failed" as const } : result.progress,
247
- }));
248
- const result: AgentToolResult<Details> = {
249
- content: [{ type: "text", text: message }],
250
- details: {
251
- ...initial.details,
252
- results: failedResults,
253
- progress: failedResults.map((entry) => entry.progress!).filter(Boolean),
254
- },
255
- };
256
- const snapshot = { result, version: nextVersion() };
257
- finalSnapshots.set(requestId, snapshot);
258
- liveSnapshots.delete(requestId);
259
- return { requestId, result };
260
- }
261
-
262
- function isSlashMessageDetails(value: unknown): value is SlashMessageDetails {
263
- if (!value || typeof value !== "object") return false;
264
- const v = value as { requestId?: string; result?: { content?: unknown; details?: { results?: unknown } } };
265
- if (typeof v.requestId !== "string" || !v.requestId) return false;
266
- if (!v.result || !Array.isArray(v.result.content)) return false;
267
- return !!v.result.details && Array.isArray(v.result.details.results);
268
- }
269
-
270
- export function resolveSlashMessageDetails(value: unknown): SlashMessageDetails | undefined {
271
- return isSlashMessageDetails(value) ? value : undefined;
272
- }
273
-
274
- export function getSlashRenderableSnapshot(details: SlashMessageDetails): SlashSnapshot {
275
- return finalSnapshots.get(details.requestId)
276
- ?? liveSnapshots.get(details.requestId)
277
- ?? { result: details.result, version: 0 };
278
- }
279
-
280
- export function restoreSlashFinalSnapshots(entries: unknown[]): void {
281
- liveSnapshots.clear();
282
- finalSnapshots.clear();
283
- for (const entry of entries) {
284
- const e = entry as { type?: string; customType?: string; details?: unknown };
285
- if (e?.type !== "custom_message" || e.customType !== SLASH_RESULT_TYPE) continue;
286
- const details = resolveSlashMessageDetails(e.details);
287
- if (!details) continue;
288
- finalSnapshots.set(details.requestId, { result: details.result, version: nextVersion() });
289
- }
290
- }
291
-
292
- export function clearSlashSnapshots(): void {
293
- liveSnapshots.clear();
294
- finalSnapshots.clear();
295
- }
@@ -1,151 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Nico Bailon
2
- // SPDX-License-Identifier: MIT
3
- // Source: https://github.com/nicobailon/pi-subagents
4
- import {
5
- type ActivityState,
6
- type ControlConfig,
7
- type ControlEvent,
8
- type ControlEventType,
9
- type ControlNotificationChannel,
10
- type ResolvedControlConfig,
11
- } from "./types.ts";
12
-
13
- const CONTROL_EVENT_TYPES: ControlEventType[] = ["needs_attention"];
14
- const CONTROL_NOTIFICATION_CHANNELS: ControlNotificationChannel[] = ["event", "async", "intercom"];
15
- const DEFAULT_NOTIFY_ON: ControlEventType[] = ["needs_attention"];
16
-
17
- export const DEFAULT_CONTROL_CONFIG: ResolvedControlConfig = {
18
- enabled: true,
19
- needsAttentionAfterMs: 60_000,
20
- notifyOn: DEFAULT_NOTIFY_ON,
21
- notifyChannels: CONTROL_NOTIFICATION_CHANNELS,
22
- };
23
-
24
- function parsePositiveInt(value: unknown): number | undefined {
25
- if (typeof value !== "number") return undefined;
26
- if (!Number.isFinite(value) || !Number.isInteger(value) || value < 1) return undefined;
27
- return value;
28
- }
29
-
30
- function parseControlList<T extends string>(value: unknown, allowed: readonly T[]): T[] | undefined {
31
- if (!Array.isArray(value)) return undefined;
32
- if (value.length === 0) return [];
33
- const allowedSet = new Set(allowed);
34
- const parsed = value.filter((entry): entry is T => typeof entry === "string" && allowedSet.has(entry as T));
35
- return parsed.length > 0 ? Array.from(new Set(parsed)) : undefined;
36
- }
37
-
38
- export function resolveControlConfig(
39
- globalConfig?: ControlConfig,
40
- override?: ControlConfig,
41
- ): ResolvedControlConfig {
42
- const enabled = override?.enabled ?? globalConfig?.enabled ?? DEFAULT_CONTROL_CONFIG.enabled;
43
- const needsAttentionAfterMs = parsePositiveInt(override?.needsAttentionAfterMs)
44
- ?? parsePositiveInt(globalConfig?.needsAttentionAfterMs)
45
- ?? DEFAULT_CONTROL_CONFIG.needsAttentionAfterMs;
46
- const notifyOn = parseControlList(override?.notifyOn, CONTROL_EVENT_TYPES)
47
- ?? parseControlList(globalConfig?.notifyOn, CONTROL_EVENT_TYPES)
48
- ?? DEFAULT_CONTROL_CONFIG.notifyOn;
49
- const notifyChannels = parseControlList(override?.notifyChannels, CONTROL_NOTIFICATION_CHANNELS)
50
- ?? parseControlList(globalConfig?.notifyChannels, CONTROL_NOTIFICATION_CHANNELS)
51
- ?? DEFAULT_CONTROL_CONFIG.notifyChannels;
52
- return {
53
- enabled,
54
- needsAttentionAfterMs,
55
- notifyOn: [...notifyOn],
56
- notifyChannels: [...notifyChannels],
57
- };
58
- }
59
-
60
- export function deriveActivityState(input: {
61
- config: ResolvedControlConfig;
62
- startedAt: number;
63
- lastActivityAt?: number;
64
- now?: number;
65
- }): ActivityState | undefined {
66
- if (!input.config.enabled) return undefined;
67
- const now = input.now ?? Date.now();
68
- const lastActivity = input.lastActivityAt ?? input.startedAt;
69
- const ageMs = Math.max(0, now - lastActivity);
70
- return ageMs > input.config.needsAttentionAfterMs ? "needs_attention" : undefined;
71
- }
72
-
73
- export function shouldEmitControlEvent(
74
- config: ResolvedControlConfig,
75
- from: ActivityState | undefined,
76
- to: ActivityState | undefined,
77
- ): boolean {
78
- return config.enabled && from !== to && to === "needs_attention";
79
- }
80
-
81
- export function buildControlEvent(input: {
82
- from?: ActivityState;
83
- to: ActivityState;
84
- runId: string;
85
- agent: string;
86
- index?: number;
87
- ts?: number;
88
- lastActivityAt?: number;
89
- }): ControlEvent {
90
- const ts = input.ts ?? Date.now();
91
- const elapsedMs = input.lastActivityAt ? Math.max(0, ts - input.lastActivityAt) : undefined;
92
- const elapsedSeconds = elapsedMs !== undefined ? Math.floor(elapsedMs / 1000) : undefined;
93
- const message = elapsedSeconds !== undefined
94
- ? `${input.agent} needs attention (no observed activity for ${elapsedSeconds}s)`
95
- : `${input.agent} needs attention`;
96
- return {
97
- type: "needs_attention",
98
- from: input.from,
99
- to: input.to,
100
- ts,
101
- runId: input.runId,
102
- agent: input.agent,
103
- index: input.index,
104
- message,
105
- };
106
- }
107
-
108
- export function shouldNotifyControlEvent(config: ResolvedControlConfig, event: ControlEvent): boolean {
109
- return config.enabled && config.notifyOn.includes(event.type);
110
- }
111
-
112
- export function controlNotificationKey(event: ControlEvent, childIntercomTarget?: string): string {
113
- const childKey = childIntercomTarget ?? (event.index !== undefined ? `${event.runId}:${event.index}` : event.runId);
114
- return `${childKey}:${event.type}`;
115
- }
116
-
117
- export function claimControlNotification(config: ResolvedControlConfig, event: ControlEvent, seenKeys: Set<string>, childIntercomTarget?: string): boolean {
118
- if (!shouldNotifyControlEvent(config, event)) return false;
119
- const key = controlNotificationKey(event, childIntercomTarget);
120
- if (seenKeys.has(key)) return false;
121
- seenKeys.add(key);
122
- return true;
123
- }
124
-
125
- export function formatControlNoticeMessage(event: ControlEvent, childIntercomTarget?: string): string {
126
- const runTarget = event.runId;
127
- const nudgeCommand = childIntercomTarget
128
- ? `intercom({ action: "send", to: "${childIntercomTarget}", message: "What are you blocked on? Reply with the smallest next step or ask for a decision." })`
129
- : undefined;
130
- return [
131
- `Subagent needs attention: ${event.agent}`,
132
- `Run: ${runTarget}${event.index !== undefined ? ` step ${event.index + 1}` : ""}`,
133
- `Signal: ${event.message}`,
134
- "Hint: Inspect status first unless the run is clearly blocked.",
135
- childIntercomTarget
136
- ? `Nudge: ${nudgeCommand}`
137
- : "Nudge: no child message route registered",
138
- `Status: subagent({ action: "status", id: "${runTarget}" })`,
139
- `Interrupt: subagent({ action: "interrupt", id: "${runTarget}" })`,
140
- ].join("\n");
141
- }
142
-
143
- export function formatControlIntercomMessage(event: ControlEvent, childIntercomTarget?: string): string {
144
- return [
145
- "subagent needs attention",
146
- "",
147
- `${event.agent} needs attention in run ${event.runId}.`,
148
- "",
149
- formatControlNoticeMessage(event, childIntercomTarget),
150
- ].join("\n");
151
- }