supipowers 0.7.9 → 0.7.10
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
CHANGED
|
@@ -95,10 +95,91 @@ async function executeSubAgent(
|
|
|
95
95
|
task: PlanTask,
|
|
96
96
|
config: SupipowersConfig,
|
|
97
97
|
): Promise<SubAgentResult> {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
const { createAgentSession } = pi.pi;
|
|
99
|
+
|
|
100
|
+
const { session } = await createAgentSession({
|
|
101
|
+
cwd: process.cwd(),
|
|
102
|
+
hasUI: false,
|
|
103
|
+
taskDepth: 1,
|
|
104
|
+
parentTaskPrefix: `task-${task.id}`,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Track files changed by monitoring tool calls
|
|
108
|
+
const filesChanged = new Set<string>();
|
|
109
|
+
const FILE_TOOLS = new Set(["Edit", "Write", "NotebookEdit"]);
|
|
110
|
+
const pendingToolArgs = new Map<string, Record<string, unknown>>();
|
|
111
|
+
const unsubscribe = session.subscribe((event) => {
|
|
112
|
+
if (event.type === "tool_execution_start" && FILE_TOOLS.has(event.toolName)) {
|
|
113
|
+
if (event.args?.file_path) {
|
|
114
|
+
pendingToolArgs.set(event.toolCallId, event.args as Record<string, unknown>);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (event.type === "tool_execution_end" && !event.isError) {
|
|
118
|
+
const args = pendingToolArgs.get(event.toolCallId);
|
|
119
|
+
if (args?.file_path) {
|
|
120
|
+
filesChanged.add(String(args.file_path));
|
|
121
|
+
}
|
|
122
|
+
pendingToolArgs.delete(event.toolCallId);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await session.prompt(prompt, { expandPromptTemplates: false });
|
|
128
|
+
|
|
129
|
+
// Extract the last assistant message
|
|
130
|
+
const messages = session.state.messages;
|
|
131
|
+
const lastAssistant = [...messages]
|
|
132
|
+
.reverse()
|
|
133
|
+
.find((m) => m.role === "assistant");
|
|
134
|
+
|
|
135
|
+
const output = extractTextContent(lastAssistant?.content);
|
|
136
|
+
const status = parseAgentStatus(output);
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
status,
|
|
140
|
+
output,
|
|
141
|
+
concerns: status === "done_with_concerns"
|
|
142
|
+
? extractConcerns(output)
|
|
143
|
+
: undefined,
|
|
144
|
+
filesChanged: [...filesChanged],
|
|
145
|
+
};
|
|
146
|
+
} finally {
|
|
147
|
+
unsubscribe();
|
|
148
|
+
await session.dispose();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function extractTextContent(content: unknown): string {
|
|
153
|
+
if (!content) return "";
|
|
154
|
+
if (typeof content === "string") return content;
|
|
155
|
+
if (Array.isArray(content)) {
|
|
156
|
+
return content
|
|
157
|
+
.filter((block: { type?: string }) => block.type === "text")
|
|
158
|
+
.map((block: { text?: string }) => block.text ?? "")
|
|
159
|
+
.join("\n");
|
|
160
|
+
}
|
|
161
|
+
return String(content);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function parseAgentStatus(output: string): AgentStatus {
|
|
165
|
+
const upper = output.toUpperCase();
|
|
166
|
+
if (upper.includes("BLOCKED") || upper.includes("NEEDS_CONTEXT")) {
|
|
167
|
+
return "blocked";
|
|
168
|
+
}
|
|
169
|
+
if (upper.includes("DONE_WITH_CONCERNS")) {
|
|
170
|
+
return "done_with_concerns";
|
|
171
|
+
}
|
|
172
|
+
// "DONE" appears in both "DONE" and "DONE_WITH_CONCERNS", so check after
|
|
173
|
+
if (upper.includes("**STATUS:** DONE") || upper.includes("STATUS: DONE")) {
|
|
174
|
+
return "done";
|
|
175
|
+
}
|
|
176
|
+
// Default: if agent completed without explicit status, treat as done
|
|
177
|
+
return "done";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function extractConcerns(output: string): string {
|
|
181
|
+
const match = output.match(/(?:concerns?|issues?|worries):\s*(.+?)(?:\n\n|$)/is);
|
|
182
|
+
return match?.[1]?.trim() ?? "";
|
|
102
183
|
}
|
|
103
184
|
|
|
104
185
|
/** Review result from a spec compliance or code quality reviewer */
|