mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 05:56:21 -10:00
fix(daemon): the Pi runner shows a failed or cancelled compaction as such (#2537)
A Pi seat whose compaction Pi reports as cancelled now shows the compaction as cancelled, and one that failed shows it as failed with Pi's reason, instead of always reporting it done. The reason goes through the runner's existing diagnostic cleaner and is bounded to 400 characters. An event without either field still reads done. Reported in #2521 by @eisenrigbot.
This commit is contained in:
1 parent
2a1e609cb1
commit
16946c577a
2 files changed
+31
-5
No files matched your search
@@ -179,11 +179,16 @@ function piCredentialHint(message: string): string {
|
||||
: " For managed Pi, configure this provider in the seat's PI_CODING_AGENT_DIR (auth.json or models.json). Its key is not in OpenRig's Pi environment passthrough map; default Pi logins are not automatically shared.";
|
||||
}
|
||||
|
||||
function errorNotice(details: unknown[], runtime: RunnerRuntime): string {
|
||||
// Empty or control-only fields must not hide a later usable diagnostic.
|
||||
const text = details.map(detail => typeof detail === "string"
|
||||
/** The first usable diagnostic, on one line with control characters removed. Empty or control-only fields must not hide
|
||||
* a later usable one. */
|
||||
function diagnosticText(details: unknown[]): string {
|
||||
return details.map(detail => typeof detail === "string"
|
||||
? stripVTControlCharacters(detail).replace(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu, " ").replace(/\s+/g, " ").trim()
|
||||
: "").find(Boolean) ?? "";
|
||||
}
|
||||
|
||||
function errorNotice(details: unknown[], runtime: RunnerRuntime): string {
|
||||
const text = diagnosticText(details);
|
||||
const marker = runtime === "omp" ? "[omp-runner] ERROR" : PI_RUNNER_ERROR_MARKER;
|
||||
return `${marker} ${text.slice(0, 400) || "request failed"}${runtime === "pi" ? piCredentialHint(text) : ""}`;
|
||||
}
|
||||
@@ -257,8 +262,13 @@ export function mapPiEvent(event: Record<string, unknown>, runtime: RunnerRuntim
|
||||
return { mirrorLines: [] };
|
||||
case "compaction_start":
|
||||
return { mirrorLines: [`[${runtime}] compacting context…`], activity: { hookEvent: "active", subtype: "compaction" } };
|
||||
case "compaction_end":
|
||||
return { mirrorLines: [`[${runtime}] compaction done`] };
|
||||
case "compaction_end": {
|
||||
// Pi's compaction_end says `aborted` when it was cancelled, and carries `errorMessage` when it failed and wrote no
|
||||
// summary (Pi's docs/rpc.md). An end that names neither is done.
|
||||
const failure = diagnosticText([event.errorMessage]).slice(0, 400);
|
||||
return { mirrorLines: [event.aborted === true ? `[${runtime}] compaction cancelled`
|
||||
: failure ? `[${runtime}] compaction failed: ${failure}` : `[${runtime}] compaction done`] };
|
||||
}
|
||||
// OMP names its automatic compaction separately. Pi keeps main's mapping
|
||||
// (unmapped), so an idle Pi seat never reads as running after one.
|
||||
case "auto_compaction_start":
|
||||
|
||||
@@ -745,6 +745,22 @@ describe("mapPiEvent", () => {
|
||||
expect(mapPiEvent({ type: "auto_retry_start" }).activity).toEqual({ hookEvent: "active", subtype: "auto_retry" });
|
||||
});
|
||||
|
||||
// Pi's compaction_end (its docs/rpc.md): `aborted` when it was cancelled, otherwise `errorMessage` when it failed and no
|
||||
// summary was written (#2521). The JSON line carries no `result` then.
|
||||
it("reports a compaction's end the way Pi does: cancelled, failed with Pi's reason, or done", () => {
|
||||
const done = { type: "compaction_end", reason: "threshold", result: { summary: "s", firstKeptEntryId: "e1", tokensBefore: 150000 }, aborted: false, willRetry: false };
|
||||
const failed = { type: "compaction_end", reason: "threshold", aborted: false, willRetry: false,
|
||||
errorMessage: "Auto-compaction failed: Summarization failed: generation hit the token cap and the summary is incomplete" };
|
||||
const cancelled = { type: "compaction_end", reason: "manual", aborted: true, willRetry: false };
|
||||
expect(mapPiEvent(done).mirrorLines).toEqual(["[pi] compaction done"]);
|
||||
expect(mapPiEvent(failed).mirrorLines).toEqual(["[pi] compaction failed: Auto-compaction failed: Summarization failed: generation hit the token cap and the summary is incomplete"]);
|
||||
expect(mapPiEvent(cancelled).mirrorLines).toEqual(["[pi] compaction cancelled"]);
|
||||
expect(mapPiEvent({ ...failed, errorMessage: "Compaction failed: \u001b[31mquota\u001b[0m\nexceeded" }).mirrorLines)
|
||||
.toEqual(["[pi] compaction failed: Compaction failed: quota exceeded"]);
|
||||
// An end that names neither a cancel nor a failure keeps reading done, as before.
|
||||
expect(mapPiEvent({ type: "compaction_end" }, "omp").mirrorLines).toEqual(["[omp] compaction done"]);
|
||||
});
|
||||
|
||||
it("leaves auto_compaction_* unmapped for Pi so an idle seat never reads as running", () => {
|
||||
for (const type of ["auto_compaction_start", "auto_compaction_end"]) {
|
||||
expect(mapPiEvent({ type })).toEqual({ mirrorLines: [] });
|
||||
|
||||
Reference in new issue
Block a user