@g3un/pi-orchestra 0.2.1 → 0.9.2
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 +14 -3
- package/docs/orchestration-model.md +17 -12
- package/package.json +5 -1
- package/skills/pi-orchestra/SKILL.md +92 -0
- package/src/adapters/in-memory-store.ts +45 -20
- package/src/adapters/index.ts +1 -0
- package/src/adapters/pi-runtime.ts +114 -38
- package/src/adapters/sqlite-store.ts +276 -0
- package/src/adapters/store-subscriptions.ts +20 -0
- package/src/core/bus-format.ts +13 -4
- package/src/core/bus.ts +66 -0
- package/src/core/orchestra.ts +21 -26
- package/src/core/store.ts +12 -3
- package/src/core/subagent.ts +5 -3
- package/src/core/workflow.ts +5 -4
- package/src/core/workgroup.ts +3 -3
- package/src/extension/index.ts +13 -5
- package/src/extension/orchestra-events.ts +107 -24
- package/src/extension/workflow-monitor.ts +16 -14
- package/src/profiles/code-reviewer.ts +20 -0
- package/src/profiles/evidence-synthesizer.ts +20 -0
- package/src/profiles/external-researcher.ts +20 -0
- package/src/profiles/index.ts +5 -1
- package/src/profiles/profile.ts +31 -0
- package/src/profiles/source-code-qa.ts +19 -0
- package/src/tools/bus.ts +93 -35
- package/src/tools/subagent.ts +29 -8
- package/src/tools/workflow.ts +47 -50
- package/src/tools/workgroup.ts +22 -14
- package/src/utils.ts +12 -2
- package/src/profiles/stage-leader.ts +0 -20
package/src/tools/workgroup.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineTool, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AgentResultStatus, AgentRun, AgentRunResult } from "../core/subagent.ts";
|
|
4
4
|
import type { Bus } from "../core/bus.ts";
|
|
5
5
|
import type { OrchestraApi } from "../core/orchestra.ts";
|
|
6
6
|
import type { AgentStore } from "../core/store.ts";
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
closeAgentRuns,
|
|
10
10
|
formatError,
|
|
11
11
|
formatNamedEntityLabel,
|
|
12
|
-
|
|
12
|
+
isAgentRunActive,
|
|
13
|
+
isAgentRunFinished,
|
|
13
14
|
normalizeEntityName,
|
|
14
15
|
slugify,
|
|
15
16
|
toAgentRunResult,
|
|
@@ -18,6 +19,8 @@ import {
|
|
|
18
19
|
AgentProfileParams,
|
|
19
20
|
spawnSubagent,
|
|
20
21
|
SubagentRunNameParam,
|
|
22
|
+
toAgentProfile,
|
|
23
|
+
type RawAgentProfileParams,
|
|
21
24
|
type SubagentSpawnInput,
|
|
22
25
|
withDefaultProfileModel,
|
|
23
26
|
} from "./subagent.ts";
|
|
@@ -44,7 +47,7 @@ export interface WorkgroupSettlement {
|
|
|
44
47
|
workerResults: AgentRunResult[];
|
|
45
48
|
/** Every terminal result observed while settling this workgroup. */
|
|
46
49
|
completedResults: AgentRunResult[];
|
|
47
|
-
winner
|
|
50
|
+
winner: AgentRunResult | undefined;
|
|
48
51
|
pendingRunIds: string[];
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -69,9 +72,9 @@ export interface WorkgroupLaunchFailedEvent extends WorkgroupLaunchEvent {
|
|
|
69
72
|
|
|
70
73
|
export interface WorkgroupToolDeps {
|
|
71
74
|
orchestra: OrchestraApi;
|
|
72
|
-
onWorkgroupLaunching
|
|
73
|
-
onWorkgroupLaunched
|
|
74
|
-
onWorkgroupLaunchFailed
|
|
75
|
+
onWorkgroupLaunching: ((event: WorkgroupLaunchEvent) => void) | undefined;
|
|
76
|
+
onWorkgroupLaunched: ((event: WorkgroupLaunchedEvent) => void) | undefined;
|
|
77
|
+
onWorkgroupLaunchFailed: ((event: WorkgroupLaunchFailedEvent) => void) | undefined;
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
export const WorkgroupMemberParams = Type.Object(
|
|
@@ -144,7 +147,7 @@ export function createWorkgroupTool({
|
|
|
144
147
|
try {
|
|
145
148
|
const preparedInput: PreparedWorkgroupInput = {
|
|
146
149
|
...input,
|
|
147
|
-
members: prepareMembers(input.members, orchestra.listRuns()),
|
|
150
|
+
members: prepareMembers(input.members, orchestra.listRuns({ busId: undefined })),
|
|
148
151
|
};
|
|
149
152
|
const spawnResults = await Promise.allSettled(
|
|
150
153
|
preparedInput.members.map(async (member): Promise<SpawnSuccess> => {
|
|
@@ -157,7 +160,7 @@ export function createWorkgroupTool({
|
|
|
157
160
|
const failures = collectSpawnFailures(preparedInput.members, spawnResults);
|
|
158
161
|
if (failures.length > 0) {
|
|
159
162
|
const cleanupResults = await Promise.allSettled(
|
|
160
|
-
successes.map((success) => orchestra.closeAgent(success.run.id)),
|
|
163
|
+
successes.map((success) => orchestra.closeAgent(success.run.id, { busId: undefined })),
|
|
161
164
|
);
|
|
162
165
|
throw new Error(formatLaunchFailure(failures, successes, cleanupResults));
|
|
163
166
|
}
|
|
@@ -275,12 +278,13 @@ class WorkgroupSettlementCollector {
|
|
|
275
278
|
status: resolveWorkgroupStatus(this.completedResults),
|
|
276
279
|
workerResults: this.completedResults,
|
|
277
280
|
completedResults: this.completedResults,
|
|
281
|
+
winner: undefined,
|
|
278
282
|
pendingRunIds: this.getPendingRunIds(),
|
|
279
283
|
});
|
|
280
284
|
};
|
|
281
285
|
|
|
282
286
|
const observeRun = (run: AgentRun) => {
|
|
283
|
-
if (settled || !this.runIds.has(run.id) || !
|
|
287
|
+
if (settled || !this.runIds.has(run.id) || !isAgentRunFinished(run)) return;
|
|
284
288
|
this.recordTerminalRun(run);
|
|
285
289
|
finishFromCurrentState();
|
|
286
290
|
};
|
|
@@ -294,6 +298,7 @@ class WorkgroupSettlementCollector {
|
|
|
294
298
|
status: "failed",
|
|
295
299
|
workerResults: [],
|
|
296
300
|
completedResults: [],
|
|
301
|
+
winner: undefined,
|
|
297
302
|
pendingRunIds: [],
|
|
298
303
|
});
|
|
299
304
|
}
|
|
@@ -308,7 +313,7 @@ class WorkgroupSettlementCollector {
|
|
|
308
313
|
}
|
|
309
314
|
|
|
310
315
|
private recordTerminalRun(run: AgentRun): void {
|
|
311
|
-
if (!
|
|
316
|
+
if (!isAgentRunFinished(run) || this.completedRunIds.has(run.id)) return;
|
|
312
317
|
|
|
313
318
|
this.completedRunIds.add(run.id);
|
|
314
319
|
this.completedResults.push(toAgentRunResult(run));
|
|
@@ -317,12 +322,15 @@ class WorkgroupSettlementCollector {
|
|
|
317
322
|
private isSettled(): boolean {
|
|
318
323
|
return [...this.runIds].every((runId) => {
|
|
319
324
|
const run = this.store.getRun(runId);
|
|
320
|
-
return run !== undefined &&
|
|
325
|
+
return run !== undefined && isAgentRunFinished(run);
|
|
321
326
|
});
|
|
322
327
|
}
|
|
323
328
|
|
|
324
329
|
private getPendingRunIds(): string[] {
|
|
325
|
-
return [...this.runIds].filter((runId) =>
|
|
330
|
+
return [...this.runIds].filter((runId) => {
|
|
331
|
+
const run = this.store.getRun(runId);
|
|
332
|
+
return run !== undefined && isAgentRunActive(run);
|
|
333
|
+
});
|
|
326
334
|
}
|
|
327
335
|
}
|
|
328
336
|
|
|
@@ -353,7 +361,7 @@ function toWorkgroupInput(params: RawWorkgroupParams): WorkgroupInput {
|
|
|
353
361
|
|
|
354
362
|
export function toWorkgroupMember(member: RawWorkgroupMemberParams, label: string): WorkgroupMember {
|
|
355
363
|
if (!member.profile) throw new Error(`${label} requires profile.`);
|
|
356
|
-
return { profile: member.profile, name: member.name, assignment: member.assignment };
|
|
364
|
+
return { profile: toAgentProfile(member.profile), name: member.name, assignment: member.assignment };
|
|
357
365
|
}
|
|
358
366
|
|
|
359
367
|
function withDefaultModelsForWorkgroup(input: WorkgroupInput, ctx: ExtensionContext): WorkgroupInput {
|
|
@@ -531,7 +539,7 @@ type RawWorkgroupParams = {
|
|
|
531
539
|
};
|
|
532
540
|
|
|
533
541
|
export type RawWorkgroupMemberParams = {
|
|
534
|
-
profile?:
|
|
542
|
+
profile?: RawAgentProfileParams;
|
|
535
543
|
name?: string;
|
|
536
544
|
assignment?: string;
|
|
537
545
|
};
|
package/src/utils.ts
CHANGED
|
@@ -61,7 +61,15 @@ export function requireWorkflow(store: AgentStore, id: string): WorkflowRun {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function isTerminalAgentState(state: AgentState): boolean {
|
|
64
|
-
return state
|
|
64
|
+
return state === "success" || state === "blocked" || state === "failed" || state === "closed";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isAgentRunActive(run: AgentRun): boolean {
|
|
68
|
+
return run.state === "running" && run.result === undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isAgentRunFinished(run: AgentRun): boolean {
|
|
72
|
+
return isTerminalAgentState(run.state) || run.result !== undefined;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
export function indent(text: string, prefix = " "): string {
|
|
@@ -87,5 +95,7 @@ export function toAgentRunResult(run: AgentRun): AgentRunResult {
|
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
export async function closeAgentRuns(orchestra: OrchestraApi, runIds: string[]): Promise<void> {
|
|
90
|
-
await Promise.allSettled(
|
|
98
|
+
await Promise.allSettled(
|
|
99
|
+
[...new Set(runIds)].map(async (runId) => await orchestra.closeAgent(runId, { busId: undefined })),
|
|
100
|
+
);
|
|
91
101
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { AgentProfile } from "../core/subagent.ts";
|
|
2
|
-
|
|
3
|
-
export interface StageLeaderProfileOptions {
|
|
4
|
-
name?: string;
|
|
5
|
-
model?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function createStageLeaderProfile(options: StageLeaderProfileOptions = {}): AgentProfile {
|
|
9
|
-
return {
|
|
10
|
-
name: options.name ?? "stage-leader",
|
|
11
|
-
systemPrompt: [
|
|
12
|
-
"You are a workflow stage leader: produce concise canonical output for the next stage.",
|
|
13
|
-
"Use only supplied context (workflow/stage goals, previous outputs, worker results, bus context); do not research, inspect files, run commands, or request external info.",
|
|
14
|
-
"Deduplicate and reconcile findings; note conflicts/gaps; prefer finish results over bus context.",
|
|
15
|
-
"Prefer status=success if useful output exists; use blocked if context is insufficient, failed if synthesis fails.",
|
|
16
|
-
].join("\n"),
|
|
17
|
-
tools: [],
|
|
18
|
-
model: options.model,
|
|
19
|
-
};
|
|
20
|
-
}
|