5.7 KiB
name, description
| name | description |
|---|---|
| omp-provider-row-sources | Add a provider/model row to ~/.omp/agent/models.yml by reading the harness's own catalog tables (provider name, api, window, cost, compat) instead of guessing or web-searching, then prove it with a scratch-HOME call. |
Scope
Adding (or correcting) a provider/model row in ~/.omp/agent/models.yml for a
provider the harness may already know: an upstream vendor API (DeepSeek, OpenAI,
Anthropic, Moonshot, …) or a new local endpoint. The rule this skill exists for:
almost every field you are about to research on the web already exists in the
installed bundle — research there first, and the web only confirms it.
Canonical install root (resolve the symlink first if the repo lives under a
worktree): /home/blank/.bun/install/global/node_modules/@oh-my-pi/.
The three tables that own the facts
| You want | Read | Why |
|---|---|---|
| The legal provider name, its URL marker, and which quirks the harness gates on it | pi-catalog/src/hosts.ts (minified in dist/cli.js as the VIn map; consumed by pi-catalog/src/compat/resolve.ts) |
The provider key is a lookup key, not a display name. e.g. deepseekDirect: { providers: ["deepseek"], urlMarkers: ["api.deepseek.com"] }, anthropic: { providers: ["anthropic"], urlMarkers: ["api.anthropic.com"] }. A label matching neither loses the behaviour set silently (the max_tokens field name, the thinking extraBody, the thinking-disable mode). |
Model rows: ids, contextWindow, maxTokens, cost rates, per-model compat |
pi-catalog/src/provider-models/<api>.ts — openai-compat.ts, anthropic-messages.ts, …; factory helpers openAiCompletionsDescriptor(...) / anthropicMessagesDescriptor(...) |
Rows are fetched from the provider's models-dev key, so the bundle carries the same numbers the vendor publishes (and often rates the vendor page hides). The descriptor's compat: block is the authored truth for that provider's transport shape — copy it, never simplify it. |
| The schema itself (which keys are legal on a provider vs a model, and which are required) | pi-coding-agent/src/config/models-config-schema-bundle.ts (and the identical dist/ copy) |
Provider level and model level have different field sets. Cheaper and more correct than reading the minified bundle. |
Also in pi-coding-agent/src/config/: model-registry.ts (how models.yml
merges onto the built-in catalog — #mergeCustomModels → mergeByModelKey),
resolve-config-value.ts (how apiKey values resolve).
Two traps this table pays for
- Provider-level
apionly accepts chat/judge transports. Naming a runner API (openai-speech,openai-images,openai-embeddings) at provider level fails whole-file validation and disables every custom provider, not just yours (omp modelsprints "models.yml validation failed", lists only built-ins). Runner api belongs on the model entry; see the managed skillomp-models-yml-runner-api-placement. - A
models.ymlentry is an overlay, not a replacement. Adding one model to a provider the catalog already ships does not remove the provider's other rows —omp models <provider>will show yours (yours wins on shared fields, includingcostandcontextWindow) plus the catalog rows. Same-id rows patch with thereplacetransport policy; a row that omitscontextWindowinherits the bundled row's window and its policy tiers.
Secret handling (non-prose tracked file)
Never inline the credential. apiKey resolution order is: leading ! → command
(stdout trimmed, cached for the process lifetime) → exact env-var name → literal.
So write apiKey: "!cat ~/.config/secrets/<name>_api_key" with mode 600.
- A bare
sk-…trips the pre-commit shape gate (every file type). - An unquoted
!is a YAML tag — quote it. - A quoted command value also dodges the assignment gate: the gate's value
charset rejects
~and spaces, so only a literal key matches.
Procedure
- Read the three tables above for the provider you are adding. Take the exact
provider name, base URL, api, and compat from them; take
contextWindow/maxTokens/costfrom the model row and cite the source in a comment. - Write the secret to
~/.config/secrets/<name>_api_key,chmod 600. - Edit
models.yml; for a repo-tracked config, follow that repo's own branch/log/index rules (indank/command-center: branch → issue → PR). - Verify with a scratch HOME, because
models.ymlloads at process start and a live session keeps the old registry:Then the negative control, the step that separates a real auth success from a cached/built-in answer:mkdir -p /tmp/ompx/.omp/agent /tmp/ompx/.config cp agent/models.yml agent/config.yml /tmp/ompx/.omp/agent/ ln -sfn ~/.config/secrets /tmp/ompx/.config/secrets # ~ in a !cmd value = $HOME HOME=/tmp/ompx omp models --no-extensions | grep -c 'validation failed' # must be 0 HOME=/tmp/ompx omp --model '<provider>/<id>:off' --tools bash --no-session \ --no-skills --no-rules --no-extensions --no-pty --no-lsp --no-title \ --cwd /tmp -p 'Reply with exactly the word OK and nothing else.'sedthebaseUrlto a dead port in the scratch copy and repeat — it must hang or error, not answer. Thenrm -rf /tmp/ompx(it holds endpoint URLs).
Voice notes
- Prefer the bundled schema file over grepping
dist/cli.js; grep the bundle only when the source and the bundle disagree, or for a runtime default the schema does not state (e.g.reasoningDisableModeper provider family). costis optional in the schema. Omitting it makes the status line report$0forever; one rate per direction is all the schema models, so a peak/off-peak vendor table can only carry the peak value.