feat: add code agent otel spans

This commit is contained in:
lyon
2026-06-19 23:05:50 +08:00
parent bfceacaee1
commit 69b8e03661
4 changed files with 200 additions and 1 deletions
@@ -16,6 +16,7 @@ import {
} from "./server-http-utils.ts";
import { backendPerformanceRouteTemplate, currentBackendPerformanceContext } from "./backend-performance.ts";
import { agentRunResultSyncDeferred, buildAgentRunProjectionEventsFetchPlan, buildWorkbenchProjectionStateUpdate } from "./workbench-projection-cursor.ts";
import { codeAgentOtelTraceFields, codeAgentOtelTraceContext, emitCodeAgentOtelSpan } from "./otel-trace.ts";
const ADAPTER_ID = "agentrun-v01";
const DEFAULT_AGENTRUN_MGR_URL = "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080";
@@ -226,6 +227,7 @@ export function initialAgentRunChatResult({ params = {}, options = {}, traceId }
status: "running",
shortConnection: true,
traceId,
...codeAgentOtelTraceFields(traceId, env),
projectId: firstNonEmpty(params.projectId) || null,
conversationId: safeConversationId(params.conversationId) || null,
sessionId: safeSessionId(params.sessionId) || agentRunSessionId(traceId),
@@ -276,6 +278,7 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
waitingFor: "agentrun-run-reuse-or-create",
adapter: ADAPTER_ID,
managerHost: new URL(managerUrl).hostname,
...codeAgentOtelTraceFields(traceId, env),
...agentRunPromptEventFields(promptEvidence),
valuesPrinted: false
}, backendProfile), agentRunTraceMeta(env, params));
@@ -386,8 +389,10 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
throw error;
}
const runInput = buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, sessionId, toolCapabilities });
const runCreateStartedAt = Date.now();
run = await agentRunJson(fetchImpl, managerUrl, "/api/v1/runs", { method: "POST", body: runInput, timeoutMs, env });
const runId = requiredString(run?.id, "run.id");
void emitCodeAgentOtelSpan("agentrun_run_create", traceId, env, { startTimeMs: runCreateStartedAt, attributes: { runId, backendProfile, managerUrl } });
traceStore.append(traceId, agentRunTraceEvent({
type: "backend", status: "running",
label: "agentrun:run:created",
@@ -395,8 +400,10 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
runId, backendProfile, waitingFor: "agentrun-command-create", valuesPrinted: false,
}, backendProfile));
const commandInput = buildAgentRunCommandInput({ params, traceId, backendProfile, sessionId });
const commandCreateStartedAt = Date.now();
command = await agentRunJson(fetchImpl, managerUrl, "/api/v1/runs/" + encodeURIComponent(runId) + "/commands", { method: "POST", body: commandInput, timeoutMs, env });
const commandId = requiredString(command?.id, "command.id");
void emitCodeAgentOtelSpan("agentrun_command_create", traceId, env, { startTimeMs: commandCreateStartedAt, attributes: { runId, commandId, backendProfile, managerUrl } });
traceStore.append(traceId, agentRunTraceEvent({
type: "backend", status: "running",
label: "agentrun:command:created",
@@ -405,7 +412,9 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
}, backendProfile));
const runnerJobInput = buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities, backendProfile });
try {
const runnerJobStartedAt = Date.now();
runnerJob = await agentRunJson(fetchImpl, managerUrl, "/api/v1/runs/" + encodeURIComponent(runId) + "/runner-jobs", { method: "POST", body: runnerJobInput, timeoutMs, env });
void emitCodeAgentOtelSpan("agentrun_runner_job_create", traceId, env, { startTimeMs: runnerJobStartedAt, attributes: { runId, commandId, backendProfile, managerUrl, jobName: runnerJob?.jobName ?? runnerJob?.jobIdentity?.name ?? null } });
} catch (error) {
if (attempt === 0 && await shouldResetSessionAfterEviction("session-store-evicted", error?.message)) {
sessionReset = true;
@@ -1017,6 +1026,8 @@ function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, ses
metadata: {
adapter: ADAPTER_ID,
hwlabTraceId: traceId,
otelTraceId: codeAgentOtelTraceContext(traceId).traceId,
traceparent: codeAgentOtelTraceContext(traceId).traceparent,
hwlabApi: "/v1/agent/chat",
hwlabProjectId,
hwlabSessionId: safeSessionId(params.sessionId) || null,
@@ -1044,6 +1055,7 @@ function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, ses
traceSink: {
kind: "hwlab-cloud-api",
traceId,
...codeAgentOtelTraceFields(traceId, env),
resultUrl: `/v1/agent/chat/result/${encodeURIComponent(traceId)}`,
traceUrl: `/v1/agent/traces/${encodeURIComponent(traceId)}`,
valuesPrinted: false
@@ -1946,6 +1958,7 @@ async function fetchAgentRunEventsForTrace({ fetchImpl, managerUrl, timeoutMs, e
const limit = parsePositiveInteger(mapping.eventsPageLimit ?? env?.HWLAB_CODE_AGENT_AGENTRUN_EVENTS_PAGE_LIMIT, 500);
const path = `/api/v1/runs/${encodeURIComponent(runId)}/events?afterSeq=${encodeURIComponent(String(afterSeq))}&limit=${encodeURIComponent(String(limit))}`;
const response = await agentRunJson(fetchImpl, managerUrl, path, { method: "GET", timeoutMs, env });
void emitCodeAgentOtelSpan("projection_sync", mapping.traceId ?? mapping.hwlabTraceId ?? mapping.businessTraceId, env, { attributes: { runId, commandId: currentCommandId || null, afterSeq, rawEventCount: Array.isArray(response?.items) ? response.items.length : 0 } });
const rawEvents = Array.isArray(response?.items) ? response.items : [];
const events = rawEvents.filter((event) => agentRunEventBelongsToTrace(event, { currentCommandId, afterSeq, endSeq }));
return {
@@ -2480,6 +2493,7 @@ function agentRunMapping({ env, managerUrl, backendProfile, run, command, runner
terminalStatus: null,
lastSeq: 0,
traceId,
...codeAgentOtelTraceFields(traceId, env),
sessionId: run?.sessionRef?.sessionId ?? null,
conversationId: run?.sessionRef?.conversationId ?? null,
threadId: run?.sessionRef?.threadId ?? null,