[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6BYVG144WNGCDME7VSVPJ8Y":3,"skill-same:01M6BYVG144WNGCDME7VSVPJ8Y":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":54,"repositoryHtmlUrl":55,"repositoryHomepageUrl":56,"ownerHtmlUrl":57,"ownerBlogUrl":58,"ownerDescription":59,"updatedAt":60,"install":61,"resources":73},"01M6BYVG144WNGCDME7VSVPJ8Y","add-new-model",null,"Add support for a newly-released language or image generation model in pydantic-ai (e.g. openai:gpt-5.6, anthropic:claude-sonnet-5, openai:gpt-image-2). Use when a provider ships a new model id and you need to wire literals, profile flags, adapters, and tests to recognize it. Handles SDK-lag, gateway list conventions, capability probing, and direct image-model geometry.","pydantic\u002Fpydantic-ai","pydantic","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F110818415?v=4","01M6BYVCCAN7VAVS8DFHJF4GY1","Pydantic","01M6BYVCGHJCX3C0VZF6J7BA7V",21128,"MIT","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fadd-new-model\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,12],"add new model","new","add","model","websearch","sonnet","list","flags","edit","write","read","pydantic-ai","Bash","you","when","geometry","image","direct","openai","support","2026-11-10 10:12:30",false,"---\nname: add-new-model\ndescription: Add support for a newly-released language or image generation model in pydantic-ai (e.g. openai:gpt-5.6, anthropic:claude-sonnet-5, openai:gpt-image-2). Use when a provider ships a new model id and you need to wire literals, profile flags, adapters, and tests to recognize it. Handles SDK-lag, gateway list conventions, capability probing, and direct image-model geometry.\nuser-invocable: true\nallowed-tools: Bash, Read, Edit, Write, Glob, Grep, WebFetch, WebSearch, AskUserQuestion\n---\n\n# Add New Model\n\nWire a newly-released provider model into pydantic-ai. Optimized for the common case (mirror an existing sibling); flags the cases where it's *not* a mirror and needs deeper work.\n\n## Reference docs (read once before scoping)\n\n- `agent_docs\u002Fpydantic-ai-slim.md` — the **Ownership** section, plus `pydantic_ai_slim\u002Fpydantic_ai\u002Fnative_tools\u002FAGENTS.md`, for the user-visible surface this model needs to land on.\n- `pydantic_ai_slim\u002Fpydantic_ai\u002Fprofiles\u002FAGENTS.md`, `providers\u002FAGENTS.md`, `models\u002FAGENTS.md`, and `pydantic_ai_slim\u002Fpydantic_ai\u002FAGENTS.md` (the capability-flag and `Provider.model_profile()` rules), plus the **Design Rules** section of `agent_docs\u002Fpydantic-ai-slim.md`. These tell you where capability facts belong (profile vs. provider vs. model class) when the new id has non-mirror behavior.\n\n## Inputs\n\nUser invokes with `provider` + `model id` (e.g. `openai gpt-5.6`). If missing, ask via `AskUserQuestion`.\n\n## Curation rule\n\nThe model-name `Literal` aliases (`KnownModelName`, each provider's `*ModelName`, and the image, embedding and\nadvisor aliases) list the models a user would pick. They are not catalogs. Apply this rule to every id you add:\n\n- A **line** is a tier name: GPT `sol`\u002F`terra`\u002F`luna`\u002F`astra`, Claude `opus`\u002F`sonnet`\u002F`haiku`\u002F`fable`, Gemini\n  `pro`\u002F`flash`\u002F`flash-lite`, and the Gemini 4 element names `argon`\u002F`carbon`.\n- A **generation** is the major version, counted per provider.\n- Per line, list the newest id of the newest generation and the newest id of the previous generation. Remove\n  the older id the new one replaces, in the provider alias and in `KnownModelName`.\n- Leave out dated snapshots that have an undated alias, previews that a GA id superseded, floating `-latest`\n  aliases (Mistral and TypeSafe excepted: their `-latest` ids are canonical), and non-chat models.\n- On Bedrock, list one id per model: the `global.` profile when it exists, else `us.`, else the bare id.\n- Keep every id that a model alias in `docs\u002Fmodel_aliases\u002Faliases.json` resolves to, even when the rule above\n  would drop it. `tests\u002Ftest_docs_model_aliases.py` fails otherwise. Changing an alias target is a separate\n  decision under `docs\u002Fmodel_aliases\u002FAGENTS.md`.\n\nProfiles match any id, so removing an id from a literal changes autocomplete only. Never remove a profile branch\nbecause its id left a literal.\n\n## Image generation models\n\nImage-only models use a separate public surface from conversational models. If the model is consumed by `ImageGenerator`, update `KnownImageGenerationModelName` in `pydantic_ai_slim\u002Fpydantic_ai\u002Fimages\u002F__init__.py`, the relevant direct provider adapter, and its tests; do not also change conversational `KnownModelName`, profiles, gateway aliases, `ImageGenerationTool`, or `models\u002F\u003Cprovider>.py` unless that surface is explicitly supported and in scope. Add only the public model IDs the project intends to support, and do not infer or automatically add dated snapshots.\n\nKeep common, provider-agnostic controls in `images\u002Fsettings.py`, but import provider-specific setting types from the official SDK. Put model-specific size and aspect-ratio validation or mapping in the private `images\u002F_\u003Cprovider>_geometry.py` helper, and update the public support matrix in `docs\u002Fimage-generation.md`. Verify geometry against official documentation; if the provider does not publish exact output shapes, probe every documented aspect-ratio and resolution combination for every supported model and record the evidence. Prefer deterministic table tests for the full matrix, adding one representative VCR cassette only when the new model or wire behavior needs integration coverage rather than recording every image combination.\n\n## Step 1 — Verify the model exists at the provider\n\nNever trust marketing names, news articles, or guesses. Hit the provider's model-listing endpoint:\n\n| Provider  | Verification call |\n|-----------|-------------------|\n| OpenAI    | `curl -s https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fmodels -H \"Authorization: Bearer $OPENAI_API_KEY\"` |\n| Anthropic | `curl -s https:\u002F\u002Fapi.anthropic.com\u002Fv1\u002Fmodels -H \"x-api-key: $ANTHROPIC_API_KEY\" -H \"anthropic-version: 2023-06-01\"` |\n| xAI       | `curl -s https:\u002F\u002Fapi.x.ai\u002Fv1\u002Fmodels -H \"Authorization: Bearer $XAI_API_KEY\"` |\n| Google    | `curl -s https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels -H \"x-goog-api-key: $GOOGLE_API_KEY\"` |\n| Groq      | `curl -s https:\u002F\u002Fapi.groq.com\u002Fopenai\u002Fv1\u002Fmodels -H \"Authorization: Bearer $GROQ_API_KEY\"` |\n| Bedrock   | `aws bedrock list-foundation-models --region \"$AWS_REGION\"` |\n\nLoad credentials from the repo-root `.env` with `source .env && \u003Ccmd>`. `list-foundation-models` is region-scoped, so query the region your models are actually deployed in (not a hard-coded default). List **every** id the provider exposes for this release — base, dated snapshot, `-pro`, `-mini`, `-nano`, `-codex`, `-chat-latest`. Add only what actually exists; do not extrapolate sibling variants.\n\nIf the user-given id is **not** in the listing, stop and confirm with the user before proceeding.\n\n## Step 2 — Mirror the most recent add-model PR for this provider\n\n```bash\ngit log --all --oneline --grep=\"\u003Cprevious-version-pattern>\" -20\n# e.g. for openai: --grep=\"gpt-5\\.4\\|gpt-5\\.3\"\n# e.g. for anthropic: --grep=\"claude-opus-4\\|claude-sonnet-4\"\n```\n\nPick the smallest, most recent \"add model X\" PR for the same provider. Pull its file list with `gh pr view \u003Cnum> --json files --jq '.files[].path'`. **That file list is the floor of what you'll touch.** It is rarely the ceiling.\n\n## Step 3 — Enumerate (load-bearing step)\n\nFor every variable, tuple, and literal you're about to touch, grep its readers across the repo. **This step is what catches the snapshot\u002Fenumeration tests that ratchet on every model add.** Skipping it pushes work onto CI and produces broken PRs.\n\nSpecifically, for a typical model add, grep for:\n\n- The previous model id literal you're mirroring (e.g. `gpt-5.4`, `claude-opus-4-5`) — `rg '\u003Cprev-id>' --glob '!**\u002F*.yaml' --glob '!**\u002Fcassettes\u002F**'`\n- Search for the previous model's display name in docs and public docstrings; inspect capability rosters for the same features.\n- Every prefix\u002Fmembership key in the profile module you're editing (e.g. OpenAI's `_REASONING_SUPPORT_BY_PREFIX` keys, Anthropic's inline `model_name.startswith((...))` tuples, xAI's `_GROK_43_REASONING_MODELS`)\n- `KnownModelName` and its provider-block neighbours\n- Snapshot test files: `tests\u002Fmodels\u002Ftest_model_names.py`, `tests\u002Ftest_capability_spec.py`\n- Public API compatibility: the release comparison reports a model-name `Literal` change as an attribute-value change. The gate passes added and removed names on an alias listed under `model_name_literals` in `.github\u002Fapi-compatibility-allowlist.json`. Do not add a waiver for that change: the gate fails on an unused waiver. If the gate fails on a model-name alias that is not listed, add its `path` and `symbol` to `model_name_literals`. Any other change to the alias, such as adding a non-`Literal` arm, needs an exact waiver.\n\nClassify each hit:\n- **must update** — model-name lists, dispatch tuples\n- **snapshot to refresh** — `inline_snapshot` blocks needing `pytest --inline-snapshot=fix`\n- **skip** — VCR cassettes, docs about an unrelated model\n\nIf `rg` output looks mangled (unicode\u002Fregex artifacts), drop to `grep -n` — don't push past garbled output.\n\n## Step 3b — Verify pricing and context data\n\nPricing additions belong to the automated workflows in `pydantic\u002Fgenai-prices`.\nThe [Update prices workflow](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002Fupdate-prices.yml)\nimports provider data hourly and aggregator data weekly.\n[Genie Pricer](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002FGENIE_PRICER.md)\nhandles targeted model additions through the\n[Model Price Check workflow](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002Fagentic-model-price-check.md).\nDo not open or implement a manual genai-prices counterpart PR during a model add.\nDo not trigger a pricing request unless the user authorizes that request.\n\nVerify the exact API IDs and hosting providers independently of pricing data.\nDo not infer availability from an older sibling or a pricing match.\nDo not block model-name support on pricing-feed lag.\n\nCost and `context_window` data come from `pydantic\u002Fgenai-prices` through `_genai_prices.py`.\nBundled data requires a `genai-prices` release.\nCheck both the installed package and the live merged feed for the exact model.\nUpdate the Pydantic AI lock when adopting a package release with the entry.\nThe live merged feed can supply entries through `pydantic_ai.prices.update_in_background()`.\nCheck the updater for an entry before claiming a package release blocks support.\n`Model.profile` only consults genai-prices when nothing else set `context_window`.\nWithout a price entry in either source, `ModelResponse.cost()` raises `LookupError` and a\n`cost_limit` cannot be enforced — the run warns `CostNotFoundWarning` at the end instead.\nWithout a `context_window` value from any source, `RunContext.context_window_used` is `None`.\nCompare matched prices against the provider's official rates; a broad sibling match can silently return stale prices.\nReport missing or incorrect data and link an existing automation proposal when available.\n\n## Step 4 — SDK pin check\n\nThe OpenAI, Anthropic and xAI aliases are curated `Literal`s, not the SDK's model literal. `tests\u002Fmodels\u002Ftest_model_names.py`\nties the two together through `SDK_MODEL_LITERALS`:\n\n- `test_sdk_model_literal` snapshots each SDK's full model literal at the version in `uv.lock`. It skips on CI legs\n  that install another version (lowest-versions, the upgrade canary).\n- `test_curated_model_names_are_sdk_ids_or_bridges` requires every curated id to be in the locked SDK's literal or in\n  that entry's `bridges`, and every bridge to be absent from the SDK.\n\nCheck whether the locked SDK lists the new id:\n\n```bash\nuv run python -c \"from openai.types import AllModels; from typing import get_args; print([m for m in get_args(AllModels) if '\u003Cnew-version>' in m])\"\n```\n\nAnthropic reads `anthropic.types.ModelParam`, xAI reads `xai_sdk.types.model.ChatModel`, and the image and embedding\nentries read the SDK types `SDK_MODEL_LITERALS` names. If the locked SDK lacks the id, add the id to that entry's\n`bridges`. Remove the bridge in the PR that bumps the SDK past the release that lists it.\n\nWhen a `uv.lock` upgrade changes an SDK's model literal, `test_sdk_model_literal` fails. Review the new ids against\nthe curation rule, update the curated alias and `KnownModelName`, drop any bridge the SDK now lists, then run\n`uv run pytest tests\u002Fmodels\u002Ftest_model_names.py --inline-snapshot=fix`.\n\nIf a release lists the id but sits inside the 7-day `exclude-newer` window, bridge it. For Anthropic, the SDK-bump\nbullet in its landmine section decides between bump and bridge.\n\n## Step 5 — Probe capabilities (only if not a pure mirror)\n\nIf the new model is just another sibling in an existing family (e.g. `gpt-5.5` after `gpt-5.4`), skip to Step 6 — the existing profile branch covers it once you add the prefix to the dispatch tuple.\n\nIf the model is a new family or has unclear capabilities, write a small comparison script (`local-notes\u002Fprobe_\u003Cmodel>.py`) that hits the new model AND its closest neighbour with:\n- `temperature` \u002F `top_p` (does the API reject sampling params?)\n- `reasoning.effort` values (`none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) — note which the API accepts. OpenAI's 400 lists the accepted values. Probe `max` on both the Responses and Chat Completions APIs: they accept different sets, recorded in `openai_responses_supports_max_reasoning_effort` (set in `OpenAIProvider.model_profile`) and `openai_chat_supports_max_reasoning_effort` (set in each OpenAI-compatible provider's `model_profile`)\n- New parameters mentioned in the release notes\n- Streaming \u002F tool calls if the family is new\n\nDiff the responses. Anything that diverges from the neighbour belongs in the profile.\n\n### Gateway parity\n\nWhere the gateway serves a model, it must behave the same as the provider's canonical API. Step 3 only\ngets the id recognized; this is about behavior, and nothing enumerates it for you.\n\nThe gateway reaches the canonical API through an ordinary SDK client carrying a proxy base URL. So:\n\n- **Narrow a capability by client class, never by base URL.** Bedrock, Vertex and Foundry are separate\n  transports and earn their own gates. A proxied client is the canonical API, and must keep every\n  capability the unproxied one has.\n- **A `base_url` test inside a capability decision is the defect, not the fix.** It splits the gateway\n  off from the transport it actually reaches. No capability in `models\u002F` or `profiles\u002F` is decided that\n  way — if you are about to be the first, you are answering the wrong question.\n- **Probe the gateway leg rather than reasoning about it.** `Model('\u003Cid>', provider='gateway')`, then\n  exercise whatever capability you gated. If `PYDANTIC_AI_GATEWAY_BASE_URL` is set in the environment,\n  check it points at the gateway root: a provider-specific proxy path 404s every other provider.\n\n## Step 6 — Edit (minimal diff matching the mirrored PR)\n\nMake only the changes the enumeration step surfaced. Resist scope creep. If you suspect a pre-existing bug in a sibling model's profile, reproduce it live first. Fold a reproduced bug on the same profile gate into this PR, with a test and one PR-body line. Flag an unreproduced or larger one in the PR description instead.\n\n**Assume the Gateway serves every new id on a provider it proxies.** Add each id's `gateway\u002F` mirror to `KnownModelName` without probing the Gateway first. Never add a new id to `UNSUPPORTED_GATEWAY_MODEL_NAMES`. Until genai-prices has the id's price, the Gateway can refuse it with a 404 `No cost data available for model`; that gap closes without a Pydantic AI change. File one tracking issue per release instead, to confirm that the Gateway serves and prices each new id. Route it with the maintainer routing in the `file-followup-issue` skill. List every id of the release in it, including ids the curation rule keeps out of `KnownModelName`. List each Bedrock region prefix as its own id: Gateway support for one inference profile does not establish support for another. Name the weekly Gateway Model Health workflow (`.github\u002Fworkflows\u002Fgateway-model-health.yml`) in the issue: it runs every `gateway\u002F` id in `KnownModelName` live. Exclude an id only in a separate change, after the tracking issue confirms that the Gateway refuses it.\n\n**Assume Bedrock serves a new id that AWS gates per account.** AWS can list a model in `aws bedrock list-inference-profiles` while Converse still answers `AccessDeniedException: ... is not available for this account`. List the id anyway, as the curation rule picks it: the `global.` profile when it exists. Leave the capability gates in `providers\u002F_bedrock_model_names.py` on their existing prefixes. File one Bedrock tracking issue for the probes to run once AWS grants access. Route it with the maintainer routing in the `file-followup-issue` skill. List these probes in it:\n\n- The id serves through `BedrockConverseModel` and the Bedrock Messages API.\n- Each gate whose prefix decision contradicts the AWS model card or Anthropic's Bedrock docs.\n\nChange a gate only after its probe passes. A GPT id on `bedrock:` is the exception: list it only after a successful Converse call, as the Bedrock landmines say.\n\nDocs examples name models through the aliases in `docs\u002Fmodel_aliases\u002Faliases.json`, not model ids. Check the placement rules in `docs\u002Fmodel_aliases\u002FAGENTS.md`. When they place the new model in an alias, repoint that alias in `aliases.json` instead of editing doc pages. Repoint it in the same PR; do not wait for the Gateway to serve the new id. Then update the README mirrors that `tests\u002Ftest_docs_parity.py` and `tests\u002Fharness\u002Ftest_docs_parity.py` flag. The harness capability READMEs and their `_capability.py` docstrings mirror doc pages that use the alias but are not parity-tested: `git grep` the old id and update those mirrors too.\n\nAfter edits:\n\n```bash\nmake format && make lint\nPYRIGHT_PYTHON_IGNORE_WARNINGS=1 uv run pyright \u003Cchanged-python-files>\n```\n\nRun the tests directly touching the changed surface — the profile test plus any enumeration tests you updated. CI is the safety net for the long tail; locally you only need to verify the surface area of your change.\n\nIf snapshot tests changed: `uv run pytest \u003Cfile> --inline-snapshot=fix` then verify the diff is the expected literal addition only.\n\n## Step 7 — VCR \u002F integration tests\n\n**Default for mirror-only adds:** skip recording a new VCR. Repo convention uses one representative model per family for VCR (e.g. `gpt-5.2` covers the gpt-5.x reasoning family). The profile unit test added in Step 6 is sufficient.\n\n**When the new model introduces meaningful changes** to `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F\u003Cprovider>.py` (new request shape, new response field, new handler branch):\n\n1. Look for an existing parametrized VCR test that covers the changed feature. `rg -l '\u003Cfeature-name>' tests\u002Fmodels\u002F`. If one exists and it parametrizes over model ids, **tag the new id onto the parametrize list** rather than writing a new test.\n2. If no parametrized coverage exists and you need a new VCR test, place it:\n   - **Prefer** `tests\u002Fmodels\u002F\u003Cprovider>\u002Ftest_\u003Cfeature>.py` **only if the file already exists** (e.g. `tests\u002Fmodels\u002Fanthropic\u002Ftest_output.py`).\n   - Otherwise add it to `tests\u002Fmodels\u002Ftest_\u003Cprovider>.py`. **Do not create a new `tests\u002Fmodels\u002F\u003Cprovider>\u002F` subdirectory** if one doesn't already exist for this provider.\n3. Record using the `testing-skill` skill workflow.\n\n## Step 8 — PR\n\nFollow the `pushing-commits-to-the-repo` skill for the title, body, template, and final metadata\ncheck. Keep the model-specific evidence concise:\n\n- One sentence: what model(s) were added.\n- \"Verified via probe \u002F mirror of #NNNN\" — explicit about which changes were API-verified vs assumed-by-mirror.\n- Flag pre-existing latent bugs found but deliberately not fixed.\n- Link the prior add-model PR for context.\n- Link the Gateway tracking issue from Step 6, and the Bedrock tracking issue when Step 6 filed one.\n\n## Provider-specific landmines\n\n### OpenAI\n\n- **`_REASONING_SUPPORT_BY_PREFIX`** in `pydantic_ai_slim\u002Fpydantic_ai\u002Fprofiles\u002Fopenai.py` — a dict keyed by model-name prefix (`'gpt-5.6'`, `'gpt-5.3-chat'`, `'gpt-5'`, `'o'`, …) → `_ReasoningSupport(enabled_by_default, can_be_disabled, supports_mode, supports_context)`, resolved **first-match-wins** by `_reasoning_support()`. A new `gpt-5.N` family MUST be added here, and **ordering matters**: a more specific prefix (`'gpt-5.3-chat'`) must precede the broader one it would otherwise shadow (`'gpt-5.3'`), and every newer `gpt-5.x` family must precede the plain `'gpt-5'` catch-all. Miss it and the model falls through to the `_NO_REASONING` default (`thinking_always_enabled=False`, `openai_supports_reasoning_effort_none=False`) — wrong defaults, no error. The resolved matrix is pinned in `tests\u002Fprofiles\u002Ftest_openai.py`.\n- **`KnownModelName` lives in `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F_known_model_names.py`** (a `TypeAliasType`), **not** `models\u002F__init__.py`. Add the id to its `openai:`, `openai-chat:` and `gateway\u002Fopenai:` entries, and remove the ids the curation rule retires.\n- **Most `gpt-5.x-chat` variants DO reason** (`_ALWAYS_ON_REASONING`: reason at a fixed effort, reject `reasoning_effort='none'` and sampling parameters). The non-reasoning exception is the original `gpt-5-chat`\u002F`gpt-5-chat-latest` (`_NO_REASONING`). Verify each `-chat`\u002F`-chat-latest` variant against the live Responses API; don't copy a sibling's reasoning class blindly.\n- **`-pro` variants map to `_ALWAYS_ON_REASONING`** (`gpt-5.2-pro`, `gpt-5.4-pro`, `gpt-5.5-pro`) — they reason and reject `effort='none'`. `_ReasoningSupport` doesn't encode per-effort-*value* rejection, so if a new `-pro` rejects a specific value (e.g. `'low'`), flag it rather than assuming the enum covers it.\n- **`tests\u002Fmodels\u002Ftest_model_names.py::test_known_model_names`** asserts `known_model_names()` equals the set the curated aliases generate, gateway mirror included. Step 4's bridge check reads `AllModels` (the broad union, not the chat-only `ChatModel`).\n- **`tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`** is a snapshot test enumerating every `KnownModelName`. Refresh with `--inline-snapshot=fix`.\n- **A dotted point release matches none of its family's prefixes.** `gpt-6.1-sol` does not start with `'gpt-6-sol'`. Before you add it, it resolves to `_NO_REASONING` and misses every `startswith` gate in `openai_model_profile()`. Add it to `_REASONING_SUPPORT_BY_PREFIX` and to the generation's gate tuple (`_GPT_6_MODEL_PREFIXES`).\n- **Probe a point release against every sibling, not only its namesake.** GPT-6.1 Sol rejects `effort='none'` like GPT-6 Astra; GPT-6 Sol accepts it. The accepted-effort list decides `can_be_disabled`. Decide `supports_image_output` by forcing the tool (`tool_choice={'type': 'image_generation'}`), not from the model page's tool list.\n- **Chat Completions rejects function tools while reasoning is on** for the GPT-6 family: `Function tools with reasoning_effort are not supported`. A model that rejects `effort='none'` therefore has no Chat Completions tool calling. Document the limit in `docs\u002Fmodels\u002Fopenai.md`.\n- **clai2 keeps a curated Codex menu**: `CODEX_MODELS` in `src\u002Fpydantic_clai2\u002Fpydantic_clai2\u002Fmodel_catalog.py`. Add the id when Codex offers it. Check `openai\u002Fcodex`'s `codex_tui__chatwidget__tests__model_selection_popup.snap`, then run `Agent('openai-codex:\u003Cid>')` with a local Codex login. Update the Codex model lists in `src\u002Fpydantic_clai2\u002FREADME.md` (two of them), `src\u002Fpydantic_clai2\u002FPLUGINS.md` and `docs\u002Fharness\u002Fclai2.md`: `rg 'openai-codex:gpt-|gpt-5.6-luna' src\u002Fpydantic_clai2 docs\u002Fharness`.\n\nOpenAI image-model landmines:\n\n- **Probe `quality` with a valid `size`.** The Images API validates `size` before `quality`. An unknown `quality` returns the same `low, medium, high, auto` list for every model, so it tells you nothing. Only a request that passes size validation shows the per-model rejection: `The model 'gpt-image-2' does not support quality 'xhigh'.`\n- **Probe geometry with out-of-bounds sizes.** The API rejects a size before it generates anything. When the new model rejects each boundary size with the same message as a known family, add its ids to that family's tuple in `images\u002F_openai_geometry.py`.\n- **A model page's \"Responses: Not supported\" means the top-level `model`.** GPT Image 2.6 pages say it, yet the Responses `image_generation` tool accepts both 2.6 ids. Probe the tool with `tool_choice={'type': 'image_generation'}` before deciding `ImageGenerationModelName`.\n\n### Anthropic\n\n- **TWO literal lists, not one.** Add the id to BOTH:\n  1. `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F_known_model_names.py` — the `anthropic:` AND `gateway\u002Fanthropic:` blocks (the `KnownModelName` alias moved here from `models\u002F__init__.py` in #5803; older add-model PR diffs that edit `__init__.py` are stale on this point).\n  2. `LatestAnthropicModelNames` in `models\u002Fanthropic\u002F__init__.py` — see the SDK-lag bridge below.\n- **Anthropic names are enumeration-tested.** `LatestAnthropicModelNames` is the curated `Literal`; `test_known_model_names` ties it to `KnownModelName`.\n- **SDK-lag bridge (the Step 4 mechanism for Anthropic when the locked SDK lacks the id).** When the locked SDK's `anthropic.types.ModelParam` doesn't list the new id, add it to the `anthropic` entry's `bridges` in `SDK_MODEL_LITERALS`. `ModelParam` ≠ `anthropic.types.model.Model`; check `ModelParam`.\n- **Capability flags live as `startswith` prefix tuples in `profiles\u002Fanthropic.py`** inside `anthropic_model_profile()` (+ the module-level `_ANTHROPIC_CODE_EXECUTION_20260120_MODEL_PREFIXES`). A new family is NOT a literal-only add — it almost always needs at least one profile override (a literal-only add is only right when the family truly inherits every default branch, which is rare). Probe and set each independently: `models_that_support_json_schema_output`, `supports_adaptive`, `supports_effort`, `supports_xhigh_effort`, `disallows_budget_thinking`, `disallows_sampling_settings`, `supports_task_budgets`, `supports_tool_search`, code-exec version, `anthropic_supports_fast_speed`. Default-`False` flags (e.g. fast speed) are subtractive — just omit the id from that tuple.\n- **A point release inherits every flag of its base id silently.** The tuples are `startswith` prefixes, so `'claude-opus-5'` already matches `claude-opus-5-5` (as `'claude-fable-5'` matches `claude-fable-5-1`): before you touch anything, the new id resolves to the base model's profile. Tests stay green and nothing warns, so the only way to find a divergence is to read the model's migration guide and probe side by side with the base id. Opus 5.5 looked like an Opus 5 mirror and broke default `output_type` runs with a 400 until it opted out of forcing. Where a flag must *not* carry over, carve the id out explicitly (`startswith('claude-opus-5') and not startswith('claude-opus-5-5')`).\n- **Read the migration guide's \"breaking changes\" before probing.** Anthropic's `platform.claude.com\u002Fdocs\u002Fen\u002Fmodels\u002F\u003Cid>\u002Fmigration-guide` and `whats-new-\u003Cid>` pages list every divergence from the previous model and name which other models share it (e.g. \"the first three also apply on Claude Fable 5.1\"). Those map straight onto profile flags, and they tell you what to probe.\n- **Bump the SDK through the 7-day quarantine rather than bridging, once a release of the locked SDK major lists the id.** When only a newer major lists it, bridge the id instead: a bump would raise the floor to that major and move every Anthropic user onto it. `exclude-newer = \"7 days\"` in the root `pyproject.toml` keeps a same-day `anthropic` release out of the lock; admit exactly that release with a timestamp cutoff under `[tool.uv.exclude-newer-package]` (one second past its last artifact's PyPI `upload_time`, plus a `TODO` to remove it once the global window covers it — past that date it turns into a ceiling), raise the floor under `tool.hatch.metadata.hooks.uv-dynamic-versioning.optional-dependencies` in `pydantic_ai_slim\u002Fpyproject.toml` (move the exact `uv add --optional`-generated requirement there, add a comment above it naming what the code now needs from that version, as the `anthropic` and `xai-sdk` floors there have, and remove its conflicting `[project.optional-dependencies]` table), run `uv lock --upgrade-package anthropic`, and refresh the gh-aw runner's own lock with `uv lock --script .github\u002Fscripts\u002Fpydantic-ai-runner`. File a tracking issue for removing the cutoff and link it from the `TODO`. Precedents: #7989 (1.3.0), #8637 (1.8.0). The `bridges` entry above covers every case where the locked SDK lacks the id and no bump applies.\n- **An SDK bump is a real change: pyright `models\u002Fanthropic\u002F` and the Anthropic tests against it.** 1.8.0 renamed the citations request TypedDict to `BetaCitationsConfigParamParam` (`BetaCitationsConfigParam` became a response model, and passing it into a request param broke a dict assertion) and widened `BetaInputTransformation` to a union with `thinking_mismatch_allowed`.\n- **Opus 5.5 skips thinking on trivial prompts at its default `medium` effort.** A cassette test that needs a thinking block (e.g. `stale_thinking_block_history`) has to raise `anthropic_effort` for it.\n- **A point release falls into its base model's price entry.** The base entries' prefix and `contains` clauses (`starts_with: claude-opus-5`) also capture `claude-opus-5-5`. So until the new entry exists, `calc_price` returns the *old* model's price with no error: genai-prices 0.1.7 priced Opus 5.5 at Opus 5's $5\u002F$25 instead of $4\u002F$20. Check `calc_price(..., model_ref='\u003Cnew-id>')` against the published price. Report an incorrect sibling match to the pricing automation owner per Step 3b. Link genai-prices #671 and #709 for the match-boundary regression pattern.\n- **Forced `tool_choice` is a real per-model divergence worth probing.** Most Anthropic models accept `tool_choice` `{'type':'any'}`\u002F`{'type':'tool'}` and only reject forcing alongside *thinking*; Claude Fable 5.1, Claude Mythos 5.1, and Claude Opus 5.5 reject it **unconditionally** (400 `tool_choice forces tool use is not compatible with this model`). That's modeled by `AnthropicModelProfile.anthropic_supports_forced_tool_choice` (default `True`) threaded into `_support_tool_forcing` in `models\u002Fanthropic\u002F__init__.py`. Probe `tool_choice={'type':'any'}` against the new id AND its neighbour to tell a genuine divergence from a thinking-only constraint.\n- **Record the automatic stale-thinking-block retry for a model that runs the prefix check on every account.** The recording account predates the 2026-08-31 enforcement cutoff, so on Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 a default request never reaches the retry. Claude Fable 5.2 and Mythos 5.2 enforce the check on every account. Probe the new id with `prefix_mismatch_behavior` unset after a `system` change: a 400 means the retry path runs live. Precedent: `test_anthropic_fable_5_2_retries_a_stale_thinking_block_on_a_legacy_account`.\n- **Keep Mythos ids out of `LatestAnthropicModelNames`.** Mythos models are open only to verified organizations; our key gets a 404 `not_found_error` for them. Add a new Mythos id to each profile tuple that names its Fable sibling explicitly, on the evidence of Anthropic's published docs, and say so in the PR.\n- **Probe the stale-thinking-block retry shape on every new binding model.** When the request set no thinking, the retry sends a `thinking` object through `extra_body`. Claude Fable 5.1 and Claude Opus 5.5 accept `{'block_binding': ...}` alone; Claude Sonnet 5.5 rejects it with `thinking.type: Field required`, so the retry fills in `'type': 'adaptive'`. Probe `extra_body={'thinking': {'block_binding': {'prefix_mismatch_behavior': 'drop_block'}}}` against the new id. Also probe any new `thinking.type` the release adds with `block_binding`: Sonnet 5.5's `between_tools` rejects it (`Extra inputs are not permitted`), so the retry skips that type.\n- **Probe a mid-conversation `system` entry against the `\u003Csystem>`-tagged fallback before touching `_INLINE_SYSTEM_PROMPT_MODEL_PREFIXES`.** Ask each rendering to lift a restriction the top-level prompt set; a plain non-conflicting instruction lands on every model and discriminates nothing. Claude Opus 5 obeys the entry 6\u002F6 and the tagged text 0\u002F6. Claude Sonnet 5.5 refuses both 6\u002F6, so Anthropic's published support decides and it stays in: the entry keeps operator authority at no measured cost. Leave an id out only when the tagged fallback does measurably better, as it did on Claude Sonnet 5. `_TOOL_AVAILABILITY_DELTA_MODEL_PREFIXES` is a separate gate: probe a `tool_addition` by reference and check that the model calls the added tool.\n- **List Bedrock inference profiles, not only foundation models.** Claude Sonnet 5.5 launched with `global.anthropic.claude-sonnet-5-5` and no `us.` profile. Run `aws bedrock list-inference-profiles` and add only the profiles it returns.\n- **Tests:** profile-flag unit tests go in `tests\u002Fprofiles\u002Ftest_anthropic.py` (NOT `tests\u002Fmodels\u002Ftest_anthropic.py`). Forced-tool-choice \u002F `_prepare_tools_and_tool_choice` fallback tests go in `tests\u002Fmodels\u002Ftest_tool_choice_unit.py`. The capability behaviors keyed on shared flags (sampling drop, budget-thinking reject, xhigh) are already covered by the opus-4-7\u002F4-8 parametrized tests — adding the new id to those lists is redundant once a dedicated profile test asserts the flags.\n- **`tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`** snapshots the whole `KnownModelName` enum. Refresh it by running THAT TEST ALONE with `--inline-snapshot=fix` — running the whole file can pull in unrelated `snapshot()` blocks and abort the fix.\n- **`providers\u002F_bedrock_model_names.py` `bedrock_lacks_claude_structured_output`**: only relevant if the new id is actually served on Bedrock. A direct-API-only model (not in Bedrock's foundation-model list) doesn't belong there; don't add it speculatively just because the mirrored PR did.\n\n### xAI (Grok)\n\n- **`XaiModelName` is a curated `Literal`.** `test_known_model_names` ties its ids to the `xai:` entries in `models\u002F_known_model_names.py`.\n- **SDK-lag bridge.** `xai_sdk`'s `ChatModel` frequently lags a release, so bumping the floor often won't help (check newer wheels first: download from PyPI and grep `xai_sdk\u002Ftypes\u002Fmodel.py` for `ChatModel: TypeAlias = Literal[`). Add the id to the `xai` entry's `bridges` in `SDK_MODEL_LITERALS`.\n- **A new `grok-4.x` is NOT a pure mirror.** Reasoning-effort support lives in `profiles\u002Fgrok.py` as membership sets (`_GROK_43_REASONING_MODELS` + a per-family effort frozenset), not startswith prefixes. The `grok-4` prefix auto-grants `grok_supports_builtin_tools=True` but leaves `grok_reasoning_efforts` **empty** (→ `supports_thinking=False`) unless you add the id to a reasoning-models set. Forgetting this silently ships a reasoning model with thinking off. Add a `_GROK_\u003Cver>_REASONING_MODELS` set + effort frozenset and an `elif` branch in `grok_model_profile`.\n- **Probe reasoning efforts via the OpenAI-compatible REST endpoint**, comparing against the closest neighbour: `POST https:\u002F\u002Fapi.x.ai\u002Fv1\u002Fchat\u002Fcompletions` with `{\"model\":..., \"reasoning_effort\": \u003Cval>, \"max_tokens\":1}`. A rejected value returns 400 `This model does not support 'reasoning_effort' value '\u003Cval>'`. **Whether `none` is accepted decides `thinking_always_enabled`** (rejected → always-on). CAVEAT: REST silently accepts `xhigh`\u002F`minimal` even though the gRPC `ReasoningEffort` (in `xai_sdk\u002Ftypes\u002Fchat.py`) is `Literal['none','low','medium','high']` — don't over-read REST acceptance; `GrokReasoningEffort` is those four and `_map_reasoning_effort` collapses `xhigh`→`high`, `minimal`→`low`. Grok 4.5 example: accepts `low\u002Fmedium\u002Fhigh`, rejects `none` → always-on; Grok 4.3 accepts `none` too.\n- **Floating aliases** (`grok-latest`, `grok-build-latest`) go in the profile reasoning-models set (so passing them resolves the right behavior) but are **NOT** added as `KnownModelName` literals: the curation rule leaves out `-latest` aliases.\n- **xai is NOT a gateway provider** (`'xai'` absent from `providers\u002Fgateway.py`'s `ModelProvider`) — no `gateway\u002Fxai:` entries in `_known_model_names.py`.\n- **Snapshot that ratchets:** `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities` embeds the full `KnownModelName` enum. It's a plain sorted string list — hand-add the new ids in sorted position (deterministic, no need for `--inline-snapshot=fix`). Profile-flag tests go in `tests\u002Fproviders\u002Ftest_xai.py` (see `test_xai_model_profile`); the parametrized `tests\u002Ftest_thinking.py::test_grok_43_profile_thinking_support` asserts the *4.3* effort set specifically — don't add a different-effort model to it.\n- **env \u002F probing:** `XAI_API_KEY` lives in the repo-root `.env` (not in every worktree). Run probes with `source .env && \u003Cscript>` so `$XAI_API_KEY` is exported; put any `curl` referencing it in a script file rather than passing the key inline. Verify enumeration\u002Fprofile logic with a plain `uv run python` snippet (recurse `get_args(XaiModelName)`, compare to `known_model_names()`; call `grok_model_profile(...)` directly) rather than a full `uv run pytest tests\u002F` run.\n\n### Bedrock\n\n- **Bedrock Mantle is a separate provider from Bedrock Runtime.** `bedrock:` (the `BedrockProvider`, boto3-only) talks to the Converse API; `bedrock-mantle:` (the `BedrockMantleProvider`, an `openai`-backed `Provider[AsyncOpenAI]` built on `AsyncBedrockOpenAI`) talks to Mantle's OpenAI-compatible API. They have separate model catalogs and separate optional extras (`bedrock` vs `bedrock-mantle`); don't fold Mantle deps into the `bedrock` group.\n- **Mantle model families use different endpoints, keyed off the profile.** `BedrockMantleProvider.model_profile` stamps `bedrock_mantle_interface: Literal['chat','responses','openai-responses']` on the profile (GPT-5.4+ → `openai-responses` at `\u002Fopenai\u002Fv1`; GPT-OSS → `responses` at `\u002Fv1`; GPT-OSS Safeguard → `chat` at `\u002Fv1`). `infer_model` reads that (via the profile, not a separate interface method) to pick `BedrockMantleResponsesModel` vs `BedrockMantleChatModel`, and the Responses model overrides `client` to pick the base URL. Add a family only after verifying its endpoint against the AWS model card + a live request.\n- **`bedrock:` stays on Converse; it does NOT auto-route to Mantle.** `bedrock_openai_model_profile` allows Converse only for the GPT ids it lists; any other proprietary GPT id on `bedrock:` raises, pointing users to `bedrock-mantle:`. Add a `bedrock:` GPT id to that allowed set and to `LatestBedrockModelNames` only after a successful Converse call.\n- **Response-scoped tool-call IDs are a profile flag, not a Mantle-wide behavior.** `openai_responses_tool_call_ids_are_response_scoped` (on `OpenAIModelProfile`) is enabled only for Mantle GPT-5.6 Responses; `OpenAIResponsesModel` qualifies call IDs with the response ID in both request and streaming ingestion so history stays uniquely keyed (#6536).\n\n### Google (Gemini)\n\n- **TWO places for the id, FOUR `KnownModelName` blocks.** Add to:\n  1. `LatestGoogleModelNames` in `models\u002Fgoogle.py` (`GoogleModelName = str | LatestGoogleModelNames` — the `str` arm is permissive at typecheck time, but the enumeration test only walks the `Literal` arm).\n  2. `models\u002F_known_model_names.py` — **four** blocks: `gateway\u002Fgoogle-cloud:`, `gateway\u002Fgoogle:`, `google-cloud:`, `google:` (older add-model PRs that only edit three blocks or `models\u002F__init__.py` are stale; KnownModelName moved in #5803).\n- **No SDK-lag bridge needed.** `google-genai` does not ship a model-id Literal the enumeration test consumes — the local `LatestGoogleModelNames` Literal *is* the source of truth. Adding the id lands green immediately.\n- **Profile is substring-gated, with a per-model level table.** `profiles\u002Fgoogle.py::google_model_profile` gates by an older-Gemini negative list (`gemini-1`, `gemini-2.x`, `gemma`): every other id, `gemini-4-*` included, gets the modern branch (thinking level, tool combination, server-side tool invocations, MIME types in tool returns). `'pro' in model_name and 'flash' not in model_name` sets always-on thinking. The exception is `_MODEL_THINKING_LEVELS`, a `startswith` table mapping id prefixes to their documented level sets that already holds both pro previews, the 3.7 and 3.8 flash ids, and `gemini-3.1-flash-lite-image` — so probe every new id rather than assuming the Gemini-3 branch covers it. Probe all four levels with `generateContent` and `thinkingConfig.thinkingLevel` (`MINIMAL`, `LOW`, `MEDIUM`, `HIGH`) on the Gemini API and on Vertex separately. A 400 on both means the id needs an entry in the table carrying exactly the levels it accepts (non-contiguous sets like `minimal, high` are fine — unsupported unified efforts snap to the nearest documented level). A 400 on only one of them means a level set in `GoogleModel.profile` gated on the client's transport (`_is_google_cloud`), as `gemini-3.1-flash-image` has for the Gemini API, so the other API keeps the levels it accepts. Reach Vertex with application-default credentials, `GOOGLE_PROJECT`, and `location='global'`, as `tests\u002Fconftest.py::vertex_provider` does. If you can probe only the Gemini API and it 400s, use the transport-gated branch too, so Vertex keeps its current behavior. Cite Google's documented level sets in the code comment: the Gemini API [thinking table](https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fthinking) (for image models, the [image-generation page](https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fimage-generation) instead) and the Vertex [thinking table](https:\u002F\u002Fdocs.cloud.google.com\u002Fgemini-enterprise-agent-platform\u002Fmodels\u002Fthinking). The probe results decide the entry, even where they diverge from those tables. When neither API can be probed, such as a model with no free tier and no Vertex project, add the entry only where both tables give the same level set, and write \"Not probed live\" in the comment. Probe too when the release notes claim any other capability divergence (no thinking, image-only, Pro always-on).\n- **API verification:** `curl -s \"https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels?pageSize=200&key=$GOOGLE_API_KEY\"` (key is often in the main worktree `.env`, not every linked worktree). Confirm exact ids; do **not** invent dated snapshots or `-preview` suffixes. Specialized \u002F limited-access models (e.g. Flash Cyber via CodeMender) are out of scope unless they appear in that public listing.\n- **A Vertex 404 at the default `us-central1` does not mean Vertex lacks the id.** Probe `location='global'` before you conclude the id is Gemini-API-only.\n- **Gateway support is opt-out, not opt-in.** The enumeration test generates `gateway\u002F{google,google-cloud}:*` for every `LatestGoogleModelNames` entry **except** those listed in `UNSUPPORTED_GATEWAY_MODEL_NAMES` in `tests\u002Fmodels\u002Ftest_model_names.py`. Do not add a new id there; Step 6 covers Gateway support. `test_unsupported_gateway_model_names_are_curated` fails on an entry whose id left the curated aliases; remove that entry.\n- **Snapshots \u002F tests:** hand-add the new ids in sorted position in `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities` (plain sorted string list). Mirror-only adds skip new VCR by default; #5527 recorded one for `gemini-3.5-flash` but that is not required for a pure name add.\n- **Docs:** doc pages name models through the tiered aliases in `docs\u002Fmodel_aliases\u002Faliases.json`. Leave pages that pin a model on purpose (`docs\u002Fmodels\u002Fgoogle.md`, `docs\u002Fcapabilities\u002Fthinking.md`) alone.\n\nGoogle image-model landmines:\n\n- Direct image generation has a separate public literal, `KnownImageGenerationModelName` in `pydantic_ai_slim\u002Fpydantic_ai\u002Fimages\u002F__init__.py`. When the task is scoped to `ImageGenerator`, update and test this literal independently; do not automatically widen the change to conversational `KnownModelName`, gateway aliases, profiles, and capability snapshots unless those surfaces are explicitly in scope.\n- `Client().models.list()` returns a lazy pager. Keep the client in a named variable until iteration finishes; constructing it inline can let it be closed before the pager sends its request. The endpoint can still list deprecated preview image IDs, so cross-check the official deprecation page and add only current IDs.\n- Probe image settings on the exact model and API surface. For `gemini-3.1-flash-image`, the minimum `generateContent` value is `ImageConfigDict(image_size='512')`; the superficially similar literal `'0.5K'` is invalid and returns HTTP 400. `gemini-3.1-flash-lite-image` supports only 1K output. Do not transfer value spellings between model families or API examples without a live check.\n\n### MoonshotAI (Kimi)\n\n- `MoonshotAIModelName` in `providers\u002Fmoonshotai.py` is a local literal, independent of the OpenAI SDK's model enum. Update it and `models\u002F_known_model_names.py` together, then refresh `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`.\n- The `kimi-k3` prefix already covers `kimi-k3.1-pro` and `kimi-k3.1-pro-highspeed` in both family and provider profiles. Probe before adding another prefix or changing profile flags.\n- Verify the API at `https:\u002F\u002Fapi.moonshot.ai\u002Fv1`. The separate Kimi Code subscription uses different model IDs. Read the [canonical API guide](https:\u002F\u002Fplatform.kimi.ai\u002Fdocs\u002Fguide\u002Fkimi-k3-1-pro-quickstart) and compare live behavior with the nearest sibling; do not transfer subscription semantics.\n\n### Others\n\nNot yet documented here. **When you add the next model for one of these providers, add the landmines you encountered to this section before closing the session** (see Step 9).\n\n## Step 9 — Update this skill\n\nAfter completing the model-add, before closing the session: if anything came up that isn't already documented in this skill — a new test that ratcheted, a provider-specific dispatch tuple, a misleading SDK behavior, a corrected misconception, an iteration the user had to walk you through — **add it to this SKILL.md**.\n\nSpecifically:\n- Provider-specific landmines → the matching subsection (or create it).\n- Generic process gaps → the relevant numbered step.\n- Workflow shape errors → restructure the steps.\n\nThis skill exists to compound learnings. A model-add that surfaced new friction and didn't update this file wasted that friction.\n","# Add New Model\n\nWire a newly-released provider model into pydantic-ai. Optimized for the common case (mirror an existing sibling); flags the cases where it's *not* a mirror and needs deeper work.\n\n## Reference docs (read once before scoping)\n\n- `agent_docs\u002Fpydantic-ai-slim.md` — the **Ownership** section, plus `pydantic_ai_slim\u002Fpydantic_ai\u002Fnative_tools\u002FAGENTS.md`, for the user-visible surface this model needs to land on.\n- `pydantic_ai_slim\u002Fpydantic_ai\u002Fprofiles\u002FAGENTS.md`, `providers\u002FAGENTS.md`, `models\u002FAGENTS.md`, and `pydantic_ai_slim\u002Fpydantic_ai\u002FAGENTS.md` (the capability-flag and `Provider.model_profile()` rules), plus the **Design Rules** section of `agent_docs\u002Fpydantic-ai-slim.md`. These tell you where capability facts belong (profile vs. provider vs. model class) when the new id has non-mirror behavior.\n\n## Inputs\n\nUser invokes with `provider` + `model id` (e.g. `openai gpt-5.6`). If missing, ask via `AskUserQuestion`.\n\n## Curation rule\n\nThe model-name `Literal` aliases (`KnownModelName`, each provider's `*ModelName`, and the image, embedding and\nadvisor aliases) list the models a user would pick. They are not catalogs. Apply this rule to every id you add:\n\n- A **line** is a tier name: GPT `sol`\u002F`terra`\u002F`luna`\u002F`astra`, Claude `opus`\u002F`sonnet`\u002F`haiku`\u002F`fable`, Gemini\n  `pro`\u002F`flash`\u002F`flash-lite`, and the Gemini 4 element names `argon`\u002F`carbon`.\n- A **generation** is the major version, counted per provider.\n- Per line, list the newest id of the newest generation and the newest id of the previous generation. Remove\n  the older id the new one replaces, in the provider alias and in `KnownModelName`.\n- Leave out dated snapshots that have an undated alias, previews that a GA id superseded, floating `-latest`\n  aliases (Mistral and TypeSafe excepted: their `-latest` ids are canonical), and non-chat models.\n- On Bedrock, list one id per model: the `global.` profile when it exists, else `us.`, else the bare id.\n- Keep every id that a model alias in `docs\u002Fmodel_aliases\u002Faliases.json` resolves to, even when the rule above\n  would drop it. `tests\u002Ftest_docs_model_aliases.py` fails otherwise. Changing an alias target is a separate\n  decision under `docs\u002Fmodel_aliases\u002FAGENTS.md`.\n\nProfiles match any id, so removing an id from a literal changes autocomplete only. Never remove a profile branch\nbecause its id left a literal.\n\n## Image generation models\n\nImage-only models use a separate public surface from conversational models. If the model is consumed by `ImageGenerator`, update `KnownImageGenerationModelName` in `pydantic_ai_slim\u002Fpydantic_ai\u002Fimages\u002F__init__.py`, the relevant direct provider adapter, and its tests; do not also change conversational `KnownModelName`, profiles, gateway aliases, `ImageGenerationTool`, or `models\u002F\u003Cprovider>.py` unless that surface is explicitly supported and in scope. Add only the public model IDs the project intends to support, and do not infer or automatically add dated snapshots.\n\nKeep common, provider-agnostic controls in `images\u002Fsettings.py`, but import provider-specific setting types from the official SDK. Put model-specific size and aspect-ratio validation or mapping in the private `images\u002F_\u003Cprovider>_geometry.py` helper, and update the public support matrix in `docs\u002Fimage-generation.md`. Verify geometry against official documentation; if the provider does not publish exact output shapes, probe every documented aspect-ratio and resolution combination for every supported model and record the evidence. Prefer deterministic table tests for the full matrix, adding one representative VCR cassette only when the new model or wire behavior needs integration coverage rather than recording every image combination.\n\n## Step 1 — Verify the model exists at the provider\n\nNever trust marketing names, news articles, or guesses. Hit the provider's model-listing endpoint:\n\n| Provider  | Verification call |\n|-----------|-------------------|\n| OpenAI    | `curl -s https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fmodels -H \"Authorization: Bearer $OPENAI_API_KEY\"` |\n| Anthropic | `curl -s https:\u002F\u002Fapi.anthropic.com\u002Fv1\u002Fmodels -H \"x-api-key: $ANTHROPIC_API_KEY\" -H \"anthropic-version: 2023-06-01\"` |\n| xAI       | `curl -s https:\u002F\u002Fapi.x.ai\u002Fv1\u002Fmodels -H \"Authorization: Bearer $XAI_API_KEY\"` |\n| Google    | `curl -s https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels -H \"x-goog-api-key: $GOOGLE_API_KEY\"` |\n| Groq      | `curl -s https:\u002F\u002Fapi.groq.com\u002Fopenai\u002Fv1\u002Fmodels -H \"Authorization: Bearer $GROQ_API_KEY\"` |\n| Bedrock   | `aws bedrock list-foundation-models --region \"$AWS_REGION\"` |\n\nLoad credentials from the repo-root `.env` with `source .env && \u003Ccmd>`. `list-foundation-models` is region-scoped, so query the region your models are actually deployed in (not a hard-coded default). List **every** id the provider exposes for this release — base, dated snapshot, `-pro`, `-mini`, `-nano`, `-codex`, `-chat-latest`. Add only what actually exists; do not extrapolate sibling variants.\n\nIf the user-given id is **not** in the listing, stop and confirm with the user before proceeding.\n\n## Step 2 — Mirror the most recent add-model PR for this provider\n\n```bash\ngit log --all --oneline --grep=\"\u003Cprevious-version-pattern>\" -20\n# e.g. for openai: --grep=\"gpt-5\\.4\\|gpt-5\\.3\"\n# e.g. for anthropic: --grep=\"claude-opus-4\\|claude-sonnet-4\"\n```\n\nPick the smallest, most recent \"add model X\" PR for the same provider. Pull its file list with `gh pr view \u003Cnum> --json files --jq '.files[].path'`. **That file list is the floor of what you'll touch.** It is rarely the ceiling.\n\n## Step 3 — Enumerate (load-bearing step)\n\nFor every variable, tuple, and literal you're about to touch, grep its readers across the repo. **This step is what catches the snapshot\u002Fenumeration tests that ratchet on every model add.** Skipping it pushes work onto CI and produces broken PRs.\n\nSpecifically, for a typical model add, grep for:\n\n- The previous model id literal you're mirroring (e.g. `gpt-5.4`, `claude-opus-4-5`) — `rg '\u003Cprev-id>' --glob '!**\u002F*.yaml' --glob '!**\u002Fcassettes\u002F**'`\n- Search for the previous model's display name in docs and public docstrings; inspect capability rosters for the same features.\n- Every prefix\u002Fmembership key in the profile module you're editing (e.g. OpenAI's `_REASONING_SUPPORT_BY_PREFIX` keys, Anthropic's inline `model_name.startswith((...))` tuples, xAI's `_GROK_43_REASONING_MODELS`)\n- `KnownModelName` and its provider-block neighbours\n- Snapshot test files: `tests\u002Fmodels\u002Ftest_model_names.py`, `tests\u002Ftest_capability_spec.py`\n- Public API compatibility: the release comparison reports a model-name `Literal` change as an attribute-value change. The gate passes added and removed names on an alias listed under `model_name_literals` in `.github\u002Fapi-compatibility-allowlist.json`. Do not add a waiver for that change: the gate fails on an unused waiver. If the gate fails on a model-name alias that is not listed, add its `path` and `symbol` to `model_name_literals`. Any other change to the alias, such as adding a non-`Literal` arm, needs an exact waiver.\n\nClassify each hit:\n- **must update** — model-name lists, dispatch tuples\n- **snapshot to refresh** — `inline_snapshot` blocks needing `pytest --inline-snapshot=fix`\n- **skip** — VCR cassettes, docs about an unrelated model\n\nIf `rg` output looks mangled (unicode\u002Fregex artifacts), drop to `grep -n` — don't push past garbled output.\n\n## Step 3b — Verify pricing and context data\n\nPricing additions belong to the automated workflows in `pydantic\u002Fgenai-prices`.\nThe [Update prices workflow](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002Fupdate-prices.yml)\nimports provider data hourly and aggregator data weekly.\n[Genie Pricer](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002FGENIE_PRICER.md)\nhandles targeted model additions through the\n[Model Price Check workflow](https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fgenai-prices\u002Fblob\u002Fmain\u002F.github\u002Fworkflows\u002Fagentic-model-price-check.md).\nDo not open or implement a manual genai-prices counterpart PR during a model add.\nDo not trigger a pricing request unless the user authorizes that request.\n\nVerify the exact API IDs and hosting providers independently of pricing data.\nDo not infer availability from an older sibling or a pricing match.\nDo not block model-name support on pricing-feed lag.\n\nCost and `context_window` data come from `pydantic\u002Fgenai-prices` through `_genai_prices.py`.\nBundled data requires a `genai-prices` release.\nCheck both the installed package and the live merged feed for the exact model.\nUpdate the Pydantic AI lock when adopting a package release with the entry.\nThe live merged feed can supply entries through `pydantic_ai.prices.update_in_background()`.\nCheck the updater for an entry before claiming a package release blocks support.\n`Model.profile` only consults genai-prices when nothing else set `context_window`.\nWithout a price entry in either source, `ModelResponse.cost()` raises `LookupError` and a\n`cost_limit` cannot be enforced — the run warns `CostNotFoundWarning` at the end instead.\nWithout a `context_window` value from any source, `RunContext.context_window_used` is `None`.\nCompare matched prices against the provider's official rates; a broad sibling match can silently return stale prices.\nReport missing or incorrect data and link an existing automation proposal when available.\n\n## Step 4 — SDK pin check\n\nThe OpenAI, Anthropic and xAI aliases are curated `Literal`s, not the SDK's model literal. `tests\u002Fmodels\u002Ftest_model_names.py`\nties the two together through `SDK_MODEL_LITERALS`:\n\n- `test_sdk_model_literal` snapshots each SDK's full model literal at the version in `uv.lock`. It skips on CI legs\n  that install another version (lowest-versions, the upgrade canary).\n- `test_curated_model_names_are_sdk_ids_or_bridges` requires every curated id to be in the locked SDK's literal or in\n  that entry's `bridges`, and every bridge to be absent from the SDK.\n\nCheck whether the locked SDK lists the new id:\n\n```bash\nuv run python -c \"from openai.types import AllModels; from typing import get_args; print([m for m in get_args(AllModels) if '\u003Cnew-version>' in m])\"\n```\n\nAnthropic reads `anthropic.types.ModelParam`, xAI reads `xai_sdk.types.model.ChatModel`, and the image and embedding\nentries read the SDK types `SDK_MODEL_LITERALS` names. If the locked SDK lacks the id, add the id to that entry's\n`bridges`. Remove the bridge in the PR that bumps the SDK past the release that lists it.\n\nWhen a `uv.lock` upgrade changes an SDK's model literal, `test_sdk_model_literal` fails. Review the new ids against\nthe curation rule, update the curated alias and `KnownModelName`, drop any bridge the SDK now lists, then run\n`uv run pytest tests\u002Fmodels\u002Ftest_model_names.py --inline-snapshot=fix`.\n\nIf a release lists the id but sits inside the 7-day `exclude-newer` window, bridge it. For Anthropic, the SDK-bump\nbullet in its landmine section decides between bump and bridge.\n\n## Step 5 — Probe capabilities (only if not a pure mirror)\n\nIf the new model is just another sibling in an existing family (e.g. `gpt-5.5` after `gpt-5.4`), skip to Step 6 — the existing profile branch covers it once you add the prefix to the dispatch tuple.\n\nIf the model is a new family or has unclear capabilities, write a small comparison script (`local-notes\u002Fprobe_\u003Cmodel>.py`) that hits the new model AND its closest neighbour with:\n- `temperature` \u002F `top_p` (does the API reject sampling params?)\n- `reasoning.effort` values (`none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) — note which the API accepts. OpenAI's 400 lists the accepted values. Probe `max` on both the Responses and Chat Completions APIs: they accept different sets, recorded in `openai_responses_supports_max_reasoning_effort` (set in `OpenAIProvider.model_profile`) and `openai_chat_supports_max_reasoning_effort` (set in each OpenAI-compatible provider's `model_profile`)\n- New parameters mentioned in the release notes\n- Streaming \u002F tool calls if the family is new\n\nDiff the responses. Anything that diverges from the neighbour belongs in the profile.\n\n### Gateway parity\n\nWhere the gateway serves a model, it must behave the same as the provider's canonical API. Step 3 only\ngets the id recognized; this is about behavior, and nothing enumerates it for you.\n\nThe gateway reaches the canonical API through an ordinary SDK client carrying a proxy base URL. So:\n\n- **Narrow a capability by client class, never by base URL.** Bedrock, Vertex and Foundry are separate\n  transports and earn their own gates. A proxied client is the canonical API, and must keep every\n  capability the unproxied one has.\n- **A `base_url` test inside a capability decision is the defect, not the fix.** It splits the gateway\n  off from the transport it actually reaches. No capability in `models\u002F` or `profiles\u002F` is decided that\n  way — if you are about to be the first, you are answering the wrong question.\n- **Probe the gateway leg rather than reasoning about it.** `Model('\u003Cid>', provider='gateway')`, then\n  exercise whatever capability you gated. If `PYDANTIC_AI_GATEWAY_BASE_URL` is set in the environment,\n  check it points at the gateway root: a provider-specific proxy path 404s every other provider.\n\n## Step 6 — Edit (minimal diff matching the mirrored PR)\n\nMake only the changes the enumeration step surfaced. Resist scope creep. If you suspect a pre-existing bug in a sibling model's profile, reproduce it live first. Fold a reproduced bug on the same profile gate into this PR, with a test and one PR-body line. Flag an unreproduced or larger one in the PR description instead.\n\n**Assume the Gateway serves every new id on a provider it proxies.** Add each id's `gateway\u002F` mirror to `KnownModelName` without probing the Gateway first. Never add a new id to `UNSUPPORTED_GATEWAY_MODEL_NAMES`. Until genai-prices has the id's price, the Gateway can refuse it with a 404 `No cost data available for model`; that gap closes without a Pydantic AI change. File one tracking issue per release instead, to confirm that the Gateway serves and prices each new id. Route it with the maintainer routing in the `file-followup-issue` skill. List every id of the release in it, including ids the curation rule keeps out of `KnownModelName`. List each Bedrock region prefix as its own id: Gateway support for one inference profile does not establish support for another. Name the weekly Gateway Model Health workflow (`.github\u002Fworkflows\u002Fgateway-model-health.yml`) in the issue: it runs every `gateway\u002F` id in `KnownModelName` live. Exclude an id only in a separate change, after the tracking issue confirms that the Gateway refuses it.\n\n**Assume Bedrock serves a new id that AWS gates per account.** AWS can list a model in `aws bedrock list-inference-profiles` while Converse still answers `AccessDeniedException: ... is not available for this account`. List the id anyway, as the curation rule picks it: the `global.` profile when it exists. Leave the capability gates in `providers\u002F_bedrock_model_names.py` on their existing prefixes. File one Bedrock tracking issue for the probes to run once AWS grants access. Route it with the maintainer routing in the `file-followup-issue` skill. List these probes in it:\n\n- The id serves through `BedrockConverseModel` and the Bedrock Messages API.\n- Each gate whose prefix decision contradicts the AWS model card or Anthropic's Bedrock docs.\n\nChange a gate only after its probe passes. A GPT id on `bedrock:` is the exception: list it only after a successful Converse call, as the Bedrock landmines say.\n\nDocs examples name models through the aliases in `docs\u002Fmodel_aliases\u002Faliases.json`, not model ids. Check the placement rules in `docs\u002Fmodel_aliases\u002FAGENTS.md`. When they place the new model in an alias, repoint that alias in `aliases.json` instead of editing doc pages. Repoint it in the same PR; do not wait for the Gateway to serve the new id. Then update the README mirrors that `tests\u002Ftest_docs_parity.py` and `tests\u002Fharness\u002Ftest_docs_parity.py` flag. The harness capability READMEs and their `_capability.py` docstrings mirror doc pages that use the alias but are not parity-tested: `git grep` the old id and update those mirrors too.\n\nAfter edits:\n\n```bash\nmake format && make lint\nPYRIGHT_PYTHON_IGNORE_WARNINGS=1 uv run pyright \u003Cchanged-python-files>\n```\n\nRun the tests directly touching the changed surface — the profile test plus any enumeration tests you updated. CI is the safety net for the long tail; locally you only need to verify the surface area of your change.\n\nIf snapshot tests changed: `uv run pytest \u003Cfile> --inline-snapshot=fix` then verify the diff is the expected literal addition only.\n\n## Step 7 — VCR \u002F integration tests\n\n**Default for mirror-only adds:** skip recording a new VCR. Repo convention uses one representative model per family for VCR (e.g. `gpt-5.2` covers the gpt-5.x reasoning family). The profile unit test added in Step 6 is sufficient.\n\n**When the new model introduces meaningful changes** to `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F\u003Cprovider>.py` (new request shape, new response field, new handler branch):\n\n1. Look for an existing parametrized VCR test that covers the changed feature. `rg -l '\u003Cfeature-name>' tests\u002Fmodels\u002F`. If one exists and it parametrizes over model ids, **tag the new id onto the parametrize list** rather than writing a new test.\n2. If no parametrized coverage exists and you need a new VCR test, place it:\n   - **Prefer** `tests\u002Fmodels\u002F\u003Cprovider>\u002Ftest_\u003Cfeature>.py` **only if the file already exists** (e.g. `tests\u002Fmodels\u002Fanthropic\u002Ftest_output.py`).\n   - Otherwise add it to `tests\u002Fmodels\u002Ftest_\u003Cprovider>.py`. **Do not create a new `tests\u002Fmodels\u002F\u003Cprovider>\u002F` subdirectory** if one doesn't already exist for this provider.\n3. Record using the `testing-skill` skill workflow.\n\n## Step 8 — PR\n\nFollow the `pushing-commits-to-the-repo` skill for the title, body, template, and final metadata\ncheck. Keep the model-specific evidence concise:\n\n- One sentence: what model(s) were added.\n- \"Verified via probe \u002F mirror of #NNNN\" — explicit about which changes were API-verified vs assumed-by-mirror.\n- Flag pre-existing latent bugs found but deliberately not fixed.\n- Link the prior add-model PR for context.\n- Link the Gateway tracking issue from Step 6, and the Bedrock tracking issue when Step 6 filed one.\n\n## Provider-specific landmines\n\n### OpenAI\n\n- **`_REASONING_SUPPORT_BY_PREFIX`** in `pydantic_ai_slim\u002Fpydantic_ai\u002Fprofiles\u002Fopenai.py` — a dict keyed by model-name prefix (`'gpt-5.6'`, `'gpt-5.3-chat'`, `'gpt-5'`, `'o'`, …) → `_ReasoningSupport(enabled_by_default, can_be_disabled, supports_mode, supports_context)`, resolved **first-match-wins** by `_reasoning_support()`. A new `gpt-5.N` family MUST be added here, and **ordering matters**: a more specific prefix (`'gpt-5.3-chat'`) must precede the broader one it would otherwise shadow (`'gpt-5.3'`), and every newer `gpt-5.x` family must precede the plain `'gpt-5'` catch-all. Miss it and the model falls through to the `_NO_REASONING` default (`thinking_always_enabled=False`, `openai_supports_reasoning_effort_none=False`) — wrong defaults, no error. The resolved matrix is pinned in `tests\u002Fprofiles\u002Ftest_openai.py`.\n- **`KnownModelName` lives in `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F_known_model_names.py`** (a `TypeAliasType`), **not** `models\u002F__init__.py`. Add the id to its `openai:`, `openai-chat:` and `gateway\u002Fopenai:` entries, and remove the ids the curation rule retires.\n- **Most `gpt-5.x-chat` variants DO reason** (`_ALWAYS_ON_REASONING`: reason at a fixed effort, reject `reasoning_effort='none'` and sampling parameters). The non-reasoning exception is the original `gpt-5-chat`\u002F`gpt-5-chat-latest` (`_NO_REASONING`). Verify each `-chat`\u002F`-chat-latest` variant against the live Responses API; don't copy a sibling's reasoning class blindly.\n- **`-pro` variants map to `_ALWAYS_ON_REASONING`** (`gpt-5.2-pro`, `gpt-5.4-pro`, `gpt-5.5-pro`) — they reason and reject `effort='none'`. `_ReasoningSupport` doesn't encode per-effort-*value* rejection, so if a new `-pro` rejects a specific value (e.g. `'low'`), flag it rather than assuming the enum covers it.\n- **`tests\u002Fmodels\u002Ftest_model_names.py::test_known_model_names`** asserts `known_model_names()` equals the set the curated aliases generate, gateway mirror included. Step 4's bridge check reads `AllModels` (the broad union, not the chat-only `ChatModel`).\n- **`tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`** is a snapshot test enumerating every `KnownModelName`. Refresh with `--inline-snapshot=fix`.\n- **A dotted point release matches none of its family's prefixes.** `gpt-6.1-sol` does not start with `'gpt-6-sol'`. Before you add it, it resolves to `_NO_REASONING` and misses every `startswith` gate in `openai_model_profile()`. Add it to `_REASONING_SUPPORT_BY_PREFIX` and to the generation's gate tuple (`_GPT_6_MODEL_PREFIXES`).\n- **Probe a point release against every sibling, not only its namesake.** GPT-6.1 Sol rejects `effort='none'` like GPT-6 Astra; GPT-6 Sol accepts it. The accepted-effort list decides `can_be_disabled`. Decide `supports_image_output` by forcing the tool (`tool_choice={'type': 'image_generation'}`), not from the model page's tool list.\n- **Chat Completions rejects function tools while reasoning is on** for the GPT-6 family: `Function tools with reasoning_effort are not supported`. A model that rejects `effort='none'` therefore has no Chat Completions tool calling. Document the limit in `docs\u002Fmodels\u002Fopenai.md`.\n- **clai2 keeps a curated Codex menu**: `CODEX_MODELS` in `src\u002Fpydantic_clai2\u002Fpydantic_clai2\u002Fmodel_catalog.py`. Add the id when Codex offers it. Check `openai\u002Fcodex`'s `codex_tui__chatwidget__tests__model_selection_popup.snap`, then run `Agent('openai-codex:\u003Cid>')` with a local Codex login. Update the Codex model lists in `src\u002Fpydantic_clai2\u002FREADME.md` (two of them), `src\u002Fpydantic_clai2\u002FPLUGINS.md` and `docs\u002Fharness\u002Fclai2.md`: `rg 'openai-codex:gpt-|gpt-5.6-luna' src\u002Fpydantic_clai2 docs\u002Fharness`.\n\nOpenAI image-model landmines:\n\n- **Probe `quality` with a valid `size`.** The Images API validates `size` before `quality`. An unknown `quality` returns the same `low, medium, high, auto` list for every model, so it tells you nothing. Only a request that passes size validation shows the per-model rejection: `The model 'gpt-image-2' does not support quality 'xhigh'.`\n- **Probe geometry with out-of-bounds sizes.** The API rejects a size before it generates anything. When the new model rejects each boundary size with the same message as a known family, add its ids to that family's tuple in `images\u002F_openai_geometry.py`.\n- **A model page's \"Responses: Not supported\" means the top-level `model`.** GPT Image 2.6 pages say it, yet the Responses `image_generation` tool accepts both 2.6 ids. Probe the tool with `tool_choice={'type': 'image_generation'}` before deciding `ImageGenerationModelName`.\n\n### Anthropic\n\n- **TWO literal lists, not one.** Add the id to BOTH:\n  1. `pydantic_ai_slim\u002Fpydantic_ai\u002Fmodels\u002F_known_model_names.py` — the `anthropic:` AND `gateway\u002Fanthropic:` blocks (the `KnownModelName` alias moved here from `models\u002F__init__.py` in #5803; older add-model PR diffs that edit `__init__.py` are stale on this point).\n  2. `LatestAnthropicModelNames` in `models\u002Fanthropic\u002F__init__.py` — see the SDK-lag bridge below.\n- **Anthropic names are enumeration-tested.** `LatestAnthropicModelNames` is the curated `Literal`; `test_known_model_names` ties it to `KnownModelName`.\n- **SDK-lag bridge (the Step 4 mechanism for Anthropic when the locked SDK lacks the id).** When the locked SDK's `anthropic.types.ModelParam` doesn't list the new id, add it to the `anthropic` entry's `bridges` in `SDK_MODEL_LITERALS`. `ModelParam` ≠ `anthropic.types.model.Model`; check `ModelParam`.\n- **Capability flags live as `startswith` prefix tuples in `profiles\u002Fanthropic.py`** inside `anthropic_model_profile()` (+ the module-level `_ANTHROPIC_CODE_EXECUTION_20260120_MODEL_PREFIXES`). A new family is NOT a literal-only add — it almost always needs at least one profile override (a literal-only add is only right when the family truly inherits every default branch, which is rare). Probe and set each independently: `models_that_support_json_schema_output`, `supports_adaptive`, `supports_effort`, `supports_xhigh_effort`, `disallows_budget_thinking`, `disallows_sampling_settings`, `supports_task_budgets`, `supports_tool_search`, code-exec version, `anthropic_supports_fast_speed`. Default-`False` flags (e.g. fast speed) are subtractive — just omit the id from that tuple.\n- **A point release inherits every flag of its base id silently.** The tuples are `startswith` prefixes, so `'claude-opus-5'` already matches `claude-opus-5-5` (as `'claude-fable-5'` matches `claude-fable-5-1`): before you touch anything, the new id resolves to the base model's profile. Tests stay green and nothing warns, so the only way to find a divergence is to read the model's migration guide and probe side by side with the base id. Opus 5.5 looked like an Opus 5 mirror and broke default `output_type` runs with a 400 until it opted out of forcing. Where a flag must *not* carry over, carve the id out explicitly (`startswith('claude-opus-5') and not startswith('claude-opus-5-5')`).\n- **Read the migration guide's \"breaking changes\" before probing.** Anthropic's `platform.claude.com\u002Fdocs\u002Fen\u002Fmodels\u002F\u003Cid>\u002Fmigration-guide` and `whats-new-\u003Cid>` pages list every divergence from the previous model and name which other models share it (e.g. \"the first three also apply on Claude Fable 5.1\"). Those map straight onto profile flags, and they tell you what to probe.\n- **Bump the SDK through the 7-day quarantine rather than bridging, once a release of the locked SDK major lists the id.** When only a newer major lists it, bridge the id instead: a bump would raise the floor to that major and move every Anthropic user onto it. `exclude-newer = \"7 days\"` in the root `pyproject.toml` keeps a same-day `anthropic` release out of the lock; admit exactly that release with a timestamp cutoff under `[tool.uv.exclude-newer-package]` (one second past its last artifact's PyPI `upload_time`, plus a `TODO` to remove it once the global window covers it — past that date it turns into a ceiling), raise the floor under `tool.hatch.metadata.hooks.uv-dynamic-versioning.optional-dependencies` in `pydantic_ai_slim\u002Fpyproject.toml` (move the exact `uv add --optional`-generated requirement there, add a comment above it naming what the code now needs from that version, as the `anthropic` and `xai-sdk` floors there have, and remove its conflicting `[project.optional-dependencies]` table), run `uv lock --upgrade-package anthropic`, and refresh the gh-aw runner's own lock with `uv lock --script .github\u002Fscripts\u002Fpydantic-ai-runner`. File a tracking issue for removing the cutoff and link it from the `TODO`. Precedents: #7989 (1.3.0), #8637 (1.8.0). The `bridges` entry above covers every case where the locked SDK lacks the id and no bump applies.\n- **An SDK bump is a real change: pyright `models\u002Fanthropic\u002F` and the Anthropic tests against it.** 1.8.0 renamed the citations request TypedDict to `BetaCitationsConfigParamParam` (`BetaCitationsConfigParam` became a response model, and passing it into a request param broke a dict assertion) and widened `BetaInputTransformation` to a union with `thinking_mismatch_allowed`.\n- **Opus 5.5 skips thinking on trivial prompts at its default `medium` effort.** A cassette test that needs a thinking block (e.g. `stale_thinking_block_history`) has to raise `anthropic_effort` for it.\n- **A point release falls into its base model's price entry.** The base entries' prefix and `contains` clauses (`starts_with: claude-opus-5`) also capture `claude-opus-5-5`. So until the new entry exists, `calc_price` returns the *old* model's price with no error: genai-prices 0.1.7 priced Opus 5.5 at Opus 5's $5\u002F$25 instead of $4\u002F$20. Check `calc_price(..., model_ref='\u003Cnew-id>')` against the published price. Report an incorrect sibling match to the pricing automation owner per Step 3b. Link genai-prices #671 and #709 for the match-boundary regression pattern.\n- **Forced `tool_choice` is a real per-model divergence worth probing.** Most Anthropic models accept `tool_choice` `{'type':'any'}`\u002F`{'type':'tool'}` and only reject forcing alongside *thinking*; Claude Fable 5.1, Claude Mythos 5.1, and Claude Opus 5.5 reject it **unconditionally** (400 `tool_choice forces tool use is not compatible with this model`). That's modeled by `AnthropicModelProfile.anthropic_supports_forced_tool_choice` (default `True`) threaded into `_support_tool_forcing` in `models\u002Fanthropic\u002F__init__.py`. Probe `tool_choice={'type':'any'}` against the new id AND its neighbour to tell a genuine divergence from a thinking-only constraint.\n- **Record the automatic stale-thinking-block retry for a model that runs the prefix check on every account.** The recording account predates the 2026-08-31 enforcement cutoff, so on Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 a default request never reaches the retry. Claude Fable 5.2 and Mythos 5.2 enforce the check on every account. Probe the new id with `prefix_mismatch_behavior` unset after a `system` change: a 400 means the retry path runs live. Precedent: `test_anthropic_fable_5_2_retries_a_stale_thinking_block_on_a_legacy_account`.\n- **Keep Mythos ids out of `LatestAnthropicModelNames`.** Mythos models are open only to verified organizations; our key gets a 404 `not_found_error` for them. Add a new Mythos id to each profile tuple that names its Fable sibling explicitly, on the evidence of Anthropic's published docs, and say so in the PR.\n- **Probe the stale-thinking-block retry shape on every new binding model.** When the request set no thinking, the retry sends a `thinking` object through `extra_body`. Claude Fable 5.1 and Claude Opus 5.5 accept `{'block_binding': ...}` alone; Claude Sonnet 5.5 rejects it with `thinking.type: Field required`, so the retry fills in `'type': 'adaptive'`. Probe `extra_body={'thinking': {'block_binding': {'prefix_mismatch_behavior': 'drop_block'}}}` against the new id. Also probe any new `thinking.type` the release adds with `block_binding`: Sonnet 5.5's `between_tools` rejects it (`Extra inputs are not permitted`), so the retry skips that type.\n- **Probe a mid-conversation `system` entry against the `\u003Csystem>`-tagged fallback before touching `_INLINE_SYSTEM_PROMPT_MODEL_PREFIXES`.** Ask each rendering to lift a restriction the top-level prompt set; a plain non-conflicting instruction lands on every model and discriminates nothing. Claude Opus 5 obeys the entry 6\u002F6 and the tagged text 0\u002F6. Claude Sonnet 5.5 refuses both 6\u002F6, so Anthropic's published support decides and it stays in: the entry keeps operator authority at no measured cost. Leave an id out only when the tagged fallback does measurably better, as it did on Claude Sonnet 5. `_TOOL_AVAILABILITY_DELTA_MODEL_PREFIXES` is a separate gate: probe a `tool_addition` by reference and check that the model calls the added tool.\n- **List Bedrock inference profiles, not only foundation models.** Claude Sonnet 5.5 launched with `global.anthropic.claude-sonnet-5-5` and no `us.` profile. Run `aws bedrock list-inference-profiles` and add only the profiles it returns.\n- **Tests:** profile-flag unit tests go in `tests\u002Fprofiles\u002Ftest_anthropic.py` (NOT `tests\u002Fmodels\u002Ftest_anthropic.py`). Forced-tool-choice \u002F `_prepare_tools_and_tool_choice` fallback tests go in `tests\u002Fmodels\u002Ftest_tool_choice_unit.py`. The capability behaviors keyed on shared flags (sampling drop, budget-thinking reject, xhigh) are already covered by the opus-4-7\u002F4-8 parametrized tests — adding the new id to those lists is redundant once a dedicated profile test asserts the flags.\n- **`tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`** snapshots the whole `KnownModelName` enum. Refresh it by running THAT TEST ALONE with `--inline-snapshot=fix` — running the whole file can pull in unrelated `snapshot()` blocks and abort the fix.\n- **`providers\u002F_bedrock_model_names.py` `bedrock_lacks_claude_structured_output`**: only relevant if the new id is actually served on Bedrock. A direct-API-only model (not in Bedrock's foundation-model list) doesn't belong there; don't add it speculatively just because the mirrored PR did.\n\n### xAI (Grok)\n\n- **`XaiModelName` is a curated `Literal`.** `test_known_model_names` ties its ids to the `xai:` entries in `models\u002F_known_model_names.py`.\n- **SDK-lag bridge.** `xai_sdk`'s `ChatModel` frequently lags a release, so bumping the floor often won't help (check newer wheels first: download from PyPI and grep `xai_sdk\u002Ftypes\u002Fmodel.py` for `ChatModel: TypeAlias = Literal[`). Add the id to the `xai` entry's `bridges` in `SDK_MODEL_LITERALS`.\n- **A new `grok-4.x` is NOT a pure mirror.** Reasoning-effort support lives in `profiles\u002Fgrok.py` as membership sets (`_GROK_43_REASONING_MODELS` + a per-family effort frozenset), not startswith prefixes. The `grok-4` prefix auto-grants `grok_supports_builtin_tools=True` but leaves `grok_reasoning_efforts` **empty** (→ `supports_thinking=False`) unless you add the id to a reasoning-models set. Forgetting this silently ships a reasoning model with thinking off. Add a `_GROK_\u003Cver>_REASONING_MODELS` set + effort frozenset and an `elif` branch in `grok_model_profile`.\n- **Probe reasoning efforts via the OpenAI-compatible REST endpoint**, comparing against the closest neighbour: `POST https:\u002F\u002Fapi.x.ai\u002Fv1\u002Fchat\u002Fcompletions` with `{\"model\":..., \"reasoning_effort\": \u003Cval>, \"max_tokens\":1}`. A rejected value returns 400 `This model does not support 'reasoning_effort' value '\u003Cval>'`. **Whether `none` is accepted decides `thinking_always_enabled`** (rejected → always-on). CAVEAT: REST silently accepts `xhigh`\u002F`minimal` even though the gRPC `ReasoningEffort` (in `xai_sdk\u002Ftypes\u002Fchat.py`) is `Literal['none','low','medium','high']` — don't over-read REST acceptance; `GrokReasoningEffort` is those four and `_map_reasoning_effort` collapses `xhigh`→`high`, `minimal`→`low`. Grok 4.5 example: accepts `low\u002Fmedium\u002Fhigh`, rejects `none` → always-on; Grok 4.3 accepts `none` too.\n- **Floating aliases** (`grok-latest`, `grok-build-latest`) go in the profile reasoning-models set (so passing them resolves the right behavior) but are **NOT** added as `KnownModelName` literals: the curation rule leaves out `-latest` aliases.\n- **xai is NOT a gateway provider** (`'xai'` absent from `providers\u002Fgateway.py`'s `ModelProvider`) — no `gateway\u002Fxai:` entries in `_known_model_names.py`.\n- **Snapshot that ratchets:** `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities` embeds the full `KnownModelName` enum. It's a plain sorted string list — hand-add the new ids in sorted position (deterministic, no need for `--inline-snapshot=fix`). Profile-flag tests go in `tests\u002Fproviders\u002Ftest_xai.py` (see `test_xai_model_profile`); the parametrized `tests\u002Ftest_thinking.py::test_grok_43_profile_thinking_support` asserts the *4.3* effort set specifically — don't add a different-effort model to it.\n- **env \u002F probing:** `XAI_API_KEY` lives in the repo-root `.env` (not in every worktree). Run probes with `source .env && \u003Cscript>` so `$XAI_API_KEY` is exported; put any `curl` referencing it in a script file rather than passing the key inline. Verify enumeration\u002Fprofile logic with a plain `uv run python` snippet (recurse `get_args(XaiModelName)`, compare to `known_model_names()`; call `grok_model_profile(...)` directly) rather than a full `uv run pytest tests\u002F` run.\n\n### Bedrock\n\n- **Bedrock Mantle is a separate provider from Bedrock Runtime.** `bedrock:` (the `BedrockProvider`, boto3-only) talks to the Converse API; `bedrock-mantle:` (the `BedrockMantleProvider`, an `openai`-backed `Provider[AsyncOpenAI]` built on `AsyncBedrockOpenAI`) talks to Mantle's OpenAI-compatible API. They have separate model catalogs and separate optional extras (`bedrock` vs `bedrock-mantle`); don't fold Mantle deps into the `bedrock` group.\n- **Mantle model families use different endpoints, keyed off the profile.** `BedrockMantleProvider.model_profile` stamps `bedrock_mantle_interface: Literal['chat','responses','openai-responses']` on the profile (GPT-5.4+ → `openai-responses` at `\u002Fopenai\u002Fv1`; GPT-OSS → `responses` at `\u002Fv1`; GPT-OSS Safeguard → `chat` at `\u002Fv1`). `infer_model` reads that (via the profile, not a separate interface method) to pick `BedrockMantleResponsesModel` vs `BedrockMantleChatModel`, and the Responses model overrides `client` to pick the base URL. Add a family only after verifying its endpoint against the AWS model card + a live request.\n- **`bedrock:` stays on Converse; it does NOT auto-route to Mantle.** `bedrock_openai_model_profile` allows Converse only for the GPT ids it lists; any other proprietary GPT id on `bedrock:` raises, pointing users to `bedrock-mantle:`. Add a `bedrock:` GPT id to that allowed set and to `LatestBedrockModelNames` only after a successful Converse call.\n- **Response-scoped tool-call IDs are a profile flag, not a Mantle-wide behavior.** `openai_responses_tool_call_ids_are_response_scoped` (on `OpenAIModelProfile`) is enabled only for Mantle GPT-5.6 Responses; `OpenAIResponsesModel` qualifies call IDs with the response ID in both request and streaming ingestion so history stays uniquely keyed (#6536).\n\n### Google (Gemini)\n\n- **TWO places for the id, FOUR `KnownModelName` blocks.** Add to:\n  1. `LatestGoogleModelNames` in `models\u002Fgoogle.py` (`GoogleModelName = str | LatestGoogleModelNames` — the `str` arm is permissive at typecheck time, but the enumeration test only walks the `Literal` arm).\n  2. `models\u002F_known_model_names.py` — **four** blocks: `gateway\u002Fgoogle-cloud:`, `gateway\u002Fgoogle:`, `google-cloud:`, `google:` (older add-model PRs that only edit three blocks or `models\u002F__init__.py` are stale; KnownModelName moved in #5803).\n- **No SDK-lag bridge needed.** `google-genai` does not ship a model-id Literal the enumeration test consumes — the local `LatestGoogleModelNames` Literal *is* the source of truth. Adding the id lands green immediately.\n- **Profile is substring-gated, with a per-model level table.** `profiles\u002Fgoogle.py::google_model_profile` gates by an older-Gemini negative list (`gemini-1`, `gemini-2.x`, `gemma`): every other id, `gemini-4-*` included, gets the modern branch (thinking level, tool combination, server-side tool invocations, MIME types in tool returns). `'pro' in model_name and 'flash' not in model_name` sets always-on thinking. The exception is `_MODEL_THINKING_LEVELS`, a `startswith` table mapping id prefixes to their documented level sets that already holds both pro previews, the 3.7 and 3.8 flash ids, and `gemini-3.1-flash-lite-image` — so probe every new id rather than assuming the Gemini-3 branch covers it. Probe all four levels with `generateContent` and `thinkingConfig.thinkingLevel` (`MINIMAL`, `LOW`, `MEDIUM`, `HIGH`) on the Gemini API and on Vertex separately. A 400 on both means the id needs an entry in the table carrying exactly the levels it accepts (non-contiguous sets like `minimal, high` are fine — unsupported unified efforts snap to the nearest documented level). A 400 on only one of them means a level set in `GoogleModel.profile` gated on the client's transport (`_is_google_cloud`), as `gemini-3.1-flash-image` has for the Gemini API, so the other API keeps the levels it accepts. Reach Vertex with application-default credentials, `GOOGLE_PROJECT`, and `location='global'`, as `tests\u002Fconftest.py::vertex_provider` does. If you can probe only the Gemini API and it 400s, use the transport-gated branch too, so Vertex keeps its current behavior. Cite Google's documented level sets in the code comment: the Gemini API [thinking table](https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fthinking) (for image models, the [image-generation page](https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fimage-generation) instead) and the Vertex [thinking table](https:\u002F\u002Fdocs.cloud.google.com\u002Fgemini-enterprise-agent-platform\u002Fmodels\u002Fthinking). The probe results decide the entry, even where they diverge from those tables. When neither API can be probed, such as a model with no free tier and no Vertex project, add the entry only where both tables give the same level set, and write \"Not probed live\" in the comment. Probe too when the release notes claim any other capability divergence (no thinking, image-only, Pro always-on).\n- **API verification:** `curl -s \"https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels?pageSize=200&key=$GOOGLE_API_KEY\"` (key is often in the main worktree `.env`, not every linked worktree). Confirm exact ids; do **not** invent dated snapshots or `-preview` suffixes. Specialized \u002F limited-access models (e.g. Flash Cyber via CodeMender) are out of scope unless they appear in that public listing.\n- **A Vertex 404 at the default `us-central1` does not mean Vertex lacks the id.** Probe `location='global'` before you conclude the id is Gemini-API-only.\n- **Gateway support is opt-out, not opt-in.** The enumeration test generates `gateway\u002F{google,google-cloud}:*` for every `LatestGoogleModelNames` entry **except** those listed in `UNSUPPORTED_GATEWAY_MODEL_NAMES` in `tests\u002Fmodels\u002Ftest_model_names.py`. Do not add a new id there; Step 6 covers Gateway support. `test_unsupported_gateway_model_names_are_curated` fails on an entry whose id left the curated aliases; remove that entry.\n- **Snapshots \u002F tests:** hand-add the new ids in sorted position in `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities` (plain sorted string list). Mirror-only adds skip new VCR by default; #5527 recorded one for `gemini-3.5-flash` but that is not required for a pure name add.\n- **Docs:** doc pages name models through the tiered aliases in `docs\u002Fmodel_aliases\u002Faliases.json`. Leave pages that pin a model on purpose (`docs\u002Fmodels\u002Fgoogle.md`, `docs\u002Fcapabilities\u002Fthinking.md`) alone.\n\nGoogle image-model landmines:\n\n- Direct image generation has a separate public literal, `KnownImageGenerationModelName` in `pydantic_ai_slim\u002Fpydantic_ai\u002Fimages\u002F__init__.py`. When the task is scoped to `ImageGenerator`, update and test this literal independently; do not automatically widen the change to conversational `KnownModelName`, gateway aliases, profiles, and capability snapshots unless those surfaces are explicitly in scope.\n- `Client().models.list()` returns a lazy pager. Keep the client in a named variable until iteration finishes; constructing it inline can let it be closed before the pager sends its request. The endpoint can still list deprecated preview image IDs, so cross-check the official deprecation page and add only current IDs.\n- Probe image settings on the exact model and API surface. For `gemini-3.1-flash-image`, the minimum `generateContent` value is `ImageConfigDict(image_size='512')`; the superficially similar literal `'0.5K'` is invalid and returns HTTP 400. `gemini-3.1-flash-lite-image` supports only 1K output. Do not transfer value spellings between model families or API examples without a live check.\n\n### MoonshotAI (Kimi)\n\n- `MoonshotAIModelName` in `providers\u002Fmoonshotai.py` is a local literal, independent of the OpenAI SDK's model enum. Update it and `models\u002F_known_model_names.py` together, then refresh `tests\u002Ftest_capability_spec.py::test_model_json_schema_with_capabilities`.\n- The `kimi-k3` prefix already covers `kimi-k3.1-pro` and `kimi-k3.1-pro-highspeed` in both family and provider profiles. Probe before adding another prefix or changing profile flags.\n- Verify the API at `https:\u002F\u002Fapi.moonshot.ai\u002Fv1`. The separate Kimi Code subscription uses different model IDs. Read the [canonical API guide](https:\u002F\u002Fplatform.kimi.ai\u002Fdocs\u002Fguide\u002Fkimi-k3-1-pro-quickstart) and compare live behavior with the nearest sibling; do not transfer subscription semantics.\n\n### Others\n\nNot yet documented here. **When you add the next model for one of these providers, add the landmines you encountered to this section before closing the session** (see Step 9).\n\n## Step 9 — Update this skill\n\nAfter completing the model-add, before closing the session: if anything came up that isn't already documented in this skill — a new test that ratcheted, a provider-specific dispatch tuple, a misleading SDK behavior, a corrected misconception, an iteration the user had to walk you through — **add it to this SKILL.md**.\n\nSpecifically:\n- Provider-specific landmines → the matching subsection (or create it).\n- Generic process gaps → the relevant numbered step.\n- Workflow shape errors → restructure the steps.\n\nThis skill exists to compound learnings. A model-add that surfaced new friction and didn't update this file wasted that friction.\n",{"name":5,"description":7,"allowed-tools":49,"user-invocable":50},"Bash, Read, Edit, Write, Glob, Grep, WebFetch, WebSearch, AskUserQuestion",true,"main","0458d8c1627ac3a4e318cb1c931a99bc92ce2aa2",".agents\u002Fskills\u002Fadd-new-model",3147,"https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai","https:\u002F\u002Fpydantic.dev\u002Fpydantic-ai","https:\u002F\u002Fgithub.com\u002Fpydantic","https:\u002F\u002Fpydantic.dev","Pydantic, Pydantic Logfire and Pydantic AI","2026-11-11 09:14:35",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":50},[63,66,69],{"tool":64,"command":65},"npx","npx skills add pydantic\u002Fpydantic-ai --skill add-new-model",{"tool":67,"command":68},"bunx","bunx skills add pydantic\u002Fpydantic-ai --skill add-new-model",{"tool":70,"command":71},"pnpm","pnpm dlx skills add pydantic\u002Fpydantic-ai --skill add-new-model","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fadd-new-model\u002FSKILL.md",[],[75,103,113,135,154,170],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":44},"01M6BYX16NP31D2ACFSNDNNJEV","migrating-agno-to-pydantic-ai","Migrate Python Agno applications to Pydantic AI and, only when needed, Pydantic AI Harness. Use when source code imports `agno` or relies on Agno agents, teams, workflows, sessions, memory, knowledge, tools, hooks, guardrails, approvals, skills, streaming, or AgentOS.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Fpydantic_ai_slim\u002Fpydantic_ai\u002F.agents\u002Fskills\u002Fmigrating-agno-to-pydantic-ai\u002FSKILL.md",[],[82,12,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,38,102],"pydantic ai","migrating agno to pydantic ai","agno","harness","memory","applications","Guardrails","python","sessions","teams","knowledge","workflows","migrate","Tools","code","streaming","hooks","only","ai harness","use","pydantic ai harness",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":44},"01M6BYY08B7335R8J3EKFM2GX7","reviewer","Review changes.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Ftests\u002Fharness\u002Fskills\u002Ftemporal_workspace\u002Fskills\u002Freviewer\u002FSKILL.md",[],[105,110,111,112],"review changes","review","changes",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":125,"publishedAt":44},"01M6BYXW6FV6Z0BB3ARTAJ0VKM","pydantic-ai-harness","Extend Pydantic AI agents with capabilities from pydantic-ai-harness -- the Coder coding agent, file and shell tools in local or sandboxed workspaces (Modal, E2B, Render, Sprites, Daytona, boxd, smolvm, BoxLite), Code Mode, sub-agents and planning, memory and skills, context compaction, guardrails and spend limits, web research and browsers, hosted SaaS integrations, step persistence, and background agents on Render Workflows. Use when the user mentions pydantic-ai-harness or pydantic_ai_harness, imports a harness capability such as Coder, CodeMode, FileSystem, Shell, SubAgents, Memory, or ToolGuardrail, or wants a Pydantic AI agent that edits files, runs commands or agent-written Python, delegates, remembers, manages long context, stays within limits, or runs model and tool operations as chained Render task runs.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Fsrc\u002Fpydantic_ai_harness\u002Fpydantic_ai_harness\u002F.agents\u002Fskills\u002Fpydantic-ai-harness\u002FSKILL.md",[119,122],{"categoryNo":120,"categoryName":121,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":123,"categoryName":124,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[85,82,102,12,100,27,86,88,126,93,96,127,128,129,130,131,132,133,134,38],"ai agent","e2b","workspaces","render","local","files","smolvm","render workflows","mode",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":44},"01M6BYXS3HEQYWXFJXYACRCA4H","migrating-deep-agents-to-pydantic-ai-harness","Migrate Python LangChain Deep Agents applications to Pydantic AI and Pydantic AI Harness. Use when the source uses the upstream `deepagents` package or demonstrably reproduces its middleware, backends, skills, memory, subagents, or sandbox contracts. Use `migrating-langchain-to-pydantic-ai` for plain LangChain, LangGraph, or LCEL migrations and `pydantic-ai-harness` for greenfield Harness usage.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Fsrc\u002Fpydantic_ai_harness\u002Fpydantic_ai_harness\u002F.agents\u002Fskills\u002Fmigrating-deep-agents-to-pydantic-ai-harness\u002FSKILL.md",[],[85,82,12,142,143,100,144,102,86,145,87,89,146,147,148,94,149,150,151,152,153,101,38],"migrating deep agents to pydantic ai harness","deep","deep agents","langgraph","sandbox","package","langchain","usage","for","deepagents","middleware","upstream",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":44},"01M6BYXP4FFSW83DR07RZ789DR","migrating-vercel-ai-sdk-and-eve-to-pydantic-ai","Migrate TypeScript Vercel AI SDK or Eve applications to Python with Pydantic AI and, only when needed, Pydantic AI Harness. Use when source code imports `ai`, `@ai-sdk\u002F*`, or `eve`, or relies on `generateText`, `streamText`, `ToolLoopAgent`, `useChat`, Eve agents, tools, skills, subagents, approvals, sessions, channels, schedules, or sandboxes.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Fpydantic_ai_slim\u002Fpydantic_ai\u002F.agents\u002Fskills\u002Fmigrating-vercel-ai-sdk-and-eve-to-pydantic-ai\u002FSKILL.md",[],[82,12,161,162,163,164,165,166,85,87,89,167,90,94,95,96,168,99,100,101,169,38,102],"sdk","ai sdk","eve","migrating vercel ai sdk and eve to pydantic ai","vercel","vercel ai sdk","typescript","sandboxes","schedules",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":176,"publishedAt":44},"01M6BYXJXKEK0384TZNH0R1ZVY","migrating-pi-to-pydantic-ai","Migrate TypeScript Pi coding-agent applications, extensions, or packages to Python with Pydantic AI and Pydantic AI Harness. Use when source code imports `@earendil-works\u002Fpi-*`, calls `createAgentSession`, registers Pi extensions, or relies on Pi tools, hooks, skills, sessions, compaction, providers, TUI, RPC, or packages.","https:\u002F\u002Fgithub.com\u002Fpydantic\u002Fpydantic-ai\u002Fblob\u002Fmain\u002Fpydantic_ai_slim\u002Fpydantic_ai\u002F.agents\u002Fskills\u002Fmigrating-pi-to-pydantic-ai\u002FSKILL.md",[],[82,12,177,178,85,179,87,89,167,90,180,94,95,96,181,182,98,38,183,102,184,185,186,187,188],"migrating pi to pydantic ai","pi","packages","rpc","coding","Providers","pi extensions","imports","source","Coding-Agent","source code","compaction"]