Skip to content

Commit 44cc987

Browse files
committed
fix(acp-registry): bound Copilot launch error details
1 parent c771190 commit 44cc987

2 files changed

Lines changed: 59 additions & 43 deletions

File tree

‎packages/provider-acp-registry/src/server/copilotTextGeneration.test.ts‎

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import * as Effect from "effect/Effect";
1414
import * as Layer from "effect/Layer";
1515
import { vi } from "vite-plus/test";
1616

17+
import { AcpRegistryError } from "./AcpRegistrySupport.ts";
1718
import { makeCopilotTextGeneration } from "./copilotTextGeneration.ts";
1819

1920
const mockAgentPath = NodePath.join(
@@ -40,7 +41,11 @@ interface MockLog {
4041
readonly clientResponse?: { readonly id: string; readonly result?: unknown };
4142
}
4243

43-
const harness = (input: { readonly scenario: string; readonly userConfig?: string }) =>
44+
const harness = (input: {
45+
readonly scenario: string;
46+
readonly userConfig?: string;
47+
readonly resolveFailure?: AcpRegistryError;
48+
}) =>
4449
Effect.gen(function* () {
4550
const root = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-copilot-text-test-"));
4651
yield* Effect.addFinalizer(() =>
@@ -63,19 +68,21 @@ const harness = (input: { readonly scenario: string; readonly userConfig?: strin
6368
const textGeneration = yield* makeCopilotTextGeneration({
6469
environment: { COPILOT_HOME: userHome },
6570
resolveSpawn: (cwd) =>
66-
Effect.succeed({
67-
command,
68-
// A local install's own arguments must not reach the helper.
69-
args: ["--acp", "--additional-mcp-config", "@mcp.json", "--allow-all"],
70-
cwd,
71-
env: {
72-
...process.env,
73-
T3_MOCK_SCENARIO: input.scenario,
74-
T3_MOCK_LOG: logPath,
75-
COPILOT_ALLOW_ALL: "true",
76-
COPILOT_CUSTOM_INSTRUCTIONS_DIRS: userHome,
77-
},
78-
}),
71+
input.resolveFailure
72+
? Effect.fail(input.resolveFailure)
73+
: Effect.succeed({
74+
command,
75+
// A local install's own arguments must not reach the helper.
76+
args: ["--acp", "--additional-mcp-config", "@mcp.json", "--allow-all"],
77+
cwd,
78+
env: {
79+
...process.env,
80+
T3_MOCK_SCENARIO: input.scenario,
81+
T3_MOCK_LOG: logPath,
82+
COPILOT_ALLOW_ALL: "true",
83+
COPILOT_CUSTOM_INSTRUCTIONS_DIRS: userHome,
84+
},
85+
}),
7986
});
8087
const readLog = (): ReadonlyArray<MockLog> =>
8188
NodeFS.existsSync(logPath)
@@ -203,33 +210,42 @@ describe("Copilot text generation", () => {
203210
}).pipe(Effect.scoped, Effect.provide(layer)),
204211
);
205212

206-
it.live(
207-
"refuses before launching when sign-in state is unreadable or a review guide is asked",
208-
() =>
209-
Effect.gen(function* () {
210-
const unreadable = yield* harness({ scenario: "reply", userConfig: "{ not json" });
211-
const signInError = yield* Effect.flip(generateTitle(unreadable.textGeneration, "default"));
212-
assert.equal(
213-
signInError.detail,
214-
"Could not read the GitHub Copilot sign-in state for text generation.",
215-
);
216-
assert.deepEqual(unreadable.readLog(), []);
217-
218-
const review = yield* harness({ scenario: "reply" });
219-
const reviewError = yield* Effect.flip(
220-
review.textGeneration.generateReviewGuide({
221-
cwd: process.cwd(),
222-
number: 1,
223-
title: "Title",
224-
description: "",
225-
baseBranch: "main",
226-
baseCommit: "abc",
227-
settledReview: "",
228-
modelSelection: createModelSelection(instanceId, "gpt-6-luna"),
229-
}),
230-
);
231-
assert.match(reviewError.detail, /^Copilot cannot investigate a checkout read-only\./);
232-
assert.deepEqual(review.readLog(), []);
233-
}).pipe(Effect.scoped, Effect.provide(layer)),
213+
it.live("refuses before launching on sign-in, resolver or unsupported operation failures", () =>
214+
Effect.gen(function* () {
215+
const unreadable = yield* harness({ scenario: "reply", userConfig: "{ not json" });
216+
const signInError = yield* Effect.flip(generateTitle(unreadable.textGeneration, "default"));
217+
assert.equal(
218+
signInError.detail,
219+
"Could not read the GitHub Copilot sign-in state for text generation.",
220+
);
221+
assert.deepEqual(unreadable.readLog(), []);
222+
223+
const resolveFailure = new AcpRegistryError({
224+
reason: "runner_unavailable",
225+
detail: "arbitrary-output-secret-marker",
226+
});
227+
const unavailable = yield* harness({ scenario: "reply", resolveFailure });
228+
const launchError = yield* Effect.flip(generateTitle(unavailable.textGeneration, "default"));
229+
assert.equal(launchError.detail, "Could not launch GitHub Copilot (runner_unavailable).");
230+
assert.notInclude(launchError.detail, resolveFailure.detail);
231+
assert.strictEqual(launchError.cause, resolveFailure);
232+
assert.deepEqual(unavailable.readLog(), []);
233+
234+
const review = yield* harness({ scenario: "reply" });
235+
const reviewError = yield* Effect.flip(
236+
review.textGeneration.generateReviewGuide({
237+
cwd: process.cwd(),
238+
number: 1,
239+
title: "Title",
240+
description: "",
241+
baseBranch: "main",
242+
baseCommit: "abc",
243+
settledReview: "",
244+
modelSelection: createModelSelection(instanceId, "gpt-6-luna"),
245+
}),
246+
);
247+
assert.match(reviewError.detail, /^Copilot cannot investigate a checkout read-only\./);
248+
assert.deepEqual(review.readLog(), []);
249+
}).pipe(Effect.scoped, Effect.provide(layer)),
234250
);
235251
});

‎packages/provider-acp-registry/src/server/copilotTextGeneration.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export const makeCopilotTextGeneration = Effect.fn("makeCopilotTextGeneration")(
122122
(cause) =>
123123
new TextGenerationError({
124124
operation,
125-
detail: `Could not launch GitHub Copilot: ${cause.message}`,
125+
detail: `Could not launch GitHub Copilot (${cause.reason}).`,
126126
cause,
127127
}),
128128
),

0 commit comments

Comments
 (0)