mirror of
https://github.com/vercel/eve.git
synced 2026-09-20 05:35:39 +08:00
fix(eve): let /login connect source-backed gateway models without editing agent.ts
When agent.ts sets model to a gateway SDK call (gateway(...)), the login flow tried to rewrite the model, the source editor bailed, and the throw skipped the provider selection write, returning to the connection picker after every successful OAuth. A Gateway connection serves such a model as-is, so skip the rewrite and commit the connection. Signed-off-by: Rui Conti <ruiconti@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"eve": patch
|
||||
---
|
||||
|
||||
`/login` now connects a Vercel account or AI Gateway key to an agent whose `model` is a gateway SDK call (such as `gateway(...)`) without trying to rewrite `agent.ts`. Previously the failed source edit discarded the connection and returned to the connection picker, leaving the agent unusable.
|
||||
@@ -304,6 +304,35 @@ it.each(["openai", "anthropic"] as const)(
|
||||
expect(mocks.writeDefault).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
it.each(["vercel", "ai-gateway-key"] as const)(
|
||||
"connects %s to a source-backed gateway model without rewriting agent.ts",
|
||||
async (selected) => {
|
||||
mocks.authored.mockResolvedValue(undefined);
|
||||
mocks.inspect.mockResolvedValue({
|
||||
compiledState: {
|
||||
manifest: {
|
||||
config: {
|
||||
model: {
|
||||
id: "anthropic/claude-sonnet-5",
|
||||
source: {},
|
||||
routing: { kind: "gateway", target: "anthropic" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const fake = createFakePrompter({ single: () => selected, password: () => "new-key" });
|
||||
await expect(
|
||||
runModelLogin({ appRoot: "/agent", prompter: fake.prompter }),
|
||||
).resolves.toMatchObject({ kind: "ready", reload: false });
|
||||
expect(fake.selectMessages).toEqual(["Choose a connection"]);
|
||||
expect(mocks.change).not.toHaveBeenCalled();
|
||||
expect(mocks.catalog).not.toHaveBeenCalled();
|
||||
expect(mocks.writeSelection.mock.calls[0]?.slice(0, 2)).toEqual(["/agent", selected]);
|
||||
expect(mocks.writeDefault).toHaveBeenCalledWith(selected);
|
||||
expect(fake.prompter.log.warning).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
it("preserves an explicitly authored eve helper's compatible custom model", async () => {
|
||||
mocks.inspect.mockResolvedValue({
|
||||
compiledState: {
|
||||
|
||||
@@ -45,20 +45,23 @@ export function environmentConnection(
|
||||
interface LoginModel {
|
||||
selection?: string;
|
||||
external: boolean;
|
||||
/** A gateway-routed SDK model call (`gateway(...)`) the source editor cannot rewrite. */
|
||||
gatewaySource: boolean;
|
||||
}
|
||||
|
||||
async function readLoginModel(agentRoot: string): Promise<LoginModel> {
|
||||
const selection = await readAuthoredModelSelection(agentRoot);
|
||||
if (selection !== undefined)
|
||||
return { selection, external: parseModelHelper(selection) !== undefined };
|
||||
return { selection, external: parseModelHelper(selection) !== undefined, gatewaySource: false };
|
||||
// Dynamic models still need routing inspection, but ordinary source literals
|
||||
// and eve helpers do not need to compile the agent just to sign in.
|
||||
const inspection = await inspectApplication(agentRoot);
|
||||
const model = inspection.compiledState?.manifest.config.model;
|
||||
const gateway = model?.routing.kind === "gateway";
|
||||
return {
|
||||
selection:
|
||||
model?.routing.kind === "gateway" && model.source === undefined ? model.id : undefined,
|
||||
selection: gateway && model.source === undefined ? model.id : undefined,
|
||||
external: model?.routing.kind === "external",
|
||||
gatewaySource: gateway && model.source !== undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,9 +71,11 @@ function modelSelection(selected: ModelConnectionSelection, model: LoginModel) {
|
||||
? selected
|
||||
: undefined;
|
||||
const authored = model.selection === undefined ? undefined : parseModelHelper(model.selection);
|
||||
// A Gateway connection serves a source-backed gateway model as-is; signing in
|
||||
// must not depend on rewriting a `model` the editor cannot touch.
|
||||
const compatible = helper
|
||||
? authored?.helper === helper
|
||||
: model.selection !== undefined && !model.external;
|
||||
: model.gatewaySource || (model.selection !== undefined && !model.external);
|
||||
const defaultId = helper ? MODEL_HELPERS[helper].defaultModel : "openai/gpt-5.6-luna-fast";
|
||||
const currentId = authored?.id ?? model.selection;
|
||||
return { helper, compatible, defaultId, needsModels: !compatible || currentId === defaultId };
|
||||
|
||||
Reference in New Issue
Block a user