@hyav/pi-provider 0.1.5 → 0.1.6
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 +4 -0
- package/core/adapter-extensions.ts +22 -12
- package/core/provider-registration.ts +28 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
This file is the authoritative user-facing release history for `@hyav/pi-provider`.
|
|
4
4
|
|
|
5
|
+
## 0.1.6 - 2026-08-24
|
|
6
|
+
|
|
7
|
+
- Prevent Charm Hyper model-refresh warnings when no credentials are configured by registering OAuth-capable Providers without unresolved optional environment API keys and clearing stale API-key configuration after `/reload`; configured environment and stored API keys remain supported.
|
|
8
|
+
|
|
5
9
|
## 0.1.5 - 2026-08-24
|
|
6
10
|
|
|
7
11
|
- Skip network model-catalog refreshes for Providers whose environment-backed API key is not configured and which have no resolved stored credential, retaining cached models without Pi refresh warnings.
|
|
@@ -61,9 +61,10 @@ function getStartupBridge(pi: ExtensionAPI): StartupBridge {
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
function emitRegistration(pi: ExtensionAPI, envelope: AdapterRegistrationEnvelope): void {
|
|
64
|
+
function emitRegistration(pi: ExtensionAPI, envelope: AdapterRegistrationEnvelope, onSessionStart?: () => void): void {
|
|
65
65
|
pi.events.emit(PI_PROVIDER_ADAPTER_EVENT, envelope);
|
|
66
66
|
pi.on("session_start", () => {
|
|
67
|
+
onSessionStart?.();
|
|
67
68
|
pi.events.emit(PI_PROVIDER_ADAPTER_EVENT, envelope);
|
|
68
69
|
});
|
|
69
70
|
}
|
|
@@ -92,17 +93,26 @@ function createAdapterExtension<TAdapter extends ProviderAdapter | StatusAdapter
|
|
|
92
93
|
// Host runs in a different Pi module context and cannot use this
|
|
93
94
|
// extension's module-local state. The factory is retained so a Host
|
|
94
95
|
// loaded later can recreate the adapter with its configured runtime.
|
|
95
|
-
registerProviderAdapter(pi, providerAdapter, bridge.dependencies, {}, modelDrafts);
|
|
96
|
-
emitRegistration(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
const registeredProvider = registerProviderAdapter(pi, providerAdapter, bridge.dependencies, {}, modelDrafts);
|
|
97
|
+
emitRegistration(
|
|
98
|
+
pi,
|
|
99
|
+
{
|
|
100
|
+
version: PI_PROVIDER_ADAPTER_PROTOCOL_VERSION,
|
|
101
|
+
kind: "provider",
|
|
102
|
+
id,
|
|
103
|
+
token,
|
|
104
|
+
adapter: providerAdapter,
|
|
105
|
+
factory: createAdapter,
|
|
106
|
+
startupDependencies: bridge.dependencies,
|
|
107
|
+
modelDrafts,
|
|
108
|
+
},
|
|
109
|
+
// During extension loading Pi can only remove queued registrations;
|
|
110
|
+
// repeat OAuth-only replacement after binding so /reload clears a
|
|
111
|
+
// raw environment key retained by Pi's merge semantics.
|
|
112
|
+
registeredProvider.apiKey === undefined
|
|
113
|
+
? () => registerProviderAdapter(pi, providerAdapter, bridge.dependencies, {}, modelDrafts)
|
|
114
|
+
: undefined,
|
|
115
|
+
);
|
|
106
116
|
return;
|
|
107
117
|
}
|
|
108
118
|
if (kind === "status") {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProviderConfig } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { validateProviderModelDrafts } from "./adapter-validation.ts";
|
|
3
3
|
import { applyOfficialModelCosts, findOfficialMeta, type OfficialModelMeta } from "./official-pricing.ts";
|
|
4
4
|
import { resolvePricingDetails } from "./pricing-adjustments.ts";
|
|
@@ -17,6 +17,11 @@ import type {
|
|
|
17
17
|
const DEFAULT_CONTEXT_WINDOW = 128_000;
|
|
18
18
|
const DEFAULT_MAX_TOKENS = 16_384;
|
|
19
19
|
|
|
20
|
+
type ProviderRegistrationApi = {
|
|
21
|
+
registerProvider(name: string, config: ProviderConfig): void;
|
|
22
|
+
unregisterProvider?(name: string): void;
|
|
23
|
+
};
|
|
24
|
+
|
|
20
25
|
function finiteNonNegative(value: unknown): number {
|
|
21
26
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
22
27
|
}
|
|
@@ -233,12 +238,23 @@ function replaceModels(target: ProviderModel[], source: ProviderModel[]): Provid
|
|
|
233
238
|
return target;
|
|
234
239
|
}
|
|
235
240
|
|
|
236
|
-
function
|
|
237
|
-
if (context.allowNetwork !== true || context.credential !== undefined) return false;
|
|
241
|
+
function hasMissingEnvironmentReference(apiKey: string): boolean {
|
|
238
242
|
const environmentNames = getEnvironmentReferences(apiKey);
|
|
239
243
|
return environmentNames.length > 0 && environmentNames.some((name) => !process.env[name]);
|
|
240
244
|
}
|
|
241
245
|
|
|
246
|
+
function lacksCatalogRefreshCredential(apiKey: string, context: ProviderRefreshContext): boolean {
|
|
247
|
+
return context.allowNetwork === true && context.credential === undefined && hasMissingEnvironmentReference(apiKey);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function shouldOmitOptionalApiKey(adapter: ProviderAdapter, runtime: PiProviderDependencies): boolean {
|
|
251
|
+
return (
|
|
252
|
+
adapter.provider.oauth !== undefined &&
|
|
253
|
+
hasMissingEnvironmentReference(adapter.provider.apiKey) &&
|
|
254
|
+
runtime.readStoredCredential(adapter.id)?.type !== "api_key"
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
242
258
|
/**
|
|
243
259
|
* Register a normalized Provider before the Host has assembled its final
|
|
244
260
|
* registry. The original drafts remain attached to the adapter so a Host in a
|
|
@@ -276,6 +292,10 @@ export function prepareProviderRegistration(
|
|
|
276
292
|
|
|
277
293
|
const { models: _draftModels, refreshModels: originalRefresh, ...providerMetadata } = adapter.provider;
|
|
278
294
|
const registeredProvider: ProviderConfig = { ...providerMetadata, models };
|
|
295
|
+
// Pi 0.84.2 resolves a declared environment API key before it can skip an
|
|
296
|
+
// unauthenticated catalog refresh. Register OAuth-only until the optional
|
|
297
|
+
// key exists, while preserving API-key credentials already stored by Pi.
|
|
298
|
+
if (shouldOmitOptionalApiKey(adapter, runtime)) delete registeredProvider.apiKey;
|
|
279
299
|
if (originalRefresh) {
|
|
280
300
|
registeredProvider.refreshModels = async (options: ProviderRefreshContext) => {
|
|
281
301
|
// Pi may ask every dynamic Provider to refresh. Keep the current catalog
|
|
@@ -329,7 +349,7 @@ export function cancelDeferredProviderRegistrations(providers: readonly Provider
|
|
|
329
349
|
}
|
|
330
350
|
|
|
331
351
|
export function refreshProviderRegistrations(
|
|
332
|
-
pi:
|
|
352
|
+
pi: ProviderRegistrationApi,
|
|
333
353
|
providers: readonly ProviderAdapter[],
|
|
334
354
|
runtime: PiProviderDependencies,
|
|
335
355
|
officialPricing: Record<string, OfficialModelMeta>,
|
|
@@ -348,13 +368,16 @@ export function refreshProviderRegistrations(
|
|
|
348
368
|
}
|
|
349
369
|
|
|
350
370
|
export function registerProviderAdapter(
|
|
351
|
-
pi:
|
|
371
|
+
pi: ProviderRegistrationApi,
|
|
352
372
|
adapter: ProviderAdapter,
|
|
353
373
|
runtime: PiProviderDependencies,
|
|
354
374
|
officialPricing: Record<string, OfficialModelMeta> = {},
|
|
355
375
|
modelDrafts?: ProviderModelDraft[],
|
|
356
376
|
): ProviderConfig {
|
|
357
377
|
const registeredProvider = prepareProviderRegistration(adapter, runtime, officialPricing, modelDrafts);
|
|
378
|
+
// Pi merges re-registrations, so omission alone cannot clear a raw API key
|
|
379
|
+
// left by the previous extension instance during /reload.
|
|
380
|
+
if (registeredProvider.apiKey === undefined) pi.unregisterProvider?.(adapter.id);
|
|
358
381
|
pi.registerProvider(adapter.id, registeredProvider);
|
|
359
382
|
return registeredProvider;
|
|
360
383
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyav/pi-provider",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Provider extension toolkit for Pi to integrate and manage custom LLM providers with dynamic models, request tuners, and account status.",
|
|
5
5
|
"author": "hyav",
|
|
6
6
|
"license": "MIT",
|