@inceptionstack/roundhouse 0.5.21 → 0.5.22

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inceptionstack/roundhouse",
3
- "version": "0.5.21",
3
+ "version": "0.5.22",
4
4
  "type": "module",
5
5
  "description": "Multi-platform chat gateway that routes messages through a configured AI agent",
6
6
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { mkdir, stat } from "node:fs/promises";
2
+ import { mkdir, stat, readFile } from "node:fs/promises";
3
3
  import type { ChildProcess } from "node:child_process";
4
4
  import { homedir } from "node:os";
5
5
  import { join } from "node:path";
@@ -168,10 +168,29 @@ export class SubAgentOrchestratorImpl implements SubAgentOrchestrator, SubAgentL
168
168
 
169
169
  const outcome = current.requestedOutcome
170
170
  ? this.terminationHandler.terminalStatusFor(current)
171
- : (exitCode === 0 ? "complete" : "failed");
171
+ : await this.inferOutcome(runId, exitCode);
172
172
 
173
173
  await this.finalizer.finalizeRun(runId, outcome, { exitCode: exitCode ?? undefined });
174
174
  }
175
+ /**
176
+ * Determine terminal status for a child exit.
177
+ * If exit code is non-zero but the agent produced meaningful stdout output,
178
+ * treat as "complete" — the work succeeded but the process had a teardown error
179
+ * (e.g. pi-hard-no stale context exception on session close).
180
+ */
181
+ private async inferOutcome(runId: string, exitCode: number | null): Promise<"complete" | "failed"> {
182
+ if (exitCode === 0) return "complete";
183
+ if (exitCode === null) return "failed"; // signal-killed, not a teardown error
184
+ try {
185
+ const stdoutPath = join(this.store.getRunDir(runId), "stdout.log");
186
+ const content = await readFile(stdoutPath, "utf-8");
187
+ // If stdout has substantial content (>50 chars), the agent did its job
188
+ if (content.trim().length > 50) return "complete";
189
+ } catch {
190
+ // No stdout file or can't read — fall through to failed
191
+ }
192
+ return "failed";
193
+ }
175
194
  }
176
195
 
177
196
  async function assertDirectoryExists(path: string): Promise<void> {