iriai-build 0.2.6 → 0.2.8
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 +1 -1
- package/v3/agent-supervisor.js +12 -6
- package/v3/operator.js +4 -5
- package/v3/orchestrator.js +37 -5
package/package.json
CHANGED
package/v3/agent-supervisor.js
CHANGED
|
@@ -192,12 +192,18 @@ export class AgentSupervisor extends EventEmitter {
|
|
|
192
192
|
console.log(`[supervisor] Scheduling retry ${updatedAgent.retry_count}/${agent.max_retries} for ${agent.agent_key} in ${backoffS}s (${isFastExit ? "fast-exit" : "normal"})`);
|
|
193
193
|
|
|
194
194
|
const entry = this._processes[agent.agent_key] || {};
|
|
195
|
-
entry.retryTimer = setTimeout(() => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
entry.retryTimer = setTimeout(async () => {
|
|
196
|
+
try {
|
|
197
|
+
const result = await promptFn(updatedAgent);
|
|
198
|
+
// promptFn can return null (already handled spawn), a string, or { prompt, continue }
|
|
199
|
+
if (result == null) return;
|
|
200
|
+
const prompt = typeof result === "string" ? result : result.prompt;
|
|
201
|
+
const spawnOpts = typeof result === "string" ? {} : { continue: !!result.continue };
|
|
202
|
+
this.spawn(agentId, prompt, spawnOpts);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
console.error(`[supervisor] Retry callback error for ${agent.agent_key}:`, err.message);
|
|
205
|
+
queries.updateAgentStatus(agentId, "crashed");
|
|
206
|
+
}
|
|
201
207
|
}, backoffS * 1000);
|
|
202
208
|
this._processes[agent.agent_key] = entry;
|
|
203
209
|
|
package/v3/operator.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
* @param {AgentSupervisor} opts.supervisor - Agent supervisor instance
|
|
26
26
|
* @param {number} opts.agentId - Operator agent DB id
|
|
27
27
|
*/
|
|
28
|
-
export async function invokeOperator({ feature, operatorDir, flDir, featureDir, userMessage, supervisor, agentId, planDir, activePlanningRole }) {
|
|
28
|
+
export async function invokeOperator({ feature, operatorDir, flDir, featureDir, userMessage, supervisor, agentId, planDir, activePlanningRole, continue: useContinue }) {
|
|
29
29
|
// 1. Assemble context from SQLite (async — Haiku summarization is non-blocking)
|
|
30
30
|
const history = await assembleHistory(feature.id);
|
|
31
31
|
const activeAgents = assembleActiveAgents(feature.id);
|
|
@@ -49,10 +49,9 @@ export async function invokeOperator({ feature, operatorDir, flDir, featureDir,
|
|
|
49
49
|
directoryMap,
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
// 3. Spawn claude via supervisor
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
supervisor.spawn(agentId, prompt, { continue: true });
|
|
52
|
+
// 3. Spawn claude via supervisor — default to --continue for session context,
|
|
53
|
+
// but allow caller to force a fresh session (e.g. after "Prompt is too long")
|
|
54
|
+
supervisor.spawn(agentId, prompt, { continue: useContinue !== undefined ? useContinue : true });
|
|
56
55
|
|
|
57
56
|
// Record the event
|
|
58
57
|
queries.insertEvent(feature.id, "user-message", "bridge", `Operator invoked for: ${userMessage.slice(0, 100)}`);
|
package/v3/orchestrator.js
CHANGED
|
@@ -1863,9 +1863,13 @@ export class Orchestrator {
|
|
|
1863
1863
|
// Parse structured blocks from Operator output
|
|
1864
1864
|
const parsed = parseOperatorResponse(content);
|
|
1865
1865
|
|
|
1866
|
-
// Post the text content (with [DECISION] blocks stripped via parsed.plainText)
|
|
1867
|
-
|
|
1868
|
-
|
|
1866
|
+
// Post the text content (with [DECISION]/[ROUTE] blocks stripped via parsed.plainText).
|
|
1867
|
+
// If plainText is empty (response was only routes/decisions), skip posting to avoid
|
|
1868
|
+
// leaking raw [ROUTE:...] markup to the user.
|
|
1869
|
+
const textContent = parsed.plainText;
|
|
1870
|
+
if (textContent) {
|
|
1871
|
+
await this.adapter.postAgentResponse(feature.id, "Operator", textContent);
|
|
1872
|
+
}
|
|
1869
1873
|
|
|
1870
1874
|
// Handle [DECISION] blocks — render as separate decision prompts.
|
|
1871
1875
|
// Skip any that duplicate a deferred decision (already queued by _requestPhaseReview).
|
|
@@ -2232,6 +2236,11 @@ export class Orchestrator {
|
|
|
2232
2236
|
|
|
2233
2237
|
// Invoke ephemeral operator with planning-phase context
|
|
2234
2238
|
const planDir = tree.plansDir || path.join(tree.featureDir, "plans");
|
|
2239
|
+
|
|
2240
|
+
// Stash context for retry if "Prompt is too long" — readSignal already deleted the file
|
|
2241
|
+
if (!this._lastOperatorContext) this._lastOperatorContext = {};
|
|
2242
|
+
this._lastOperatorContext[feature.slug] = { userMessage, planDir, tree, feature };
|
|
2243
|
+
|
|
2235
2244
|
try {
|
|
2236
2245
|
await invokeOperator({
|
|
2237
2246
|
feature,
|
|
@@ -2263,6 +2272,8 @@ export class Orchestrator {
|
|
|
2263
2272
|
if (exitCode === 0) {
|
|
2264
2273
|
queries.updateAgentStatus(agentId, "idle");
|
|
2265
2274
|
queries.resetAgentRetry(agentId);
|
|
2275
|
+
// Clean up stashed context
|
|
2276
|
+
if (this._lastOperatorContext) delete this._lastOperatorContext[feature.slug];
|
|
2266
2277
|
return;
|
|
2267
2278
|
}
|
|
2268
2279
|
|
|
@@ -2275,8 +2286,29 @@ export class Orchestrator {
|
|
|
2275
2286
|
|
|
2276
2287
|
console.log(`[orchestrator] Operator exited with code ${exitCode} after ${elapsed}ms — scheduling retry`);
|
|
2277
2288
|
|
|
2278
|
-
|
|
2279
|
-
|
|
2289
|
+
// Capture stashed context for the retry closure
|
|
2290
|
+
const stashedCtx = this._lastOperatorContext?.[feature.slug];
|
|
2291
|
+
|
|
2292
|
+
const retried = this.supervisor.scheduleRetry(agentId, async () => {
|
|
2293
|
+
// Retry with continue:false to start a fresh session (old session hit context limit).
|
|
2294
|
+
// Re-invoke the full Operator with the original user message so it doesn't lose context.
|
|
2295
|
+
if (stashedCtx) {
|
|
2296
|
+
console.log(`[orchestrator] Operator retry: re-invoking with original user message (continue:false)`);
|
|
2297
|
+
const freshFeature = queries.getFeatureById(feature.id) || feature;
|
|
2298
|
+
await invokeOperator({
|
|
2299
|
+
feature: freshFeature,
|
|
2300
|
+
operatorDir: tree.operator,
|
|
2301
|
+
flDir: tree.featureLead,
|
|
2302
|
+
featureDir: tree.featureDir,
|
|
2303
|
+
userMessage: stashedCtx.userMessage,
|
|
2304
|
+
supervisor: this.supervisor,
|
|
2305
|
+
agentId,
|
|
2306
|
+
planDir: stashedCtx.planDir,
|
|
2307
|
+
activePlanningRole: freshFeature.active_planning_role,
|
|
2308
|
+
continue: false,
|
|
2309
|
+
});
|
|
2310
|
+
return null; // invokeOperator already called supervisor.spawn
|
|
2311
|
+
}
|
|
2280
2312
|
return { prompt: "Re-read your CLAUDE.md and check for pending relay queue items or user messages. Write a status update to .agent-response if there's nothing to relay.", continue: false };
|
|
2281
2313
|
});
|
|
2282
2314
|
|