@hyav/pi-provider 0.1.7 → 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 +23 -0
- package/README.md +7 -7
- package/README.zh-CN.md +7 -7
- package/core/adapter-extensions.ts +9 -2
- package/core/adapter-protocol.ts +4 -2
- package/core/adapter-validation.ts +14 -1
- package/core/catalog-preflight.ts +14 -1
- package/core/host.ts +43 -75
- package/core/model-catalog.ts +289 -0
- package/core/opencode-preflight.ts +6 -0
- package/core/pi-model-metadata.ts +739 -0
- package/core/provider-registration.ts +111 -56
- package/core/public-adapters.ts +16 -1
- package/core/runtime-config.ts +18 -38
- package/core/runtime-entry.ts +11 -6
- package/core/runtime.ts +26 -104
- package/core/status-report.ts +327 -229
- package/core/types.ts +37 -20
- package/index.ts +37 -18
- 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 +106 -236
- 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 -899
|
@@ -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,
|
|
@@ -114,56 +107,104 @@ function selectPricingAdjustment(
|
|
|
114
107
|
return model.pricingAdjustment ?? policy?.models?.[model.id.trim()] ?? policy?.defaultAdjustment;
|
|
115
108
|
}
|
|
116
109
|
|
|
110
|
+
function costsEqual(left: ProviderModelDraft["cost"], right: ProviderCost): boolean {
|
|
111
|
+
if (left === undefined) return false;
|
|
112
|
+
const candidate = left as Partial<ProviderCost>;
|
|
113
|
+
if (
|
|
114
|
+
candidate.input !== right.input ||
|
|
115
|
+
candidate.output !== right.output ||
|
|
116
|
+
candidate.cacheRead !== right.cacheRead ||
|
|
117
|
+
candidate.cacheWrite !== right.cacheWrite
|
|
118
|
+
) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const leftTiers = candidate.tiers ?? [];
|
|
122
|
+
const rightTiers = right.tiers ?? [];
|
|
123
|
+
return (
|
|
124
|
+
leftTiers.length === rightTiers.length &&
|
|
125
|
+
leftTiers.every((tier, index) => {
|
|
126
|
+
const normalized = rightTiers[index];
|
|
127
|
+
return (
|
|
128
|
+
normalized !== undefined &&
|
|
129
|
+
tier.inputTokensAbove === normalized.inputTokensAbove &&
|
|
130
|
+
tier.input === normalized.input &&
|
|
131
|
+
tier.output === normalized.output &&
|
|
132
|
+
tier.cacheRead === normalized.cacheRead &&
|
|
133
|
+
tier.cacheWrite === normalized.cacheWrite
|
|
134
|
+
);
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function inputsEqual(left: ProviderModelDraft["input"], right: ProviderModel["input"]): boolean {
|
|
140
|
+
return Array.isArray(left) && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
141
|
+
}
|
|
142
|
+
|
|
117
143
|
function resolveModelRegistration(
|
|
118
144
|
adapter: ProviderAdapter,
|
|
119
145
|
runtime: PiProviderDependencies,
|
|
120
146
|
modelDrafts: ProviderModelDraft[],
|
|
121
|
-
|
|
147
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
122
148
|
): { models: ProviderModel[]; modelMetadata: Record<string, ProviderModelMetadata> } {
|
|
123
149
|
validateProviderModelDrafts(modelDrafts, `Provider ${adapter.id}`);
|
|
124
|
-
const
|
|
150
|
+
const catalog = toPiCatalogSnapshot(catalogSnapshot);
|
|
125
151
|
const pricingPolicy = runtime.pricingPolicies?.[adapter.id] ?? adapter.pricing;
|
|
126
152
|
const metadata: Record<string, ProviderModelMetadata> = {};
|
|
127
|
-
const adjustedDrafts =
|
|
128
|
-
const modelId =
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
reasoning
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
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
|
+
|
|
157
182
|
const source: ProviderPricingSource | "none" =
|
|
158
|
-
|
|
159
|
-
|
|
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
|
+
|
|
194
|
+
const pricing = resolvePricingDetails(
|
|
195
|
+
mergedDraft.cost === undefined ? undefined : normalizedCost,
|
|
196
|
+
source,
|
|
197
|
+
selectPricingAdjustment(adapter, mergedDraft, pricingPolicy),
|
|
198
|
+
);
|
|
199
|
+
if (fieldSources.costBySku) {
|
|
200
|
+
pricing.costBySku = fieldSources.costBySku;
|
|
201
|
+
}
|
|
160
202
|
metadata[modelId] = {
|
|
161
203
|
pricing,
|
|
162
204
|
fieldSources,
|
|
163
|
-
...(officialMeta?.quality ? { quality: cloneQuality(officialMeta.quality) } : {}),
|
|
164
205
|
};
|
|
165
206
|
return {
|
|
166
|
-
...
|
|
207
|
+
...mergedDraft,
|
|
167
208
|
...(pricing.effectiveCost ? { cost: pricing.effectiveCost } : {}),
|
|
168
209
|
};
|
|
169
210
|
});
|
|
@@ -228,7 +269,6 @@ function getRegistrationState(adapter: ProviderAdapter): NonNullable<ProviderAda
|
|
|
228
269
|
if (!registration) return undefined;
|
|
229
270
|
registration.normalizedModels ??= [];
|
|
230
271
|
registration.modelMetadata ??= {};
|
|
231
|
-
registration.officialPricing ??= {};
|
|
232
272
|
registration.activeRefreshes ??= 0;
|
|
233
273
|
return registration;
|
|
234
274
|
}
|
|
@@ -263,7 +303,7 @@ function shouldOmitOptionalApiKey(adapter: ProviderAdapter, runtime: PiProviderD
|
|
|
263
303
|
export function prepareProviderRegistration(
|
|
264
304
|
adapter: ProviderAdapter,
|
|
265
305
|
runtime: PiProviderDependencies,
|
|
266
|
-
|
|
306
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
267
307
|
modelDrafts?: ProviderModelDraft[],
|
|
268
308
|
): ProviderConfig {
|
|
269
309
|
const drafts =
|
|
@@ -271,18 +311,24 @@ export function prepareProviderRegistration(
|
|
|
271
311
|
(adapter.registration?.normalizedModels === adapter.provider.models
|
|
272
312
|
? adapter.registration.modelDrafts
|
|
273
313
|
: adapter.provider.models);
|
|
274
|
-
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);
|
|
275
320
|
const existingRegistration = getRegistrationState(adapter);
|
|
276
321
|
const registration: NonNullable<ProviderAdapter["registration"]> = existingRegistration ?? {
|
|
277
322
|
modelDrafts: drafts,
|
|
278
323
|
normalizedModels: [],
|
|
279
324
|
modelMetadata: {},
|
|
280
|
-
|
|
325
|
+
piCatalog: catalog,
|
|
281
326
|
activeRefreshes: 0,
|
|
282
327
|
};
|
|
283
328
|
registration.modelDrafts = drafts;
|
|
284
329
|
registration.modelMetadata = resolved.modelMetadata;
|
|
285
|
-
registration.
|
|
330
|
+
registration.piCatalog = catalog;
|
|
331
|
+
registration.officialPricing = catalogSnapshot as any;
|
|
286
332
|
const models = replaceModels(registration.normalizedModels, resolved.models);
|
|
287
333
|
const adapterOwnsCatalog = adapter.catalog !== undefined;
|
|
288
334
|
adapter.registration = registration;
|
|
@@ -307,7 +353,12 @@ export function prepareProviderRegistration(
|
|
|
307
353
|
registration.activeRefreshes++;
|
|
308
354
|
try {
|
|
309
355
|
const refreshedModels = await originalRefresh(options);
|
|
310
|
-
const resolved = resolveModelRegistration(
|
|
356
|
+
const resolved = resolveModelRegistration(
|
|
357
|
+
adapter,
|
|
358
|
+
runtime,
|
|
359
|
+
refreshedModels,
|
|
360
|
+
registration.piCatalog ?? registration.officialPricing,
|
|
361
|
+
);
|
|
311
362
|
const normalizedModels = replaceModels(registration.normalizedModels, resolved.models);
|
|
312
363
|
registration.modelDrafts = refreshedModels;
|
|
313
364
|
registration.modelMetadata = resolved.modelMetadata;
|
|
@@ -352,18 +403,22 @@ export function refreshProviderRegistrations(
|
|
|
352
403
|
pi: ProviderRegistrationApi,
|
|
353
404
|
providers: readonly ProviderAdapter[],
|
|
354
405
|
runtime: PiProviderDependencies,
|
|
355
|
-
|
|
406
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
356
407
|
providerDrafts?: ReadonlyMap<ProviderAdapter, ProviderModelDraft[]>,
|
|
357
408
|
): void {
|
|
409
|
+
const catalog = toPiCatalogSnapshot(catalogSnapshot);
|
|
358
410
|
for (const adapter of providers) {
|
|
359
411
|
const registration = getRegistrationState(adapter);
|
|
360
|
-
if (registration)
|
|
412
|
+
if (registration) {
|
|
413
|
+
registration.piCatalog = catalog;
|
|
414
|
+
registration.officialPricing = catalogSnapshot as any;
|
|
415
|
+
}
|
|
361
416
|
if (registration && registration.activeRefreshes > 0) {
|
|
362
417
|
registration.deferredRegistration = () =>
|
|
363
|
-
registerProviderAdapter(pi, adapter, runtime,
|
|
418
|
+
registerProviderAdapter(pi, adapter, runtime, catalogSnapshot, providerDrafts?.get(adapter));
|
|
364
419
|
continue;
|
|
365
420
|
}
|
|
366
|
-
registerProviderAdapter(pi, adapter, runtime,
|
|
421
|
+
registerProviderAdapter(pi, adapter, runtime, catalogSnapshot, providerDrafts?.get(adapter));
|
|
367
422
|
}
|
|
368
423
|
}
|
|
369
424
|
|
|
@@ -371,10 +426,10 @@ export function registerProviderAdapter(
|
|
|
371
426
|
pi: ProviderRegistrationApi,
|
|
372
427
|
adapter: ProviderAdapter,
|
|
373
428
|
runtime: PiProviderDependencies,
|
|
374
|
-
|
|
429
|
+
catalogSnapshot?: PiCatalogSnapshot | Record<string, unknown>,
|
|
375
430
|
modelDrafts?: ProviderModelDraft[],
|
|
376
431
|
): ProviderConfig {
|
|
377
|
-
const registeredProvider = prepareProviderRegistration(adapter, runtime,
|
|
432
|
+
const registeredProvider = prepareProviderRegistration(adapter, runtime, catalogSnapshot, modelDrafts);
|
|
378
433
|
// Pi merges re-registrations, so omission alone cannot clear a raw API key
|
|
379
434
|
// left by the previous extension instance during /reload.
|
|
380
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 {
|
|
@@ -29,7 +29,15 @@ export {
|
|
|
29
29
|
mergeDiagnosticHeaders,
|
|
30
30
|
} from "./diagnostic-auth.ts";
|
|
31
31
|
export { isProviderDataError, ProviderDataError } from "./errors.ts";
|
|
32
|
+
export type {
|
|
33
|
+
ModelCatalogDiagnostics,
|
|
34
|
+
ModelCatalogDiscoveryResult,
|
|
35
|
+
ModelCatalogLifecycle,
|
|
36
|
+
ModelCatalogLifecycleOptions,
|
|
37
|
+
} from "./model-catalog.ts";
|
|
38
|
+
export { createModelCatalogLifecycle } from "./model-catalog.ts";
|
|
32
39
|
export { createOpenCodeCatalogPreflightAdapter } from "./opencode-preflight.ts";
|
|
40
|
+
export { isLegacyNormalizedModel, isLegacyNormalizedSnapshot } from "./pi-model-metadata.ts";
|
|
33
41
|
export type {
|
|
34
42
|
PreflightAdapter,
|
|
35
43
|
PreflightContextLike,
|
|
@@ -41,10 +49,15 @@ export { parseRetryAfter } from "./retry-after.ts";
|
|
|
41
49
|
export type { StatusContextLike } from "./status-manager.ts";
|
|
42
50
|
export type {
|
|
43
51
|
ActiveModel,
|
|
52
|
+
ModelCatalogSource,
|
|
44
53
|
ModelCatalogStatus,
|
|
45
54
|
ProviderAdapter,
|
|
55
|
+
ProviderCost,
|
|
46
56
|
ProviderModel,
|
|
47
57
|
ProviderModelDraft,
|
|
58
|
+
ProviderPricingAdjustment,
|
|
59
|
+
ProviderPricingPolicy,
|
|
60
|
+
ProviderPricingSource,
|
|
48
61
|
ProviderRefreshContext,
|
|
49
62
|
ProviderRequestAuth,
|
|
50
63
|
StatusAdapter,
|
|
@@ -52,5 +65,7 @@ export type {
|
|
|
52
65
|
StatusEntry,
|
|
53
66
|
StatusSnapshot,
|
|
54
67
|
StoredCredentialLike,
|
|
68
|
+
ThinkingLevel,
|
|
69
|
+
TunerAdapter,
|
|
55
70
|
TunerContext,
|
|
56
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
|
}
|