| ... | ... | @@ -0,0 +1,117 @@ |
| 1 | # Adding a provider |
| 2 | |
| 3 | A provider integration is judged by whether every T3 feature behaves honestly on it, not by |
| 4 | whether a turn runs. This page lists the decisions and evidence a new driver needs. The |
| 5 | [provider constraints](./providers.md) and the |
| 6 | [capability system](../orchestration-v2/provider-capability-system.md) explain why these rules exist. |
| 7 | |
| 8 | ## Choose the integration shape |
| 9 | |
| 10 | - **ACP agents** start as [ACP Registry](../user/providers-acp.md) entries, which follow the ACP |
| 11 | spec with no per-agent handling. An agent gets a dedicated driver only when it needs behavior the |
| 12 | spec does not cover, and then it is a small flavor over the |
| 13 | [shared ACP adapter](../../apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts), like Grok |
| 14 | and Antigravity. Never add agent-id checks to the generic registry adapter. |
| 15 | - **Other protocols** get a native adapter that implements |
| 16 | [`ProviderAdapterV2`](../../apps/server/src/orchestration-v2/ProviderAdapter.ts), like Codex, |
| 17 | Claude, Cursor, OpenCode, Pi, and Muse. |
| 18 | |
| 19 | Provider-specific behavior stays in the adapter and driver. Orchestration and clients read |
| 20 | capabilities, never the driver kind. |
| 21 | |
| 22 | ## Report only what the provider does |
| 23 | |
| 24 | - **Capabilities.** Set every flag in `OrchestrationV2ProviderCapabilities` to what the provider |
| 25 | really does. Turn off fork, rollback, steering, or subagent support it lacks; orchestration then |
| 26 | falls back, for example to portable context handoff for forks. A capability left on that fails |
| 27 | at runtime is a bug. |
| 28 | - **Permission modes.** Offer only modes the provider enforces natively, through |
| 29 | `supportedRuntimeModes` in the provider presentation ([Grok](../../apps/server/src/provider/GrokProvider.ts) |
| 30 | and [Pi](../../apps/server/src/provider/PiProvider.ts) are examples). Do not imitate a missing |
| 31 | mode by answering approvals in T3: T3's check is weaker than the agent's own enforcement. The |
| 32 | server runs an unoffered stored mode as Supervised |
| 33 | ([`RuntimePolicy.ts`](../../apps/server/src/orchestration-v2/RuntimePolicy.ts)). |
| 34 | - **Approval and question options.** Pass the provider's own option IDs through unchanged. Every |
| 35 | request needs a way to decline that the provider honors. |
| 36 | - **Interaction modes.** Hide the plan toggle (`showInteractionModeToggle: false`) unless the |
| 37 | provider's plan output becomes T3's proposed-plan card. |
| 38 | |
| 39 | ## Process, account, and setup boundaries |
| 40 | |
| 41 | - **Instances.** Session state, catalogs, and credentials belong to a provider instance, not the |
| 42 | driver. Remove ambient credentials the instance did not configure, so two instances cannot |
| 43 | silently share an account or billing. |
| 44 | - **Status checks.** Background status and model refreshes must not open a session that can start |
| 45 | MCP servers, run hooks, or launch a login. Keep heavier probes behind an explicit refresh. |
| 46 | - **T3 MCP tools.** Inject the thread's MCP server so agents can use T3's tools, and make a turn |
| 47 | survive when that server is unreachable. |
| 48 | - **Updates.** Run an update only through the installer that provably owns the binary; otherwise |
| 49 | leave it manual. See [`providerMaintenance.ts`](../../apps/server/src/provider/providerMaintenance.ts). |
| 50 | |
| 51 | ## Tests |
| 52 | |
| 53 | Prove adapter behavior with replay fixtures: a provider transcript replayed through the real |
| 54 | orchestrator, adapter, and projections. See the [testing strategy](../orchestration-v2/testing-strategy.md). |
| 55 | |
| 56 | - Record transcripts from the real provider with a recorder script in |
| 57 | [`apps/server/scripts`](../../apps/server/scripts) (`record-*-replay-fixture.ts`). A new protocol |
| 58 | usually needs its own recorder. |
| 59 | - Cover the shared scenarios under |
| 60 | [`testkit/fixtures`](../../apps/server/src/orchestration-v2/testkit/fixtures) that the provider |
| 61 | supports: `simple`, `multi_turn`, `queued_turn`, `turn_interrupt`, `message_steering`, |
| 62 | `provider_thread_resume`, and the `tool_call_*` approval cases. Add provider-specific fixtures |
| 63 | for behavior the shared ones do not reach. |
| 64 | - Unit tests are for pure logic and for failures a real provider cannot produce on demand. A test |
| 65 | that drives the adapter with hand-written frames is a guess about the protocol; live testing |
| 66 | regularly finds what those guesses missed. |
| 67 | - A gated live test against the real binary is welcome, but it does not replace replays, because |
| 68 | CI skips it. |
| 69 | |
| 70 | ## Traps several providers hit |
| 71 | |
| 72 | Each of these broke more than one adapter. A replay fixture for each case your provider can |
| 73 | produce catches them. |
| 74 | |
| 75 | - **Settings applied before the provider advertises them.** Agents often list config options after |
| 76 | the session opens, in a later update, or only once a model runs (an effort option that exists |
| 77 | only for models with effort). An agent can accept a write before then and change nothing. Wait |
| 78 | for the option to be advertised before writing it, and treat a stored option the live session |
| 79 | does not offer as skipped, not as a failure. |
| 80 | - **"Default" is a sentinel, not a model.** A default-model selection must switch the session back |
| 81 | after a named model ran, including in a resumed session. Never send the sentinel to the |
| 82 | provider. |
| 83 | - **Stop sent before the turn started.** A cancel that reaches the provider before it registered |
| 84 | the prompt can be ignored while the turn runs to completion, or can leave a session the provider |
| 85 | never saved. Find the provider's own turn-started signal, and test a Stop pressed right after |
| 86 | sending. |
| 87 | - **Work the provider starts on its own.** Background commands, subagents, workflows, and goals can |
| 88 | finish or start a turn after T3's turn settled. Offer a continuation through |
| 89 | [`ProviderContinuationRequests`](../../apps/server/src/orchestration-v2/ProviderContinuationRequests.ts) |
| 90 | so the parent wakes, and report `hasPendingBackgroundWork` so the session is not released as |
| 91 | idle. Dropping it, or killing the session, loses the result. |
| 92 | - **Subagents outlive the run that launched them.** A child can report after its parent's turn |
| 93 | settled, or resume during a later run. Route its updates by the subagent, not by whichever run |
| 94 | is currently active. |
| 95 | - **A failed or stopped turn leaves nothing open.** Settle the turn's tool calls, subagents, and |
| 96 | pending approvals and questions. Each terminal path needs its own replay: completion, Stop, |
| 97 | provider failure, and process exit. |
| 98 | - **Usage limits are not generic failures.** Classify quota and rate-limit errors as `usage_limit` |
| 99 | with a reset time when the provider gives one, so the thread shows Limited and can resume. |
| 100 | - **Paths and environment.** Test a symlinked workspace, such as macOS `/tmp`; an agent that |
| 101 | compares canonical paths fails every turn there. Drop inherited credentials the instance did not |
| 102 | configure. Report unknown sign-in as unknown rather than as signed in. |
| 103 | |
| 104 | ## Where a driver plugs in |
| 105 | |
| 106 | - **Contracts:** settings schema and patch, default model, and display name in |
| 107 | [`packages/contracts`](../../packages/contracts/src). New providers are off by default. |
| 108 | - **Server:** the driver in [`provider/Drivers`](../../apps/server/src/provider/Drivers) and its entry |
| 109 | in [`builtInDrivers.ts`](../../apps/server/src/provider/builtInDrivers.ts). Also its position in |
| 110 | the [status order](../../apps/server/src/provider/providerStatusCache.ts), a compatibility policy |
| 111 | in [`model-manifest.json`](../../apps/server/src/provider/model-manifest.json) (bump `updatedAt`; |
| 112 | see [model manifest](./model-manifest.md)), and text generation for titles and commit messages. |
| 113 | - **Clients:** web settings metadata and badge, provider icons on web and mobile, and settings |
| 114 | search terms. |
| 115 | - **Docs:** a `docs/user/providers-<name>.md` guide in the product's voice, a row in the |
| 116 | [install](../user/install.md#providers) table, and any provider difference that changes the |
| 117 | [permission modes](../user/permission-modes.md) page. |