mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(ai): replace bundled Radius catalog with gateway catalog
Models disabled by an organization owner were still listed because the fetched catalog was merged into the shipped default catalog.
This commit is contained in:
parent
36a686ee8d
commit
43d3763991
3 changed files with 29 additions and 14 deletions
|
|
@ -12,6 +12,7 @@
|
|||
- Fixed `server_busy` and `servers are currently busy` provider errors ending the turn instead of being retried ([#10543](https://github.com/earendil-works/pi/issues/10543))
|
||||
- Fixed the error message of a failed lazy API setup, such as a module load or auth failure, using its failure time as `timestamp` instead of the request start
|
||||
- Reduced context-limit request failures by estimating input at 3.5 characters per token instead of 4 when calculating output limits ([#10497](https://github.com/earendil-works/pi/issues/10497))
|
||||
- Fixed Radius models disabled by an organization owner still being listed: a fetched or cached Radius catalog now replaces the shipped default catalog instead of being merged into it
|
||||
|
||||
## [1.0.4] - 2026-10-05
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
|||
gateway === normalizeRadiusGatewayUrl(DEFAULT_RADIUS_GATEWAY)
|
||||
? Object.values(RADIUS_MODELS).map((model) => ({ ...model, provider: id }))
|
||||
: [];
|
||||
let dynamicModels = getRadiusModels(id, undefined);
|
||||
// Gateway catalog for this account. Radius org owners can disable models, so once known it replaces
|
||||
// the shipped baseline instead of overlaying it. The baseline only covers the time before any catalog exists.
|
||||
let dynamicModels: Model<"pi-messages">[] | undefined;
|
||||
const streams = piMessagesApi();
|
||||
|
||||
return {
|
||||
|
|
@ -37,19 +39,11 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
|||
apiKey: envApiKeyAuth("Radius API key", ["RADIUS_API_KEY"]),
|
||||
oauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) }),
|
||||
},
|
||||
getModels: () => {
|
||||
const merged = [...baselineModels];
|
||||
for (const model of dynamicModels) {
|
||||
const index = merged.findIndex((entry) => entry.id === model.id);
|
||||
if (index >= 0) merged[index] = model;
|
||||
else merged.push(model);
|
||||
}
|
||||
return merged;
|
||||
},
|
||||
getModels: () => dynamicModels ?? baselineModels,
|
||||
refreshModels: async (context) => {
|
||||
const stored = context.stored;
|
||||
if (stored) {
|
||||
const restored = stored.models.filter((model) => model.provider === id) as typeof dynamicModels;
|
||||
const restored = stored.models.filter((model) => model.provider === id) as Model<"pi-messages">[];
|
||||
if (
|
||||
!(await context.publish({
|
||||
update: () => {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ describe("Radius provider catalogs", () => {
|
|||
expect(provider.getModels()).toEqual([]);
|
||||
});
|
||||
|
||||
it("overlays refreshed models on the static public catalog", async () => {
|
||||
it("replaces the static public catalog with refreshed models", async () => {
|
||||
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
||||
new Response(JSON.stringify(radiusConfig()), {
|
||||
status: 200,
|
||||
|
|
@ -70,10 +70,11 @@ describe("Radius provider catalogs", () => {
|
|||
contextWindow: 424242,
|
||||
});
|
||||
expect(models.getModel("radius", "organization-only")).toBeDefined();
|
||||
expect(models.getModels("radius").length).toBeGreaterThan(radiusConfig().models.length);
|
||||
// Models disabled by the organization must not reappear from the shipped catalog.
|
||||
expect(models.getModels("radius").map((model) => model.id)).toEqual(["balanced", "organization-only"]);
|
||||
});
|
||||
|
||||
it("overlays a cached effective catalog without network access", async () => {
|
||||
it("replaces the static public catalog with a cached catalog without network access", async () => {
|
||||
const store = new InMemoryModelsStore();
|
||||
await store.write("radius", {
|
||||
models: getRadiusModelsFromConfig("radius", radiusConfig()),
|
||||
|
|
@ -86,5 +87,24 @@ describe("Radius provider catalogs", () => {
|
|||
|
||||
expect(models.getModel("radius", "balanced")?.name).toBe("Fresh Balanced");
|
||||
expect(models.getModel("radius", "organization-only")).toBeDefined();
|
||||
expect(models.getModels("radius").map((model) => model.id)).toEqual(["balanced", "organization-only"]);
|
||||
});
|
||||
|
||||
it("exposes no models when the organization disabled all of them", async () => {
|
||||
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
||||
new Response(JSON.stringify({ baseUrl: "https://radius.example/v1", models: [] }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
);
|
||||
const credentials = new InMemoryCredentialStore();
|
||||
await credentials.modify("radius", async () => ({ type: "api_key", key: "radius-key" }));
|
||||
const models = createModels({ credentials });
|
||||
models.setProvider(radiusProvider());
|
||||
|
||||
const result = await models.refresh({ providers: ["radius"] });
|
||||
|
||||
expect(result.errors).toEqual(new Map());
|
||||
expect(models.getModels("radius")).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue