Archived
fix: improve executor failure handling
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { createOpencodeClient } from "@opencode-ai/sdk/v2";
|
||||
import { Agent, type Dispatcher } from "undici";
|
||||
import { Agent, fetch as undiciFetch } from "undici";
|
||||
import { log } from "../../core/contracts.js";
|
||||
|
||||
type OpenCodeClient = ReturnType<typeof createOpencodeClient>;
|
||||
@@ -27,12 +27,23 @@ export async function withPromptTransport<T>(
|
||||
bodyTimeout: 0,
|
||||
});
|
||||
try {
|
||||
return await operation((input, init) =>
|
||||
fetch(input, {
|
||||
...init,
|
||||
const customFetch: typeof fetch = async (input, init) => {
|
||||
const request = new Request(input, init);
|
||||
const body =
|
||||
request.method === "GET" || request.method === "HEAD"
|
||||
? undefined
|
||||
: new Uint8Array(await request.arrayBuffer());
|
||||
const response = await undiciFetch(request.url, {
|
||||
method: request.method,
|
||||
headers: Object.fromEntries(request.headers),
|
||||
...(body ? { body } : {}),
|
||||
signal: request.signal,
|
||||
redirect: request.redirect,
|
||||
dispatcher,
|
||||
} as RequestInit & { dispatcher: Dispatcher }),
|
||||
);
|
||||
});
|
||||
return response as unknown as Response;
|
||||
};
|
||||
return await operation(customFetch);
|
||||
} finally {
|
||||
await dispatcher.close();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function publishJob(
|
||||
context.botLogin,
|
||||
job,
|
||||
`Agent ${job.mode} failed`,
|
||||
`Request \`${job.id.slice(0, 12)}\` failed. Inspect the redacted executor and controller logs.`,
|
||||
failureDetail(job.id, result.message),
|
||||
);
|
||||
return { terminal: "failed" };
|
||||
}
|
||||
@@ -39,3 +39,12 @@ export async function publishJob(
|
||||
? publishPlan(context, job)
|
||||
: publishImplementation(context, job);
|
||||
}
|
||||
|
||||
export function failureDetail(jobId: string, message: string): string {
|
||||
const failure = message
|
||||
.replaceAll("\r\n", "\n")
|
||||
.split("\n")
|
||||
.map((line) => ` ${line}`)
|
||||
.join("\n");
|
||||
return `Request \`${jobId.slice(0, 12)}\` failed.\n\nFailure:\n\n${failure}`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import test from "node:test";
|
||||
import { withWorkBudget } from "../../adapters/opencode/transport.js";
|
||||
import {
|
||||
withPromptTransport,
|
||||
withWorkBudget,
|
||||
} from "../../adapters/opencode/transport.js";
|
||||
|
||||
test("uses a fetch implementation compatible with the prompt dispatcher", async () => {
|
||||
const server = createServer((_request, response) => response.end("ok"));
|
||||
await new Promise<void>((resolve) =>
|
||||
server.listen(0, "127.0.0.1", resolve),
|
||||
);
|
||||
try {
|
||||
const address = server.address();
|
||||
assert.ok(address && typeof address === "object");
|
||||
const response = await withPromptTransport((customFetch) =>
|
||||
customFetch(new Request(`http://127.0.0.1:${address.port}/prompt`)),
|
||||
);
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(await response.text(), "ok");
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
});
|
||||
|
||||
test("returns completed OpenCode work without finalization", async () => {
|
||||
let stopped = false;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { failureDetail } from "../../application/publication/service.js";
|
||||
|
||||
test("renders the full executor failure as literal issue comment text", () => {
|
||||
assert.equal(
|
||||
failureDetail(
|
||||
"15f9edbf-ff6f-4b29-8231-5fc394071976",
|
||||
"OpenCode prompt failed\n```embedded markdown```\nfinal detail",
|
||||
),
|
||||
"Request `15f9edbf-ff6` failed.\n\nFailure:\n\n OpenCode prompt failed\n ```embedded markdown```\n final detail",
|
||||
);
|
||||
});
|
||||
+1
-1
@@ -42,7 +42,7 @@ CMD ["node", "/opt/ci-agents/dist/application/controller/main.js"]
|
||||
|
||||
FROM runtime AS executor
|
||||
ARG TARGETARCH=amd64
|
||||
ARG OPENCODE_VERSION=1.18.2
|
||||
ARG OPENCODE_VERSION=1
|
||||
ARG GITEA_MCP_VERSION=1.3.0
|
||||
USER root
|
||||
RUN npm install --global --omit=dev "opencode-ai@${OPENCODE_VERSION}" \
|
||||
|
||||
Reference in New Issue
Block a user