fix: carry MDTODO HWPOD context into Workbench

This commit is contained in:
root
2026-06-28 17:43:58 +08:00
committed by root
parent d17dd6f6a8
commit dc5b06cc62
16 changed files with 777 additions and 29 deletions
+77 -1
View File
@@ -97,6 +97,7 @@ export async function handleCodeAgentChatHttp(request, response, options) {
});
return;
}
params = withMdtodoExecutionPrompt(params);
const traceId = safeTraceId(getHeader(request, "x-trace-id") || params.traceId) || `trc_${randomUUID()}`;
const lifecycle = codeAgentTurnLifecycleFields(traceId, params);
@@ -133,7 +134,7 @@ export async function handleCodeAgentChatHttp(request, response, options) {
const admittedTiming = codeAgentAdmissionTimingFields(submitted?.createdAt ?? submitted?.updatedAt);
void emitCodeAgentOtelSpan("POST /v1/agent/chat", traceId, options.env ?? process.env, {
kind: 2,
attributes: { "http.method": "POST", "http.route": "/v1/agent/chat", "http.status_code": statusCode, sessionId: safeSessionId(nativeSessionChatParams.sessionId) || null, turnId: lifecycle.turnId }
attributes: { "http.method": "POST", "http.route": "/v1/agent/chat", "http.status_code": statusCode, sessionId: safeSessionId(nativeSessionChatParams.sessionId) || null, turnId: lifecycle.turnId, ...agentChatOtelAttributes(nativeSessionChatParams) }
});
sendJson(response, 202, {
accepted: true,
@@ -800,6 +801,80 @@ function safeOtelUrlHost(value) {
}
}
function withMdtodoExecutionPrompt(params = {}) {
const execution = mdtodoExecutionContextFromParams(params);
if (!execution?.hwpodId || !execution?.hwpodWorkspaceArgs) return params;
const message = firstNonEmptyValue(params.message, params.prompt, params.text);
if (!message || /hwpodWorkspaceArgs\s*:/u.test(message)) return params;
const taskRef = firstNonEmptyValue(params.taskRef, execution.taskRef) ?? "-";
const mdtodoRootRef = execution.mdtodoRootRef ?? "docs/MDTODO";
const prefix = [
"# MDTODO HWPOD 执行上下文",
`TaskRef: ${taskRef}`,
`sourceId: ${execution.sourceId ?? "-"}`,
`hwpodId: ${execution.hwpodId}`,
`nodeId: ${execution.nodeId ?? "-"}`,
`mdtodoRootRef: ${mdtodoRootRef}`,
`hwpodWorkspaceArgs: ${execution.hwpodWorkspaceArgs}`,
"所有 hwpod/hwpod-ctl 命令都必须携带上述 hwpodWorkspaceArgs。读取 MDTODO、报告和工程文件必须通过 HWPOD workspace/node-ops 入口,不得猜测或访问普通容器本地路径,也不得创建本地 .hwlab/hwpod-spec.yaml fallback。"
].join("\n");
const nextMessage = `${prefix}\n\n${message}`;
return {
...params,
message: nextMessage,
prompt: nextMessage,
launchContext: {
...(params.launchContext && typeof params.launchContext === "object" ? params.launchContext : {}),
hwpodId: execution.hwpodId,
nodeId: execution.nodeId,
mdtodoRootRef: execution.mdtodoRootRef,
hwpodWorkspaceArgs: execution.hwpodWorkspaceArgs,
contextFingerprint: execution.contextFingerprint,
executionContext: execution,
valuesRedacted: true
}
};
}
function mdtodoExecutionContextFromParams(params = {}) {
const launchContext = params.launchContext && typeof params.launchContext === "object" && !Array.isArray(params.launchContext) ? params.launchContext : null;
const execution = launchContext?.executionContext && typeof launchContext.executionContext === "object" && !Array.isArray(launchContext.executionContext) ? launchContext.executionContext : launchContext;
if (!execution || typeof execution !== "object") return null;
return {
sourceId: safeOtelConfigText(execution.sourceId ?? launchContext?.sourceId),
sourceKind: safeOtelConfigText(execution.sourceKind ?? launchContext?.sourceKind),
projectId: safeOtelConfigText(execution.projectId ?? launchContext?.projectId ?? params.projectId),
taskRef: safeOtelText(execution.taskRef ?? launchContext?.taskRef ?? params.taskRef),
fileRef: safeOtelConfigText(execution.fileRef ?? launchContext?.fileRef),
relativePath: safeOtelText(execution.relativePath ?? launchContext?.relativePath),
taskId: safeOtelConfigText(execution.taskId ?? launchContext?.taskId),
hwpodId: safeOtelText(execution.hwpodId ?? launchContext?.hwpodId),
nodeId: safeOtelText(execution.nodeId ?? launchContext?.nodeId),
mdtodoRootRef: safeOtelText(execution.mdtodoRootRef ?? launchContext?.mdtodoRootRef),
workspaceRootHash: safeOtelText(execution.workspaceRootHash ?? launchContext?.workspaceRootHash),
hwpodWorkspaceArgs: safeOtelText(execution.hwpodWorkspaceArgs ?? launchContext?.hwpodWorkspaceArgs, 500),
contextFingerprint: safeOtelText(execution.contextFingerprint ?? launchContext?.contextFingerprint),
valuesRedacted: true
};
}
function agentChatOtelAttributes(params = {}) {
const execution = mdtodoExecutionContextFromParams(params);
return {
"agent.chat.session_id": safeSessionId(params.sessionId) || null,
"agent.chat.task_ref": safeOtelText(params.taskRef ?? execution?.taskRef),
"agent.chat.source_id": safeOtelConfigText(execution?.sourceId ?? params.sourceId),
"agent.chat.hwpod_id": safeOtelText(execution?.hwpodId),
"agent.chat.workspace_root_hash": safeOtelText(execution?.workspaceRootHash),
"agent.chat.context_fingerprint": safeOtelText(execution?.contextFingerprint)
};
}
function safeOtelText(value, max = 360) {
const text = firstNonEmptyValue(value);
return text === null ? null : text.slice(0, max);
}
async function submitCodeAgentChatTurn({ params, options, traceId }) {
const traceStore = options.traceStore ?? defaultCodeAgentTraceStore;
const results = options.codeAgentChatResults ?? createCodeAgentChatResultStore();
@@ -822,6 +897,7 @@ async function submitCodeAgentChatTurn({ params, options, traceId }) {
results.set(traceId, annotateOwner(acceptedPayload, params));
void emitCodeAgentOtelSpan("provider_decision", traceId, runtimeEnv, {
attributes: {
...agentChatOtelAttributes(params),
adapterEnabled,
adapter: safeOtelConfigText(runtimeEnv.HWLAB_CODE_AGENT_ADAPTER ?? runtimeEnv.HWLAB_CODE_AGENT_PROVIDER),
provider: safeOtelConfigText(runtimeEnv.HWLAB_CODE_AGENT_PROVIDER),