// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010403 API契约 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010205 HWLAB接入 draft-2026-06-25-p0-session-warm-runner-contract; PJ2026-0102 Agent编排 draft-2026-06-17-r0; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. // Responsibility: Shared Code Agent HTTP lifecycle, billing, ownership, projection-read, and response helpers. import { createHash, randomUUID } from "node:crypto"; import { M3_IO_CONTROL_ROUTE, M3_STATUS_ROUTE, describeM3StatusLive, handleM3IoControl } from "./m3-io-control.ts"; import { agentRunSessionEvidence, cancelAgentRunChatTurn, codeAgentAgentRunAdapterEnabled, initialAgentRunChatResult, loadPersistedAgentRunResult, steerAgentRunChatTurn, submitAgentRunChatTurn } from "./code-agent-agentrun-adapter.ts"; import { createCodeAgentErrorPayload, handleCodeAgentChat } from "./code-agent-chat.ts"; import { defaultCodeAgentTraceStore } from "./code-agent-trace-store.ts"; import { codeAgentSessionLifecycleSummary } from "./code-agent-session-lifecycle.ts"; import { messageAuthorityTextValue } from "./code-agent-agentrun-prompt.ts"; import { recordWorkbenchSessionOwner } from "./workbench-projection-writer.ts"; import { createWorkbenchReadModel } from "./workbench-read-model.ts"; import { codeAgentOtelTraceFields, emitCodeAgentOtelSpan } from "./otel-trace.ts"; import { firstHeaderValue, getHeader, parsePositiveInteger, positiveInteger, readBody, safeConversationId, safeOpaqueId, safeSessionId, safeTraceId, sendJson, truthyFlag } from "./server-http-utils.ts"; const DEFAULT_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT = 120; const DEFAULT_CODE_AGENT_TRACE_PAGE_LIMIT = 100; const MAX_CODE_AGENT_TRACE_PAGE_LIMIT = 100; const DEFAULT_CODE_AGENT_TURN_STATUS_REFRESH_TIMEOUT_MS = 2500; const DEFAULT_CODE_AGENT_PROJECT_ID = "prj_hwpod_workbench"; const DEFAULT_CODE_AGENT_PROVIDER_PROFILE = "deepseek"; const CODE_AGENT_TERMINAL_STATUSES = new Set(["completed", "failed", "blocked", "timeout", "cancelled", "canceled"]); const CODE_AGENT_PROVIDER_PROFILE_ALIASES = Object.freeze({ codex: "codex-api" }); const CODE_AGENT_PROVIDER_PROFILE_ID_PATTERN = /^[a-z0-9][a-z0-9.-]{0,63}$/u; const CODE_AGENT_PROVIDER_PROFILE_LABELS = Object.freeze({ "deepseek": "DeepSeek", "codex-api": "Codex API", "gpt.pika": "gpt.pika", "minimax-m3": "MiniMax-M3 via AgentRun", "runtime-default": "运行默认" }); const DEFAULT_CODE_AGENT_CODEX_API_MODEL = "gpt-5.5"; const DEFAULT_CODE_AGENT_CODEX_API_BASE_URL = "http://127.0.0.1:49280/responses"; const DEFAULT_CODE_AGENT_DEEPSEEK_MODEL = "deepseek-chat"; const DEFAULT_CODE_AGENT_MINIMAX_M3_MODEL = "MiniMax-M3"; function normalizeCodeAgentProviderProfile(value) { const text = String(value ?? DEFAULT_CODE_AGENT_PROVIDER_PROFILE).trim().toLowerCase(); if (!text) return DEFAULT_CODE_AGENT_PROVIDER_PROFILE; if (text === "runtime-default") return text; const normalized = CODE_AGENT_PROVIDER_PROFILE_ALIASES[text] ?? text; return CODE_AGENT_PROVIDER_PROFILE_ID_PATTERN.test(normalized) ? normalized : DEFAULT_CODE_AGENT_PROVIDER_PROFILE; } function firstNonEmptyValue(...values) { for (const value of values) { const text = String(value ?? "").trim(); if (text) return text; } return null; } async function recordCodeAgentSessionInputFact({ params = {}, options = {}, traceId, delivery = "queue", status = "admitted", messageId = null, commandId = null, agentRun = null, error = null } = {}) { const runtimeStore = options.runtimeStore ?? null; if (typeof runtimeStore?.writeWorkbenchFacts !== "function") return null; const fact = buildCodeAgentSessionInputFact({ params, options, traceId, delivery, status, messageId, commandId, agentRun, error }); if (!fact) return null; return runtimeStore.writeWorkbenchFacts({ facts: { inputs: [fact] } }, codeAgentSessionInputRequestMeta(fact, params, options)); } function buildCodeAgentSessionInputFact({ params = {}, options = {}, traceId, delivery = "queue", status = "admitted", messageId = null, commandId = null, agentRun = null, error = null } = {}) { const resolvedTraceId = safeTraceId(traceId ?? params.traceId) || null; const lifecycle = codeAgentTurnLifecycleFields(resolvedTraceId, params); const sessionId = safeSessionId(params.sessionId ?? params.session?.sessionId) || null; if (!sessionId) return null; const resolvedMessageId = safeMessageId(messageId ?? params.messageId ?? lifecycle.userMessageId) || lifecycle.userMessageId; const resolvedCommandId = textValue(commandId ?? agentRun?.commandId ?? params.commandId ?? params.agentRun?.commandId) || null; const normalizedDelivery = codeAgentInputDelivery(delivery); const normalizedStatus = codeAgentInputStatus(status); const now = new Date().toISOString(); const sourceEventId = `${sessionId}:${lifecycle.turnId}:${normalizedDelivery}:${resolvedTraceId ?? resolvedCommandId ?? resolvedMessageId}`; // Command allocation happens after the initial admitting write. Keep one stable // row across admitting -> blocked/failed/promoted transitions for the trace. const inputId = stableCodeAgentInputId({ sessionId, turnId: lifecycle.turnId, traceId: resolvedTraceId, messageId: resolvedMessageId, delivery: normalizedDelivery, sourceEventId }); return { inputId, sessionId, turnId: lifecycle.turnId, traceId: resolvedTraceId, messageId: resolvedMessageId, commandId: resolvedCommandId, runId: textValue(agentRun?.runId ?? params.agentRun?.runId) || null, dispatchIntentId: textValue(agentRun?.dispatchIntentId ?? params.agentRun?.dispatchIntentId) || null, runnerJobId: textValue(agentRun?.runnerJobId ?? params.agentRun?.runnerJobId) || null, durableDispatch: agentRun?.durableDispatch === true || params.agentRun?.durableDispatch === true, delivery: normalizedDelivery, status: normalizedStatus, errorCode: textValue(error?.code ?? error?.error?.code) || null, sourceEventId, promptHash: params.message || params.prompt || params.text ? sha256Text(params.message ?? params.prompt ?? params.text).slice(0, 16) : null, textBytes: params.message || params.prompt || params.text ? Buffer.byteLength(String(params.message ?? params.prompt ?? params.text), "utf8") : 0, valuesRedacted: true, secretMaterialStored: false, createdAt: now, updatedAt: now }; } function codeAgentSessionInputRequestMeta(fact, params = {}, options = {}) { return { sessionId: fact.sessionId, traceId: fact.traceId, turnId: fact.turnId, messageId: fact.messageId, ownerUserId: options.actor?.id ?? params.ownerUserId, projectId: params.projectId ?? DEFAULT_CODE_AGENT_PROJECT_ID, valuesPrinted: false }; } function stableCodeAgentInputId(value) { const payload = Object.fromEntries(Object.entries(value ?? {}).filter(([, item]) => item !== undefined && item !== null && item !== "").sort(([left], [right]) => left.localeCompare(right))); return `wsi_${sha256Text(JSON.stringify(payload)).slice(0, 32)}`; } function codeAgentInputDelivery(value) { const text = textValue(value).toLowerCase(); return ["queue", "steer", "cancel"].includes(text) ? text : "queue"; } function codeAgentInputStatus(value) { const text = textValue(value).toLowerCase().replace(/-/gu, "_"); return ["admitting", "admitted", "promoted", "blocked", "failed", "canceled", "completed"].includes(text) ? text : "admitted"; } function codeAgentResultTimingFields(...sources) { const records = sources.filter((source) => source && typeof source === "object"); const timingSource = records.map((source) => source.timing).find((timing) => timing && typeof timing === "object") ?? {}; const startedAt = firstTimestampIso(timingSource.startedAt, ...records.map((source) => source.startedAt), ...records.map((source) => source.createdAt)); const lastEventAt = firstLatestTimestampIso(timingSource.lastEventAt, ...records.map((source) => source.lastEventAt), ...records.map((source) => source.updatedAt), ...records.map((source) => source.createdAt)); const finishedAt = firstLatestTimestampIso(timingSource.finishedAt, ...records.map((source) => source.finishedAt), ...records.map((source) => source.completedAt)); const durationMs = numberOrNull(timingSource.durationMs ?? records.map((source) => source.durationMs).find((value) => numberOrNull(value) !== null)); const observedAt = timestampIsoOrNull(timingSource.observedAt); const lastEventAgeMs = numberOrNull(timingSource.lastEventAgeMs); if (!startedAt && !lastEventAt && !finishedAt && durationMs === null && lastEventAgeMs === null) return {}; const timing = { ...(timingSource && typeof timingSource === "object" ? timingSource : {}), startedAt: startedAt ?? null, lastEventAt: lastEventAt ?? null, finishedAt: finishedAt ?? null, durationMs, observedAt: observedAt ?? null, lastEventAgeMs, valuesRedacted: timingSource.valuesRedacted !== false }; return { timing, startedAt: timing.startedAt, lastEventAt: timing.lastEventAt, finishedAt: timing.finishedAt, durationMs: timing.durationMs }; } function firstTimestampIso(...values) { for (const value of values) { const timestamp = timestampIsoOrNull(value); if (timestamp) return timestamp; } return null; } function firstLatestTimestampIso(...values) { let latest = null; let latestMs = Number.NEGATIVE_INFINITY; for (const value of values) { const timestamp = timestampIsoOrNull(value); if (!timestamp) continue; const ms = Date.parse(timestamp); if (!Number.isFinite(ms) || ms < latestMs) continue; latest = timestamp; latestMs = ms; } return latest; } function codeAgentChatShortConnectionRequested(request, params, options = {}) { const header = firstHeaderValue(request, "prefer"); const explicit = firstHeaderValue(request, "x-hwlab-short-connection"); const envValue = options.env?.HWLAB_CODE_AGENT_CHAT_SHORT_CONNECTION; return codeAgentAgentRunAdapterEnabled(options.env ?? process.env) || /(?:^|,)\s*respond-async\s*(?:,|$)/iu.test(String(header ?? "")) || truthyFlag(explicit) || params?.shortConnection === true || truthyFlag(envValue); } async function preflightCodeAgentBilling({ params = {}, options = {}, traceId, response, sendResponse = true } = {}) { const client = options.userBillingClient; if (!codeAgentBillingEnabled(options) || !client?.configured || !options.userBillingAuth?.active) return null; const estimatedCredits = parsePositiveInteger(options.env?.HWLAB_USER_BILLING_CODE_AGENT_ESTIMATED_CREDITS, 1); const body = { ...(options.actorApiKeySecret ? { apiKey: options.actorApiKeySecret } : { userId: options.actor?.id }), serviceId: "hwlab-code-agent", estimatedCredits, idempotencyKey: `code-agent:${traceId}:preflight`, metadata: codeAgentBillingMetadata(params, traceId, { stage: "preflight" }) }; const result = await client.billingPreflight(body); if (result.ok && result.body?.allowed !== false) return { reservation: sanitizeBillingReservation(result.body) }; const status = [402, 403, 429].includes(Number(result.status)) ? Number(result.status) : 503; const payload = { ok: false, accepted: false, status: status === 402 ? "payment_required" : status === 403 ? "not_entitled" : status === 429 ? "rate_limited" : "billing_unavailable", traceId, error: { code: result.error?.code ?? (status === 402 ? "insufficient_credits" : "user_billing_preflight_failed"), layer: "billing", retryable: status === 429 || status === 503, message: result.error?.message ?? "Code Agent billing preflight failed", route: "/v1/agent/chat" }, blocker: { code: result.error?.code ?? (status === 402 ? "insufficient_credits" : "user_billing_preflight_failed"), layer: "billing", retryable: status === 429 || status === 503, summary: result.error?.message ?? "Code Agent billing preflight failed" }, valuesRedacted: true }; if (sendResponse && response) sendJson(response, status, payload); return { blocked: true, statusCode: status, payload, error: payload.error, blocker: payload.blocker }; } async function recordCodeAgentBillingUsage({ payload = {}, params = {}, options = {} } = {}) { const reservation = params.userBillingReservation ?? payload.userBillingReservation; const reservationId = typeof reservation?.reservationId === "string" ? reservation.reservationId : ""; const client = options.userBillingClient; if (payload.billing?.recorded === true || payload.billing?.released === true || payload.status === "running") return payload.billing ?? null; if (!reservationId || !client?.configured) return null; const traceId = safeTraceId(payload.traceId ?? params.traceId); const usedTokens = codeAgentUsedTokens(payload); const usedCredits = parsePositiveInteger(options.env?.HWLAB_USER_BILLING_CODE_AGENT_USED_CREDITS, 1); const result = await client.billingRecord({ reservationId, serviceId: "hwlab-code-agent", usedCredits, usedTokens, idempotencyKey: `code-agent:${traceId}:record`, metadata: codeAgentBillingMetadata(params, traceId, { stage: "record", status: payload.status ?? "unknown" }) }); const billing = result.ok ? sanitizeBillingRecord(result.body, reservation) : { recorded: false, reservationId, errorCode: result.error?.code ?? "user_billing_record_failed", valuesRedacted: true }; payload.billing = billing; const traceStore = options.traceStore ?? defaultCodeAgentTraceStore; if (traceId) { traceStore.append(traceId, { type: "billing", status: result.ok ? "recorded" : "degraded", label: result.ok ? "billing:recorded" : "billing:record_failed", reservationId, recordId: result.ok ? result.body?.recordId ?? null : null, errorCode: result.ok ? null : billing.errorCode, valuesPrinted: false }); } return billing; } async function finalizeCodeAgentBillingUsage({ payload = {}, params = {}, options = {} } = {}) { if (payload.billing?.recorded === true || payload.billing?.released === true) return payload.billing; if (payload.status === "running") return null; if (payload.status === "completed") { return recordCodeAgentBillingUsage({ payload, params, options }); } return releaseCodeAgentBillingReservation({ payload, params, options }); } async function releaseCodeAgentBillingReservation({ payload = {}, params = {}, options = {} } = {}) { const reservation = params.userBillingReservation ?? payload.userBillingReservation; const reservationId = typeof reservation?.reservationId === "string" ? reservation.reservationId : ""; const client = options.userBillingClient; if (payload.billing?.recorded === true || payload.billing?.released === true || !reservationId || !client?.configured) return payload.billing ?? null; const traceId = safeTraceId(payload.traceId ?? params.traceId); const releaseReason = String(payload.status ?? "not_completed").trim() || "not_completed"; const releaseBody = { reservationId, serviceId: "hwlab-code-agent", idempotencyKey: `code-agent:${traceId}:release`, reason: releaseReason, metadata: codeAgentBillingMetadata(params, traceId, { stage: "release", status: payload.status ?? "unknown", errorCode: payload.error?.code ?? payload.blocker?.code ?? null }) }; const result = typeof client.billingRelease === "function" ? await client.billingRelease(releaseBody) : { ok: false, error: { code: "user_billing_release_not_supported" } }; const billing = result.ok ? sanitizeBillingRelease(result.body, reservation) : { released: false, reservationId, errorCode: result.error?.code ?? "user_billing_release_failed", valuesRedacted: true }; payload.billing = billing; const traceStore = options.traceStore ?? defaultCodeAgentTraceStore; if (traceId) { traceStore.append(traceId, { type: "billing", status: result.ok ? "released" : "degraded", label: result.ok ? "billing:released" : "billing:release_failed", reservationId, reason: releaseReason, errorCode: result.ok ? null : billing.errorCode, valuesPrinted: false }); } return billing; } function withCodeAgentBillingReservation(payload = {}, params = {}) { if (!payload || typeof payload !== "object" || payload.userBillingReservation) return payload; const reservation = params.userBillingReservation; return reservation ? { ...payload, userBillingReservation: reservation } : payload; } function codeAgentBillingEnabled(options = {}) { const env = options.env ?? process.env; if (String(env.HWLAB_USER_BILLING_CODE_AGENT_ENABLED ?? "").trim() === "0") return false; return Boolean(options.userBillingClient?.configured); } function codeAgentBillingMetadata(params = {}, traceId, extra = {}) { return { traceId, conversationId: safeConversationId(params.conversationId) || null, sessionId: safeSessionId(params.sessionId) || null, projectId: textValue(params.projectId) || null, route: "/v1/agent/chat", resource: "code-agent-turn", ...extra, valuesRedacted: true }; } function sanitizeBillingReservation(value = {}) { return { allowed: value.allowed === true, reservationId: textValue(value.reservationId) || null, resourceType: textValue(value.resourceType) || null, planId: textValue(value.planId) || null, estimatedCredits: Number.isFinite(Number(value.estimatedCredits)) ? Number(value.estimatedCredits) : null, estimatedTokens: Number.isFinite(Number(value.estimatedTokens)) ? Number(value.estimatedTokens) : null, expiresAt: textValue(value.expiresAt) || null, valuesRedacted: true }; } function sanitizeBillingRecord(value = {}, reservation = {}) { return { recorded: true, reservationId: textValue(reservation.reservationId) || null, recordId: textValue(value.recordId) || null, credits: Number.isFinite(Number(value.credits)) ? Number(value.credits) : null, balance: Number.isFinite(Number(value.balance)) ? Number(value.balance) : null, valuesRedacted: true }; } function sanitizeBillingRelease(value = {}, reservation = {}) { return { released: true, reservationId: textValue(value.reservationId) || textValue(reservation.reservationId) || null, releasedCredits: Number.isFinite(Number(value.releasedCredits)) ? Number(value.releasedCredits) : null, status: textValue(value.status) || "cancelled", valuesRedacted: true }; } function codeAgentUsedTokens(payload = {}) { const usage = payload.usage && typeof payload.usage === "object" ? payload.usage : null; const traceSummary = payload.traceSummary && typeof payload.traceSummary === "object" ? payload.traceSummary : null; const candidates = [ usage?.totalTokens, usage?.total_tokens, usage?.tokens, Number(usage?.inputTokens ?? usage?.input_tokens ?? 0) + Number(usage?.outputTokens ?? usage?.output_tokens ?? 0), traceSummary?.tokenCount, traceSummary?.tokens ]; for (const value of candidates) { const parsed = Number(value); if (Number.isFinite(parsed) && parsed > 0) return Math.ceil(parsed); } return 0; } function normalizeTurnStatus(...values) { for (const value of values) { const text = textValue(value).toLowerCase().replace(/_/gu, "-"); if (!text) continue; if (["accepted", "pending", "processing", "running", "busy", "creating", "queued", "in-flight"].includes(text)) return "running"; if (["completed", "done", "succeeded", "success"].includes(text)) return "completed"; if (["failed", "failure", "error", "stale", "thread-resume-failed", "aborted", "interrupted", "expired"].includes(text)) return "failed"; if (["cancelled", "canceled"].includes(text)) return "canceled"; if (["blocked", "timeout"].includes(text)) return text; } return null; } function recordCodeAgentConversationFact(payload = {}, options = {}) { const registry = options.sessionRegistry; const conversationId = safeConversationId(payload.conversationId); if (!conversationId || typeof registry?.recordFact !== "function") return null; try { return registry.recordFact(conversationId, { kind: payload.status === "completed" ? "runner_turn" : "runner_turn_terminal", conversationId, sessionId: payload.sessionId, traceId: payload.traceId, provider: payload.provider, backend: payload.backend, workspace: payload.workspace, sandbox: payload.sandbox, session: payload.session, sessionMode: payload.sessionMode, sessionReuse: payload.sessionReuse, implementationType: payload.implementationType, runner: payload.runner, runnerTrace: payload.runnerTrace, partialContext: payload.partialContext ?? payload.runnerTrace?.partialContext, capabilityLevel: payload.capabilityLevel, toolCalls: payload.toolCalls, skills: payload.skills }, { now: options.now }); } catch { return null; } } async function recordCodeAgentSessionOwner({ payload = {}, params = {}, options = {}, status = "active", preserveLastTraceId = false } = {}) { const ownerUserId = options.actor?.id ?? params.ownerUserId; if (!ownerUserId || !options.accessController?.recordAgentSessionOwner) return null; const traceId = safeTraceId(payload.traceId ?? params.traceId); const session = payload.session && typeof payload.session === "object" ? payload.session : null; const sessionReuse = payload.sessionReuse && typeof payload.sessionReuse === "object" ? payload.sessionReuse : null; const sessionId = safeSessionId(payload.sessionId ?? session?.sessionId ?? sessionReuse?.sessionId ?? params.sessionId) || null; const conversationId = safeConversationId(payload.conversationId ?? session?.conversationId ?? sessionReuse?.conversationId ?? params.conversationId) || null; const threadId = safeOpaqueId(session?.threadId ?? sessionReuse?.threadId ?? payload.threadId ?? params.threadId) || null; return recordWorkbenchSessionOwner({ accessController: options.accessController, traceId, ownerUserId, ownerRole: options.actor?.role ?? params.ownerRole ?? null, sessionId, projectId: params.projectId ?? payload.projectId ?? null, conversationId, threadId, status, preserveLastTraceId, session: codeAgentSessionOwnerEvidence(payload, params) }); } function codeAgentOwnerStatusForResult(result = {}) { const sessionStatus = textValue(result?.session?.status ?? result?.sessionSummary?.status ?? result?.sessionLifecycleStatus); if (sessionStatus === "thread-resume-failed") return "thread-resume-failed"; if (codeAgentFreshContinuationFailure(result)) return "thread-resume-failed"; if (codeAgentPayloadHasSealedFinalResponse(result)) return "completed"; if (result?.status === "completed") return "completed"; if (result?.status === "canceled" || result?.status === "cancelled") return "canceled"; return result?.status ?? "active"; } function textValue(value) { return String(value ?? "").trim(); } function timestampIsoOrNow(value = null) { const parsed = Date.parse(String(value ?? "")); return Number.isFinite(parsed) ? new Date(parsed).toISOString() : new Date().toISOString(); } function timestampIsoOrNull(value = null) { const parsed = Date.parse(String(value ?? "")); return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null; } function codeAgentSessionOwnerEvidence(payload = {}, params = {}) { const traceId = payload.traceId ?? params.traceId ?? null; const finalResponse = codeAgentFinalResponseEvidence(payload, traceId); const traceSummary = codeAgentTraceSummaryEvidence(payload, traceId, finalResponse); const messages = codeAgentConversationMessagesEvidence(payload, params, traceId, finalResponse); const firstUserMessagePreview = messages.find((message) => message.role === "user")?.text?.slice(0, 240) ?? null; const promptEvidence = codeAgentPromptMetadata(payload, params, traceId); const traceResult = codeAgentTraceResultEvidence(payload, params, traceId, finalResponse, traceSummary); const providerProfile = codeAgentProviderProfileEvidence(payload, params); const continuation = codeAgentContinuationEvidence(payload, params); const sessionLifecycleStatus = continuation.requiresFreshSession ? "thread-resume-failed" : payload.sessionLifecycleStatus ?? null; return { ...(providerProfile ? { providerProfile, codeAgentProviderProfile: providerProfile } : {}), provider: payload.provider ?? null, model: payload.model ?? null, backend: payload.backend ?? null, status: payload.status ?? null, sessionMode: payload.sessionMode ?? payload.session?.sessionMode ?? null, sessionLifecycleStatus, continuation, runnerKind: payload.runner?.kind ?? payload.runnerTrace?.runnerKind ?? null, conversationId: payload.conversationId ?? params.conversationId ?? null, sessionId: payload.sessionId ?? payload.session?.sessionId ?? payload.sessionReuse?.sessionId ?? params.sessionId ?? null, threadId: payload.session?.threadId ?? payload.sessionReuse?.threadId ?? payload.threadId ?? params.threadId ?? null, traceId, projectId: payload.projectId ?? params.projectId ?? null, ...codeAgentPromptFields(promptEvidence), finalResponse, traceSummary, ...(traceResult ? { traceResults: { [traceResult.traceId]: traceResult } } : {}), ...(messages.length ? { messages, messageCount: messages.length } : {}), ...(firstUserMessagePreview ? { firstUserMessagePreview } : {}), ...agentRunSessionEvidence(payload), secretMaterialStored: false, valuesRedacted: true }; } function codeAgentContinuationEvidence(payload = {}, params = {}) { const failure = codeAgentFreshContinuationFailure(payload); const providerProfile = codeAgentProviderProfileEvidence(payload, params); const traceId = safeTraceId(payload.traceId ?? params.traceId) || null; if (!failure) { return { requiresFreshSession: false, providerProfile, traceId, valuesRedacted: true }; } return { requiresFreshSession: true, reasonCode: failure.code, reason: failure.message, staleThreadId: safeOpaqueId(payload.session?.threadId ?? payload.sessionReuse?.threadId ?? payload.threadId ?? params.threadId ?? payload.agentRun?.threadId) || null, providerProfile, traceId, valuesRedacted: true }; } function codeAgentFreshContinuationFailure(payload = {}) { if (!payload || typeof payload !== "object") return null; const sessionStatus = String(payload.session?.status ?? payload.sessionLifecycleStatus ?? payload.sessionReuse?.status ?? "").trim().toLowerCase().replace(/_/gu, "-"); if (sessionStatus === "thread-resume-failed") return { code: "thread-resume-failed", message: "previous AgentRun thread/session resume failed", valuesRedacted: true }; const status = normalizeTurnStatus(payload.status, payload.agentRun?.terminalStatus, payload.agentRun?.commandState, payload.agentRun?.status, payload.session?.status, payload.sessionReuse?.status); if (!status || !["failed", "blocked", "timeout"].includes(status)) return null; const code = normalizeCodeAgentFailureKind(firstNonEmptyValue( payload.error?.code, payload.blocker?.code, payload.providerTrace?.failureKind, payload.providerTrace?.errorCode, payload.agentRun?.failureKind, payload.agentRun?.errorCode, payload.transient?.failureKind, payload.transient?.errorCode )); const message = firstNonEmptyValue( payload.error?.message, payload.error?.userMessage, payload.blocker?.summary, payload.blocker?.message, payload.providerTrace?.failureMessage, payload.providerTrace?.summary, payload.agentRun?.failureMessage, payload.agentRun?.message ) ?? ""; if (!codeAgentFailureRequiresFreshContinuation(code, message)) return null; return { code: code ?? "stale-continuation", message: message || code || "stale continuation", valuesRedacted: true }; } function normalizeCodeAgentFailureKind(value) { const normalized = String(value ?? "").trim().toLowerCase().replace(/_/gu, "-"); return normalized || null; } function codeAgentFailureRequiresFreshContinuation(code, message = "") { const failureKind = normalizeCodeAgentFailureKind(code); if (["thread-resume-failed", "session-store-evicted", "provider-stream-disconnected"].includes(failureKind)) return true; return /session stor(?:e|age).*evicted|pvc-backed session|no rollout found for thread id|no rollout found|thread\/resume failed|provider stream disconnected/iu.test(String(message ?? "")); } function codeAgentProviderProfileEvidence(payload = {}, params = {}) { const raw = firstNonEmptyValue( params.providerProfile, params.codeAgentProviderProfile, payload.providerProfile, payload.codeAgentProviderProfile, payload.agentRun?.backendProfile, payload.providerTrace?.backendProfile, payload.backendProfile ); if (!raw) return null; const normalized = normalizeCodeAgentProviderProfile(raw); return normalized === "runtime-default" ? null : normalized; } function codeAgentTraceResultEvidence(payload = {}, params = {}, traceId = null, finalResponse = null, traceSummary = null) { const resolvedTraceId = safeTraceId(traceId); if (!resolvedTraceId) return null; const agentRun = agentRunSessionEvidence(payload).agentRun ?? null; const userBillingReservation = codeAgentBillingReservationEvidence(payload.userBillingReservation ?? params.userBillingReservation); const resultSession = payload.session && typeof payload.session === "object" ? payload.session : null; const sessionReuse = payload.sessionReuse && typeof payload.sessionReuse === "object" ? payload.sessionReuse : null; const conversationId = safeConversationId(payload.conversationId ?? agentRun?.conversationId ?? resultSession?.conversationId ?? sessionReuse?.conversationId ?? params.conversationId) || null; const sessionId = safeSessionId(payload.sessionId ?? resultSession?.sessionId ?? sessionReuse?.sessionId ?? params.sessionId) || null; const threadId = safeOpaqueId(payload.threadId ?? resultSession?.threadId ?? sessionReuse?.threadId ?? params.threadId ?? agentRun?.threadId) || null; const promptEvidence = codeAgentPromptMetadata(payload, params, resolvedTraceId); if (!agentRun && !finalResponse && !traceSummary) return null; return { traceId: resolvedTraceId, status: codeAgentPayloadHasSealedFinalResponse(payload) ? "completed" : payload.status ?? agentRun?.terminalStatus ?? agentRun?.commandState ?? null, conversationId, sessionId, threadId, ...codeAgentPromptFields(promptEvidence), messageId: finalResponse?.messageId ?? payload.messageId ?? null, createdAt: payload.createdAt ?? finalResponse?.createdAt ?? null, updatedAt: payload.updatedAt ?? finalResponse?.updatedAt ?? null, finalResponse, traceSummary, agentRun, ...(userBillingReservation ? { userBillingReservation } : {}), valuesRedacted: true, secretMaterialStored: false }; } function codeAgentPromptMetadata(payload = {}, params = {}, traceId = null) { const prompt = payload?.prompt && typeof payload.prompt === "object" ? payload.prompt : null; const rawPrompt = firstNonEmptyValue( params.message, params.prompt, params.text, payload.userMessage, typeof payload.prompt === "string" ? payload.prompt : null ); const fromText = codeAgentPromptMetadataFromText(rawPrompt, traceId, "code-agent-request", { fullText: Boolean(rawPrompt) }); return codeAgentPromptMetadataFromParts({ traceId, source: prompt?.source ?? payload.promptSource ?? fromText?.prompt?.source ?? "code-agent-request", promptId: firstNonEmptyValue(payload.promptId, prompt?.id, fromText?.promptId), promptSha256: firstNonEmptyValue(payload.promptSha256, prompt?.sha256, fromText?.promptSha256), promptSummary: firstNonEmptyValue(payload.promptSummary, prompt?.summary, fromText?.promptSummary), promptPreview: firstNonEmptyValue(payload.promptPreview, prompt?.preview, fromText?.promptPreview), textChars: Number.isInteger(prompt?.textChars) ? prompt.textChars : fromText?.prompt?.textChars }); } function codeAgentPromptMetadataFromText(value, traceId = null, source = "code-agent-request", options = {}) { const promptText = String(value ?? "").trim(); if (!promptText) return null; return codeAgentPromptMetadataFromParts({ traceId, source, promptSha256: options.fullText === true ? sha256Text(promptText) : undefined, promptSummary: promptText, promptPreview: promptText, textChars: options.fullText === true ? promptText.length : undefined }); } function codeAgentPromptMetadataFromParts({ traceId = null, source = "code-agent-request", promptId = null, promptSha256 = null, promptSummary = null, promptPreview = null, textChars = undefined } = {}) { const digest = firstNonEmptyValue(promptSha256); const summary = clippedPromptText(firstNonEmptyValue(promptSummary, promptPreview), 240); const preview = clippedPromptText(firstNonEmptyValue(promptPreview, promptSummary), 500); const explicitId = firstNonEmptyValue(promptId); if (!explicitId && !digest && !summary && !preview) return null; const id = explicitId || codeAgentPromptId(traceId, digest); const prompt = compactCodeAgentObject({ id, sha256: digest || undefined, summary, preview, textChars: Number.isInteger(textChars) ? textChars : undefined, source, valuesPrinted: false }); return compactCodeAgentObject({ promptId: id, promptSha256: digest || undefined, promptSummary: summary, promptPreview: preview, prompt, valuesPrinted: false }) ?? null; } function codeAgentPromptFields(metadata = null) { if (!metadata) return {}; return compactCodeAgentObject({ promptId: metadata.promptId, promptSha256: metadata.promptSha256, promptSummary: metadata.promptSummary, promptPreview: metadata.promptPreview, prompt: metadata.prompt }) ?? {}; } function codeAgentPromptId(traceId = null, digest = null) { const traceSuffix = safeTraceId(traceId)?.slice(4).replace(/[^A-Za-z0-9_.:-]/gu, "_"); const digestSuffix = firstNonEmptyValue(digest)?.slice(0, 16); const suffix = firstNonEmptyValue(traceSuffix, digestSuffix); return suffix ? `prm_${suffix}` : undefined; } function clippedPromptText(value, limit) { const promptText = String(value ?? "").trim(); if (!promptText) return undefined; return promptText.length > limit ? `${promptText.slice(0, limit)}...` : promptText; } function sha256Text(value) { return createHash("sha256").update(String(value)).digest("hex"); } function compactCodeAgentObject(value) { const result = {}; for (const [key, item] of Object.entries(value ?? {})) { if (item === undefined || item === null) continue; if (Array.isArray(item) && item.length === 0) continue; if (typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0) continue; result[key] = item; } return Object.keys(result).length > 0 ? result : undefined; } function codeAgentBillingReservationEvidence(value = null) { if (!value || typeof value !== "object") return null; const reservationId = textValue(value.reservationId); if (!reservationId) return null; return { reservationId, resourceType: textValue(value.resourceType) || null, planId: textValue(value.planId) || null, estimatedCredits: numberOrNull(value.estimatedCredits), estimatedTokens: numberOrNull(value.estimatedTokens), expiresAt: textValue(value.expiresAt) || null, valuesRedacted: true, secretMaterialStored: false }; } function codeAgentConversationMessagesEvidence(payload = {}, params = {}, traceId = null, finalResponse = null) { const userText = boundedConversationMessageText(params.message ?? params.prompt ?? payload.userMessage ?? payload.prompt); if (!userText) return []; const resolvedTraceId = safeTraceId(traceId) || null; const lifecycle = codeAgentTurnLifecycleFields(resolvedTraceId, payload); const session = payload.session && typeof payload.session === "object" ? payload.session : null; const sessionReuse = payload.sessionReuse && typeof payload.sessionReuse === "object" ? payload.sessionReuse : null; const conversationId = safeConversationId(payload.conversationId ?? session?.conversationId ?? sessionReuse?.conversationId ?? params.conversationId) || null; const sessionId = safeSessionId(payload.sessionId ?? session?.sessionId ?? sessionReuse?.sessionId ?? params.sessionId) || null; const threadId = safeOpaqueId(session?.threadId ?? sessionReuse?.threadId ?? payload.threadId ?? params.threadId) || null; const createdAt = payload.createdAt ?? payload.reply?.createdAt ?? new Date().toISOString(); const updatedAt = payload.updatedAt ?? createdAt; const userMessage = { id: lifecycle.userMessageId, messageId: lifecycle.userMessageId, role: "user", title: "用户", text: userText, status: "sent", traceId: resolvedTraceId, turnId: lifecycle.turnId, conversationId, sessionId, threadId, createdAt, updatedAt, source: "code-agent-submit", secretMaterialStored: false, valuesRedacted: true }; const agentText = boundedConversationMessageText( finalResponse?.text ?? payload.reply?.content ?? payload.message?.content ?? payload.assistantText ?? payload.error?.userMessage ?? payload.error?.message ?? payload.blocker?.userMessage ?? payload.blocker?.message ?? payload.blocker?.summary ); const agentStatus = codeAgentConversationAgentMessageStatus(payload); const agentMessage = { id: lifecycle.assistantMessageId, messageId: lifecycle.assistantMessageId, role: "agent", title: agentStatus === "failed" ? "Code Agent 返回阻塞" : agentStatus === "running" ? "Code Agent 处理中" : "Code Agent 回复", text: agentText || (agentStatus === "running" ? "" : "Code Agent 请求已结束,请查看 Trace 详情。"), status: agentStatus, traceId: resolvedTraceId, turnId: lifecycle.turnId, conversationId, sessionId, threadId, createdAt: payload.reply?.createdAt ?? updatedAt, updatedAt, source: "code-agent-result", ...(payload.runnerTrace && typeof payload.runnerTrace === "object" ? { runnerTrace: codeAgentConversationRunnerTraceEvidence(payload.runnerTrace, resolvedTraceId) } : {}), secretMaterialStored: false, valuesRedacted: true }; return [userMessage, agentMessage]; } function boundedConversationMessageText(value, limit = 12000) { const text = conversationText(value); if (!text) return ""; return text.length > limit ? text.slice(0, limit) : text; } function conversationText(value) { const extracted = conversationTextRaw(value).replace(/\r\n?/gu, "\n"); if (!extracted.trim() || extracted.trim() === "[object Object]") return ""; return extracted; } function conversationTextRaw(value) { if (value === undefined || value === null) return ""; if (typeof value === "string") return value; if (typeof value === "number" || typeof value === "boolean") return String(value); if (Array.isArray(value)) return value.map(conversationTextRaw).filter(Boolean).join("\n"); if (typeof value === "object") { for (const key of ["text", "content", "message", "prompt", "value", "summary", "preview", "title"]) { const text = conversationTextRaw(value[key]); if (text) return text; } } return ""; } function codeAgentMessageTraceSuffix(traceId) { const text = safeTraceId(traceId) || `local_${Date.now().toString(36)}`; return text.replace(/^trc_/u, "").replace(/[^A-Za-z0-9_.:-]/gu, "_").slice(0, 48) || "trace"; } function codeAgentTurnLifecycleFields(traceId, source = {}) { const resolvedTraceId = safeTraceId(source?.traceId ?? traceId) || safeTraceId(traceId) || null; const turnId = safeTurnId(source?.turnId) || resolvedTraceId; const traceSuffix = codeAgentMessageTraceSuffix(resolvedTraceId); return { turnId, userMessageId: safeMessageId(source?.userMessageId ?? source?.userMessage?.messageId) || codeAgentLifecycleMessageId(traceSuffix, "user"), assistantMessageId: safeMessageId(source?.assistantMessageId ?? source?.assistantMessage?.messageId) || codeAgentLifecycleMessageId(traceSuffix, "agent") }; } function codeAgentLifecycleMessageId(traceSuffix, role) { return `msg_${traceSuffix}_${role}`; } function safeTurnId(value) { const text = textValue(value); return /^turn_[A-Za-z0-9_.:-]+$/u.test(text) ? text : null; } function safeMessageId(value) { const text = textValue(value); return /^msg_[A-Za-z0-9_.:-]+$/u.test(text) ? text : null; } function codeAgentConversationAgentMessageStatus(payload = {}) { const status = textValue(payload.status ?? payload.agentRun?.terminalStatus ?? payload.commandState ?? payload.runStatus).toLowerCase(); if (codeAgentPayloadHasSealedFinalResponse(payload)) return "completed"; if (["completed", "done", "success"].includes(status)) return "completed"; if (["failed", "blocked", "error", "timeout", "canceled", "cancelled"].includes(status)) return "failed"; if (payload.error || payload.blocker) return "failed"; return "running"; } function codeAgentPayloadHasSealedFinalResponse(payload = {}) { if (!payload || typeof payload !== "object") return false; if (payload.error || payload.blocker) return false; if (!codeAgentFinalResponseText(payload)) return false; const agentRun = payload.agentRun && typeof payload.agentRun === "object" ? payload.agentRun : {}; return isTraceCommandTerminalStatus(payload.status) || isTraceCommandTerminalStatus(agentRun.status) || isTraceCommandTerminalStatus(agentRun.runStatus) || isTraceCommandTerminalStatus(agentRun.commandState) || isTraceCommandTerminalStatus(agentRun.terminalStatus); } function codeAgentConversationRunnerTraceEvidence(runnerTrace = {}, traceId = null) { const events = Array.isArray(runnerTrace.events) ? runnerTrace.events : []; const lastEvent = runnerTrace.lastEvent && typeof runnerTrace.lastEvent === "object" ? runnerTrace.lastEvent : events.at(-1) ?? null; const eventCount = Number.isFinite(Number(runnerTrace.eventCount)) ? Number(runnerTrace.eventCount) : events.length; return { traceId: safeTraceId(runnerTrace.traceId ?? traceId) || traceId || null, status: runnerTrace.status ?? lastEvent?.status ?? null, sessionId: runnerTrace.sessionId ?? null, threadId: runnerTrace.threadId ?? null, runId: runnerTrace.runId ?? lastEvent?.runId ?? null, commandId: runnerTrace.commandId ?? lastEvent?.commandId ?? null, eventCount, lastEvent: lastEvent ? { label: lastEvent.label ?? null, status: lastEvent.status ?? null, terminal: lastEvent.terminal === true, createdAt: lastEvent.createdAt ?? null, message: boundedConversationMessageText(lastEvent.message ?? lastEvent.text, 1000), valuesPrinted: false } : null, eventsCompacted: true, fullTraceLoaded: false, valuesPrinted: false }; } function codeAgentFinalResponseEvidence(payload = {}, traceId = null) { const text = codeAgentFinalResponseText(payload); if (!text) return null; return { text, textChars: text.length, messageId: payload.finalResponse?.messageId ?? payload.reply?.messageId ?? payload.messageId ?? null, role: payload.reply?.role ?? payload.message?.role ?? "assistant", status: codeAgentPayloadHasSealedFinalResponse(payload) ? "completed" : payload.finalResponse?.status ?? payload.status ?? null, traceId, createdAt: payload.finalResponse?.createdAt ?? payload.reply?.createdAt ?? payload.createdAt ?? null, updatedAt: payload.finalResponse?.updatedAt ?? payload.updatedAt ?? null, source: payload.finalResponse?.source ?? "code-agent-result", valuesPrinted: false }; } function codeAgentFinalResponseText(payload = {}) { for (const value of [ payload?.finalResponse?.text, payload?.finalResponse?.content, payload?.finalResponse, payload?.reply?.content, payload?.reply, payload?.message?.content, payload?.message, payload?.assistantText, payload?.finalText, payload?.text, payload?.content ]) { const text = conversationText(value); if (text) return text; } return ""; } function codeAgentTraceSummaryEvidence(payload = {}, traceId = null, finalResponse = null) { const runnerTrace = payload.runnerTrace && typeof payload.runnerTrace === "object" ? payload.runnerTrace : null; const events = Array.isArray(runnerTrace?.events) ? runnerTrace.events : []; const terminalEvent = [...events].reverse().find((event) => event?.terminal === true) ?? runnerTrace?.lastEvent ?? null; return { traceId, source: "code-agent-derived-session-evidence", sourceEventCount: Number.isFinite(Number(runnerTrace?.eventCount)) ? Number(runnerTrace.eventCount) : events.length, terminalStatus: payload.agentRun?.terminalStatus ?? payload.status ?? terminalEvent?.status ?? null, lastEventLabel: terminalEvent?.label ?? null, finalAssistantRow: finalResponse ? { role: finalResponse.role, status: finalResponse.status, textChars: finalResponse.textChars, textPreview: finalResponse.text.slice(0, 240), messageId: finalResponse.messageId, valuesPrinted: false } : null, agentRun: payload.agentRun ? { runId: payload.agentRun.runId ?? null, commandId: payload.agentRun.commandId ?? null, attemptId: payload.agentRun.attemptId ?? null, runnerId: payload.agentRun.runnerId ?? null, jobName: payload.agentRun.jobName ?? null, namespace: payload.agentRun.namespace ?? null, lastSeq: payload.agentRun.lastSeq ?? null, valuesPrinted: false } : null, updatedAt: payload.updatedAt ?? null, valuesPrinted: false }; } function annotateOwner(payload, params = {}) { if (!params.ownerUserId) return payload; return { ...payload, ownerUserId: params.ownerUserId, ownerRole: params.ownerRole ?? null }; } function canAccessOwnedResult(result, actor) { if (!result?.ownerUserId || !actor) return true; return actor.role === "admin" || actor.id === result.ownerUserId; } function isCodeAgentResultCanceled(result) { return result?.status === "canceled" || result?.canceled === true || result?.error?.code === "codex_stdio_canceled"; } function codeAgentCancelScopeMismatch(params = {}, result = {}) { return cancelScopeFieldMismatch("conversationId", safeConversationId(params.conversationId), cancelExpectedValues(safeConversationId, result.conversationId, result.agentRun?.conversationId, result.session?.conversationId, result.sessionReuse?.conversationId, result.runnerTrace?.conversationId )) ?? cancelScopeFieldMismatch("sessionId", safeSessionId(params.sessionId), cancelExpectedValues(safeSessionId, result.sessionId, result.session?.sessionId, result.sessionReuse?.sessionId, result.agentRun?.hwlabSessionId )) ?? cancelScopeFieldMismatch("threadId", safeOpaqueId(params.threadId), cancelExpectedValues(safeOpaqueId, result.threadId, result.agentRun?.threadId, result.session?.threadId, result.sessionReuse?.threadId, result.runnerTrace?.threadId )); } function cancelExpectedValues(normalize, ...values) { return [...new Set(values.map((value) => normalize(value)).filter(Boolean))]; } function cancelScopeFieldMismatch(field, requested, expectedValues) { if (!requested || expectedValues.length === 0 || expectedValues.includes(requested)) return null; return { field, requested, expected: expectedValues[0] }; } function cancelBlockedPayload({ code, message, traceId, conversationId = null, sessionId = null, session = null, runnerTrace = null, status = "failed", unsupported = false, degraded = false }) { const sessionSummary = codeAgentSessionLifecycleSummary({ session, runnerTrace, status, unsupported, degraded, error: { code, userMessage: message, message } }); return { accepted: false, canceled: false, status, conversationId, sessionId, traceId, session, sessionLifecycleStatus: sessionSummary.status, sessionLifecycle: sessionSummary, sessionSummary, unsupported, degraded, runnerTrace, lastTraceEvent: runnerTrace?.lastEvent ?? null, error: { code, layer: "session", category: "cancel_blocked", retryable: true, userMessage: message, message, traceId, route: "/v1/agent/chat/cancel", toolName: "codex-stdio.cancel" }, blocker: { code, layer: "session", category: "cancel_blocked", retryable: true, summary: message, userMessage: message, traceId, route: "/v1/agent/chat/cancel", toolName: "codex-stdio.cancel" } }; } function isTraceCommandTerminalStatus(status) { return CODE_AGENT_TERMINAL_STATUSES.has(String(status ?? "").trim().toLowerCase().replace(/_/gu, "-")); } function traceSnapshotWithTerminalEvidence(snapshot, result, traceId, refreshError = null) { const evidence = agentRunTerminalTraceEvidence(result, traceId); if (snapshot && snapshot.status !== "missing") return traceSnapshotWithAttachedTerminalEvidence(snapshot, evidence, refreshError); if (!evidence) return { ...snapshot, ok: false, traceStatus: "missing", retention: traceRetentionSummary("missing") }; return { ...snapshot, ok: true, status: "expired", traceStatus: "expired", projectionStatus: "projecting", projectionHealth: "degraded", persisted: true, retention: traceRetentionSummary("expired"), conversationId: evidence.conversationId, sessionId: evidence.sessionId, threadId: evidence.threadId, ...codeAgentPromptFields(evidence), agentRun: evidence.agentRun, finalResponse: evidence.finalResponse, traceSummary: evidence.traceSummary, terminalEvidence: { available: true, source: evidence.source, refresh: refreshError ? { attempted: true, ok: false, code: refreshError?.code ?? "agentrun_trace_refresh_failed", message: refreshError?.message ?? "AgentRun trace events could not be refreshed; command result remains authoritative for final response.", valuesPrinted: false } : { attempted: false, ok: null }, conversationId: evidence.conversationId, sessionId: evidence.sessionId, threadId: evidence.threadId, ...codeAgentPromptFields(evidence), agentRun: evidence.agentRun, traceSummary: evidence.traceSummary, finalResponse: evidence.finalResponse, valuesPrinted: false } }; } function traceSnapshotWithAttachedTerminalEvidence(snapshot, evidence, refreshError = null) { if (!evidence) return snapshot; return { ...snapshot, conversationId: snapshot.conversationId ?? evidence.conversationId, sessionId: snapshot.sessionId ?? evidence.sessionId, threadId: snapshot.threadId ?? evidence.threadId, ...codeAgentPromptFields(evidence), agentRun: snapshot.agentRun ?? evidence.agentRun, finalResponse: snapshot.finalResponse ?? evidence.finalResponse, traceSummary: snapshot.traceSummary ?? evidence.traceSummary, terminalEvidence: snapshot.terminalEvidence ?? (refreshError ? { available: true, source: evidence.source, refresh: { attempted: true, ok: false, code: refreshError?.code ?? "agentrun_trace_refresh_failed", message: refreshError?.message ?? "AgentRun trace events could not be refreshed; live events may be partial.", valuesPrinted: false }, valuesPrinted: false } : undefined) }; } function agentRunTerminalTraceEvidence(result, traceId) { if (!result || typeof result !== "object") return null; const storedSummary = result.traceSummary && typeof result.traceSummary === "object" && result.traceSummary.source === "agentrun-command-result" ? result.traceSummary : null; const finalResponse = agentRunTerminalFinalResponse(result, traceId); const promptEvidence = codeAgentPromptMetadata(result, {}, traceId); const agentRun = result.agentRun && typeof result.agentRun === "object" ? { adapter: result.agentRun.adapter ?? null, runId: result.agentRun.runId ?? null, commandId: result.agentRun.commandId ?? null, attemptId: result.agentRun.attemptId ?? null, runnerId: result.agentRun.runnerId ?? null, jobName: result.agentRun.jobName ?? null, namespace: result.agentRun.namespace ?? null, terminalStatus: result.agentRun.terminalStatus ?? null, lastSeq: result.agentRun.lastSeq ?? null, valuesPrinted: false } : null; const terminalStatus = normalizeTurnStatus(result.agentRun?.terminalStatus, result.agentRun?.commandState, result.agentRun?.status, result.agentRun?.runStatus); if (!isTraceCommandTerminalStatus(terminalStatus)) return null; if (!agentRun?.runId || !agentRun?.commandId || (!storedSummary && !finalResponse)) return null; const traceSummary = { traceId, source: "agentrun-command-result", sourceEventCount: numberOrNull(storedSummary?.sourceEventCount ?? storedSummary?.eventCount ?? result.runnerTrace?.eventCount), renderedRowSummary: storedSummary?.renderedRowSummary ?? null, noiseEventCount: numberOrNull(storedSummary?.noiseEventCount), omittedNoiseCount: numberOrNull(storedSummary?.omittedNoiseCount), terminalStatus: storedSummary?.terminalStatus ?? terminalStatus, updatedAt: storedSummary?.updatedAt ?? result.updatedAt ?? null, valuesPrinted: false }; return { source: "agentrun-command-result", conversationId: safeConversationId(result.conversationId) || null, sessionId: safeSessionId(result.sessionId) || null, threadId: safeOpaqueId(result.threadId) || null, ...codeAgentPromptFields(promptEvidence), agentRun, finalResponse, traceSummary }; } function agentRunTerminalFinalResponse(result, traceId) { const stored = result.finalResponse && typeof result.finalResponse === "object" ? result.finalResponse : null; const text = textValue(stored?.text ?? result.reply?.content ?? result.message?.content ?? result.assistantText); if (!text) return null; const storedTraceId = safeTraceId(stored?.traceId ?? result.traceId) || null; if (storedTraceId && storedTraceId !== traceId) return null; return { text, textChars: text.length, messageId: stored?.messageId ?? result.reply?.messageId ?? result.messageId ?? null, role: stored?.role ?? result.reply?.role ?? "assistant", status: stored?.status ?? result.status ?? null, traceId: traceId, createdAt: stored?.createdAt ?? result.reply?.createdAt ?? result.createdAt ?? null, updatedAt: stored?.updatedAt ?? result.updatedAt ?? null, source: "agentrun-command-result", valuesPrinted: false }; } function traceRetentionSummary(status) { return { traceStatus: status, liveTraceStore: status === "missing" ? "missing" : "expired-or-evicted", policy: "live trace events are short-term storage; terminal final response and summary are resolved from AgentRun command result by traceId and commandId", replacementEvidence: status === "missing" ? "resolve the trace through AgentRun command registry/result or report the trace as missing" : "use terminalEvidence.finalResponse, terminalEvidence.traceSummary, conversationId, sessionId, threadId, and agentRun ids", valuesPrinted: false }; } function numberOrNull(value) { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : null; } function createCodeAgentChatResultStore({ maxResults = 256 } = {}) { const limit = positiveInteger(maxResults, 256); const results = new Map(); function set(traceId, payload) { const id = safeTraceId(traceId); if (!id) return; results.set(id, { ...payload, traceId: id, cachedAt: new Date().toISOString() }); while (results.size > limit) { const oldest = results.keys().next().value; if (!oldest) break; results.delete(oldest); } } return { set, get: (traceId) => results.get(safeTraceId(traceId)) ?? null, clear: () => results.clear() }; } function compactCodeAgentChatResultPayload(payload, options = {}) { if (!payload || typeof payload !== "object") return payload; const limit = resultTraceEventLimit(options); const terminalEvidence = agentRunTerminalTraceEvidence(payload, payload.traceId); const { userBillingReservation, ...publicPayload } = payload; return { ...publicPayload, ...codeAgentTurnLifecycleFields(publicPayload.traceId, publicPayload), ...(terminalEvidence ? { terminalEvidence: terminalEvidencePayload(terminalEvidence) } : {}), ...(publicPayload.runnerTrace && typeof publicPayload.runnerTrace === "object" ? { runnerTrace: compactRunnerTraceForResult(publicPayload.runnerTrace, limit) } : {}) }; } function terminalEvidencePayload(evidence) { return { available: true, source: evidence.source, conversationId: evidence.conversationId, sessionId: evidence.sessionId, threadId: evidence.threadId, ...codeAgentPromptFields(evidence), agentRun: evidence.agentRun, traceSummary: evidence.traceSummary, finalResponse: evidence.finalResponse, valuesPrinted: false }; } function compactRunnerTraceForResult(runnerTrace, limit = DEFAULT_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT) { if (!runnerTrace || typeof runnerTrace !== "object") return runnerTrace; const events = Array.isArray(runnerTrace.events) ? runnerTrace.events : []; const total = Number.isInteger(runnerTrace.eventCount) ? runnerTrace.eventCount : events.length; const effectiveLimit = Math.max(8, positiveInteger(limit, DEFAULT_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT)); if (events.length <= effectiveLimit) { return { ...runnerTrace, eventCount: total, eventsCompacted: false }; } const headCount = Math.min(24, Math.max(1, Math.floor(effectiveLimit / 4))); const tailCount = Math.max(1, effectiveLimit - headCount - 1); const omitted = Math.max(0, events.length - headCount - tailCount); const head = events.slice(0, headCount); const tail = events.slice(events.length - tailCount); const marker = { traceId: runnerTrace.traceId ?? head[0]?.traceId ?? tail[0]?.traceId ?? null, type: "trace", stage: "trace", status: "truncated", label: "trace:compacted", createdAt: tail[0]?.createdAt ?? runnerTrace.updatedAt ?? new Date().toISOString(), message: `Compatibility result response compacted ${omitted} trace events; fetch /v1/agent/traces/${encodeURIComponent(runnerTrace.traceId ?? "")} for the full trace.`, omittedEventCount: omitted, retainedEventCount: head.length + tail.length, totalEventCount: total, valuesPrinted: false }; const compactEvents = [...head, marker, ...tail]; return { ...runnerTrace, eventCount: total, events: compactEvents, eventLabels: compactEvents.map(traceEventLabel).filter(Boolean), eventsCompacted: true, eventWindow: { mode: "head-tail", retained: compactEvents.length, omitted, total } }; } function traceEventLabel(event) { return typeof event === "string" ? event : event?.label; } function resultTraceEventLimit(options = {}) { return positiveInteger( options.env?.HWLAB_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT, DEFAULT_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT ); } function createCodeAgentM3HwlabApiRequestJson(options = {}) { return async (targetUrl, request = {}) => { const url = new URL(targetUrl); const route = url.pathname; if (route === M3_IO_CONTROL_ROUTE && request.method === "POST") { return { ok: true, status: 200, body: await handleM3IoControl(request.body ?? {}, { runtimeStore: options.runtimeStore, now: options.now, env: options.env, requestJson: options.m3IoRequestJson }) }; } if (route === M3_STATUS_ROUTE && request.method === "GET") { return { ok: true, status: 200, body: await describeM3StatusLive(options) }; } return { ok: false, status: 404, body: { error: { code: "not_found", message: `Unsupported Code Agent M3 HWLAB API route ${route}` } }, error: `Unsupported Code Agent M3 HWLAB API route ${route}` }; }; } function recordCodeAgentProjectionMetrics(options = {}, { result = null, trace = null, projection = null, refreshError = null } = {}) { const performanceStore = options.backendPerformanceStore ?? options.backendPerformance; if (!performanceStore?.recordWorkbenchProjection || !projection) return; const sourceLatestSeq = sourceLatestSeqFromResult(result); const lastProjectedSeq = Number(projection.lastProjectedSeq ?? 0); if (!Number.isFinite(sourceLatestSeq) && !Number.isFinite(lastProjectedSeq)) return; performanceStore.recordWorkbenchProjection({ sourceLatestSeq: Number.isFinite(sourceLatestSeq) ? sourceLatestSeq : lastProjectedSeq, lastProjectedSeq: Number.isFinite(lastProjectedSeq) ? lastProjectedSeq : 0, sourceLatestEventAt: sourceLatestAtFromResult(result, trace), projectedLatestEventAt: projection.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null, terminalSourceAt: terminalSourceAtFromResult(result), terminalProjectedAt: projection.projectionStatus === "caught-up" ? projection.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null : null, status: projection?.status ?? "unknown", reason: projectionReason(projection, refreshError), projectionStatus: projection.projectionStatus ?? "unknown", source: "workbench_read_model" }); } function recordCodeAgentTurnReadMetric(options = {}, url, statusCode, body = {}, startedAt = nowMs()) { const performanceStore = options.backendPerformanceStore ?? options.backendPerformance; if (!performanceStore?.recordWorkbenchTurnRead) return; performanceStore.recordWorkbenchTurnRead({ route: url?.pathname ?? "/v1/agent/turns/:id", status: body?.status ?? statusClassLabel(statusCode), degradedReason: turnReadDegradedReason(body), durationMs: nowMs() - startedAt, responseBytes: responseBodyBytes(body), timedOut: statusCode === 504 || body?.error?.code === "timeout" || body?.refreshError?.code === "agentrun_timeout" }); } function turnReadDegradedReason(body = {}) { if (body?.refreshError?.code) return body.refreshError.code; if (body?.projection?.blocker?.code) return body.projection.blocker.code; if (body?.blocker?.code) return body.blocker.code; if (body?.error?.code) return body.error.code; if (body?.projectionStatus === "projecting") return "projecting"; if (body?.projectionStatus === "blocked") return "projection_blocked"; return "none"; } function responseBodyBytes(body = {}) { try { return Buffer.byteLength(JSON.stringify(body)); } catch { return 0; } } function statusClassLabel(value) { const status = Number(value); if (!Number.isFinite(status) || status <= 0) return "unknown"; return `${Math.floor(status / 100)}xx`; } function sourceLatestSeqFromResult(result = null) { const candidates = [ result?.agentRun?.lastSeq, result?.traceSummary?.agentRun?.lastSeq, result?.traceSummary?.lastSeq, result?.providerTrace?.lastSeq, result?.runnerTrace?.lastEvent?.sourceSeq, result?.runnerTrace?.lastEvent?.seq, result?.runnerTrace?.eventCount ]; for (const value of candidates) { const seq = Number(value); if (Number.isFinite(seq) && seq >= 0) return Math.floor(seq); } return NaN; } function sourceLatestAtFromResult(result = null, trace = null) { return result?.traceSummary?.updatedAt ?? result?.agentRun?.updatedAt ?? result?.providerTrace?.updatedAt ?? result?.runnerTrace?.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null; } function terminalSourceAtFromResult(result = null) { if (!result) return null; const terminalStatus = result?.agentRun?.terminalStatus ?? result?.traceSummary?.terminalStatus ?? result?.status; if (!isTraceCommandTerminalStatus(terminalStatus)) return null; return result?.traceSummary?.updatedAt ?? result?.agentRun?.updatedAt ?? result?.updatedAt ?? null; } function projectionReason(projection = null, refreshError = null) { if (refreshError) return refreshError.code ?? "refresh_error"; if (projection?.blocker) return projection.blocker.code ?? "projection_blocked"; if (projection?.projectionStatus === "projecting") return "projecting"; if (projection?.projectionStatus === "caught-up") return "none"; return projection?.projectionStatus ?? "unknown"; } function nowMs() { if (typeof performance !== "undefined" && typeof performance.now === "function") return performance.now(); return Date.now(); } function uniqueStrings(values) { return [...new Set(values.map((value) => String(value ?? "").trim()).filter(Boolean))]; } export { normalizeCodeAgentProviderProfile, firstNonEmptyValue, recordCodeAgentSessionInputFact, buildCodeAgentSessionInputFact, stableCodeAgentInputId, codeAgentInputDelivery, codeAgentInputStatus, codeAgentResultTimingFields, firstTimestampIso, firstLatestTimestampIso, codeAgentChatShortConnectionRequested, preflightCodeAgentBilling, recordCodeAgentBillingUsage, finalizeCodeAgentBillingUsage, releaseCodeAgentBillingReservation, withCodeAgentBillingReservation, codeAgentBillingEnabled, codeAgentBillingMetadata, sanitizeBillingReservation, sanitizeBillingRecord, sanitizeBillingRelease, codeAgentUsedTokens, normalizeTurnStatus, recordCodeAgentConversationFact, recordCodeAgentSessionOwner, codeAgentOwnerStatusForResult, textValue, timestampIsoOrNow, timestampIsoOrNull, codeAgentSessionOwnerEvidence, codeAgentContinuationEvidence, codeAgentFreshContinuationFailure, normalizeCodeAgentFailureKind, codeAgentFailureRequiresFreshContinuation, codeAgentProviderProfileEvidence, codeAgentTraceResultEvidence, codeAgentPromptMetadata, codeAgentPromptMetadataFromText, codeAgentPromptMetadataFromParts, codeAgentPromptFields, codeAgentPromptId, clippedPromptText, sha256Text, compactCodeAgentObject, codeAgentBillingReservationEvidence, codeAgentConversationMessagesEvidence, boundedConversationMessageText, conversationText, conversationTextRaw, codeAgentMessageTraceSuffix, codeAgentTurnLifecycleFields, codeAgentLifecycleMessageId, safeTurnId, safeMessageId, codeAgentConversationAgentMessageStatus, codeAgentPayloadHasSealedFinalResponse, codeAgentConversationRunnerTraceEvidence, codeAgentFinalResponseEvidence, codeAgentFinalResponseText, codeAgentTraceSummaryEvidence, annotateOwner, canAccessOwnedResult, isCodeAgentResultCanceled, codeAgentCancelScopeMismatch, cancelExpectedValues, cancelScopeFieldMismatch, cancelBlockedPayload, isTraceCommandTerminalStatus, traceSnapshotWithTerminalEvidence, traceSnapshotWithAttachedTerminalEvidence, agentRunTerminalTraceEvidence, agentRunTerminalFinalResponse, traceRetentionSummary, numberOrNull, createCodeAgentChatResultStore, compactCodeAgentChatResultPayload, terminalEvidencePayload, compactRunnerTraceForResult, traceEventLabel, resultTraceEventLimit, createCodeAgentM3HwlabApiRequestJson, recordCodeAgentProjectionMetrics, recordCodeAgentTurnReadMetric, turnReadDegradedReason, responseBodyBytes, statusClassLabel, sourceLatestSeqFromResult, sourceLatestAtFromResult, terminalSourceAtFromResult, projectionReason, nowMs, uniqueStrings };