mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): reload model config in picker (#7036)
This commit is contained in:
parent
8472c486f4
commit
f87468131f
4 changed files with 79 additions and 10 deletions
|
|
@ -25,8 +25,8 @@ export class ModelRegistry {
|
|||
}
|
||||
|
||||
/** Reload models.json asynchronously. Await before making synchronous registry reads. */
|
||||
refresh(): Promise<void> {
|
||||
return this.runtime.reloadConfig();
|
||||
async refresh(): Promise<void> {
|
||||
await this.runtime.refresh();
|
||||
}
|
||||
|
||||
getError(): string | undefined {
|
||||
|
|
|
|||
|
|
@ -513,14 +513,10 @@ export class ModelRuntime implements Models {
|
|||
await this.refresh({ allowNetwork: this.modelNetworkEnabled });
|
||||
}
|
||||
|
||||
async reloadConfig(): Promise<void> {
|
||||
async refresh(options: ModelsRefreshOptions = {}): Promise<ModelsRefreshResult> {
|
||||
this.config = await ModelConfig.load(this.modelsPath);
|
||||
this.configureRadiusProviders();
|
||||
this.rebuildProviders();
|
||||
await this.refresh({ allowNetwork: this.modelNetworkEnabled });
|
||||
}
|
||||
|
||||
async refresh(options: ModelsRefreshOptions = {}): Promise<ModelsRefreshResult> {
|
||||
const refreshOptions = {
|
||||
...options,
|
||||
allowNetwork: options.allowNetwork ?? this.modelNetworkEnabled,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { createInMemoryModelRegistry, getModelRuntime } from "../model-runtime-test-utils.ts";
|
||||
import { createInMemoryModelRegistry, createModelRegistry, getModelRuntime } from "../model-runtime-test-utils.ts";
|
||||
/**
|
||||
* Local test harness for the new coding-agent test suite.
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import type { AgentMessage, AgentTool } from "@earendil-works/pi-agent-core";
|
||||
|
|
@ -71,6 +71,7 @@ export interface HarnessOptions {
|
|||
resourceLoader?: ResourceLoader;
|
||||
extensionFactories?: Array<InlineExtension | CreateTestExtensionsResultInput>;
|
||||
withConfiguredAuth?: boolean;
|
||||
modelsJson?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface Harness {
|
||||
|
|
@ -115,7 +116,11 @@ export async function createHarness(options: HarnessOptions = {}): Promise<Harne
|
|||
if (withConfiguredAuth) {
|
||||
await authStorage.modify(model.provider, async () => ({ type: "api_key", key: "faux-key" }));
|
||||
}
|
||||
const modelRegistry = await createInMemoryModelRegistry(authStorage);
|
||||
const modelsPath = options.modelsJson === undefined ? undefined : join(tempDir, "models.json");
|
||||
if (modelsPath) writeFileSync(modelsPath, JSON.stringify(options.modelsJson));
|
||||
const modelRegistry = modelsPath
|
||||
? await createModelRegistry(authStorage, modelsPath)
|
||||
: await createInMemoryModelRegistry(authStorage);
|
||||
if (withConfiguredAuth) {
|
||||
modelRegistry.registerProvider(model.provider, {
|
||||
baseUrl: model.baseUrl,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
import { writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { setKeybindings, type TUI } from "@earendil-works/pi-tui";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { KeybindingsManager } from "../../../src/core/keybindings.ts";
|
||||
import { ModelSelectorComponent } from "../../../src/modes/interactive/components/model-selector.ts";
|
||||
import { initTheme } from "../../../src/modes/interactive/theme/theme.ts";
|
||||
import { stripAnsi } from "../../../src/utils/ansi.ts";
|
||||
import { createHarness, type Harness } from "../harness.ts";
|
||||
|
||||
function createFakeTui(): TUI {
|
||||
return {
|
||||
requestRender: () => {},
|
||||
} as unknown as TUI;
|
||||
}
|
||||
|
||||
function modelsJson(provider: string, model: string): Record<string, unknown> {
|
||||
return {
|
||||
providers: {
|
||||
[provider]: {
|
||||
baseUrl: "https://example.test/v1",
|
||||
api: "openai-completions",
|
||||
apiKey: "test-key",
|
||||
models: [{ id: model }],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("issue #6999 models.json hot reload", () => {
|
||||
let harness: Harness | undefined;
|
||||
|
||||
beforeAll(() => {
|
||||
initTheme("dark");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
setKeybindings(new KeybindingsManager());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
harness?.cleanup();
|
||||
harness = undefined;
|
||||
});
|
||||
|
||||
it("reloads models.json when opening /model", async () => {
|
||||
harness = await createHarness({ modelsJson: modelsJson("old-provider", "old-model") });
|
||||
expect(harness.session.modelRuntime.getModel("old-provider", "old-model")).toBeDefined();
|
||||
|
||||
writeFileSync(join(harness.tempDir, "models.json"), JSON.stringify(modelsJson("new-provider", "new-model")));
|
||||
const selector = new ModelSelectorComponent(
|
||||
createFakeTui(),
|
||||
harness.getModel(),
|
||||
harness.settingsManager,
|
||||
harness.session.modelRuntime,
|
||||
[],
|
||||
() => {},
|
||||
() => {},
|
||||
);
|
||||
|
||||
await vi.waitFor(() => {
|
||||
const rendered = stripAnsi(selector.render(120).join("\n"));
|
||||
expect(rendered).toContain("new-model [new-provider]");
|
||||
expect(rendered).toContain("Model catalogs refreshed.");
|
||||
});
|
||||
expect(harness.session.modelRuntime.getModel("old-provider", "old-model")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue