grind mode baby

This commit is contained in:
Harivansh Rathi 2026-03-08 23:38:13 -07:00
parent aa70afbd7e
commit ff6e39dd10
17 changed files with 1232 additions and 8 deletions

View file

@ -0,0 +1,132 @@
import { randomUUID } from "node:crypto";
import type { SessionEntry } from "@mariozechner/pi-coding-agent";
import {
GRIND_STATE_ENTRY_TYPE,
type GrindActivation,
type GrindRunState,
type GrindRunStatus,
type GrindStatusPayload,
} from "./types.js";
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object";
}
function isGrindRunStatus(value: unknown): value is GrindRunStatus {
return (
value === "active" ||
value === "paused" ||
value === "done" ||
value === "blocked" ||
value === "expired" ||
value === "stopped"
);
}
function isGrindActivation(value: unknown): value is GrindActivation {
return value === "explicit" || value === "command";
}
function isNullableString(value: unknown): value is string | null {
return typeof value === "string" || value === null;
}
export function createRunState(input: {
activation: GrindActivation;
goal: string;
sourcePrompt: string;
deadlineAt: string | null;
completionCriterion: string | null;
}): GrindRunState {
const now = new Date().toISOString();
return {
version: 1,
runId: randomUUID(),
activation: input.activation,
status: "active",
goal: input.goal,
sourcePrompt: input.sourcePrompt,
deadlineAt: input.deadlineAt,
completionCriterion: input.completionCriterion,
lastCheckpoint: null,
lastNextAction: null,
pendingRepair: false,
consecutiveParseFailures: 0,
consecutiveControllerFailures: 0,
updatedAt: now,
};
}
export function isValidRunState(value: unknown): value is GrindRunState {
if (!isRecord(value)) {
return false;
}
return (
value.version === 1 &&
typeof value.runId === "string" &&
isGrindActivation(value.activation) &&
isGrindRunStatus(value.status) &&
typeof value.goal === "string" &&
typeof value.sourcePrompt === "string" &&
isNullableString(value.deadlineAt) &&
isNullableString(value.completionCriterion) &&
isNullableString(value.lastCheckpoint) &&
isNullableString(value.lastNextAction) &&
typeof value.pendingRepair === "boolean" &&
typeof value.consecutiveParseFailures === "number" &&
typeof value.consecutiveControllerFailures === "number" &&
typeof value.updatedAt === "string"
);
}
export function getLatestRunState(entries: readonly SessionEntry[]): GrindRunState | null {
for (let index = entries.length - 1; index >= 0; index -= 1) {
const entry = entries[index];
if (entry.type !== "custom" || entry.customType !== GRIND_STATE_ENTRY_TYPE) {
continue;
}
if (isValidRunState(entry.data)) {
return entry.data;
}
}
return null;
}
export function withStatus(
state: GrindRunState,
status: GrindRunStatus,
overrides: Partial<GrindRunState> = {},
): GrindRunState {
return {
...state,
...overrides,
status,
updatedAt: new Date().toISOString(),
};
}
export function withLoopStatus(state: GrindRunState, payload: GrindStatusPayload): GrindRunState {
return {
...state,
status: payload.state === "continue" ? "active" : payload.state === "done" ? "done" : "blocked",
lastCheckpoint: payload.summary,
lastNextAction: payload.nextAction ?? null,
pendingRepair: false,
consecutiveParseFailures: 0,
consecutiveControllerFailures: 0,
updatedAt: new Date().toISOString(),
};
}
export function withControllerFailure(state: GrindRunState, note: string): GrindRunState {
return {
...state,
status: "blocked",
lastCheckpoint: note,
lastNextAction: null,
pendingRepair: false,
consecutiveControllerFailures: state.consecutiveControllerFailures + 1,
updatedAt: new Date().toISOString(),
};
}