fix: 收敛 session detail 按 id 精确拉取 (#137)
Co-authored-by: Codex <codex@pikas.tech>
This commit is contained in:
+57
-7
@@ -355,14 +355,16 @@ function withSessionDetailCommands(items: JsonRecord[], kind: "trace" | "output"
|
||||
const seq = numberValue(item.seq);
|
||||
const itemId = stringValue(item.itemId);
|
||||
const eventId = stringValue(item.eventId);
|
||||
const detail = seq === null ? null : `./scripts/agentrun sessions ${kind} ${sessionId} --seq ${seq}${runId ? ` --run-id ${runId}` : ""} --full`;
|
||||
const pageHint = seq === null ? "" : ` --after-seq ${Math.max(0, seq - 1)} --limit 1`;
|
||||
const runFlag = runId ? ` --run-id ${runId}` : "";
|
||||
const detail = seq === null ? null : `./scripts/agentrun sessions ${kind} ${sessionId}${pageHint} --seq ${seq}${runFlag} --full`;
|
||||
return {
|
||||
...item,
|
||||
...(detail || itemId || eventId ? {
|
||||
detailCommands: {
|
||||
...(detail ? { seq: detail } : {}),
|
||||
...(itemId ? { item: `./scripts/agentrun sessions ${kind} ${sessionId} --item-id ${itemId}${runId ? ` --run-id ${runId}` : ""} --full` } : {}),
|
||||
...(eventId ? { event: `./scripts/agentrun sessions ${kind} ${sessionId} --event-id ${eventId}${runId ? ` --run-id ${runId}` : ""} --full` } : {}),
|
||||
...(itemId ? { item: `./scripts/agentrun sessions ${kind} ${sessionId}${pageHint} --item-id ${itemId}${runFlag} --full` } : {}),
|
||||
...(eventId ? { event: `./scripts/agentrun sessions ${kind} ${sessionId}${pageHint} --event-id ${eventId}${runFlag} --full` } : {}),
|
||||
},
|
||||
} : {}),
|
||||
};
|
||||
@@ -390,6 +392,13 @@ function sessionEventDetailResult(page: JsonValue, options: { kind: "trace" | "o
|
||||
},
|
||||
});
|
||||
}
|
||||
return sessionEventDetailResultFromMatches(page, matches, options);
|
||||
}
|
||||
|
||||
function sessionEventDetailResultFromMatches(page: JsonValue, matches: JsonRecord[], options: { kind: "trace" | "output"; sessionId: string; runId: string | null; summaryChars: number; filter: SessionEventDetailFilter; pagesScanned?: number; eventsScanned?: number }): JsonRecord {
|
||||
const record = jsonRecordValue(page);
|
||||
if (!record) throw new AgentRunError("schema-invalid", "sessions event response must be an object", { httpStatus: 2 });
|
||||
const events = eventPageItems(page);
|
||||
const runId = stringValue(record.runId) ?? options.runId;
|
||||
return {
|
||||
action: `session-${options.kind}-event-detail`,
|
||||
@@ -398,6 +407,8 @@ function sessionEventDetailResult(page: JsonValue, options: { kind: "trace" | "o
|
||||
filter: options.filter as unknown as JsonRecord,
|
||||
sourceCount: events.length,
|
||||
count: matches.length,
|
||||
...(options.pagesScanned === undefined ? {} : { pagesScanned: options.pagesScanned }),
|
||||
...(options.eventsScanned === undefined ? {} : { eventsScanned: options.eventsScanned }),
|
||||
valuesPrinted: false,
|
||||
items: matches.map((event) => ({
|
||||
summary: summarizeRunEvent(event, options.summaryChars),
|
||||
@@ -829,15 +840,19 @@ async function listSessions(args: ParsedArgs): Promise<JsonValue> {
|
||||
async function sessionEvents(args: ParsedArgs, sessionId: string, kind: "trace" | "output"): Promise<JsonValue> {
|
||||
const params = new URLSearchParams();
|
||||
const requestedSeq = optionalIntegerFlag(args, "seq", { min: 0 });
|
||||
const afterSeq = requestedSeq !== null && optionalFlag(args, "after-seq") === null ? Math.max(0, requestedSeq - 1) : integerFlag(args, "after-seq", 0, { min: 0 });
|
||||
const hasExplicitAfterSeq = optionalFlag(args, "after-seq") !== null;
|
||||
const afterSeq = requestedSeq !== null && !hasExplicitAfterSeq ? Math.max(0, requestedSeq - 1) : integerFlag(args, "after-seq", 0, { min: 0 });
|
||||
const limit = requestedSeq !== null && optionalFlag(args, "limit") === null ? 1 : integerFlag(args, "limit", 100, { min: 1, max: 500 });
|
||||
const runId = optionalFlag(args, "run-id");
|
||||
const detailFilter = sessionEventDetailFilter(args, requestedSeq);
|
||||
if (detailFilter && requestedSeq === null && !hasExplicitAfterSeq && (detailFilter.eventId || detailFilter.itemId)) {
|
||||
return scanSessionEventDetail(args, { kind, sessionId, runId, afterSeq, limit, summaryChars: integerFlag(args, "summary-chars", 1_200, { min: 1, max: 8_000 }), filter: detailFilter });
|
||||
}
|
||||
params.set("afterSeq", String(afterSeq));
|
||||
params.set("limit", String(limit));
|
||||
if (runId) params.set("runId", runId);
|
||||
const query = params.toString();
|
||||
const page = await client(args).get(`/api/v1/sessions/${encodeURIComponent(sessionId)}/${kind}${query ? `?${query}` : ""}`);
|
||||
const detailFilter = sessionEventDetailFilter(args, requestedSeq);
|
||||
if (detailFilter) return sessionEventDetailResult(page, { kind, sessionId, runId, summaryChars: integerFlag(args, "summary-chars", 1_200, { min: 1, max: 8_000 }), filter: detailFilter });
|
||||
if (wantsExpandedOutput(args)) return page;
|
||||
return summarizeSessionEventPage(page, {
|
||||
@@ -852,6 +867,41 @@ async function sessionEvents(args: ParsedArgs, sessionId: string, kind: "trace"
|
||||
});
|
||||
}
|
||||
|
||||
async function scanSessionEventDetail(args: ParsedArgs, options: { kind: "trace" | "output"; sessionId: string; runId: string | null; afterSeq: number; limit: number; summaryChars: number; filter: SessionEventDetailFilter }): Promise<JsonRecord> {
|
||||
const maxPages = integerFlag(args, "detail-scan-pages", 20, { min: 1, max: 100 });
|
||||
let afterSeq = options.afterSeq;
|
||||
let pagesScanned = 0;
|
||||
let eventsScanned = 0;
|
||||
while (pagesScanned < maxPages) {
|
||||
const params = new URLSearchParams();
|
||||
params.set("afterSeq", String(afterSeq));
|
||||
params.set("limit", String(options.limit));
|
||||
if (options.runId) params.set("runId", options.runId);
|
||||
const query = params.toString();
|
||||
const page = await client(args).get(`/api/v1/sessions/${encodeURIComponent(options.sessionId)}/${options.kind}${query ? `?${query}` : ""}`);
|
||||
const events = eventPageItems(page);
|
||||
pagesScanned += 1;
|
||||
eventsScanned += events.length;
|
||||
const matches = events.filter((event) => matchesSessionEventFilter(event, options.filter));
|
||||
if (matches.length > 0) return sessionEventDetailResultFromMatches(page, matches, { kind: options.kind, sessionId: options.sessionId, runId: options.runId, summaryChars: options.summaryChars, filter: options.filter, pagesScanned, eventsScanned });
|
||||
const lastSeq = events.length > 0 ? numberValue(events[events.length - 1]?.seq) : null;
|
||||
const cursorSeq = numberValue(jsonRecordValue(page)?.cursor);
|
||||
const nextSeq = cursorSeq ?? lastSeq;
|
||||
if (nextSeq === null || nextSeq <= afterSeq) break;
|
||||
afterSeq = nextSeq;
|
||||
}
|
||||
throw new AgentRunError("schema-invalid", "no session event matched --event-id/--item-id in scanned pages", {
|
||||
httpStatus: 2,
|
||||
details: {
|
||||
filter: options.filter as unknown as JsonRecord,
|
||||
pagesScanned,
|
||||
eventsScanned,
|
||||
nextAfterSeq: afterSeq,
|
||||
hint: "use the detailCommands from the summary, pass --seq, or add --after-seq/--limit near the event if the trace is longer than the scan window",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function sessionCreate(args: ParsedArgs, positionalSessionId: string | null): Promise<JsonRecord> {
|
||||
const sessionId = positionalSessionId ?? optionalFlag(args, "session-id") ?? newSessionId();
|
||||
const profile = normalizeProfile(optionalFlag(args, "profile") ?? optionalFlag(args, "backend-profile") ?? "codex");
|
||||
@@ -1581,8 +1631,8 @@ function help(args: ParsedArgs, group?: string): JsonRecord {
|
||||
"sessions turn [sessionId] [--json-file <run-base.json>|--json-stdin] [--prompt-file <file>|--prompt-stdin|--prompt <text>] [--profile codex|deepseek|minimax-m3|dsflash-go|<dynamic-profile>|M3] [--runner-json-file <job.json>|--runner-json-stdin]",
|
||||
"sessions steer <sessionId> [--prompt-file <file>|--prompt-stdin|--prompt <text>]",
|
||||
"sessions cancel <sessionId> [--reason <text>] [--full|--raw]",
|
||||
"sessions trace <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>] [--summary-chars <n>] [--include-output] [--seq <n>|--event-id <id>|--item-id <id>] [--full|--raw]",
|
||||
"sessions output <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>] [--summary-chars <n>] [--include-output] [--seq <n>|--event-id <id>|--item-id <id>] [--full|--raw]",
|
||||
"sessions trace <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>] [--summary-chars <n>] [--include-output] [--seq <n>|--event-id <id>|--item-id <id>] [--detail-scan-pages <n>] [--full|--raw]",
|
||||
"sessions output <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>] [--summary-chars <n>] [--include-output] [--seq <n>|--event-id <id>|--item-id <id>] [--detail-scan-pages <n>] [--full|--raw]",
|
||||
"sessions read <sessionId> [--reader-id <reader>] [--full|--raw]",
|
||||
"commands create <runId> --type turn|steer|interrupt --json-file <payload.json>|--json-stdin",
|
||||
"commands show <commandId> --run-id <runId>",
|
||||
|
||||
Reference in New Issue
Block a user