feat(llm): interrogate a draft provider endpoint for its models
Once a pi-ai route became a declaration rather than a catalog lookup, adding an OpenAI-compatible gateway meant knowing its model ids up front. Most such endpoints publish that list at `GET /models`, but no seam operation could ask: every one is keyed by a registered provider route, and the provider being added has no route, no stored profile, and no stored credential — the endpoint and key are values in a form. Interrogation is therefore keyed by settings namespace, which a configuration surface already holds from the configurable-provider directory. `registerModelDiscovery` offers it per namespace, `discoverModels` asks, and the request carries the draft itself. The reply is candidates, not a catalog: every field but the id is optional because most listings disclose nothing else, and adopting one is a settings write like any other. Nothing here reads or writes settings or credentials, so `settings.yaml` still decides what a route serves. `llm.discoverModels` carries the same draft over the wire. Its apiKey is the third and last payload a secret may ride, and it is never stored, logged, or echoed; every refusal folds into `model-discovery-failed`, naming the endpoint asked but never the credential offered. The pi-ai side is a plain GET for OpenAI-compatible protocols only — their listing shape is the one gateways, self-hosted servers, and the official endpoints agree on. Others say so, sending the user to hand-entry rather than reporting a guessed shape as an empty provider. The reply is read under a four-megabyte ceiling held on the bytes actually received, because the endpoint is a URL the user typed.
This commit is contained in:
@@ -588,7 +588,7 @@ The provider topology changed: an adapter registered or unregistered routes, or
|
||||
'llm/adapters-updated'(): void
|
||||
```
|
||||
|
||||
Source: [`packages/llm/llm/src/index.ts:71`](../../packages/llm/llm/src/index.ts)
|
||||
Source: [`packages/llm/llm/src/index.ts:73`](../../packages/llm/llm/src/index.ts)
|
||||
|
||||
### `llm/stream` — waterfall
|
||||
|
||||
@@ -612,7 +612,7 @@ Waterfall around every streaming model call (retry, replay, routing). Bound to t
|
||||
|
||||
Types: [GenerateOptions](../core-data-structures/core.md) · [LlmService](../core-data-structures/llm-streaming.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
|
||||
|
||||
Source: [`packages/llm/llm/src/index.ts:60`](../../packages/llm/llm/src/index.ts)
|
||||
Source: [`packages/llm/llm/src/index.ts:62`](../../packages/llm/llm/src/index.ts)
|
||||
|
||||
## `session/*`
|
||||
|
||||
|
||||
@@ -834,9 +834,9 @@ listProviders(): LlmProviderInfo[]
|
||||
* entry, or a provider already declared by any registration throws
|
||||
* `LlmError` without registering the rest. Disposed with the fiber.
|
||||
* @param entries - every configurable provider this plugin owns.
|
||||
* @returns a handle that withdraws all of them, and can atomically replace them.
|
||||
* @returns the disposer that withdraws all of them.
|
||||
*/
|
||||
registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle
|
||||
registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): () => void
|
||||
|
||||
/**
|
||||
* List every declared configurable provider, registered or dormant.
|
||||
@@ -844,6 +844,36 @@ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): Dire
|
||||
*/
|
||||
listConfigurableProviders(): LlmConfigurableProvider[]
|
||||
|
||||
/**
|
||||
* Offer to interrogate provider endpoints on behalf of the settings
|
||||
* namespace this plugin owns. The namespace is the key because that is what
|
||||
* a configuration surface already holds from the configurable-provider
|
||||
* directory, and because a provider being *added* has no route to name yet.
|
||||
* Disposed with the fiber.
|
||||
* @param settingsNs - the namespace whose profiles this discovery serves.
|
||||
* @param discover - interrogates one endpoint; must honor `request.signal`.
|
||||
* @returns the disposer that withdraws the offer.
|
||||
*/
|
||||
registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise<readonly LlmDiscoveredModel[]>, ): () => void
|
||||
|
||||
/**
|
||||
* List the settings namespaces that can interrogate a provider endpoint, so
|
||||
* a surface can offer the action only where it will work.
|
||||
* @returns the namespaces in registration order.
|
||||
*/
|
||||
listModelDiscoveryNamespaces(): string[]
|
||||
|
||||
/**
|
||||
* Interrogate one provider endpoint for the models it advertises. The
|
||||
* request describes a draft, not a stored route, so nothing here reads or
|
||||
* writes settings or credentials — the caller owns both, and the reply is
|
||||
* candidate metadata a surface may offer for adoption.
|
||||
* @param settingsNs - namespace whose registered discovery serves this draft.
|
||||
* @param request - the endpoint, protocol, and one-shot credential to use.
|
||||
* @returns the advertised models, deduplicated in endpoint order.
|
||||
*/
|
||||
async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, ): Promise<LlmDiscoveredModel[]>
|
||||
|
||||
/**
|
||||
* Resolve the retry policy captured when one provider route was registered.
|
||||
* @param provider - registered provider route to inspect.
|
||||
@@ -908,9 +938,9 @@ async prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise<Prepared
|
||||
stream(options: GenerateOptions): AsyncIterable<StreamChunk>
|
||||
```
|
||||
|
||||
Types: [AdapterRegistrationHandle](../core-data-structures/core.md) · [DirectoryRegistrationHandle](../core-data-structures/core.md) · [GenerateOptions](../core-data-structures/core.md) · [LlmAdapter](../core-data-structures/llm-streaming.md) · [LlmCallConfig](../core-data-structures/core.md) · [LlmConfigurableProvider](../core-data-structures/core.md) · [LlmModelInfo](../core-data-structures/core.md) · [LlmProviderInfo](../core-data-structures/core.md) · [LlmResolvedModelInfo](../core-data-structures/core.md) · [PreparedLlmCall](../core-data-structures/llm-streaming.md) · [ResolvedRetryPolicy](../core-data-structures/llm-streaming.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
|
||||
Types: [AdapterRegistrationHandle](../core-data-structures/core.md) · [GenerateOptions](../core-data-structures/core.md) · [LlmAdapter](../core-data-structures/llm-streaming.md) · [LlmCallConfig](../core-data-structures/core.md) · [LlmConfigurableProvider](../core-data-structures/core.md) · [LlmDiscoveredModel](../core-data-structures/core.md) · [LlmModelDiscoveryRequest](../core-data-structures/core.md) · [LlmModelInfo](../core-data-structures/core.md) · [LlmProviderInfo](../core-data-structures/core.md) · [LlmResolvedModelInfo](../core-data-structures/core.md) · [PreparedLlmCall](../core-data-structures/llm-streaming.md) · [ResolvedRetryPolicy](../core-data-structures/llm-streaming.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
|
||||
|
||||
Source: [`packages/llm/llm/src/index.ts:253`](../../packages/llm/llm/src/index.ts)
|
||||
Source: [`packages/llm/llm/src/index.ts:234`](../../packages/llm/llm/src/index.ts)
|
||||
|
||||
## `ctx.permission` — `PermissionService`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user