From ecbb13cdf4474cf159080dd3bfef96d01c46ed54 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:32:13 +0800 Subject: [PATCH] fix: expose trace pagination in cli and otel (#1687) --- internal/cloud/server-code-agent-http.ts | 15 +++++++++++++- tools/src/hwlab-cli-lib.ts | 26 ++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/internal/cloud/server-code-agent-http.ts b/internal/cloud/server-code-agent-http.ts index 4314f522..457a5b5b 100644 --- a/internal/cloud/server-code-agent-http.ts +++ b/internal/cloud/server-code-agent-http.ts @@ -3242,7 +3242,20 @@ export async function handleCodeAgentTraceHttp(request, response, url, options) const statusCode = context.found ? 200 : 404; void emitCodeAgentOtelSpan("trace_events_read", traceId, requestOptions.env ?? process.env, { startTimeMs: startedAt, - attributes: { "http.method": "GET", "http.route": "/v1/agent/traces/:traceId", "http.status_code": statusCode, returnedEvents: Array.isArray(body?.events) ? body.events.length : 0, found: Boolean(context.found) } + attributes: { + "http.method": "GET", + "http.route": "/v1/agent/traces/:traceId", + "http.status_code": statusCode, + found: Boolean(context.found), + returnedEvents: Array.isArray(body?.events) ? body.events.length : 0, + sinceSeq: pageOptions.sinceSeq, + limit: pageOptions.limit, + fromSeq: body?.range?.fromSeq ?? null, + toSeq: body?.range?.toSeq ?? null, + totalEvents: body?.range?.total ?? body?.eventCount ?? null, + hasMore: Boolean(body?.hasMore), + fullTraceLoaded: Boolean(body?.fullTraceLoaded) + } }); sendJson(response, statusCode, codeAgentCompatProjectionPayload(body, context)); } diff --git a/tools/src/hwlab-cli-lib.ts b/tools/src/hwlab-cli-lib.ts index 4f6a5daa..857df170 100644 --- a/tools/src/hwlab-cli-lib.ts +++ b/tools/src/hwlab-cli-lib.ts @@ -1007,7 +1007,7 @@ async function agentCommand(context: any) { } if (subcommand === "trace") { const traceId = requiredTraceId(context.rest[1] ?? context.parsed.traceId); - const pathName = `/v1/agent/traces/${encodeURIComponent(traceId)}`; + const pathName = `/v1/agent/traces/${encodeURIComponent(traceId)}${agentTraceQueryString(context.parsed)}`; const turnPath = `/v1/agent/turns/${encodeURIComponent(traceId)}`; const turnResponse = await requestJson({ ...context, method: "GET", path: turnPath }); const response = await requestJson({ ...context, method: "GET", path: pathName }); @@ -1376,7 +1376,7 @@ function agentHelp() { "composer submit --message TEXT|--message-file PATH [--profile NAME] [default: auto turn/steer]", "send --message TEXT --wait [--timeout-ms N] [--poll-interval-ms N]", "result TRACE_ID [--full]", - "trace TRACE_ID [--render web] [--limit N] [--full]", + "trace TRACE_ID [--render web] [--after-seq N|--since-seq N] [--limit N|--tail N] [--full]", "inspect --trace-id TRACE_ID|--session-id ID|--thread-id ID", "steer TRACE_ID --message TEXT|--message-file PATH [--session-id ID] [--thread-id ID]", "cancel TRACE_ID" @@ -1384,6 +1384,28 @@ function agentHelp() { }); } +function agentTraceQueryString(parsed: any) { + const query = new URLSearchParams(); + const sinceSeq = nonNegativeOption(parsed.sinceSeq ?? parsed.afterSeq ?? parsed.after); + if (sinceSeq !== undefined) query.set("sinceSeq", String(sinceSeq)); + const limit = positiveOption(parsed.limit ?? parsed.tail); + if (limit !== undefined) query.set("limit", String(limit)); + const text = query.toString(); + return text ? `?${text}` : ""; +} + +function nonNegativeOption(value: unknown) { + const parsed = numberOption(value); + if (parsed === undefined || parsed < 0) return undefined; + return Math.trunc(parsed); +} + +function positiveOption(value: unknown) { + const parsed = numberOption(value); + if (parsed === undefined || parsed <= 0) return undefined; + return Math.trunc(parsed); +} + async function sessionCommand(context: any) { const subcommand = context.rest[0] || "list"; if (wantsHelp(context)) return sessionHelp();