Merge remote-tracking branch 'origin/main' into fix/issue-6647-retry-summary-requests-2
This commit is contained in:
@@ -143,7 +143,15 @@ export class ModelRuntime implements Models {
|
||||
const providers = builtinProviderCatalog
|
||||
.builtinProviders()
|
||||
.map((provider) =>
|
||||
provider.id === "radius" ? provider : withRemoteCatalog(provider, options.catalogBaseUrl),
|
||||
provider.id === "radius"
|
||||
? provider
|
||||
: withRemoteCatalog(
|
||||
provider,
|
||||
options.catalogBaseUrl,
|
||||
builtinProviderCatalog.getBuiltinModelDataUrl(
|
||||
provider.id as builtinProviderCatalog.BuiltinProvider,
|
||||
),
|
||||
),
|
||||
);
|
||||
const runtime = new ModelRuntime(
|
||||
credentials,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Api, Model, Provider } from "@earendil-works/pi-ai";
|
||||
import { stat } from "node:fs/promises";
|
||||
import type { Api, Model, ModelsStoreEntry, Provider } from "@earendil-works/pi-ai";
|
||||
import { VERSION } from "../config.ts";
|
||||
import { getPiUserAgent } from "../utils/pi-user-agent.ts";
|
||||
|
||||
@@ -29,8 +30,26 @@ function parseCatalog(providerId: string, value: unknown): Model<Api>[] {
|
||||
.map((model) => ({ ...model, provider: providerId }));
|
||||
}
|
||||
|
||||
function remoteModels(
|
||||
entry: ModelsStoreEntry | undefined,
|
||||
localLastModified: number | undefined,
|
||||
): readonly Model<Api>[] {
|
||||
if (!entry) return [];
|
||||
if (
|
||||
localLastModified !== undefined &&
|
||||
(entry.lastModified === undefined || entry.lastModified <= localLastModified)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
return entry.models;
|
||||
}
|
||||
|
||||
/** Add a persisted pi.dev catalog overlay to a static built-in provider. */
|
||||
export function withRemoteCatalog(provider: Provider, catalogBaseUrl: string = DEFAULT_CATALOG_BASE_URL): Provider {
|
||||
export function withRemoteCatalog(
|
||||
provider: Provider,
|
||||
catalogBaseUrl: string = DEFAULT_CATALOG_BASE_URL,
|
||||
localCatalogUrl?: URL,
|
||||
): Provider {
|
||||
let dynamicModels: readonly Model<Api>[] = [];
|
||||
let inflightRefresh: Promise<void> | undefined;
|
||||
|
||||
@@ -40,12 +59,21 @@ export function withRemoteCatalog(provider: Provider, catalogBaseUrl: string = D
|
||||
refreshModels: (context) => {
|
||||
inflightRefresh ??= (async () => {
|
||||
try {
|
||||
const localLastModified = localCatalogUrl
|
||||
? await stat(localCatalogUrl).then(
|
||||
(value) => value.mtimeMs,
|
||||
() => undefined,
|
||||
)
|
||||
: undefined;
|
||||
const stored = await context.store.read();
|
||||
if (stored) dynamicModels = stored.models.filter((model) => model.provider === provider.id);
|
||||
dynamicModels = remoteModels(stored, localLastModified).filter(
|
||||
(model) => model.provider === provider.id,
|
||||
);
|
||||
if (!context.allowNetwork || context.signal?.aborted) return;
|
||||
if (
|
||||
!context.force &&
|
||||
stored?.checkedAt !== undefined &&
|
||||
stored.lastModified !== undefined &&
|
||||
Date.now() - stored.checkedAt < REMOTE_CATALOG_REFRESH_INTERVAL_MS
|
||||
) {
|
||||
return;
|
||||
@@ -62,17 +90,23 @@ export function withRemoteCatalog(provider: Provider, catalogBaseUrl: string = D
|
||||
if (context.signal?.aborted) return;
|
||||
const checkedAt = Date.now();
|
||||
if (response.status === 404 || response.status === 501) {
|
||||
await context.store.write({ models: dynamicModels, checkedAt });
|
||||
await context.store.write({ ...(stored ?? { models: [] }), checkedAt, lastModified: 0 });
|
||||
return;
|
||||
}
|
||||
if (!response.ok) {
|
||||
await context.store.write({ models: dynamicModels, checkedAt });
|
||||
await context.store.write({ ...(stored ?? { models: [] }), checkedAt });
|
||||
throw new Error(`Model catalog request failed for ${provider.id}: ${response.status}`);
|
||||
}
|
||||
const refreshed = parseCatalog(provider.id, await response.json());
|
||||
const lastModified = Date.parse(response.headers.get("last-modified") ?? "");
|
||||
if (context.signal?.aborted) return;
|
||||
dynamicModels = refreshed;
|
||||
await context.store.write({ models: refreshed, checkedAt });
|
||||
const entry = {
|
||||
models: refreshed,
|
||||
checkedAt,
|
||||
lastModified: Number.isNaN(lastModified) ? 0 : lastModified,
|
||||
};
|
||||
dynamicModels = remoteModels(entry, localLastModified);
|
||||
await context.store.write(entry);
|
||||
} finally {
|
||||
inflightRefresh = undefined;
|
||||
}
|
||||
|
||||
@@ -107,9 +107,11 @@ function parseLoadProgress(data: unknown): LlamaProgress | undefined {
|
||||
|
||||
function parseDownloadProgress(data: unknown): LlamaProgress | undefined {
|
||||
if (typeof data !== "object" || data === null) return undefined;
|
||||
const nested = (data as { progress?: unknown }).progress;
|
||||
const files = typeof nested === "object" && nested !== null ? nested : data;
|
||||
let done = 0;
|
||||
let total = 0;
|
||||
for (const value of Object.values(data as Record<string, unknown>)) {
|
||||
for (const value of Object.values(files as Record<string, unknown>)) {
|
||||
if (typeof value !== "object" || value === null) continue;
|
||||
const entry = value as { done?: unknown; total?: unknown };
|
||||
if (typeof entry.done !== "number" || typeof entry.total !== "number") continue;
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function llamaExtension(pi: ExtensionAPI): void {
|
||||
model: target.id,
|
||||
initialMessage: "Starting…",
|
||||
cancelTitle: "Stop loading?",
|
||||
cancelMessage: `Stop loading ${target.id}?`,
|
||||
cancelMessage: target.id,
|
||||
run: (signal, update) => client.loadAndWait(target.id, update, signal),
|
||||
cancel: () => client.unload(target.id),
|
||||
});
|
||||
@@ -119,7 +119,7 @@ export default function llamaExtension(pi: ExtensionAPI): void {
|
||||
client: LlamaClient,
|
||||
model: LlamaModelInfo,
|
||||
): Promise<void> => {
|
||||
if (!(await ui.confirm("Unload model?", `Unload ${model.id}?`))) return;
|
||||
if (!(await ui.confirm("Unload model?", model.id))) return;
|
||||
await client.unloadAndWait(model.id);
|
||||
await syncCatalog(ctx, client);
|
||||
ctx.ui.notify(`Unloaded ${model.id}`);
|
||||
@@ -162,7 +162,7 @@ export default function llamaExtension(pi: ExtensionAPI): void {
|
||||
model,
|
||||
initialMessage: "Starting…",
|
||||
cancelTitle: "Stop download?",
|
||||
cancelMessage: `Stop downloading ${model}?`,
|
||||
cancelMessage: model,
|
||||
run: (signal, update) => client.downloadAndWait(model, update, signal),
|
||||
cancel: () => client.unload(model),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user