fix: 收敛公共 trace result 契约
This commit is contained in:
@@ -46,6 +46,8 @@
|
||||
5. 写回内存缓存和 session 派生证据时,只能写刚由 command result 生成的 payload;旧 `finalResponse`、旧 `traceSummary` 和旧 `traceResults` 不得参与 merge 覆盖。
|
||||
6. 如果 command registry 找不到该 `traceId` 对应 command,返回结构化错误,例如 `agentrun_trace_command_not_found`;不得回退到旧缓存、top-level snapshot、latest trace 或其他 command result。
|
||||
|
||||
Completed result 响应必须把 AgentRun command result 的终态证据公开为 `terminalEvidence`,并与 `agentRun.commandId`、`finalResponse.traceId` 保持一致。`/result` 和 `/trace` 响应不得导出 `fallback` 字段;降级、缺失或过期只能用 `status`、`traceStatus`、`retention`、`error` 和 `terminalEvidence` 表达,避免旧 fallback contract 重新成为并行 final response 路径。
|
||||
|
||||
Running 轮询可以返回 `202` 和当前 runnerTrace;这只是“尚未 terminal”的轮询语义,不是 final fallback。Completed / failed / canceled / blocked 等 terminal 状态必须经过同一 command registry/result 路径确认。
|
||||
|
||||
## Trace 读取与渲染流程
|
||||
|
||||
@@ -455,7 +455,6 @@ function decorateChatSessionLifecycle(payload) {
|
||||
sessionSummary: summary,
|
||||
sessionReused: summary.reused,
|
||||
isNewSession: summary.newSession,
|
||||
fallbackUsed: summary.fallback,
|
||||
degraded: summary.degraded,
|
||||
degradationReason: summary.reason,
|
||||
degradationReasonCode: summary.reasonCode
|
||||
|
||||
@@ -112,7 +112,6 @@ export function codeAgentSessionLifecycleSummary(input = {}) {
|
||||
busy: status === "busy",
|
||||
requiresNewSession,
|
||||
degraded,
|
||||
fallback: fallbackUsed,
|
||||
unsupported: input.unsupported === true,
|
||||
reasonCode: reasonCode ?? null,
|
||||
reason: reason ?? null,
|
||||
|
||||
@@ -1990,9 +1990,13 @@ test("cloud api repairs historical same-session AgentRun trace after lastTraceId
|
||||
assert.equal(secondResult.status, "completed");
|
||||
assert.equal(secondResult.agentRun.commandId, secondCommandId);
|
||||
assert.equal(secondResult.agentRun.traceId, secondTraceId);
|
||||
assert.equal(secondResult.terminalEvidence.available, true);
|
||||
assert.equal(secondResult.terminalEvidence.agentRun.commandId, secondCommandId);
|
||||
assert.equal(secondResult.terminalEvidence.finalResponse.traceId, secondTraceId);
|
||||
assert.equal(secondResult.finalResponse.traceId, secondTraceId);
|
||||
assert.match(secondText, /编译成功/u);
|
||||
assert.doesNotMatch(secondText, /目前只有一个 HWPOD 可用/u);
|
||||
assert.equal(secondText.includes('"fallback"'), false);
|
||||
assert.ok(calls.some((call) => call.path === `/api/v1/runs/${runId}/commands/${secondCommandId}/result`));
|
||||
assert.equal(ownerSessions.get("ses_issue955_historical").session.traceResults[secondTraceId].agentRun.commandId, secondCommandId);
|
||||
assert.equal(ownerSessions.get("ses_issue955_historical").session.traceResults[secondTraceId].finalResponse.text, secondFinalText);
|
||||
@@ -2109,10 +2113,14 @@ test("cloud api result polling repairs polluted completed AgentRun memory cache
|
||||
assert.equal(body.status, "completed");
|
||||
assert.equal(body.agentRun.commandId, secondCommandId);
|
||||
assert.equal(body.agentRun.traceId, secondTraceId);
|
||||
assert.equal(body.terminalEvidence.available, true);
|
||||
assert.equal(body.terminalEvidence.agentRun.commandId, secondCommandId);
|
||||
assert.equal(body.terminalEvidence.finalResponse.traceId, secondTraceId);
|
||||
assert.equal(body.reply.content, secondFinalText);
|
||||
assert.match(text, /编译成功/u);
|
||||
assert.match(text, /Keil MDK/u);
|
||||
assert.doesNotMatch(text, /目前只有一个 HWPOD 可用/u);
|
||||
assert.equal(text.includes('"fallback"'), false);
|
||||
assert.ok(calls.some((call) => call.path === `/api/v1/runs/${runId}/commands`));
|
||||
assert.ok(calls.some((call) => call.path === `/api/v1/runs/${runId}/commands/${secondCommandId}/result`));
|
||||
assert.equal(calls.some((call) => call.path === `/api/v1/runs/${runId}/commands/${firstCommandId}/result`), false);
|
||||
|
||||
@@ -2088,14 +2088,30 @@ export function createCodeAgentChatResultStore({ maxResults = 256 } = {}) {
|
||||
function compactCodeAgentChatResultPayload(payload, options = {}) {
|
||||
if (!payload || typeof payload !== "object") return payload;
|
||||
const limit = resultTraceEventLimit(options);
|
||||
const terminalEvidence = agentRunTerminalTraceEvidence(payload, payload.traceId);
|
||||
return {
|
||||
...payload,
|
||||
...(terminalEvidence ? { terminalEvidence: terminalEvidencePayload(terminalEvidence) } : {}),
|
||||
...(payload.runnerTrace && typeof payload.runnerTrace === "object"
|
||||
? { runnerTrace: compactRunnerTraceForResult(payload.runnerTrace, limit) }
|
||||
: {})
|
||||
};
|
||||
}
|
||||
|
||||
function terminalEvidencePayload(evidence) {
|
||||
return {
|
||||
available: true,
|
||||
source: evidence.source,
|
||||
conversationId: evidence.conversationId,
|
||||
sessionId: evidence.sessionId,
|
||||
threadId: evidence.threadId,
|
||||
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 : [];
|
||||
|
||||
Reference in New Issue
Block a user