fix: surface nested devicepod executor output

This commit is contained in:
Codex
2026-06-02 15:03:41 +08:00
parent 10af8aaf76
commit 11dc7df502
2 changed files with 20 additions and 3 deletions
+8 -2
View File
@@ -1400,8 +1400,13 @@ test("cloud api dispatches authorized device jobs to the internal device-pod exe
traceId: "trc_executor_refresh",
operationId: "op_executor_refresh",
job: { id: request.url.split("/").at(-2), devicePodId: "device-pod-71-freq", status: "completed", intent: "workspace.ls" },
output: { text: "executor output", bytes: 15, truncation: { maxBytes: 12000, truncated: false } },
text: "executor output"
output: {
executor: { status: "completed" },
output: { dispatch: { exitCode: 0, stdoutBytes: 15 } },
text: "executor output",
bytes: 15,
truncation: { maxBytes: 12000, truncated: false }
}
}));
return;
}
@@ -1468,6 +1473,7 @@ test("cloud api dispatches authorized device jobs to the internal device-pod exe
assert.equal(output.body.blocker, null);
assert.equal(output.body.freshness.stale, false);
assert.equal(output.body.output.text, "executor output");
assert.deepEqual(output.body.output.output.dispatch, { exitCode: 0, stdoutBytes: 15 });
assert.equal(output.body.truncation.truncated, false);
assert.ok(executorRequests.some((item) => item.method === "GET" && item.url.endsWith(`/jobs/${runningJob.body.job.id}/output`)));
+12 -1
View File
@@ -1765,6 +1765,7 @@ async function jsonBody(request) {
function requiredText(value, field) { const text = textOr(value, ""); if (!text) throw Object.assign(new Error(`${field} is required`), { statusCode: 400, code: "invalid_params" }); return text; }
function textOr(value, fallback) { const text = String(value ?? "").trim(); return text || fallback; }
function firstString(...values) { return values.find((value) => typeof value === "string") ?? ""; }
function normalizeObject(value) { return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {}; }
function assertDevicePodProfileSafe(profile, field = "profile") {
const findings = [];
@@ -1844,7 +1845,17 @@ function deviceJobBlocked(code, summary, retryable) { return { code, layer: "dev
function devicePodExecutorBlocker(summary) { return { code: "device_pod_executor_unavailable", layer: "device-pod", retryable: true, summary, userMessage: "Device Pod 已授权,但内部执行服务当前不可用。" }; }
function gatewayDispatchBlocker(summary) { return { code: "gateway_dispatch_unavailable", layer: "device-pod", retryable: true, summary, userMessage: "Device Pod 已授权,但当前没有可用 gateway/device-host-cli 执行通道。" }; }
function normalizeDeviceJobStatus(status, httpStatus) { const text = textOr(status, ""); return ["queued", "running", "completed", "failed", "blocked", "canceled"].includes(text) ? text : httpStatus >= 400 ? "blocked" : "running"; }
function executorOutputPayload(body, httpStatus) { return { executor: body ?? {}, output: normalizeObject(body?.output), text: typeof body?.text === "string" ? body.text : typeof body?.output?.text === "string" ? body.output.text : "", httpStatus }; }
function executorOutputPayload(body, httpStatus) {
const output = normalizeObject(body?.output);
const nestedOutput = normalizeObject(output.output);
const text = firstString(body?.text, output.text, nestedOutput.text);
return {
executor: body ?? {},
output: Object.keys(nestedOutput).length > 0 ? nestedOutput : output,
text,
httpStatus
};
}
function boundedOutput(output, maxBytes = DEVICE_JOB_OUTPUT_MAX_BYTES) {
const source = normalizeObject(output);
const text = typeof source.text === "string" ? source.text : stableJson(source);