fix: 修复 command result 长 trace 摘要
This commit is contained in:
+72
-16
@@ -2,10 +2,30 @@ import type { AgentRunStore } from "./store.js";
|
||||
import type { CommandRecord, JsonRecord, JsonValue, RunEvent, RunRecord, RunnerJobRecord, TerminalStatus } from "../common/types.js";
|
||||
import { outputBytesFromPayload, outputTruncatedFromPayload } from "../common/output.js";
|
||||
|
||||
const RESULT_EVENT_PAGE_LIMIT = 500;
|
||||
const RESULT_EVENT_MAX_PAGES = 200;
|
||||
|
||||
interface ResultEventPage {
|
||||
events: RunEvent[];
|
||||
capped: boolean;
|
||||
nextAfterSeq: number | null;
|
||||
}
|
||||
|
||||
interface AssistantReplySummary {
|
||||
text: string;
|
||||
seq: number | null;
|
||||
source: string | null;
|
||||
final: boolean;
|
||||
replyAuthority: boolean;
|
||||
textTruncated: boolean;
|
||||
outputTruncated: boolean;
|
||||
}
|
||||
|
||||
export async function buildRunResult(store: AgentRunStore, runId: string, commandId?: string): Promise<JsonRecord> {
|
||||
const run = await store.getRun(runId);
|
||||
const command = await selectCommand(store, runId, commandId);
|
||||
const events = await store.listEvents(runId, 0, 500);
|
||||
const eventPage = await listResultEvents(store, runId);
|
||||
const events = eventPage.events;
|
||||
const scopedEvents = command ? eventsForCommand(events, command.id) : events;
|
||||
const jobs = await store.listRunnerJobs(runId, command?.id);
|
||||
const latestJob = jobs.at(-1) ?? null;
|
||||
@@ -30,12 +50,29 @@ export async function buildRunResult(store: AgentRunStore, runId: string, comman
|
||||
terminalStatus: terminal,
|
||||
terminalSource,
|
||||
completed: terminal === "completed",
|
||||
reply,
|
||||
reply: reply.text,
|
||||
finalResponse: {
|
||||
text: reply.text,
|
||||
seq: reply.seq,
|
||||
source: reply.source,
|
||||
final: reply.final,
|
||||
replyAuthority: reply.replyAuthority,
|
||||
textTruncated: reply.textTruncated,
|
||||
outputTruncated: reply.outputTruncated,
|
||||
},
|
||||
finalAssistantSeq: reply.seq,
|
||||
finalAssistantSource: reply.source,
|
||||
finalAssistantTextTruncated: reply.textTruncated,
|
||||
finalAssistantOutputTruncated: reply.outputTruncated,
|
||||
failureKind,
|
||||
failureMessage,
|
||||
blocker,
|
||||
lastSeq: events.at(-1)?.seq ?? 0,
|
||||
eventCount: events.length,
|
||||
eventsCapped: eventPage.capped,
|
||||
nextAfterSeq: eventPage.nextAfterSeq,
|
||||
scopedEventCount: scopedEvents.length,
|
||||
scopedLastSeq: scopedEvents.at(-1)?.seq ?? 0,
|
||||
artifactSummary: artifactSummary(scopedEvents),
|
||||
sessionRef: sessionSummary(run),
|
||||
resourceBundleRef: resourceBundleSummary(run, events),
|
||||
@@ -43,6 +80,21 @@ export async function buildRunResult(store: AgentRunStore, runId: string, comman
|
||||
};
|
||||
}
|
||||
|
||||
async function listResultEvents(store: AgentRunStore, runId: string): Promise<ResultEventPage> {
|
||||
const events: RunEvent[] = [];
|
||||
let afterSeq = 0;
|
||||
for (let pageIndex = 0; pageIndex < RESULT_EVENT_MAX_PAGES; pageIndex += 1) {
|
||||
const page = await store.listEvents(runId, afterSeq, RESULT_EVENT_PAGE_LIMIT);
|
||||
if (page.length === 0) return { events, capped: false, nextAfterSeq: null };
|
||||
events.push(...page);
|
||||
const nextAfterSeq = page.at(-1)?.seq ?? afterSeq;
|
||||
if (nextAfterSeq <= afterSeq) return { events, capped: true, nextAfterSeq: afterSeq };
|
||||
afterSeq = nextAfterSeq;
|
||||
if (page.length < RESULT_EVENT_PAGE_LIMIT) return { events, capped: false, nextAfterSeq: null };
|
||||
}
|
||||
return { events, capped: true, nextAfterSeq: events.at(-1)?.seq ?? afterSeq };
|
||||
}
|
||||
|
||||
async function selectCommand(store: AgentRunStore, runId: string, commandId?: string): Promise<CommandRecord | null> {
|
||||
if (commandId) {
|
||||
const command = await store.getCommand(commandId);
|
||||
@@ -89,21 +141,25 @@ function messageFromEvents(events: RunEvent[]): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function assistantReply(events: RunEvent[]): string {
|
||||
function assistantReply(events: RunEvent[]): AssistantReplySummary {
|
||||
const assistantEvents = events.filter((event) => event.type === "assistant_message");
|
||||
const authoritative = assistantEvents
|
||||
.filter((event) => event.payload.replyAuthority === true || event.payload.final === true)
|
||||
.map((event) => textPayload(event.payload))
|
||||
.filter((text) => text.length > 0);
|
||||
const latestAuthoritative = authoritative.at(-1);
|
||||
if (latestAuthoritative) return latestAuthoritative;
|
||||
const completedAgentMessages = assistantEvents
|
||||
.filter((event) => event.payload.source === "completed-agent-message")
|
||||
.map((event) => textPayload(event.payload))
|
||||
.filter((text) => text.length > 0);
|
||||
const latestCompletedAgentMessage = completedAgentMessages.at(-1);
|
||||
if (latestCompletedAgentMessage) return latestCompletedAgentMessage;
|
||||
return assistantEvents.map((event) => textPayload(event.payload)).filter((text) => text.length > 0).join("");
|
||||
const latestAuthoritative = [...assistantEvents].reverse().find((event) => (event.payload.replyAuthority === true || event.payload.final === true) && textPayload(event.payload).length > 0);
|
||||
if (latestAuthoritative) return assistantReplySummary(latestAuthoritative);
|
||||
const latestAssistant = [...assistantEvents].reverse().find((event) => textPayload(event.payload).length > 0);
|
||||
if (latestAssistant) return assistantReplySummary(latestAssistant);
|
||||
return { text: "", seq: null, source: null, final: false, replyAuthority: false, textTruncated: false, outputTruncated: false };
|
||||
}
|
||||
|
||||
function assistantReplySummary(event: RunEvent): AssistantReplySummary {
|
||||
return {
|
||||
text: textPayload(event.payload),
|
||||
seq: event.seq,
|
||||
source: typeof event.payload.source === "string" ? event.payload.source : null,
|
||||
final: event.payload.final === true,
|
||||
replyAuthority: event.payload.replyAuthority === true,
|
||||
textTruncated: event.payload.textTruncated === true,
|
||||
outputTruncated: event.payload.outputTruncated === true,
|
||||
};
|
||||
}
|
||||
|
||||
function textPayload(payload: JsonRecord): string {
|
||||
|
||||
Reference in New Issue
Block a user