// Providers — model configuration
function Providers() {
  const shell = useShell();
  const tocItems = [
    { id: 'overview', label: 'Overview' },
    { id: 'file', label: 'providers.yaml' },
    { id: 'anthropic', label: 'Anthropic format', level: 3 },
    { id: 'openai', label: 'OpenAI-compatible', level: 3 },
    { id: 'defaults', label: 'Defaults block' },
    { id: 'supported', label: 'Supported providers' },
    { id: 'switching', label: 'Switching providers' },
    { id: 'per-tenant', label: 'Per-tenant overrides' },
    { id: 'embeddings', label: 'Embeddings' },
  ];

  return (
    <div className="app">
      <Topbar section="docs" theme={shell.theme} setTheme={shell.setTheme}
              onSearch={() => shell.setSearchOpen(true)}
              onMenuToggle={() => shell.setMobileMenuOpen(true)} />
      <div className="main">
        <Sidebar activeId="providers"
                 mobileOpen={shell.mobileMenuOpen}
                 onMobileClose={() => shell.setMobileMenuOpen(false)} />
        <article className="content">
          <div className="crumbs">
            <a href="index.html">Docs</a>
            <span className="sep">/</span>
            <a href="#">Configuration</a>
            <span className="sep">/</span>
            <span>Providers</span>
          </div>

          <div className="eyebrow">Configuration · models</div>
          <h1 className="h1">Providers <em>& models.</em></h1>
          <p className="lede">
            ClawAgen has two adapter families: OpenAI-compatible (chat completions) and Anthropic
            Messages. Between them they cover Anthropic, OpenAI, Azure OpenAI, DeepSeek, Qwen,
            Kimi, GLM, MiniMax, AWS Bedrock, and any other endpoint that speaks either protocol.
            Switching is a <code>providers.yaml</code> edit — no code change.
          </p>

          <h2 id="overview" className="h2">Overview</h2>
          <p>
            Each provider entry names an API family (<code>api: openai-completions</code> or{' '}
            <code>api: anthropic-messages</code>), a base URL, and a list of models with their
            context window and pricing. A top-level <code>defaults.primary</code> selects the
            <code>provider/model</code> pair the brain runner will call.
          </p>

          <h2 id="file" className="h2">providers.yaml</h2>
          <p>
            Lives at <code>agents/config/providers.yaml</code>. Ships with commented templates so
            swapping is uncomment + fill in the key.
          </p>

          <h3 id="anthropic" className="h3">Anthropic-format example</h3>
          <CodeBlock tabs={[{ label: 'providers.yaml', raw: `providers:\n  anthropic:\n    apiKey: \${ANTHROPIC_API_KEY}\n    baseUrl: https://api.anthropic.com\n    api: anthropic-messages\n    models:\n      - id: claude-sonnet-4-5\n        contextSize: 200000\n        maxTokens: 8192\n        reasoning: false\n        cost:\n          input: 3.00\n          output: 15.00\n          cacheRead: 0.30\n          cacheWrite: 3.75`,
            code: `<span class="tok-var">providers</span>:
  <span class="tok-var">anthropic</span>:
    <span class="tok-var">apiKey</span>: \${ANTHROPIC_API_KEY}
    <span class="tok-var">baseUrl</span>: https://api.anthropic.com
    <span class="tok-var">api</span>: anthropic-messages
    <span class="tok-var">models</span>:
      - <span class="tok-var">id</span>: claude-sonnet-4-5
        <span class="tok-var">contextSize</span>: <span class="tok-num">200000</span>
        <span class="tok-var">maxTokens</span>: <span class="tok-num">8192</span>
        <span class="tok-var">reasoning</span>: <span class="tok-kw">false</span>
        <span class="tok-var">cost</span>:
          <span class="tok-var">input</span>: <span class="tok-num">3.00</span>
          <span class="tok-var">output</span>: <span class="tok-num">15.00</span>
          <span class="tok-var">cacheRead</span>: <span class="tok-num">0.30</span>
          <span class="tok-var">cacheWrite</span>: <span class="tok-num">3.75</span>` }]} />
          <p>The same adapter covers AWS Bedrock and any Anthropic-compatible endpoint — only <code>baseUrl</code> and <code>apiKey</code> change.</p>

          <h3 id="openai" className="h3">OpenAI-compatible example</h3>
          <CodeBlock tabs={[{ label: 'providers.yaml', raw: `providers:\n  azure-openai:\n    apiKey: \${AZURE_OPENAI_API_KEY}\n    baseUrl: https://YOUR-ENDPOINT.services.ai.azure.com/openai/v1\n    api: openai-completions\n    authHeader: true\n    models:\n      - id: gpt-5.3-chat\n        contextSize: 128000\n        maxTokens: 8192\n        cost: { input: 5.00, output: 15.00, cacheRead: 2.50, cacheWrite: 5.00 }\n  deepseek:\n    apiKey: \${DEEPSEEK_API_KEY}\n    baseUrl: https://api.deepseek.com/v1\n    api: openai-completions\n    models:\n      - id: deepseek-chat\n        contextSize: 128000\n        maxTokens: 8192\n        cost: { input: 0.28, output: 0.42, cacheRead: 0.014, cacheWrite: 0.28 }`,
            code: `<span class="tok-var">providers</span>:
  <span class="tok-var">azure-openai</span>:
    <span class="tok-var">apiKey</span>: \${AZURE_OPENAI_API_KEY}
    <span class="tok-var">baseUrl</span>: https://YOUR-ENDPOINT.services.ai.azure.com/openai/v1
    <span class="tok-var">api</span>: openai-completions
    <span class="tok-var">authHeader</span>: <span class="tok-kw">true</span>
    <span class="tok-var">models</span>:
      - <span class="tok-var">id</span>: gpt-5.3-chat
        <span class="tok-var">contextSize</span>: <span class="tok-num">128000</span>
        <span class="tok-var">maxTokens</span>: <span class="tok-num">8192</span>
        <span class="tok-var">cost</span>: { input: <span class="tok-num">5.00</span>, output: <span class="tok-num">15.00</span>, cacheRead: <span class="tok-num">2.50</span>, cacheWrite: <span class="tok-num">5.00</span> }
  <span class="tok-var">deepseek</span>:
    <span class="tok-var">apiKey</span>: \${DEEPSEEK_API_KEY}
    <span class="tok-var">baseUrl</span>: https://api.deepseek.com/v1
    <span class="tok-var">api</span>: openai-completions
    <span class="tok-var">models</span>:
      - <span class="tok-var">id</span>: deepseek-chat
        <span class="tok-var">contextSize</span>: <span class="tok-num">128000</span>
        <span class="tok-var">maxTokens</span>: <span class="tok-num">8192</span>
        <span class="tok-var">cost</span>: { input: <span class="tok-num">0.28</span>, output: <span class="tok-num">0.42</span>, cacheRead: <span class="tok-num">0.014</span>, cacheWrite: <span class="tok-num">0.28</span> }` }]} />

          <h2 id="defaults" className="h2">Defaults block</h2>
          <CodeBlock tabs={[{ label: 'providers.yaml', raw: `defaults:\n  primary: deepseek/deepseek-chat\n  fallbacks: []              # no silent fallback — fail loudly\n  maxTurns: 20\n  historyLimit: 15\n  temperature: 1`,
            code: `<span class="tok-var">defaults</span>:
  <span class="tok-var">primary</span>: deepseek/deepseek-chat
  <span class="tok-var">fallbacks</span>: []              <span class="tok-com"># no silent fallback — fail loudly</span>
  <span class="tok-var">maxTurns</span>: <span class="tok-num">20</span>
  <span class="tok-var">historyLimit</span>: <span class="tok-num">15</span>
  <span class="tok-var">temperature</span>: <span class="tok-num">1</span>` }]} />
          <p>
            <code>primary</code> is the <code>provider/model</code> string the runner calls.{' '}
            <code>fallbacks</code> is empty by design — a silent fallback hides outages that
            monitoring should surface. If you want a degraded mode, wire it explicitly in your
            agent logic rather than at the provider layer.
          </p>

          <h2 id="supported" className="h2">Supported providers</h2>
          <div style={{overflow:'auto', margin:'12px 0 28px'}}>
          <table className="doc-table">
            <thead><tr><th>Provider</th><th>API family</th><th>Notes</th></tr></thead>
            <tbody>
              <tr><td>Anthropic direct</td><td><code>anthropic-messages</code></td><td>Ephemeral cache on system prompt for cost savings.</td></tr>
              <tr><td>AWS Bedrock</td><td><code>anthropic-messages</code></td><td>Via <code>@anthropic-ai/bedrock-sdk</code>. Model ids are the Bedrock-prefixed form.</td></tr>
              <tr><td>MiniMax</td><td><code>anthropic-messages</code></td><td>Anthropic-compatible endpoint.</td></tr>
              <tr><td>OpenAI</td><td><code>openai-completions</code></td><td>Standard OpenAI chat.</td></tr>
              <tr><td>Azure OpenAI</td><td><code>openai-completions</code></td><td>Set <code>authHeader: true</code> for bearer-style auth.</td></tr>
              <tr><td>DeepSeek</td><td><code>openai-completions</code></td><td>Automatic prefix caching — no code needed.</td></tr>
              <tr><td>Qwen / Alibaba</td><td><code>openai-completions</code></td><td>DashScope-compatible mode.</td></tr>
              <tr><td>Kimi / Moonshot</td><td><code>openai-completions</code></td><td>OpenAI-compatible.</td></tr>
              <tr><td>GLM / z.ai</td><td><code>openai-completions</code></td><td>OpenAI-compatible.</td></tr>
              <tr><td>Any other</td><td>either</td><td>If it speaks one of the two protocols, you can point at it.</td></tr>
            </tbody>
          </table>
          </div>

          <h2 id="switching" className="h2">Switching providers</h2>
          <ol>
            <li>Uncomment the target provider block in <code>providers.yaml</code> and set its <code>apiKey</code>.</li>
            <li>Update <code>defaults.primary</code> to the new <code>provider/model</code>.</li>
            <li>Restart the agents container (<code>make deploy</code> or <code>docker compose restart agents</code>).</li>
          </ol>
          <Callout type="note" title="No two-phase migration needed">
            Sessions are stored as a generic message list. The next call to a tenant's session
            uses whatever model is configured — no data migration, no per-session pinning.
          </Callout>

          <h2 id="per-tenant" className="h2">Per-tenant overrides</h2>
          <p>
            A tenant can pin to its own provider by dropping a{' '}
            <code>config/providers.yaml</code> under its workspace. Same schema; the per-tenant
            file wins over the operator-level file. Useful when one staff member has a preferred
            model or different budget.
          </p>
          <CodeBlock tabs={[{ label: 'layout', raw: `/data/tenants/5/config/providers.yaml   # tenant 5 uses Anthropic\nagents/config/providers.yaml            # everyone else uses the operator default`,
            code: `/data/tenants/<span class="tok-num">5</span>/config/providers.yaml   <span class="tok-com"># tenant 5 uses Anthropic</span>
agents/config/providers.yaml            <span class="tok-com"># everyone else uses the operator default</span>` }]} />

          <h2 id="embeddings" className="h2">Embeddings</h2>
          <p>
            Embeddings are a separate provider from chat — ClawAgen uses OpenAI's{' '}
            <code>text-embedding-3-large</code> (1536 dims) by default. Configured via env:
          </p>
          <CodeBlock tabs={[{ label: 'agents/.env', raw: `OPENAI_EMBEDDINGS_API_KEY=sk-...\nEMBEDDINGS_MODEL=text-embedding-3-large`,
            code: `<span class="tok-var">OPENAI_EMBEDDINGS_API_KEY</span>=sk-...
<span class="tok-var">EMBEDDINGS_MODEL</span>=text-embedding-3-large` }]} />
          <p>The embeddings provider is independent of chat — you can use DeepSeek for chat and OpenAI for embeddings in the same deployment.</p>

          <Feedback />
          <PageFoot
            prev={{ label: 'Self-host', href: 'selfhost.html' }}
            next={{ label: 'Writing skills', href: 'skills-guide.html' }}
          />
        </article>
        <TOC items={tocItems} />
      </div>
      <SearchOverlay open={shell.searchOpen} onClose={() => shell.setSearchOpen(false)} />
      <TweaksPanel visible={shell.tweaksVisible} theme={shell.theme} setTheme={shell.setTheme} />
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('root')).render(<Providers />);
