Discover and synchronize OpenAI-compatible Pi provider models #32
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
allod/nexus#32
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Let an operator add an OpenAI-compatible Pi provider from its URL and bearer token, then keep its advertised model catalog synchronized without hand-written model files or inference from Nexus.
Primary goals:
/modelsendpoint, translate useful advertised metadata into Pi model entries, and import every reported model by default.Current state
scripts/pi-provideraccepts models through--modelor--models-file. The operator must separately call the provider, translate its response into Pi's model vocabulary, preserve a temporary file long enough for the command to consume it, and repeat that work whenever the provider adds or retires models.docs/credentials.mddocuments the manual interface and currently promises that the tool never verifies a remote request.The existing lifecycle already owns repository resolution, inventory classification, credential-to-provider lookup, transaction staging, rollback, recovery, derived-output validation, and Age ciphertext. This feature should extend those mechanisms rather than create a second writer or a provider-specific helper.
Operator interface
Add discovery commands with this intended shape; the development plan may adjust spelling if the final Go CLI has a more coherent equivalent:
discover-adddefaults the credential ID to the provider ID, the adapter as described below, and the target set to all machines for which inventory reportstype == "dev"andruntime == "libvirt". Repeated/comma-separated--targetremains the advanced least-privilege override, and the existingretargetcommand remains supported. Do not add a model-selection prompt: every valid reported model enters the catalog and Pi's model selector remains the place where an operator chooses one.The URL is the provider's HTTPS API base, normally ending in
/v1; discovery performsGET <base>/models. A malformed URL, failed authentication, non-success response, invalid JSON, missing/non-arraydata, empty model set, duplicate/empty model IDs, or a response too large for a documented defensive limit must fail before repository mutation. Diagnostics may include HTTP status and a bounded provider error message, but never authorization material.Keep the existing manual
addpath for providers whose discovery endpoint is absent or insufficient.Metadata translation
Treat
/modelsas OpenAI-compatible but allow useful provider extensions. Translate only an explicit allowlist into Pi model fields; do not copy the response wholesale and do not close the existing pass-through schema used by manual--models-fileinput.At minimum:
idbecomes the required Pi modelid.context_window,context_length, ormax_model_lenmay supplycontextWindow, with documented precedence when more than one appears.max_output_tokensormax_completion_tokensmay supplymaxTokens, again with documented precedence.imagebesidetextin Pi'sinputlist; otherwise remain text-only.reasoningflag. Provider metadata wins; any name-based fallback must be conservative, documented, and reported as an inference rather than a provider fact.openai-completions. If only Responses is explicitly supported, use Pi's Responses adapter. A minimal standard response with no capability declaration remains usable with the documented conservative defaults.Omit unknown limits rather than inventing provider facts, allowing Pi's own defaults to apply, and warn that the metadata was incomplete. Validate translated positive integer limits and supported Pi field shapes before staging them.
Operational metadata such as route health, reliability, evidence timestamps, and deprecation notices should inform output but should not be persisted into
models.jsonunless it is part of Pi's model schema. Warn without blocking when a provider reports an unhealthy/unknown route, unverified tool use, deprecation, or a maximum output of 1,024 tokens or fewer.Refresh and removal safety
discover-refreshresolves the provider's credential and compares the translated result with the currently configured model list. It reports three stable, sorted groups: added models, removed models, and retained models whose translated metadata changed. New models and metadata changes are staged automatically.Absence from
/modelsis not enough by itself to remove configured state. When the first response would remove any model, fetch a second complete snapshot. Abort without mutation if either response is empty/invalid or the normalized snapshots disagree. If they agree, display the removal diff and require explicit confirmation before staging it. A declined or interrupted confirmation changes nothing. This is a safety check against inconsistent discovery responses, not an inference-health probe.Preserve model order deterministically so an unchanged provider response produces no file diff. Refresh changes provider metadata only; it never changes credential targets, named tokens, or the selected deployment default.
Credential and network boundary
When
discover-addcreates a credential, read the bearer once through the existing hidden-input path. Use it to authenticate discovery and, only after discovery and all preflight checks succeed, encrypt it as thedefaultnamed token.When
discover-adduses an existing credential, or whendiscover-refreshresolves one, authenticate with only that credential's non-nulldefaultToken. Decrypt its ciphertext on demand with the configured Nexus Age identity and stream the plaintext directly into the HTTP client's private configuration/input path. Discovery against an existing credential must never add, rotate, rewrite, or change the selection of a named token.Plaintext must never enter child arguments, inherited environment, logs, diagnostics, shell tracing, command history, or persistent storage. Temporary non-secret data stays in the existing private tmpfs staging area. Zero or release plaintext buffers as far as the implementation language permits.
--prompt-tokenforces hidden interactive input for either discovery command. A missing default, missing ciphertext, or failed decryption should fall back to the same hidden prompt with a clear explanation; a supplied fallback token authenticates only this metadata operation and does not alter an existing credential. Authentication failure must not silently try other named tokens. Discovery may use a bearer only for metadata endpoints and must never call chat completions, Responses, embeddings, audio, image, or other inference endpoints.--dry-runmay perform the authenticated read and show the normalized plan, but must not mutate either repository or ciphertext. Its help and output must state that it performs network access and may decrypt or prompt for a bearer despite being non-mutating.Documentation, plan, and validation
Update command help and
docs/credentials.mdso a cold operator can perform initial discovery, understand all-dev-VM targeting and its blast radius, refresh safely, interpret warnings, recover from empty/inconsistent discovery, and know where the command stops. Use only synthetic URLs, inventories, responses, identities, and tokens in public documentation and tests.Before implementation, write and review an R3 public development plan covering the authenticated metadata boundary, on-demand Age decryption, transaction/recovery integration, interface contracts, agent gates, acceptance witnesses, and rollback. Link this issue from the plan and every implementation PR.
Exercise the production command through local fake HTTPS/HTTP-client fixtures, including:
--prompt-token;recoverat the new mutation boundaries;Retain the existing black-box lifecycle suite as a compatibility witness. Tests must use fixture inputs with the production generator/client seam rather than test-only branches in production code.
Sequencing and scope
This work is independent of allod/nexus#28. Implement it against the current
pi-provider; if allod/nexus#28 becomes active before the feature lands, coordinate the branches and preserve the discovery witnesses through the port. Do not make this feature wait for a speculative rewrite.This issue covers the public Nexus command, documentation, synthetic tests, and any narrowly required public contract additions. It does not contain or configure a real provider, bearer token, deployment inventory, machine identity, private repository path, or ciphertext. It does not commit generated deployment artifacts, rebuild machines, verify real inference, select preferred models, monitor ongoing model health, or revoke provider-side credentials. Those are separate private integration and operator steps after the public implementation is reviewed and merged.