80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
import { asString, asNumber, parseObject, parseJson } from "@agentcompany/adapter-utils/server-utils";
|
|
|
|
export function parseCodexJsonl(stdout: string) {
|
|
let sessionId: string | null = null;
|
|
const messages: string[] = [];
|
|
let errorMessage: string | null = null;
|
|
let costUsd: number | null = null;
|
|
const usage = {
|
|
inputTokens: 0,
|
|
cachedInputTokens: 0,
|
|
outputTokens: 0,
|
|
};
|
|
|
|
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
const line = rawLine.trim();
|
|
if (!line) continue;
|
|
|
|
const event = parseJson(line);
|
|
if (!event) continue;
|
|
|
|
const type = asString(event.type, "");
|
|
if (type === "thread.started") {
|
|
sessionId = asString(event.thread_id, sessionId ?? "") || sessionId;
|
|
continue;
|
|
}
|
|
|
|
if (type === "error") {
|
|
const msg = asString(event.message, "").trim();
|
|
if (msg) errorMessage = msg;
|
|
continue;
|
|
}
|
|
|
|
if (type === "item.completed") {
|
|
const item = parseObject(event.item);
|
|
if (asString(item.type, "") === "agent_message") {
|
|
const text = asString(item.text, "");
|
|
if (text) messages.push(text);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (type === "turn.completed") {
|
|
const usageObj = parseObject(event.usage);
|
|
usage.inputTokens = asNumber(usageObj.input_tokens, usage.inputTokens);
|
|
usage.cachedInputTokens = asNumber(usageObj.cached_input_tokens, usage.cachedInputTokens);
|
|
usage.outputTokens = asNumber(usageObj.output_tokens, usage.outputTokens);
|
|
const rawCost = event.total_cost_usd;
|
|
if (typeof rawCost === "number" && Number.isFinite(rawCost)) costUsd = rawCost;
|
|
continue;
|
|
}
|
|
|
|
if (type === "turn.failed") {
|
|
const err = parseObject(event.error);
|
|
const msg = asString(err.message, "").trim();
|
|
if (msg) errorMessage = msg;
|
|
const rawCost = event.total_cost_usd;
|
|
if (typeof rawCost === "number" && Number.isFinite(rawCost)) costUsd = rawCost;
|
|
}
|
|
}
|
|
|
|
return {
|
|
sessionId,
|
|
summary: messages.join("\n\n").trim(),
|
|
usage,
|
|
costUsd,
|
|
errorMessage,
|
|
};
|
|
}
|
|
|
|
export function isCodexUnknownSessionError(stdout: string, stderr: string): boolean {
|
|
const haystack = `${stdout}\n${stderr}`
|
|
.split(/\r?\n/)
|
|
.map((line) => line.trim())
|
|
.filter(Boolean)
|
|
.join("\n");
|
|
return /unknown (session|thread)|session .* not found|thread .* not found|conversation .* not found|missing rollout path for thread|state db missing rollout path/i.test(
|
|
haystack,
|
|
);
|
|
}
|