pi-maestro-flow 0.2.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 +124 -0
- package/agents/aggregator.md +27 -0
- package/agents/cli-explore-agent.md +188 -0
- package/agents/cross-role-reviewer.md +171 -0
- package/agents/delegate.md +19 -0
- package/agents/explorer.md +23 -0
- package/agents/impeccable-agent.md +99 -0
- package/agents/ralph-executor.md +81 -0
- package/agents/reference.md +24 -0
- package/agents/role-design-author.md +220 -0
- package/agents/team-supervisor.md +143 -0
- package/agents/team-worker.md +237 -0
- package/agents/ui-design-agent.md +270 -0
- package/agents/workflow-analyzer.md +116 -0
- package/agents/workflow-codebase-mapper.md +77 -0
- package/agents/workflow-collab-planner.md +147 -0
- package/agents/workflow-debugger.md +104 -0
- package/agents/workflow-executor.md +133 -0
- package/agents/workflow-external-researcher.md +86 -0
- package/agents/workflow-integration-checker.md +83 -0
- package/agents/workflow-nyquist-auditor.md +85 -0
- package/agents/workflow-phase-researcher.md +85 -0
- package/agents/workflow-plan-checker.md +100 -0
- package/agents/workflow-planner.md +200 -0
- package/agents/workflow-project-researcher.md +74 -0
- package/agents/workflow-research-synthesizer.md +70 -0
- package/agents/workflow-reviewer.md +82 -0
- package/agents/workflow-roadmapper.md +81 -0
- package/agents/workflow-verifier.md +120 -0
- package/package.json +58 -0
- package/skills/codify-to-knowhow/SKILL.md +167 -0
- package/skills/delegation-check/SKILL.md +297 -0
- package/skills/domain-add/SKILL.md +75 -0
- package/skills/insight-challenge/SKILL.md +226 -0
- package/skills/learn-decompose/SKILL.md +124 -0
- package/skills/learn-follow/SKILL.md +163 -0
- package/skills/learn-investigate/SKILL.md +160 -0
- package/skills/learn-second-opinion/SKILL.md +128 -0
- package/skills/maestro/SKILL.md +239 -0
- package/skills/maestro-amend/SKILL.md +169 -0
- package/skills/maestro-analyze/SKILL.md +173 -0
- package/skills/maestro-blueprint/SKILL.md +159 -0
- package/skills/maestro-brainstorm/SKILL.md +193 -0
- package/skills/maestro-collab/SKILL.md +181 -0
- package/skills/maestro-companion/SKILL.md +536 -0
- package/skills/maestro-composer/SKILL.md +192 -0
- package/skills/maestro-execute/SKILL.md +193 -0
- package/skills/maestro-fork/SKILL.md +104 -0
- package/skills/maestro-grill/SKILL.md +151 -0
- package/skills/maestro-guard/SKILL.md +124 -0
- package/skills/maestro-help/SKILL.md +328 -0
- package/skills/maestro-impeccable/SKILL.md +302 -0
- package/skills/maestro-init/SKILL.md +151 -0
- package/skills/maestro-merge/SKILL.md +90 -0
- package/skills/maestro-milestone-audit/SKILL.md +117 -0
- package/skills/maestro-milestone-complete/SKILL.md +133 -0
- package/skills/maestro-milestone-release/SKILL.md +131 -0
- package/skills/maestro-next/SKILL.md +269 -0
- package/skills/maestro-overlay/SKILL.md +203 -0
- package/skills/maestro-plan/SKILL.md +194 -0
- package/skills/maestro-player/SKILL.md +184 -0
- package/skills/maestro-quick/SKILL.md +117 -0
- package/skills/maestro-ralph/SKILL.md +905 -0
- package/skills/maestro-ralph-cli/SKILL.md +976 -0
- package/skills/maestro-ralph-cli-execute/SKILL.md +229 -0
- package/skills/maestro-ralph-execute/SKILL.md +409 -0
- package/skills/maestro-ralph-v2/SKILL.md +1198 -0
- package/skills/maestro-roadmap/SKILL.md +157 -0
- package/skills/maestro-swarm-workflow/SKILL.md +272 -0
- package/skills/maestro-tools-execute/SKILL.md +143 -0
- package/skills/maestro-tools-register/SKILL.md +192 -0
- package/skills/maestro-ui-codify/SKILL.md +127 -0
- package/skills/maestro-universal-workflow/SKILL.md +622 -0
- package/skills/maestro-update/SKILL.md +156 -0
- package/skills/manage-codebase-rebuild/SKILL.md +111 -0
- package/skills/manage-drift-realign/SKILL.md +159 -0
- package/skills/manage-harvest/SKILL.md +121 -0
- package/skills/manage-issue/SKILL.md +88 -0
- package/skills/manage-issue-discover/SKILL.md +104 -0
- package/skills/manage-kg-extractors/SKILL.md +147 -0
- package/skills/manage-knowhow/SKILL.md +102 -0
- package/skills/manage-knowhow-capture/SKILL.md +109 -0
- package/skills/manage-knowledge-audit/SKILL.md +147 -0
- package/skills/manage-status/SKILL.md +80 -0
- package/skills/manage-wiki/SKILL.md +104 -0
- package/skills/odyssey-debug/SKILL.md +344 -0
- package/skills/odyssey-improve/SKILL.md +423 -0
- package/skills/odyssey-planex/SKILL.md +542 -0
- package/skills/odyssey-review-test-fix/SKILL.md +392 -0
- package/skills/odyssey-ui/SKILL.md +388 -0
- package/skills/prompt-generator/SKILL.md +470 -0
- package/skills/quality-auto-test/SKILL.md +168 -0
- package/skills/quality-debug/SKILL.md +176 -0
- package/skills/quality-refactor/SKILL.md +108 -0
- package/skills/quality-retrospective/SKILL.md +134 -0
- package/skills/quality-review/SKILL.md +169 -0
- package/skills/quality-sync/SKILL.md +90 -0
- package/skills/quality-test/SKILL.md +183 -0
- package/skills/scholar-anti-ai-writing/SKILL.md +173 -0
- package/skills/scholar-anti-ai-writing/references/patterns-chinese.md +242 -0
- package/skills/scholar-anti-ai-writing/references/patterns-english.md +242 -0
- package/skills/scholar-citation-verify/SKILL.md +166 -0
- package/skills/scholar-citation-verify/references/api-usage.md +372 -0
- package/skills/scholar-citation-verify/references/common-errors.md +384 -0
- package/skills/scholar-citation-verify/references/verification-rules.md +399 -0
- package/skills/scholar-experiment/SKILL.md +321 -0
- package/skills/scholar-ideation/SKILL.md +288 -0
- package/skills/scholar-latex-organizer/SKILL.md +186 -0
- package/skills/scholar-publish/SKILL.md +220 -0
- package/skills/scholar-rebuttal-pro/README.md +313 -0
- package/skills/scholar-rebuttal-pro/SKILL.md +511 -0
- package/skills/scholar-review/SKILL.md +227 -0
- package/skills/scholar-thesis-docx/README.md +111 -0
- package/skills/scholar-thesis-docx/README_EN.md +108 -0
- package/skills/scholar-thesis-docx/SKILL.md +212 -0
- package/skills/scholar-thesis-docx/references/failure-patterns-and-quality-gates.md +178 -0
- package/skills/scholar-thesis-docx/references/figure-and-code-rules.md +33 -0
- package/skills/scholar-thesis-docx/references/paper-format-workflow.md +68 -0
- package/skills/scholar-thesis-docx/references/script-usage.md +157 -0
- package/skills/scholar-thesis-docx/scripts/audit_docx_ooxml.py +429 -0
- package/skills/scholar-thesis-docx/scripts/check_word_com.ps1 +50 -0
- package/skills/scholar-thesis-docx/scripts/export_word_pdf.ps1 +62 -0
- package/skills/scholar-thesis-docx/scripts/normalize_word_styles.ps1 +498 -0
- package/skills/scholar-thesis-docx/scripts/render_mermaid_figure.ps1 +148 -0
- package/skills/scholar-writing/SKILL.md +296 -0
- package/skills/security-audit/SKILL.md +244 -0
- package/skills/skill-generator/SKILL.md +472 -0
- package/skills/skill-iter-tune/SKILL.md +382 -0
- package/skills/skill-simplify/SKILL.md +63 -0
- package/skills/skill-tuning/SKILL.md +174 -0
- package/skills/spec-add/SKILL.md +105 -0
- package/skills/spec-load/SKILL.md +98 -0
- package/skills/spec-remove/SKILL.md +74 -0
- package/skills/spec-setup/SKILL.md +75 -0
- package/skills/team-adversarial-swarm/SKILL.md +233 -0
- package/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
- package/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
- package/skills/team-adversarial-swarm/scripts/aco.py +473 -0
- package/skills/team-adversarial-swarm/scripts/pheromone.py +144 -0
- package/skills/team-adversarial-swarm/scripts/scoring.py +92 -0
- package/skills/team-adversarial-swarm/scripts/test_aco.py +475 -0
- package/skills/team-arch-opt/SKILL.md +158 -0
- package/skills/team-brainstorm/SKILL.md +171 -0
- package/skills/team-coordinate/SKILL.md +266 -0
- package/skills/team-designer/SKILL.md +160 -0
- package/skills/team-executor/SKILL.md +189 -0
- package/skills/team-frontend/SKILL.md +136 -0
- package/skills/team-frontend-debug/SKILL.md +198 -0
- package/skills/team-interactive-craft/SKILL.md +141 -0
- package/skills/team-issue/SKILL.md +171 -0
- package/skills/team-lifecycle-v4/SKILL.md +209 -0
- package/skills/team-motion-design/SKILL.md +142 -0
- package/skills/team-perf-opt/SKILL.md +175 -0
- package/skills/team-planex/SKILL.md +137 -0
- package/skills/team-quality-assurance/SKILL.md +147 -0
- package/skills/team-review/SKILL.md +147 -0
- package/skills/team-roadmap-dev/SKILL.md +169 -0
- package/skills/team-swarm/SKILL.md +178 -0
- package/skills/team-swarm/scripts/aco.py +473 -0
- package/skills/team-swarm/scripts/pheromone.py +144 -0
- package/skills/team-swarm/scripts/scoring.py +92 -0
- package/skills/team-swarm/scripts/test_aco.py +475 -0
- package/skills/team-tech-debt/SKILL.md +128 -0
- package/skills/team-testing/SKILL.md +143 -0
- package/skills/team-ui-polish/SKILL.md +141 -0
- package/skills/team-uidesign/SKILL.md +144 -0
- package/skills/team-ultra-analyze/SKILL.md +173 -0
- package/skills/team-ux-improve/SKILL.md +151 -0
- package/skills/team-visual-a11y/SKILL.md +156 -0
- package/skills/workflow-skill-designer/SKILL.md +496 -0
- package/src/extension/index.ts +222 -0
- package/src/extension/schemas.ts +131 -0
- package/src/providers/cli-tools-loader.ts +74 -0
- package/src/providers/provider-registry.ts +130 -0
- package/src/tools/delegate.ts +85 -0
- package/src/tools/explore.ts +134 -0
- package/src/tools/moa.ts +213 -0
- package/src/tools/status.ts +99 -0
- package/src/tools/wait.ts +166 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explore action — parallel code search via teammate sub-agents.
|
|
3
|
+
*
|
|
4
|
+
* For each prompt, spawns a teammate agent (explorer profile) that
|
|
5
|
+
* searches the codebase using read/grep/find/ls tools.
|
|
6
|
+
* Results are collected and merged into a unified exploration output.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
10
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { runTeammate } from "@pi-maestro/teammate/src/runs/execution.ts";
|
|
12
|
+
import type { SingleResult } from "@pi-maestro/teammate/src/shared/types.ts";
|
|
13
|
+
|
|
14
|
+
export interface ExploreParams {
|
|
15
|
+
prompts?: string[];
|
|
16
|
+
endpoint?: string;
|
|
17
|
+
all?: boolean;
|
|
18
|
+
maxTurns?: number;
|
|
19
|
+
concurrency?: number;
|
|
20
|
+
model?: string;
|
|
21
|
+
cwd?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ExploreResult {
|
|
25
|
+
prompt: string;
|
|
26
|
+
agent: string;
|
|
27
|
+
model: string;
|
|
28
|
+
content: string;
|
|
29
|
+
exitCode: number;
|
|
30
|
+
durationMs: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Execute explore action: spawn parallel teammate agents for code search.
|
|
35
|
+
*/
|
|
36
|
+
export async function executeExplore(
|
|
37
|
+
params: ExploreParams,
|
|
38
|
+
signal: AbortSignal,
|
|
39
|
+
ctx: ExtensionContext,
|
|
40
|
+
): Promise<AgentToolResult> {
|
|
41
|
+
const prompts = params.prompts ?? [];
|
|
42
|
+
|
|
43
|
+
if (prompts.length === 0) {
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: "No prompts provided for explore action." }],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const concurrency = params.concurrency ?? 4;
|
|
51
|
+
const results: ExploreResult[] = [];
|
|
52
|
+
const errors: string[] = [];
|
|
53
|
+
|
|
54
|
+
// Process prompts with concurrency limit
|
|
55
|
+
const queue = [...prompts];
|
|
56
|
+
const running: Promise<void>[] = [];
|
|
57
|
+
|
|
58
|
+
const processPrompt = async (prompt: string): Promise<void> => {
|
|
59
|
+
if (signal.aborted) return;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const result = await runTeammate(
|
|
63
|
+
{
|
|
64
|
+
agent: "explorer",
|
|
65
|
+
task: prompt,
|
|
66
|
+
model: params.model ?? params.endpoint,
|
|
67
|
+
cwd: params.cwd,
|
|
68
|
+
reply_to: "caller",
|
|
69
|
+
lifecycle: "ephemeral",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
baseCwd: ctx.cwd,
|
|
73
|
+
signal,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const lastMessage =
|
|
78
|
+
result.messages[result.messages.length - 1]?.content ?? "(no output)";
|
|
79
|
+
|
|
80
|
+
results.push({
|
|
81
|
+
prompt,
|
|
82
|
+
agent: result.agent,
|
|
83
|
+
model: result.model,
|
|
84
|
+
content: lastMessage,
|
|
85
|
+
exitCode: result.exitCode,
|
|
86
|
+
durationMs: result.durationMs,
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
errors.push(
|
|
90
|
+
`Prompt "${prompt.slice(0, 50)}": ${error instanceof Error ? error.message : String(error)}`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Dispatch with concurrency control
|
|
96
|
+
for (const prompt of queue) {
|
|
97
|
+
if (signal.aborted) break;
|
|
98
|
+
|
|
99
|
+
const task = processPrompt(prompt);
|
|
100
|
+
running.push(task);
|
|
101
|
+
|
|
102
|
+
if (running.length >= concurrency) {
|
|
103
|
+
await Promise.race(running);
|
|
104
|
+
// Remove completed tasks
|
|
105
|
+
for (let i = running.length - 1; i >= 0; i--) {
|
|
106
|
+
const settled = await Promise.race([
|
|
107
|
+
running[i].then(() => true),
|
|
108
|
+
Promise.resolve(false),
|
|
109
|
+
]);
|
|
110
|
+
if (settled) running.splice(i, 1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Wait for remaining
|
|
116
|
+
await Promise.allSettled(running);
|
|
117
|
+
|
|
118
|
+
// Build output
|
|
119
|
+
const outputParts: string[] = [];
|
|
120
|
+
for (const result of results) {
|
|
121
|
+
outputParts.push(
|
|
122
|
+
`## Prompt: ${result.prompt.slice(0, 80)}\n**Model**: ${result.model} | **Duration**: ${result.durationMs}ms\n\n${result.content}\n`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (errors.length > 0) {
|
|
127
|
+
outputParts.push(`## Errors\n${errors.map((e) => `- ${e}`).join("\n")}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text", text: outputParts.join("\n---\n\n") }],
|
|
132
|
+
isError: results.length === 0 && errors.length > 0,
|
|
133
|
+
};
|
|
134
|
+
}
|
package/src/tools/moa.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MOA (Mixture-of-Agents) action — multi-model synthesis.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1: Spawn parallel teammate agents (reference profile) across
|
|
5
|
+
* different models/endpoints for independent analysis.
|
|
6
|
+
* Phase 2: Spawn aggregator teammate with all reference outputs as
|
|
7
|
+
* context to synthesize a unified result.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
11
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
12
|
+
import { runTeammate } from "@pi-maestro/teammate/src/runs/execution.ts";
|
|
13
|
+
import type { SingleResult } from "@pi-maestro/teammate/src/shared/types.ts";
|
|
14
|
+
|
|
15
|
+
export interface MoaParams {
|
|
16
|
+
prompts?: string[];
|
|
17
|
+
preset?: string;
|
|
18
|
+
maxTurns?: number;
|
|
19
|
+
model?: string;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ReferenceOutput {
|
|
24
|
+
model: string;
|
|
25
|
+
content: string;
|
|
26
|
+
exitCode: number;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get available models from registered providers.
|
|
32
|
+
* Falls back to a default set if provider registry is not available.
|
|
33
|
+
*/
|
|
34
|
+
function getAvailableModels(preset?: string): string[] {
|
|
35
|
+
// Default models for MOA — the provider registry will override these
|
|
36
|
+
// when fully connected. For now, use a reasonable default set.
|
|
37
|
+
return [
|
|
38
|
+
"anthropic/claude-sonnet-4",
|
|
39
|
+
"google/gemini-2.5-pro",
|
|
40
|
+
"openai/gpt-4.1",
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Execute MOA action: parallel reference analysis + aggregator synthesis.
|
|
46
|
+
*/
|
|
47
|
+
export async function executeMoa(
|
|
48
|
+
params: MoaParams,
|
|
49
|
+
signal: AbortSignal,
|
|
50
|
+
ctx: ExtensionContext,
|
|
51
|
+
): Promise<AgentToolResult> {
|
|
52
|
+
const prompts = params.prompts ?? [];
|
|
53
|
+
const primaryPrompt = prompts[0];
|
|
54
|
+
|
|
55
|
+
if (!primaryPrompt) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{ type: "text", text: "No prompts provided for MOA action." },
|
|
59
|
+
],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const models = getAvailableModels(params.preset);
|
|
65
|
+
|
|
66
|
+
// Phase 1: Spawn parallel reference agents across different models
|
|
67
|
+
const referenceOutputs: ReferenceOutput[] = [];
|
|
68
|
+
const referencePromises: Promise<void>[] = [];
|
|
69
|
+
|
|
70
|
+
for (const model of models) {
|
|
71
|
+
if (signal.aborted) break;
|
|
72
|
+
|
|
73
|
+
const promise = (async () => {
|
|
74
|
+
try {
|
|
75
|
+
const result = await runTeammate(
|
|
76
|
+
{
|
|
77
|
+
agent: "reference",
|
|
78
|
+
task: primaryPrompt,
|
|
79
|
+
model,
|
|
80
|
+
cwd: params.cwd,
|
|
81
|
+
reply_to: "caller",
|
|
82
|
+
lifecycle: "ephemeral",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
baseCwd: ctx.cwd,
|
|
86
|
+
signal,
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const lastMessage =
|
|
91
|
+
result.messages[result.messages.length - 1]?.content ?? "(no output)";
|
|
92
|
+
|
|
93
|
+
referenceOutputs.push({
|
|
94
|
+
model: result.model,
|
|
95
|
+
content: lastMessage,
|
|
96
|
+
exitCode: result.exitCode,
|
|
97
|
+
durationMs: result.durationMs,
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
referenceOutputs.push({
|
|
101
|
+
model,
|
|
102
|
+
content: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
103
|
+
exitCode: 1,
|
|
104
|
+
durationMs: 0,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
|
|
109
|
+
referencePromises.push(promise);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Wait for all reference agents
|
|
113
|
+
await Promise.allSettled(referencePromises);
|
|
114
|
+
|
|
115
|
+
if (signal.aborted) {
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: "text", text: "MOA operation was aborted." }],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const successfulOutputs = referenceOutputs.filter((r) => r.exitCode === 0);
|
|
123
|
+
|
|
124
|
+
if (successfulOutputs.length === 0) {
|
|
125
|
+
return {
|
|
126
|
+
content: [
|
|
127
|
+
{
|
|
128
|
+
type: "text",
|
|
129
|
+
text: `All reference agents failed.\n\n${referenceOutputs.map((r) => `${r.model}: ${r.content}`).join("\n\n")}`,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
isError: true,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Phase 2: Aggregator synthesizes all reference outputs
|
|
137
|
+
const aggregationPrompt = buildAggregationPrompt(
|
|
138
|
+
primaryPrompt,
|
|
139
|
+
successfulOutputs,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const aggregatorResult = await runTeammate(
|
|
144
|
+
{
|
|
145
|
+
agent: "aggregator",
|
|
146
|
+
task: aggregationPrompt,
|
|
147
|
+
model: params.model,
|
|
148
|
+
cwd: params.cwd,
|
|
149
|
+
reply_to: "caller",
|
|
150
|
+
lifecycle: "ephemeral",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
baseCwd: ctx.cwd,
|
|
154
|
+
signal,
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const lastMessage =
|
|
159
|
+
aggregatorResult.messages[aggregatorResult.messages.length - 1]
|
|
160
|
+
?.content ?? "(no output)";
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: "text", text: lastMessage }],
|
|
164
|
+
isError: aggregatorResult.exitCode !== 0,
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
// Fallback: return raw reference outputs if aggregation fails
|
|
168
|
+
const fallbackOutput = successfulOutputs
|
|
169
|
+
.map((r) => `## ${r.model}\n\n${r.content}`)
|
|
170
|
+
.join("\n\n---\n\n");
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
content: [
|
|
174
|
+
{
|
|
175
|
+
type: "text",
|
|
176
|
+
text: `Aggregation failed, returning raw reference outputs:\n\n${fallbackOutput}`,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
isError: false,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function buildAggregationPrompt(
|
|
185
|
+
originalPrompt: string,
|
|
186
|
+
referenceOutputs: ReferenceOutput[],
|
|
187
|
+
): string {
|
|
188
|
+
const referenceSections = referenceOutputs
|
|
189
|
+
.map(
|
|
190
|
+
(r, i) =>
|
|
191
|
+
`### Reference ${i + 1} (${r.model})\n\n${r.content}`,
|
|
192
|
+
)
|
|
193
|
+
.join("\n\n---\n\n");
|
|
194
|
+
|
|
195
|
+
return `You are synthesizing multiple independent analyses into a unified, high-quality response.
|
|
196
|
+
|
|
197
|
+
## Original Question/Task
|
|
198
|
+
|
|
199
|
+
${originalPrompt}
|
|
200
|
+
|
|
201
|
+
## Independent Reference Analyses
|
|
202
|
+
|
|
203
|
+
${referenceSections}
|
|
204
|
+
|
|
205
|
+
## Your Task
|
|
206
|
+
|
|
207
|
+
Synthesize these reference analyses into a single, comprehensive response:
|
|
208
|
+
1. Identify areas of consensus across references
|
|
209
|
+
2. Note any conflicts or divergent perspectives
|
|
210
|
+
3. Produce a unified analysis that incorporates the strongest points from each reference
|
|
211
|
+
4. Where references disagree, evaluate the evidence and make a reasoned judgment
|
|
212
|
+
5. Ensure the final output is coherent, well-structured, and directly addresses the original question`;
|
|
213
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* maestro-status auxiliary tool.
|
|
3
|
+
*
|
|
4
|
+
* Inspects active and completed maestro runs.
|
|
5
|
+
* Supports fleet view (overview) and transcript view (tail logs).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
9
|
+
|
|
10
|
+
interface MaestroState {
|
|
11
|
+
activeRuns: Map<
|
|
12
|
+
string,
|
|
13
|
+
{
|
|
14
|
+
action: string;
|
|
15
|
+
startedAt: number;
|
|
16
|
+
correlationId: string;
|
|
17
|
+
}
|
|
18
|
+
>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface StatusParams {
|
|
22
|
+
id?: string;
|
|
23
|
+
view?: "fleet" | "transcript";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function formatDuration(ms: number): string {
|
|
27
|
+
if (ms < 1000) return `${ms}ms`;
|
|
28
|
+
const seconds = Math.floor(ms / 1000);
|
|
29
|
+
if (seconds < 60) return `${seconds}s`;
|
|
30
|
+
const minutes = Math.floor(seconds / 60);
|
|
31
|
+
const remainingSeconds = seconds % 60;
|
|
32
|
+
return `${minutes}m${remainingSeconds}s`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get status of maestro runs.
|
|
37
|
+
*/
|
|
38
|
+
export async function executeMaestroStatus(
|
|
39
|
+
params: StatusParams,
|
|
40
|
+
state: MaestroState,
|
|
41
|
+
): Promise<AgentToolResult> {
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
|
|
44
|
+
// Specific run by ID
|
|
45
|
+
if (params.id) {
|
|
46
|
+
const run = state.activeRuns.get(params.id);
|
|
47
|
+
if (!run) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `Run "${params.id}" not found. It may have completed.`,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const elapsed = formatDuration(now - run.startedAt);
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: [
|
|
64
|
+
`## Run: ${params.id}`,
|
|
65
|
+
`- **Action**: ${run.action}`,
|
|
66
|
+
`- **Status**: running`,
|
|
67
|
+
`- **Elapsed**: ${elapsed}`,
|
|
68
|
+
`- **Correlation ID**: ${run.correlationId}`,
|
|
69
|
+
].join("\n"),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Fleet view (default)
|
|
76
|
+
if (state.activeRuns.size === 0) {
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: "No active maestro runs.",
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const lines: string[] = ["## Maestro Fleet Status", ""];
|
|
88
|
+
|
|
89
|
+
for (const [id, run] of state.activeRuns) {
|
|
90
|
+
const elapsed = formatDuration(now - run.startedAt);
|
|
91
|
+
lines.push(`- **${id}**: ${run.action} (${elapsed})`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
lines.push("", `Total: ${state.activeRuns.size} active run(s)`);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* maestro-wait auxiliary tool.
|
|
3
|
+
*
|
|
4
|
+
* Blocks until background maestro runs finish.
|
|
5
|
+
* Supports waiting for a specific run, the first to finish, or all runs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
9
|
+
|
|
10
|
+
interface MaestroState {
|
|
11
|
+
activeRuns: Map<
|
|
12
|
+
string,
|
|
13
|
+
{
|
|
14
|
+
action: string;
|
|
15
|
+
startedAt: number;
|
|
16
|
+
correlationId: string;
|
|
17
|
+
}
|
|
18
|
+
>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface WaitParams {
|
|
22
|
+
id?: string;
|
|
23
|
+
all?: boolean;
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const DEFAULT_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
28
|
+
const POLL_INTERVAL_MS = 1000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Wait for active maestro runs to complete.
|
|
32
|
+
*
|
|
33
|
+
* Uses a poll-based approach to check run completion status.
|
|
34
|
+
* Resolves when the target run(s) finish or timeout is reached.
|
|
35
|
+
*/
|
|
36
|
+
export async function executeMaestroWait(
|
|
37
|
+
params: WaitParams,
|
|
38
|
+
signal: AbortSignal,
|
|
39
|
+
state: MaestroState,
|
|
40
|
+
): Promise<AgentToolResult> {
|
|
41
|
+
const timeout = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
|
|
44
|
+
// No active runs
|
|
45
|
+
if (state.activeRuns.size === 0) {
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "No active maestro runs to wait for.",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// If waiting for specific ID
|
|
57
|
+
if (params.id) {
|
|
58
|
+
const run = state.activeRuns.get(params.id);
|
|
59
|
+
if (!run) {
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: `Run "${params.id}" not found in active runs.`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Poll until completion or timeout
|
|
72
|
+
return new Promise<AgentToolResult>((resolve) => {
|
|
73
|
+
const checkCompletion = () => {
|
|
74
|
+
// Check abort
|
|
75
|
+
if (signal.aborted) {
|
|
76
|
+
resolve({
|
|
77
|
+
content: [
|
|
78
|
+
{
|
|
79
|
+
type: "text",
|
|
80
|
+
text: "Wait was aborted.",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check timeout
|
|
88
|
+
if (Date.now() - startTime >= timeout) {
|
|
89
|
+
const remaining = Array.from(state.activeRuns.entries())
|
|
90
|
+
.map(([id, r]) => ` - ${id}: ${r.action} (running ${Math.floor((Date.now() - r.startedAt) / 1000)}s)`)
|
|
91
|
+
.join("\n");
|
|
92
|
+
|
|
93
|
+
resolve({
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: `Wait timed out after ${timeout}ms. Active runs:\n${remaining}`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check if target run(s) finished
|
|
105
|
+
if (params.id) {
|
|
106
|
+
if (!state.activeRuns.has(params.id)) {
|
|
107
|
+
resolve({
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `Run "${params.id}" completed.`,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
} else if (params.all) {
|
|
118
|
+
if (state.activeRuns.size === 0) {
|
|
119
|
+
resolve({
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: "All maestro runs completed.",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
// Wait for first — check if any have completed since we started
|
|
131
|
+
// (This simple implementation checks if the count decreased)
|
|
132
|
+
// A full implementation would use event subscriptions
|
|
133
|
+
if (state.activeRuns.size === 0) {
|
|
134
|
+
resolve({
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: "text",
|
|
138
|
+
text: "A maestro run completed.",
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Keep polling
|
|
147
|
+
setTimeout(checkCompletion, POLL_INTERVAL_MS);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Start polling
|
|
151
|
+
checkCompletion();
|
|
152
|
+
|
|
153
|
+
// Handle abort signal
|
|
154
|
+
signal.addEventListener(
|
|
155
|
+
"abort",
|
|
156
|
+
() => {
|
|
157
|
+
resolve({
|
|
158
|
+
content: [
|
|
159
|
+
{ type: "text", text: "Wait was aborted." },
|
|
160
|
+
],
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
{ once: true },
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
}
|