Ensure custom OpenAI Responses providers resolve configured models without requiring registry entries. - update global settings model resolution to preserve custom provider model configuration - adjust engine custom-provider and fn-agent creation paths to avoid false 'model not found' failures - add regression tests for OpenAI Responses custom providers and pi create-fn-agent flows - document the custom provider model behavior and add a changeset for @runfusion/fusion Files changed: .../FN-5833-custom-provider-responses-fix.md | 10 ++++ docs/settings-reference.md | 2 +- packages/core/src/global-settings.ts | 56 +++++++++---------- packages/core/src/index.ts | 2 +- .../custom-providers-openai-responses.test.ts | 64 ++++++++++++++++++++++ .../engine/src/__tests__/custom-providers.test.ts | 33 ++++++++++- .../src/__tests__/pi-create-fn-agent.test.ts | 11 +++- packages/engine/src/custom-providers.ts | 4 +- packages/engine/src/pi.ts | 21 +++++-- 9 files changed, 162 insertions(+), 41 deletions(-) Fusion-Task-Id: FN-5833 Fusion-Task-Lineage: a59481cf-faf5-42b8-97ce-7b3eca27b4fb
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { readCustomProviders } from "../custom-providers.js";
|
|
|
|
describe("readCustomProviders", () => {
|
|
let homeDir: string;
|
|
let settingsPath: string;
|
|
|
|
beforeEach(async () => {
|
|
homeDir = await mkdtemp(join(tmpdir(), "fn-custom-providers-home-"));
|
|
settingsPath = join(homeDir, ".fusion", "settings.json");
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await rm(homeDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("returns an empty list when settings are missing or malformed", async () => {
|
|
expect(readCustomProviders(homeDir)).toEqual([]);
|
|
|
|
await mkdir(join(homeDir, ".fusion"), { recursive: true });
|
|
await writeFile(settingsPath, "{ invalid json", "utf-8");
|
|
expect(readCustomProviders(homeDir)).toEqual([]);
|
|
|
|
await writeFile(
|
|
settingsPath,
|
|
JSON.stringify({ customProviders: { id: "not-an-array" } }),
|
|
"utf-8",
|
|
);
|
|
expect(readCustomProviders(homeDir)).toEqual([]);
|
|
});
|
|
|
|
it("returns custom provider arrays from user settings", async () => {
|
|
const providers = [
|
|
{
|
|
id: "local-openai",
|
|
name: "Local OpenAI",
|
|
apiType: "openai-compatible",
|
|
baseUrl: "http://localhost:11434/v1",
|
|
apiKey: "local-key",
|
|
models: [{ id: "qwen3", name: "Qwen 3" }],
|
|
},
|
|
{
|
|
id: "anthropic-proxy",
|
|
name: "Anthropic Proxy",
|
|
apiType: "anthropic-compatible",
|
|
baseUrl: "https://anthropic.example.test",
|
|
},
|
|
];
|
|
await mkdir(join(homeDir, ".fusion"), { recursive: true });
|
|
await writeFile(
|
|
settingsPath,
|
|
JSON.stringify({ customProviders: providers }),
|
|
"utf-8",
|
|
);
|
|
|
|
expect(readCustomProviders(homeDir)).toEqual(providers);
|
|
});
|
|
|
|
it("reads from legacy ~/.pi/fusion when ~/.fusion does not exist", async () => {
|
|
const providers = [{
|
|
id: "legacy-provider",
|
|
name: "Legacy Provider",
|
|
apiType: "openai-responses",
|
|
baseUrl: "https://legacy.example.test/v1",
|
|
models: [{ id: "gpt-legacy", name: "GPT Legacy" }],
|
|
}];
|
|
const legacyPath = join(homeDir, ".pi", "fusion", "settings.json");
|
|
await mkdir(join(homeDir, ".pi", "fusion"), { recursive: true });
|
|
await writeFile(legacyPath, JSON.stringify({ customProviders: providers }), "utf-8");
|
|
|
|
expect(readCustomProviders(homeDir)).toEqual(providers);
|
|
});
|
|
|
|
it("reads from legacy ~/.pi/kb when newer settings dirs do not exist", async () => {
|
|
const providers = [{
|
|
id: "legacy-original-provider",
|
|
name: "Legacy Original Provider",
|
|
apiType: "openai-compatible",
|
|
baseUrl: "https://legacy-original.example.test/v1",
|
|
models: [{ id: "gpt-original", name: "GPT Original" }],
|
|
}];
|
|
const legacyPath = join(homeDir, ".pi", "kb", "settings.json");
|
|
await mkdir(join(homeDir, ".pi", "kb"), { recursive: true });
|
|
await writeFile(legacyPath, JSON.stringify({ customProviders: providers }), "utf-8");
|
|
|
|
expect(readCustomProviders(homeDir)).toEqual(providers);
|
|
});
|
|
});
|