@hyav/pi-provider 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +5 -5
- package/README.zh-CN.md +5 -5
- package/core/adapter-extensions.ts +9 -2
- package/core/adapter-protocol.ts +4 -2
- package/core/catalog-preflight.ts +14 -1
- package/core/host.ts +43 -75
- package/core/model-catalog.ts +13 -1
- package/core/opencode-preflight.ts +6 -0
- package/core/pi-model-metadata.ts +739 -0
- package/core/provider-registration.ts +75 -78
- package/core/public-adapters.ts +9 -1
- package/core/runtime-config.ts +18 -38
- package/core/runtime-entry.ts +11 -6
- package/core/runtime.ts +24 -104
- package/core/status-report.ts +316 -236
- package/core/types.ts +28 -19
- package/index.ts +30 -21
- package/package.json +3 -1
- package/preflight/charm-hyper.ts +6 -2
- package/preflight/deepseek.ts +10 -1
- package/preflight/github-copilot.ts +4 -0
- package/preflight/google.ts +10 -1
- package/preflight/groq.ts +10 -1
- package/preflight/openai-codex.ts +10 -1
- package/preflight/openrouter.ts +11 -2
- package/preflight/vercel-ai-gateway.ts +11 -1
- package/preflight/xai.ts +18 -4
- package/providers/charm-hyper/oauth.ts +17 -11
- package/providers/charm-hyper.ts +26 -12
- package/status/huggingface.ts +2 -1
- package/status/openrouter.ts +8 -2
- package/status/vercel-ai-gateway.ts +1 -1
- package/core/official-pricing.ts +0 -923
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ProviderConfig } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { validateProviderModelDrafts } from "./adapter-validation.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { mergeModelWithPiCatalog, type PiCatalogSnapshot, toPiCatalogSnapshot } from "./pi-model-metadata.ts";
|
|
4
4
|
import { resolvePricingDetails } from "./pricing-adjustments.ts";
|
|
5
5
|
import type { PiProviderDependencies } from "./runtime-config.ts";
|
|
6
6
|
import type {
|
|
@@ -99,13 +99,6 @@ export function normalizeProviderModels(models: ProviderModelDraft[]): ProviderM
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function cloneQuality(quality: NonNullable<OfficialModelMeta["quality"]>): NonNullable<OfficialModelMeta["quality"]> {
|
|
103
|
-
return quality.map((score) => ({
|
|
104
|
-
...score,
|
|
105
|
-
...(score.confidenceInterval ? { confidenceInterval: { ...score.confidenceInterval } } : {}),
|
|
106
|
-
}));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
102
|
function selectPricingAdjustment(
|
|
110
103
|
adapter: ProviderAdapter,
|
|
111
104
|
model: ProviderModelDraft,
|
|
@@ -147,81 +140,71 @@ function inputsEqual(left: ProviderModelDraft["input"], right: ProviderModel["in
|
|
|
147
140
|
return Array.isArray(left) && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
148
141
|
}
|
|
149
142
|
|
|
150
|
-
function getDraftCostSource(
|
|
151
|
-
draft: ProviderModelDraft | undefined,
|
|
152
|
-
officialMeta: OfficialModelMeta | undefined,
|
|
153
|
-
normalizedCost: ProviderCost,
|
|
154
|
-
): ProviderPricingSource | "default" | "normalized" {
|
|
155
|
-
const candidate = draft?.cost ?? (officialMeta?.costKnown !== false ? officialMeta?.cost : undefined);
|
|
156
|
-
if (candidate === undefined) return "default";
|
|
157
|
-
if (!costsEqual(candidate, normalizedCost)) return "normalized";
|
|
158
|
-
return draft?.cost !== undefined ? (draft.pricingSource ?? "provider") : "official";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function getFieldSource(
|
|
162
|
-
providerValue: unknown,
|
|
163
|
-
officialValue: unknown,
|
|
164
|
-
wasNormalized: boolean,
|
|
165
|
-
): "provider" | "official" | "default" | "normalized" {
|
|
166
|
-
if (providerValue === undefined && officialValue === undefined) return "default";
|
|
167
|
-
if (wasNormalized) return "normalized";
|
|
168
|
-
return providerValue !== undefined ? "provider" : "official";
|
|
169
|
-
}
|
|
170
|
-
|
|
171
143
|
function resolveModelRegistration(
|
|
172
144
|
adapter: ProviderAdapter,
|
|
173
145
|
runtime: PiProviderDependencies,
|
|
174
146
|
modelDrafts: ProviderModelDraft[],
|
|
175
|
-
|
|
147
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
176
148
|
): { models: ProviderModel[]; modelMetadata: Record<string, ProviderModelMetadata> } {
|
|
177
149
|
validateProviderModelDrafts(modelDrafts, `Provider ${adapter.id}`);
|
|
178
|
-
const
|
|
150
|
+
const catalog = toPiCatalogSnapshot(catalogSnapshot);
|
|
179
151
|
const pricingPolicy = runtime.pricingPolicies?.[adapter.id] ?? adapter.pricing;
|
|
180
152
|
const metadata: Record<string, ProviderModelMetadata> = {};
|
|
181
|
-
const adjustedDrafts =
|
|
182
|
-
const modelId =
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
reasoning
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
};
|
|
153
|
+
const adjustedDrafts = modelDrafts.map((originalDraft) => {
|
|
154
|
+
const modelId = originalDraft.id.trim();
|
|
155
|
+
const useFallback = adapter.usePiModelMetaFallback ?? true;
|
|
156
|
+
const merged = mergeModelWithPiCatalog(originalDraft, catalog, {
|
|
157
|
+
useFallback,
|
|
158
|
+
currentProviderId: adapter.id,
|
|
159
|
+
});
|
|
160
|
+
const mergedDraft = merged.draft;
|
|
161
|
+
const fieldSources = { ...merged.fieldSources };
|
|
162
|
+
|
|
163
|
+
const normalizedModel = normalizeProviderModel(mergedDraft);
|
|
164
|
+
const normalizedCost = normalizeCost(mergedDraft.cost);
|
|
165
|
+
|
|
166
|
+
if (mergedDraft.contextWindow !== undefined && mergedDraft.contextWindow !== normalizedModel.contextWindow) {
|
|
167
|
+
fieldSources.contextWindow = "normalized";
|
|
168
|
+
}
|
|
169
|
+
if (mergedDraft.maxTokens !== undefined && mergedDraft.maxTokens !== normalizedModel.maxTokens) {
|
|
170
|
+
fieldSources.maxTokens = "normalized";
|
|
171
|
+
}
|
|
172
|
+
if (mergedDraft.input !== undefined && !inputsEqual(mergedDraft.input, normalizedModel.input)) {
|
|
173
|
+
fieldSources.input = "normalized";
|
|
174
|
+
}
|
|
175
|
+
if (mergedDraft.reasoning !== undefined && mergedDraft.reasoning !== normalizedModel.reasoning) {
|
|
176
|
+
fieldSources.reasoning = "normalized";
|
|
177
|
+
}
|
|
178
|
+
if (mergedDraft.cost !== undefined && !costsEqual(mergedDraft.cost, normalizedCost)) {
|
|
179
|
+
fieldSources.cost = "normalized";
|
|
180
|
+
}
|
|
181
|
+
|
|
211
182
|
const source: ProviderPricingSource | "none" =
|
|
212
|
-
|
|
183
|
+
mergedDraft.cost === undefined
|
|
184
|
+
? "none"
|
|
185
|
+
: (mergedDraft.pricingSource ??
|
|
186
|
+
(fieldSources.cost === "mixed"
|
|
187
|
+
? "mixed"
|
|
188
|
+
: fieldSources.cost === "pi"
|
|
189
|
+
? "pi"
|
|
190
|
+
: fieldSources.cost === "provider"
|
|
191
|
+
? "provider"
|
|
192
|
+
: (originalDraft.pricingSource ?? "provider")));
|
|
193
|
+
|
|
213
194
|
const pricing = resolvePricingDetails(
|
|
214
|
-
|
|
195
|
+
mergedDraft.cost === undefined ? undefined : normalizedCost,
|
|
215
196
|
source,
|
|
216
|
-
selectPricingAdjustment(adapter,
|
|
197
|
+
selectPricingAdjustment(adapter, mergedDraft, pricingPolicy),
|
|
217
198
|
);
|
|
199
|
+
if (fieldSources.costBySku) {
|
|
200
|
+
pricing.costBySku = fieldSources.costBySku;
|
|
201
|
+
}
|
|
218
202
|
metadata[modelId] = {
|
|
219
203
|
pricing,
|
|
220
204
|
fieldSources,
|
|
221
|
-
...(officialMeta?.quality ? { quality: cloneQuality(officialMeta.quality) } : {}),
|
|
222
205
|
};
|
|
223
206
|
return {
|
|
224
|
-
...
|
|
207
|
+
...mergedDraft,
|
|
225
208
|
...(pricing.effectiveCost ? { cost: pricing.effectiveCost } : {}),
|
|
226
209
|
};
|
|
227
210
|
});
|
|
@@ -286,7 +269,6 @@ function getRegistrationState(adapter: ProviderAdapter): NonNullable<ProviderAda
|
|
|
286
269
|
if (!registration) return undefined;
|
|
287
270
|
registration.normalizedModels ??= [];
|
|
288
271
|
registration.modelMetadata ??= {};
|
|
289
|
-
registration.officialPricing ??= {};
|
|
290
272
|
registration.activeRefreshes ??= 0;
|
|
291
273
|
return registration;
|
|
292
274
|
}
|
|
@@ -321,7 +303,7 @@ function shouldOmitOptionalApiKey(adapter: ProviderAdapter, runtime: PiProviderD
|
|
|
321
303
|
export function prepareProviderRegistration(
|
|
322
304
|
adapter: ProviderAdapter,
|
|
323
305
|
runtime: PiProviderDependencies,
|
|
324
|
-
|
|
306
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
325
307
|
modelDrafts?: ProviderModelDraft[],
|
|
326
308
|
): ProviderConfig {
|
|
327
309
|
const drafts =
|
|
@@ -329,18 +311,24 @@ export function prepareProviderRegistration(
|
|
|
329
311
|
(adapter.registration?.normalizedModels === adapter.provider.models
|
|
330
312
|
? adapter.registration.modelDrafts
|
|
331
313
|
: adapter.provider.models);
|
|
332
|
-
const
|
|
314
|
+
const lifecycle = adapter.lifecycle ?? (adapter.provider.refreshModels as any)?.lifecycle;
|
|
315
|
+
if (lifecycle && drafts && drafts.length > 0) {
|
|
316
|
+
lifecycle.setModels(drafts, adapter.catalog?.source, adapter.catalog?.updatedAt);
|
|
317
|
+
}
|
|
318
|
+
const catalog = toPiCatalogSnapshot(catalogSnapshot);
|
|
319
|
+
const resolved = resolveModelRegistration(adapter, runtime, drafts, catalog);
|
|
333
320
|
const existingRegistration = getRegistrationState(adapter);
|
|
334
321
|
const registration: NonNullable<ProviderAdapter["registration"]> = existingRegistration ?? {
|
|
335
322
|
modelDrafts: drafts,
|
|
336
323
|
normalizedModels: [],
|
|
337
324
|
modelMetadata: {},
|
|
338
|
-
|
|
325
|
+
piCatalog: catalog,
|
|
339
326
|
activeRefreshes: 0,
|
|
340
327
|
};
|
|
341
328
|
registration.modelDrafts = drafts;
|
|
342
329
|
registration.modelMetadata = resolved.modelMetadata;
|
|
343
|
-
registration.
|
|
330
|
+
registration.piCatalog = catalog;
|
|
331
|
+
registration.officialPricing = catalogSnapshot as any;
|
|
344
332
|
const models = replaceModels(registration.normalizedModels, resolved.models);
|
|
345
333
|
const adapterOwnsCatalog = adapter.catalog !== undefined;
|
|
346
334
|
adapter.registration = registration;
|
|
@@ -365,7 +353,12 @@ export function prepareProviderRegistration(
|
|
|
365
353
|
registration.activeRefreshes++;
|
|
366
354
|
try {
|
|
367
355
|
const refreshedModels = await originalRefresh(options);
|
|
368
|
-
const resolved = resolveModelRegistration(
|
|
356
|
+
const resolved = resolveModelRegistration(
|
|
357
|
+
adapter,
|
|
358
|
+
runtime,
|
|
359
|
+
refreshedModels,
|
|
360
|
+
registration.piCatalog ?? registration.officialPricing,
|
|
361
|
+
);
|
|
369
362
|
const normalizedModels = replaceModels(registration.normalizedModels, resolved.models);
|
|
370
363
|
registration.modelDrafts = refreshedModels;
|
|
371
364
|
registration.modelMetadata = resolved.modelMetadata;
|
|
@@ -410,18 +403,22 @@ export function refreshProviderRegistrations(
|
|
|
410
403
|
pi: ProviderRegistrationApi,
|
|
411
404
|
providers: readonly ProviderAdapter[],
|
|
412
405
|
runtime: PiProviderDependencies,
|
|
413
|
-
|
|
406
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
414
407
|
providerDrafts?: ReadonlyMap<ProviderAdapter, ProviderModelDraft[]>,
|
|
415
408
|
): void {
|
|
409
|
+
const catalog = toPiCatalogSnapshot(catalogSnapshot);
|
|
416
410
|
for (const adapter of providers) {
|
|
417
411
|
const registration = getRegistrationState(adapter);
|
|
418
|
-
if (registration)
|
|
412
|
+
if (registration) {
|
|
413
|
+
registration.piCatalog = catalog;
|
|
414
|
+
registration.officialPricing = catalogSnapshot as any;
|
|
415
|
+
}
|
|
419
416
|
if (registration && registration.activeRefreshes > 0) {
|
|
420
417
|
registration.deferredRegistration = () =>
|
|
421
|
-
registerProviderAdapter(pi, adapter, runtime,
|
|
418
|
+
registerProviderAdapter(pi, adapter, runtime, catalogSnapshot, providerDrafts?.get(adapter));
|
|
422
419
|
continue;
|
|
423
420
|
}
|
|
424
|
-
registerProviderAdapter(pi, adapter, runtime,
|
|
421
|
+
registerProviderAdapter(pi, adapter, runtime, catalogSnapshot, providerDrafts?.get(adapter));
|
|
425
422
|
}
|
|
426
423
|
}
|
|
427
424
|
|
|
@@ -429,10 +426,10 @@ export function registerProviderAdapter(
|
|
|
429
426
|
pi: ProviderRegistrationApi,
|
|
430
427
|
adapter: ProviderAdapter,
|
|
431
428
|
runtime: PiProviderDependencies,
|
|
432
|
-
|
|
429
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
433
430
|
modelDrafts?: ProviderModelDraft[],
|
|
434
431
|
): ProviderConfig {
|
|
435
|
-
const registeredProvider = prepareProviderRegistration(adapter, runtime,
|
|
432
|
+
const registeredProvider = prepareProviderRegistration(adapter, runtime, catalogSnapshot, modelDrafts);
|
|
436
433
|
// Pi merges re-registrations, so omission alone cannot clear a raw API key
|
|
437
434
|
// left by the previous extension instance during /reload.
|
|
438
435
|
if (registeredProvider.apiKey === undefined) pi.unregisterProvider?.(adapter.id);
|
package/core/public-adapters.ts
CHANGED
|
@@ -18,7 +18,7 @@ export {
|
|
|
18
18
|
defineStatusExtension,
|
|
19
19
|
defineTunerExtension,
|
|
20
20
|
} from "./adapter-extensions.ts";
|
|
21
|
-
export { MAX_PROVIDER_MODEL_COUNT } from "./adapter-validation.ts";
|
|
21
|
+
export { MAX_PROVIDER_MODEL_COUNT, validateProviderModelDrafts } from "./adapter-validation.ts";
|
|
22
22
|
export { createCatalogPreflightAdapter } from "./catalog-preflight.ts";
|
|
23
23
|
export { withDeadline } from "./deadline.ts";
|
|
24
24
|
export {
|
|
@@ -37,6 +37,7 @@ export type {
|
|
|
37
37
|
} from "./model-catalog.ts";
|
|
38
38
|
export { createModelCatalogLifecycle } from "./model-catalog.ts";
|
|
39
39
|
export { createOpenCodeCatalogPreflightAdapter } from "./opencode-preflight.ts";
|
|
40
|
+
export { isLegacyNormalizedModel, isLegacyNormalizedSnapshot } from "./pi-model-metadata.ts";
|
|
40
41
|
export type {
|
|
41
42
|
PreflightAdapter,
|
|
42
43
|
PreflightContextLike,
|
|
@@ -48,10 +49,15 @@ export { parseRetryAfter } from "./retry-after.ts";
|
|
|
48
49
|
export type { StatusContextLike } from "./status-manager.ts";
|
|
49
50
|
export type {
|
|
50
51
|
ActiveModel,
|
|
52
|
+
ModelCatalogSource,
|
|
51
53
|
ModelCatalogStatus,
|
|
52
54
|
ProviderAdapter,
|
|
55
|
+
ProviderCost,
|
|
53
56
|
ProviderModel,
|
|
54
57
|
ProviderModelDraft,
|
|
58
|
+
ProviderPricingAdjustment,
|
|
59
|
+
ProviderPricingPolicy,
|
|
60
|
+
ProviderPricingSource,
|
|
55
61
|
ProviderRefreshContext,
|
|
56
62
|
ProviderRequestAuth,
|
|
57
63
|
StatusAdapter,
|
|
@@ -59,5 +65,7 @@ export type {
|
|
|
59
65
|
StatusEntry,
|
|
60
66
|
StatusSnapshot,
|
|
61
67
|
StoredCredentialLike,
|
|
68
|
+
ThinkingLevel,
|
|
69
|
+
TunerAdapter,
|
|
62
70
|
TunerContext,
|
|
63
71
|
} from "./types.ts";
|
package/core/runtime-config.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { homedir } from "node:os";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isValidTimeoutMs } from "./deadline.ts";
|
|
4
4
|
import type { PiProviderDefinition } from "./definition.ts";
|
|
5
|
-
import { getDefaultOpenRouterMetadataCachePath, OPENROUTER_MODELS_URL } from "./official-pricing.ts";
|
|
6
5
|
import { validatePricingPolicy } from "./pricing-adjustments.ts";
|
|
7
6
|
import type { ProviderPricingPolicy, StoredCredentialLike } from "./types.ts";
|
|
8
7
|
|
|
@@ -12,21 +11,26 @@ export interface PiProviderDependencies {
|
|
|
12
11
|
modelDiscoveryTimeoutMs: number;
|
|
13
12
|
statusRequestTimeoutMs: number;
|
|
14
13
|
liveCheckRequestTimeoutMs: number;
|
|
15
|
-
|
|
16
|
-
officialPricingTimeoutMs: number;
|
|
17
|
-
officialPricingCacheTtlMs: number;
|
|
18
|
-
officialPricingMaxStaleMs: number;
|
|
19
|
-
/** Resolved Pi agent directory; empty disables disk persistence of pricing metadata. */
|
|
14
|
+
/** Resolved Pi agent directory. */
|
|
20
15
|
agentDir: string;
|
|
21
|
-
/** Persistent cache for OpenRouter metadata used by the pricing fallback. */
|
|
22
|
-
openRouterMetadataCachePath: string;
|
|
23
16
|
/** Read Pi's stored credential metadata; injected by the Pi entrypoint. */
|
|
24
17
|
readStoredCredential: (providerId: string) => StoredCredentialLike | undefined;
|
|
25
18
|
/** Wrap ANSI-aware text to a render width; injected by the Pi entrypoint. */
|
|
26
19
|
wrapTextWithAnsi: (text: string, width: number) => string[];
|
|
27
|
-
enableOfficialPricingFallback: boolean;
|
|
28
20
|
/** Optional Pi Provider-level price policies keyed by Provider ID. */
|
|
29
21
|
pricingPolicies?: Record<string, ProviderPricingPolicy>;
|
|
22
|
+
/** @deprecated OpenRouter pricing metadata has been removed. */
|
|
23
|
+
officialPricingUrl?: string;
|
|
24
|
+
/** @deprecated No longer used. */
|
|
25
|
+
officialPricingTimeoutMs?: number;
|
|
26
|
+
/** @deprecated No longer used. */
|
|
27
|
+
officialPricingCacheTtlMs?: number;
|
|
28
|
+
/** @deprecated No longer used. */
|
|
29
|
+
officialPricingMaxStaleMs?: number;
|
|
30
|
+
/** @deprecated No longer used. */
|
|
31
|
+
openRouterMetadataCachePath?: string;
|
|
32
|
+
/** @deprecated No longer used. */
|
|
33
|
+
enableOfficialPricingFallback?: boolean;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
export type PiProviderLoader = (runtime: PiProviderDependencies) => Promise<PiProviderDefinition>;
|
|
@@ -90,7 +94,7 @@ function defaultWrapTextWithAnsi(text: string, width: number): string[] {
|
|
|
90
94
|
return chunks;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
type DefaultDependencies = Omit<PiProviderDependencies, "agentDir"
|
|
97
|
+
type DefaultDependencies = Omit<PiProviderDependencies, "agentDir">;
|
|
94
98
|
|
|
95
99
|
const defaultDependencies: DefaultDependencies = {
|
|
96
100
|
fetch: globalThis.fetch,
|
|
@@ -98,25 +102,19 @@ const defaultDependencies: DefaultDependencies = {
|
|
|
98
102
|
modelDiscoveryTimeoutMs: 3_000,
|
|
99
103
|
statusRequestTimeoutMs: 8_000,
|
|
100
104
|
liveCheckRequestTimeoutMs: 8_000,
|
|
101
|
-
officialPricingUrl: OPENROUTER_MODELS_URL,
|
|
102
|
-
officialPricingTimeoutMs: 3_000,
|
|
103
|
-
officialPricingCacheTtlMs: 60 * 60 * 1_000,
|
|
104
|
-
officialPricingMaxStaleMs: 24 * 60 * 60 * 1_000,
|
|
105
105
|
readStoredCredential: () => undefined,
|
|
106
106
|
wrapTextWithAnsi: defaultWrapTextWithAnsi,
|
|
107
|
-
enableOfficialPricingFallback: true,
|
|
108
107
|
pricingPolicies: {},
|
|
109
108
|
};
|
|
110
109
|
|
|
111
110
|
/**
|
|
112
|
-
* Programmatic defaults keep the resolved agent directory
|
|
113
|
-
*
|
|
111
|
+
* Programmatic defaults keep the resolved agent directory.
|
|
112
|
+
* The Pi entrypoint overrides `agentDir` with Pi's own resolution.
|
|
114
113
|
*/
|
|
115
114
|
export function getDefaultPiProviderDependencies(agentDir = resolveDefaultAgentDir()): PiProviderDependencies {
|
|
116
115
|
return {
|
|
117
116
|
...defaultDependencies,
|
|
118
117
|
agentDir,
|
|
119
|
-
openRouterMetadataCachePath: getDefaultOpenRouterMetadataCachePath(agentDir),
|
|
120
118
|
};
|
|
121
119
|
}
|
|
122
120
|
|
|
@@ -127,23 +125,11 @@ export function validatePiProviderDependencies(runtime: PiProviderDependencies):
|
|
|
127
125
|
["modelDiscoveryTimeoutMs", runtime.modelDiscoveryTimeoutMs],
|
|
128
126
|
["statusRequestTimeoutMs", runtime.statusRequestTimeoutMs],
|
|
129
127
|
["liveCheckRequestTimeoutMs", runtime.liveCheckRequestTimeoutMs],
|
|
130
|
-
["officialPricingTimeoutMs", runtime.officialPricingTimeoutMs],
|
|
131
128
|
] as const) {
|
|
132
129
|
if (!isValidTimeoutMs(value)) throw new Error(`Pi Provider ${name} must be a valid timeout`);
|
|
133
130
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
["officialPricingMaxStaleMs", runtime.officialPricingMaxStaleMs],
|
|
137
|
-
] as const) {
|
|
138
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
139
|
-
throw new Error(`Pi Provider ${name} must be a finite non-negative number`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (typeof runtime.officialPricingUrl !== "string" || runtime.officialPricingUrl.trim() === "") {
|
|
143
|
-
throw new Error("Pi Provider officialPricingUrl must be a non-empty string");
|
|
144
|
-
}
|
|
145
|
-
if (typeof runtime.openRouterMetadataCachePath !== "string") {
|
|
146
|
-
throw new Error("Pi Provider openRouterMetadataCachePath must be a string");
|
|
131
|
+
if (typeof runtime.agentDir !== "string") {
|
|
132
|
+
throw new Error("Pi Provider agentDir must be a string");
|
|
147
133
|
}
|
|
148
134
|
if (typeof runtime.readStoredCredential !== "function") {
|
|
149
135
|
throw new Error("Pi Provider readStoredCredential must be a function");
|
|
@@ -151,9 +137,6 @@ export function validatePiProviderDependencies(runtime: PiProviderDependencies):
|
|
|
151
137
|
if (typeof runtime.wrapTextWithAnsi !== "function") {
|
|
152
138
|
throw new Error("Pi Provider wrapTextWithAnsi must be a function");
|
|
153
139
|
}
|
|
154
|
-
if (typeof runtime.enableOfficialPricingFallback !== "boolean") {
|
|
155
|
-
throw new Error("Pi Provider enableOfficialPricingFallback must be a boolean");
|
|
156
|
-
}
|
|
157
140
|
if (runtime.pricingPolicies !== undefined) {
|
|
158
141
|
if (
|
|
159
142
|
runtime.pricingPolicies === null ||
|
|
@@ -173,9 +156,6 @@ export function resolvePiProviderDependencies(
|
|
|
173
156
|
dependencies: Partial<PiProviderDependencies> = {},
|
|
174
157
|
): PiProviderDependencies {
|
|
175
158
|
const runtime = { ...getDefaultPiProviderDependencies(), ...dependencies };
|
|
176
|
-
if (!Object.hasOwn(dependencies, "openRouterMetadataCachePath")) {
|
|
177
|
-
runtime.openRouterMetadataCachePath = getDefaultOpenRouterMetadataCachePath(runtime.agentDir);
|
|
178
|
-
}
|
|
179
159
|
if (runtime.pricingPolicies === undefined) runtime.pricingPolicies = {};
|
|
180
160
|
validatePiProviderDependencies(runtime);
|
|
181
161
|
return runtime;
|
package/core/runtime-entry.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { loadPackageAdapterExtensions } from "./adapter-loader.ts";
|
|
3
3
|
import { createPiProviderHost } from "./host.ts";
|
|
4
|
+
import type { PiCatalogSource } from "./pi-model-metadata.ts";
|
|
4
5
|
import type { PiProviderDependencies } from "./runtime-config.ts";
|
|
5
6
|
import type { StoredCredentialLike } from "./types.ts";
|
|
6
7
|
|
|
@@ -11,16 +12,20 @@ export interface PiProviderEntry {
|
|
|
11
12
|
wrapTextWithAnsi: (text: string, width: number) => string[];
|
|
12
13
|
adapterRoot?: string;
|
|
13
14
|
dependencies?: Partial<PiProviderDependencies>;
|
|
15
|
+
piCatalogSource?: PiCatalogSource;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/** Runs the Pi Provider host and adapter discovery inside a single Jiti module graph. */
|
|
17
19
|
export async function runPiProviderEntry(pi: ExtensionAPI, entry: PiProviderEntry): Promise<void> {
|
|
18
|
-
const piProviderHost = createPiProviderHost(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const piProviderHost = createPiProviderHost(
|
|
21
|
+
{
|
|
22
|
+
agentDir: entry.agentDir,
|
|
23
|
+
readStoredCredential: entry.readStoredCredential,
|
|
24
|
+
wrapTextWithAnsi: entry.wrapTextWithAnsi,
|
|
25
|
+
...entry.dependencies,
|
|
26
|
+
},
|
|
27
|
+
{ piCatalogSource: entry.piCatalogSource },
|
|
28
|
+
);
|
|
24
29
|
piProviderHost(pi);
|
|
25
30
|
await loadPackageAdapterExtensions(pi, { agentDir: entry.agentDir, userRoot: entry.adapterRoot });
|
|
26
31
|
}
|