Files
pikasTech-unidesk/scripts/code-queue-trace-summary-contract-test.ts
T
2026-05-20 04:59:20 +00:00

243 lines
10 KiB
TypeScript

import { configureTaskView, taskTraceSummaryFixtureResponse } from "../src/components/microservices/code-queue/src/task-view";
import { configureTaskOutput } from "../src/components/microservices/code-queue/src/task-output";
import { configureJudge } from "../src/components/microservices/code-queue/src/judge";
import type { OaTraceStepSummary } from "../src/components/microservices/code-queue/src/oa-events";
import type { JsonValue, PromptHistoryItem, QueueTask, QueuedStatusReason } from "../src/components/microservices/code-queue/src/types";
type JsonRecord = Record<string, unknown>;
function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
function asRecord(value: unknown): JsonRecord | null {
return typeof value === "object" && value !== null && !Array.isArray(value) ? value as JsonRecord : null;
}
function pageBySeq<T extends { seq: number }>(
items: T[],
_url: URL,
_limit: number,
): { mode: "tail" | "after" | "before"; afterSeq: number; beforeSeq: number | null; nextAfterSeq: number; previousBeforeSeq: number | null; hasMore: boolean; hasBefore: boolean; chunk: T[] } {
return {
mode: "tail",
afterSeq: 0,
beforeSeq: null,
nextAfterSeq: items.at(-1)?.seq ?? 0,
previousBeforeSeq: null,
hasMore: false,
hasBefore: false,
chunk: items,
};
}
function configureFixtureTaskView(): void {
configureTaskOutput({
config: { maxInMemoryOutputRecords: 1000, outputArchiveDir: "/tmp/code-queue-trace-summary-contract/output" },
allocateSeq: () => 1000,
errorToJson: (error: unknown): JsonValue => error instanceof Error ? { message: error.message } : String(error),
logger: () => undefined,
markTaskDirty: () => undefined,
nowIso: () => "2026-05-19T00:10:00.000Z",
schedulePersistState: () => undefined,
});
configureJudge({
config: {
minimaxApiKey: "",
minimaxApiBase: "",
minimaxModel: "minimax-m1",
judgeTimeoutMs: 1000,
judgeRepairAttempts: 0,
judgeMaxTokens: 1000,
},
logger: () => undefined,
safePreview: (value: string, max = 300) => value.length > max ? `${value.slice(0, max)}...` : value,
userPromptForDisplay: (prompt: string) => prompt,
taskFullOutput: (task: QueueTask) => task.output,
taskReferenceIds: (task: QueueTask) => task.referenceTaskIds,
extractRecord: (value: unknown) => typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null,
extractString: (value: unknown, key: string) => {
const record = typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
const item = record?.[key];
return typeof item === "string" ? item : null;
},
promptLineCount: (text: string) => text.length > 0 ? text.split(/\r\n|\r|\n/u).length : 0,
judgeFailRetryLimit: 3,
});
configureTaskView({
config: { codexHome: "/tmp/code-queue-trace-summary-contract" },
errorToJson: (error: unknown): JsonValue => error instanceof Error ? { message: error.message } : String(error),
jsonResponse: (body: unknown, status = 200): Response => Response.json(body, { status }),
logger: () => undefined,
mergePromptHistory: (items: PromptHistoryItem[]) => items,
nowIso: () => "2026-05-19T00:10:00.000Z",
outputPromptHistory: () => [],
pageBySeq,
parseLimit: () => 100,
parseSeqParam: () => null,
queueIdOf: (task: QueueTask) => task.queueId,
queuedStatusReason: (): QueuedStatusReason | null => null,
queuedTaskPromptEditable: () => false,
taskQueueEnteredAt: (task: QueueTask) => task.queueEnteredAt,
});
}
function fixtureTask(): QueueTask {
const at = "2026-05-19T00:00:00.000Z";
return {
id: "codex_trace_contract",
queueId: "default",
queueEnteredAt: at,
prompt: "Trace summary contract fixture",
basePrompt: "Trace summary contract fixture",
referenceTaskIds: [],
referenceInjection: null,
providerId: "D601",
cwd: "/workspace",
model: "gpt-5.5",
reasoningEffort: null,
executionMode: "default",
maxAttempts: 99,
status: "running",
createdAt: at,
updatedAt: "2026-05-19T00:06:30.000Z",
startedAt: at,
finishedAt: null,
readAt: null,
currentAttempt: 2,
currentMode: "retry",
codexThreadId: "thread_trace_contract",
activeTurnId: "turn_trace_contract",
finalResponse: "",
lastError: null,
lastJudge: { decision: "retry", confidence: 1, reason: "attempt 1 asked for retry", source: "fallback" },
judgeFailCount: 0,
promptHistory: [],
output: [
{ seq: 1, at, channel: "user", text: "Trace summary contract fixture", method: "enqueue" },
{ seq: 2, at: "2026-05-19T00:00:10.000Z", channel: "system", text: "attempt 1 / 99", method: "queue" },
{ seq: 3, at: "2026-05-19T00:01:00.000Z", channel: "command", text: "rg trace-summary src/components/microservices/code-queue/src", method: "item/started", itemId: "call-1" },
{ seq: 4, at: "2026-05-19T00:02:00.000Z", channel: "system", text: "judge=retry confidence=1 source=fallback: attempt 1 asked for retry", method: "judge" },
],
events: [],
attempts: [
{
index: 1,
mode: "initial",
startedAt: "2026-05-19T00:00:10.000Z",
finishedAt: "2026-05-19T00:02:00.000Z",
terminalStatus: "completed",
transportClosedBeforeTerminal: false,
appServerExitCode: 0,
appServerSignal: null,
error: null,
finalResponse: "Attempt 1 response",
finalResponsePreview: "Attempt 1 response",
finalResponseChars: 18,
stderrTail: "",
judge: { decision: "retry", confidence: 1, reason: "attempt 1 asked for retry", source: "fallback" },
judgeAt: "2026-05-19T00:02:00.000Z",
judgeSeq: 4,
outputStartSeq: 2,
outputEndSeq: 4,
},
],
cancelRequested: false,
nextPrompt: null,
nextMode: null,
};
}
function attempt2Steps(): OaTraceStepSummary[] {
return [
{
eventSequence: 20,
seq: 20,
at: "2026-05-19T00:06:00.000Z",
kind: "ran",
title: "Run",
status: "item/started",
summaryLines: ["attempt 2 / 99", "pnpm test"],
rawSeqs: [20],
scopeId: "task:codex_trace_contract:attempt:2",
attemptIndex: 2,
source: "oa-event-flow",
},
{
eventSequence: 21,
seq: 21,
at: "2026-05-19T00:06:20.000Z",
kind: "explored",
title: "Read",
status: "item/completed",
summaryLines: ["src/components/microservices/code-queue/src/task-view.ts"],
rawSeqs: [21],
scopeId: "task:codex_trace_contract:attempt:2",
attemptIndex: 2,
source: "oa-event-flow",
},
];
}
export function runCodeQueueTraceSummaryContract(): JsonRecord {
configureFixtureTaskView();
const task = fixtureTask();
const steps = attempt2Steps();
const summary = taskTraceSummaryFixtureResponse(task, {
stats: null,
taskStats: null,
allSteps: [
{
eventSequence: 1,
seq: 1,
at: "2026-05-19T00:00:10.000Z",
kind: "message",
title: "Assistant message",
status: "item/completed",
summaryLines: ["Attempt 1 judge complete"],
rawSeqs: [4],
scopeId: "task:codex_trace_contract",
attemptIndex: null,
source: "oa-event-flow",
},
...steps,
],
attemptSteps: new Map([[2, steps]]),
}) as JsonRecord;
const attempts = Array.isArray(summary.attempts) ? summary.attempts.map(asRecord).filter((item): item is JsonRecord => item !== null) : [];
const attempt2 = attempts.find((attempt) => Number(attempt.index) === 2) ?? null;
const taskStats = asRecord(summary.traceStats);
const taskExecution = asRecord(summary.execution);
const attempt2Stats = asRecord(attempt2?.traceStats);
const attempt2Execution = asRecord(attempt2?.execution);
assertCondition(summary.currentAttempt === 2, "summary must retain currentAttempt=2", summary);
assertCondition(summary.statsSource === "raw-trace-fallback", "summary must distinguish raw trace fallback from empty STEP", summary);
assertCondition(summary.traceStatsState === "degraded", "summary must mark OA stats sync degraded", summary);
assertCondition(summary.traceStatsReason === "oa-event-flow-stats-unavailable-raw-trace-present", "summary must explain degraded OA sync", summary);
assertCondition(taskStats?.source === "oa-event-flow" && taskStats?.sourceHint === "raw-trace-fallback", "summary must expose countable synthetic stats with source hint", taskStats ?? {});
assertCondition(taskExecution?.statsSource === "oa-event-flow" && taskExecution?.traceStatsState === "degraded", "execution summary must stay countable while degraded", taskExecution ?? {});
assertCondition(Number(summary.stepCount ?? 0) > 0, "summary fallback STEP count must be visible", summary);
assertCondition(attempt2 !== null, "summary must materialize the latest running retry attempt", { attempts });
assertCondition(Number(attempt2?.stepCount ?? 0) > 0, "attempt 2 must expose live fallback STEP count", attempt2 ?? {});
assertCondition(attempt2Stats?.source === "oa-event-flow" && attempt2Stats?.sourceHint === "raw-trace-fallback", "attempt 2 fallback stats must remain countable", attempt2Stats ?? {});
assertCondition(attempt2Execution?.statsSource === "oa-event-flow" && attempt2Execution?.traceStatsState === "degraded", "attempt 2 execution must be countable while degraded", attempt2Execution ?? {});
return {
ok: true,
checks: [
{ name: "code-queue:trace-summary-latest-attempt-visible", ok: true },
{ name: "code-queue:trace-summary-raw-trace-step-fallback", ok: true },
],
taskId: task.id,
stepCount: summary.stepCount,
statsSource: summary.statsSource,
traceStatsState: summary.traceStatsState,
attempt2StepCount: attempt2?.stepCount,
};
}
if (import.meta.main) {
process.stdout.write(`${JSON.stringify(runCodeQueueTraceSummaryContract(), null, 2)}\n`);
}