> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bettertoken.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pi Agent में third-party API: Base URL, API Key और मॉडल सेटअप

> Pi Agent को models.json, Base URL, API Key और Model ID से third-party API से जोड़ें। प्रोटोकॉल चुनें, कनेक्शन जांचें, मॉडल बदलें और सामान्य त्रुटियां ठीक करें।

export const PiModelPicker = ({locale = "en", plazaUrl = "https://bettertoken.ai/pricing"}) => {
  const translations = {
    en: {
      get: "Get model list",
      refresh: "Refresh model list",
      loading: "Loading models...",
      api: "API",
      search: "Search models",
      models: "Models",
      selected: "Selected",
      select: "Select",
      copyId: "Copy Model ID",
      copyConfig: "Copy configuration",
      download: "Download models.json",
      copied: "Copied",
      copyError: "Copy failed. Select and copy the text below.",
      error: "Could not load models. Try again or open the model plaza.",
      empty: "No matching models.",
      plaza: "Model plaza",
      config: "Pi configuration",
      selectAll: "Select all visible models"
    },
    zh: {
      get: "获取模型列表",
      refresh: "刷新模型列表",
      loading: "正在获取模型...",
      api: "接口",
      search: "搜索模型",
      models: "模型",
      selected: "已选择",
      select: "选择",
      copyId: "复制 Model ID",
      copyConfig: "复制配置",
      download: "下载 models.json",
      copied: "已复制",
      copyError: "复制失败，请选中下方文本复制。",
      error: "暂时无法获取模型，请重试或前往模型广场。",
      empty: "没有匹配的模型。",
      plaza: "模型广场",
      config: "Pi 配置",
      selectAll: "选择当前显示的全部模型"
    },
    ru: {
      get: "Получить список моделей",
      refresh: "Обновить список моделей",
      loading: "Загрузка моделей...",
      api: "API",
      search: "Поиск моделей",
      models: "Модели",
      selected: "Выбрано",
      select: "Выбрать",
      copyId: "Скопировать Model ID",
      copyConfig: "Скопировать настройки",
      download: "Скачать models.json",
      copied: "Скопировано",
      copyError: "Не удалось скопировать. Выделите и скопируйте текст ниже.",
      error: "Не удалось загрузить модели. Повторите попытку или откройте каталог моделей.",
      empty: "Подходящих моделей нет.",
      plaza: "Каталог моделей",
      config: "Настройки Pi",
      selectAll: "Выбрать все показанные модели"
    },
    hi: {
      get: "मॉडल सूची प्राप्त करें",
      refresh: "मॉडल सूची रीफ़्रेश करें",
      loading: "मॉडल लोड हो रहे हैं...",
      api: "API",
      search: "मॉडल खोजें",
      models: "मॉडल",
      selected: "चुने गए",
      select: "चुनें",
      copyId: "Model ID कॉपी करें",
      copyConfig: "कॉन्फ़िगरेशन कॉपी करें",
      download: "models.json डाउनलोड करें",
      copied: "कॉपी हो गया",
      copyError: "कॉपी नहीं हो सका। नीचे दिए गए टेक्स्ट को चुनकर कॉपी करें।",
      error: "मॉडल लोड नहीं हो सके। फिर से प्रयास करें या मॉडल कैटलॉग खोलें।",
      empty: "कोई मेल खाने वाला मॉडल नहीं मिला।",
      plaza: "मॉडल कैटलॉग",
      config: "Pi कॉन्फ़िगरेशन",
      selectAll: "दिखाए गए सभी मॉडल चुनें"
    },
    es: {
      get: "Obtener lista de modelos",
      refresh: "Actualizar lista de modelos",
      loading: "Cargando modelos...",
      api: "API",
      search: "Buscar modelos",
      models: "Modelos",
      selected: "Seleccionados",
      select: "Seleccionar",
      copyId: "Copiar Model ID",
      copyConfig: "Copiar configuración",
      download: "Descargar models.json",
      copied: "Copiado",
      copyError: "No se pudo copiar. Selecciona y copia el texto de abajo.",
      error: "No se pudieron cargar los modelos. Inténtalo de nuevo o abre el catálogo.",
      empty: "No hay modelos coincidentes.",
      plaza: "Catálogo de modelos",
      config: "Configuración de Pi",
      selectAll: "Seleccionar todos los modelos visibles"
    },
    "pt-br": {
      get: "Obter lista de modelos",
      refresh: "Atualizar lista de modelos",
      loading: "Carregando modelos...",
      api: "API",
      search: "Buscar modelos",
      models: "Modelos",
      selected: "Selecionados",
      select: "Selecionar",
      copyId: "Copiar Model ID",
      copyConfig: "Copiar configuração",
      download: "Baixar models.json",
      copied: "Copiado",
      copyError: "Não foi possível copiar. Selecione e copie o texto abaixo.",
      error: "Não foi possível carregar os modelos. Tente novamente ou abra o catálogo.",
      empty: "Nenhum modelo correspondente.",
      plaza: "Catálogo de modelos",
      config: "Configuração do Pi",
      selectAll: "Selecionar todos os modelos visíveis"
    },
    ja: {
      get: "モデル一覧を取得",
      refresh: "モデル一覧を更新",
      loading: "モデルを取得中...",
      api: "API",
      search: "モデルを検索",
      models: "モデル",
      selected: "選択済み",
      select: "選択",
      copyId: "Model ID をコピー",
      copyConfig: "設定をコピー",
      download: "models.json をダウンロード",
      copied: "コピーしました",
      copyError: "コピーできませんでした。下のテキストを選択してコピーしてください。",
      error: "モデルを取得できませんでした。再試行するか、モデルカタログを開いてください。",
      empty: "一致するモデルがありません。",
      plaza: "モデルカタログ",
      config: "Pi の設定",
      selectAll: "表示中のモデルをすべて選択"
    },
    fr: {
      get: "Obtenir la liste des modèles",
      refresh: "Actualiser les modèles",
      loading: "Chargement des modèles...",
      api: "API",
      search: "Rechercher des modèles",
      models: "Modèles",
      selected: "Sélectionnés",
      select: "Sélectionner",
      copyId: "Copier le Model ID",
      copyConfig: "Copier la configuration",
      download: "Télécharger models.json",
      copied: "Copié",
      copyError: "La copie a échoué. Sélectionnez et copiez le texte ci-dessous.",
      error: "Impossible de charger les modèles. Réessayez ou ouvrez le catalogue.",
      empty: "Aucun modèle correspondant.",
      plaza: "Catalogue de modèles",
      config: "Configuration de Pi",
      selectAll: "Sélectionner tous les modèles affichés"
    },
    de: {
      get: "Modellliste abrufen",
      refresh: "Modellliste aktualisieren",
      loading: "Modelle werden geladen...",
      api: "API",
      search: "Modelle suchen",
      models: "Modelle",
      selected: "Ausgewählt",
      select: "Auswählen",
      copyId: "Model ID kopieren",
      copyConfig: "Konfiguration kopieren",
      download: "models.json herunterladen",
      copied: "Kopiert",
      copyError: "Kopieren fehlgeschlagen. Markiere und kopiere den Text unten.",
      error: "Modelle konnten nicht geladen werden. Versuche es erneut oder öffne den Modellkatalog.",
      empty: "Keine passenden Modelle.",
      plaza: "Modellkatalog",
      config: "Pi-Konfiguration",
      selectAll: "Alle angezeigten Modelle auswählen"
    },
    ko: {
      get: "모델 목록 가져오기",
      refresh: "모델 목록 새로고침",
      loading: "모델을 가져오는 중...",
      api: "API",
      search: "모델 검색",
      models: "모델",
      selected: "선택됨",
      select: "선택",
      copyId: "Model ID 복사",
      copyConfig: "설정 복사",
      download: "models.json 다운로드",
      copied: "복사됨",
      copyError: "복사하지 못했습니다. 아래 텍스트를 선택하여 복사하세요.",
      error: "모델을 가져오지 못했습니다. 다시 시도하거나 모델 카탈로그를 여세요.",
      empty: "일치하는 모델이 없습니다.",
      plaza: "모델 카탈로그",
      config: "Pi 설정",
      selectAll: "표시된 모든 모델 선택"
    }
  };
  const t = translations[locale] || translations.en;
  const protocols = {
    "openai-responses": {
      label: "Responses",
      endpoint: "openai-response",
      baseUrl: "https://bettertoken.ai/v1"
    },
    "openai-completions": {
      label: "Chat Completions",
      endpoint: "openai",
      baseUrl: "https://bettertoken.ai/v1"
    },
    "anthropic-messages": {
      label: "Anthropic Messages",
      endpoint: "anthropic",
      baseUrl: "https://bettertoken.ai"
    }
  };
  const [models, setModels] = useState(null);
  const [api, setApi] = useState("openai-completions");
  const [search, setSearch] = useState("");
  const [selected, setSelected] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [feedback, setFeedback] = useState("");
  const request = useRef(null);
  const protocolGroup = useId();
  useEffect(() => () => {
    request.current?.abort();
    request.current = null;
  }, []);
  const eligible = (models || []).filter(model => model.endpoints.includes(protocols[api].endpoint));
  const visible = eligible.filter(model => model.id.toLowerCase().includes(search.trim().toLowerCase()));
  const chosen = eligible.filter(model => selected.includes(model.id));
  const configuration = JSON.stringify({
    providers: {
      bettertoken: {
        baseUrl: protocols[api].baseUrl,
        api,
        apiKey: "$BETTERTOKEN_API_KEY",
        models: chosen.map(model => ({
          id: model.id
        }))
      }
    }
  }, null, 2);
  const loadModels = async () => {
    if (request.current) return;
    const controller = new AbortController();
    request.current = controller;
    setLoading(true);
    setError(false);
    setFeedback("");
    const timer = setTimeout(() => controller.abort(), 15000);
    try {
      const response = await fetch("https://bettertoken.ai/api/pricing", {
        credentials: "omit",
        cache: "no-store",
        headers: {
          Accept: "application/json"
        },
        signal: controller.signal
      });
      if (!response.ok) throw new Error("Catalog request failed");
      const body = await response.json();
      if (body.success !== true || !Array.isArray(body.data)) throw new Error("Invalid catalog");
      const catalog = new Map();
      for (const entry of body.data) {
        if (typeof entry?.model_name !== "string" || !entry.model_name.trim() || !Array.isArray(entry.supported_endpoint_types)) continue;
        if ((/^(?:nano-banana-|gpt-image-)/i).test(entry.model_name)) continue;
        if (entry.supported_endpoint_types.some(endpoint => ["image-generation", "openai-video", "embeddings", "jina-rerank"].includes(endpoint))) continue;
        const endpoints = entry.supported_endpoint_types.filter(endpoint => Object.values(protocols).some(protocol => protocol.endpoint === endpoint));
        if (!endpoints.length) continue;
        const previous = catalog.get(entry.model_name);
        catalog.set(entry.model_name, {
          id: entry.model_name,
          endpoints: Array.from(new Set([...previous?.endpoints || [], ...endpoints]))
        });
      }
      const next = Array.from(catalog.values()).sort((a, b) => a.id.localeCompare(b.id, "en"));
      if (request.current !== controller) return;
      setModels(next);
      setSelected(current => current.filter(id => next.some(model => model.id === id && model.endpoints.includes(protocols[api].endpoint))));
    } catch {
      if (request.current === controller) setError(true);
    } finally {
      clearTimeout(timer);
      if (request.current === controller) {
        request.current = null;
        setLoading(false);
      }
    }
  };
  const copy = async value => {
    try {
      await navigator.clipboard.writeText(value);
      setFeedback(t.copied);
    } catch {
      setFeedback(t.copyError);
    }
  };
  const download = () => {
    const url = URL.createObjectURL(new Blob([configuration + "\n"], {
      type: "application/json"
    }));
    const link = document.createElement("a");
    link.href = url;
    link.download = "models.json";
    link.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  };
  return <div className="bt-pi-models not-prose">
      <div className="bt-pi-models-toolbar">
        <fieldset className="bt-pi-models-protocols" disabled={loading}>
          <legend>{t.api}</legend>
          <div className="bt-pi-models-options">
            {Object.entries(protocols).map(([value, protocol]) => <label key={value}>
                <input type="radio" name={protocolGroup} value={value} checked={api === value} onChange={() => {
    setApi(value);
    setSelected([]);
    setFeedback("");
  }} />
                <span>{protocol.label}</span>
              </label>)}
          </div>
        </fieldset>
        <button type="button" className="bt-pi-models-load" disabled={loading} onClick={loadModels}>
          <Icon icon={models === null ? "list" : "rotate-right"} size={16} />
          <span>{loading ? t.loading : models === null ? t.get : t.refresh}</span>
        </button>
      </div>
      {error && <p role="alert" className="bt-pi-models-error">{t.error} <a href={plazaUrl}>{t.plaza}</a></p>}
      {models !== null && <div>
          <label className="bt-pi-models-field bt-pi-models-search">
            <span>{t.search}</span>
            <input type="search" value={search} onChange={event => setSearch(event.target.value)} />
          </label>
          <p className="bt-pi-models-count" aria-live="polite">{t.models}: {visible.length} / {eligible.length} · {t.selected}: {chosen.length}</p>
          <div className="bt-pi-models-list">
            <table>
              <thead>
                <tr>
                  <th className="bt-pi-models-check">
                    <input type="checkbox" aria-label={t.selectAll} disabled={!visible.length} checked={visible.length > 0 && visible.every(model => selected.includes(model.id))} onChange={event => setSelected(current => event.target.checked ? Array.from(new Set([...current, ...visible.map(model => model.id)])) : current.filter(id => !visible.some(model => model.id === id)))} />
                  </th>
                  <th>Model ID</th>
                  <th className="bt-pi-models-copy" aria-label={t.copyId}></th>
                </tr>
              </thead>
              <tbody>
                {visible.map(model => <tr key={model.id}>
                    <td className="bt-pi-models-check">
                      <input type="checkbox" aria-label={t.select + " " + model.id} checked={selected.includes(model.id)} onChange={event => setSelected(current => event.target.checked ? [...current, model.id] : current.filter(id => id !== model.id))} />
                    </td>
                    <td><code>{model.id}</code></td>
                    <td className="bt-pi-models-copy">
                      <button type="button" className="bt-pi-models-icon" title={t.copyId} aria-label={t.copyId + " " + model.id} onClick={() => copy(model.id)}><Icon icon="copy" size={16} /></button>
                    </td>
                  </tr>)}
              </tbody>
            </table>
            {!visible.length && <p className="bt-pi-models-empty">{t.empty}</p>}
          </div>
          {chosen.length > 0 && <div className="bt-pi-models-config">
              <div className="bt-pi-models-config-header">
                <span>{t.config}</span>
                <div className="bt-pi-models-actions">
                  <button type="button" className="bt-pi-models-icon" title={t.copyConfig} aria-label={t.copyConfig} onClick={() => copy(configuration)}><Icon icon="copy" size={16} /></button>
                  <button type="button" className="bt-pi-models-icon" title={t.download} aria-label={t.download} onClick={download}><Icon icon="download" size={16} /></button>
                </div>
              </div>
              <pre aria-label={t.config}><code>{configuration}</code></pre>
            </div>}
        </div>}
      <p role="status" className="bt-pi-models-feedback">{feedback}</p>
    </div>;
};

Pi Agent, terminal coding agent Pi है। यह `models.json` से compatible third-party API से जुड़ता है। इस गाइड में BetterToken का उदाहरण है: API Key, प्रोटोकॉल के अनुसार Base URL और Model ID सेट करें। दूसरे सेवा प्रदाता के लिए उसी सेवा का URL, credentials और मॉडल ID उपयोग करें।

## मुख्य सेटिंग्स

| फ़ील्ड | मान |
| - | - |
| API Key | `BETTERTOKEN_API_KEY` environment variable से BetterToken API Key |
| Base URL | OpenAI प्रोटोकॉल: `https://bettertoken.ai/v1`; Anthropic प्रोटोकॉल: `https://bettertoken.ai` |
| Model | <a href={"https://bettertoken.ai/pricing"}>model plaza</a> का सटीक Model ID |
| कॉन्फ़िगरेशन फ़ाइल | `~/.pi/agent/models.json` |

## आवश्यकताएं

* Node.js 22.19 या नया।
* <a href={"https://bettertoken.ai/register"}>BetterToken API Key बनाएं</a> और model plaza से tool calling वाला मॉडल चुनें।
* Native Windows में Pi के Bash tool के लिए [Git for Windows](https://git-scm.com/downloads/win) इंस्टॉल करें, या Pi को WSL में चलाएं।

## इंस्टॉल करें

Pi का मौजूदा आधिकारिक npm कमांड चलाएं:

```bash theme={null}
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
pi --version
```

## मैन्युअल सेटअप

### API Key सेट करें

Pi शुरू करने वाले terminal में `YOUR_API_KEY` को अपनी Key से बदलें:

<Tabs>
  <Tab title="macOS / Linux">
    ```bash theme={null}
    export BETTERTOKEN_API_KEY="YOUR_API_KEY"
    ```
  </Tab>

  <Tab title="Windows PowerShell">
    ```powershell theme={null}
    $env:BETTERTOKEN_API_KEY="YOUR_API_KEY"
    ```
  </Tab>
</Tabs>

### मॉडल प्राप्त करें और कॉन्फ़िगरेशन बनाएं

**मॉडल सूची प्राप्त करें** पर क्लिक करके API Key दर्ज किए बिना BetterToken का वर्तमान सार्वजनिक कैटलॉग प्राप्त करें। API और टूल कॉलिंग का समर्थन करने वाले मॉडल चुनें, फिर Model ID कॉपी करें या तैयार `models.json` डाउनलोड करें।

यदि `models.json` पहले से मौजूद है, तो पूरी फ़ाइल बदलने के बजाय बनाई गई `bettertoken` एंट्री को मौजूदा कॉन्फ़िगरेशन में मिलाएं। कॉन्फ़िगरेशन ऊपर सेट किए गए `$BETTERTOKEN_API_KEY` का उपयोग करता है; ज़रूरी अतिरिक्त मॉडल पैरामीटर वास्तविक क्षमताओं के अनुसार जोड़ें।

Pi कई प्रोटोकॉल का समर्थन करता है; मॉडल और सर्वर द्वारा समर्थित प्रोटोकॉल चुनें। इस सेटअप में Claude के लिए **Anthropic Messages**, सर्वर के समर्थन पर GPT के लिए **Responses**, और अन्य OpenAI-संगत मॉडलों के लिए **Chat Completions** की सलाह है। चयनकर्ता में Chat Completions डिफ़ॉल्ट है और सूची सार्वजनिक कैटलॉग में घोषित API के अनुसार फ़िल्टर होती है। Responses में मॉडल न दिखे तो पुष्टि किए गए Responses समर्थन वाले मॉडल के लिए नीचे का मैन्युअल उदाहरण उपयोग करें।

<PiModelPicker locale="hi" plazaUrl="https://bettertoken.ai/pricing" />

### URL और मॉडल जोड़ें

`~/.pi/agent/models.json` बनाएं। Windows में डिफ़ॉल्ट पथ `%USERPROFILE%\.pi\agent\models.json` है। फ़ाइल पहले से हो तो उसके मौजूदा `providers` object में `bettertoken` entry जोड़ें।

बनाए गए कॉन्फ़िगरेशन के विकल्प के रूप में, नीचे दिया गया Responses API उदाहरण मैन्युअल रूप से भरें। `YOUR_MODEL_ID` को model plaza की ID से बदलें; `$BETTERTOKEN_API_KEY` को environment variable reference के रूप में रखें:

```json theme={null}
{
  "providers": {
    "bettertoken": {
      "baseUrl": "https://bettertoken.ai/v1",
      "api": "openai-responses",
      "apiKey": "$BETTERTOKEN_API_KEY",
      "models": [{ "id": "YOUR_MODEL_ID" }]
    }
  }
}
```

दूसरी API के लिए `baseUrl` और `api` दोनों को सही जोड़ी में बदलें:

| API | `api` | `baseUrl` |
| - | - | - |
| Responses API | `openai-responses` | `https://bettertoken.ai/v1` |
| Chat Completions | `openai-completions` | `https://bettertoken.ai/v1` |
| Anthropic Messages | `anthropic-messages` | `https://bettertoken.ai` |

अपने मॉडल की tool calling का समर्थन करने वाली API चुनें। उदाहरण के लिए GPT-6.1 Sol, Responses उपयोग करता है। Base URL को तालिका के अनुसार रखें; Pi request path जोड़ता है।

### Pi शुरू करें

Project directory में अपना configured Model ID देकर चलाएं:

```bash theme={null}
pi --provider bettertoken --model YOUR_MODEL_ID
```

नए terminal में variable फिर सेट करें, या shell configuration में सहेजें।

## कनेक्शन सत्यापित करें

`pi --list-models` चलाकर देखें कि `bettertoken` और आपका मॉडल दिखाई दे रहे हैं। फिर Pi शुरू करके भेजें:

```text theme={null}
Reply with PI_OK only. Do not use tools.
```

`PI_OK` मिलने के बाद एक छोटा read-only कार्य देकर tool calling भी जांचें।

## मॉडल बदलें

`models` array में entries जोड़ें और Pi में `/model` चलाएं। यह `models.json` को दोबारा पढ़ता है। मॉडल चुनकर `Ctrl+S` दबाएं ताकि नई sessions के लिए default बन जाए। अलग प्रोटोकॉल के endpoints के लिए अलग local names और उनके अपने `api` तथा `baseUrl` रखें।

## सामान्य त्रुटियां

| समस्या | समाधान |
| - | - |
| मॉडल सूची में नहीं है | JSON, Model ID और environment variable जांचें; `/model` फिर खोलें। |
| `401` या `Unauthorized` | Variable में valid BetterToken API Key जांचें और Pi को उसी terminal से शुरू करें। |
| `404` या गलत URL | तालिका से `api` और `baseUrl` मिलाएं। हाथ से जोड़े गए `/responses`, `/chat/completions` या `/v1/messages` हटाएं। |
| Text आता है लेकिन tools विफल होते हैं | मॉडल और API का tool support जांचें; Responses मांगने वाले मॉडल के लिए `openai-responses` उपयोग करें। |
| Windows में Bash नहीं मिलता | Git for Windows इंस्टॉल कर terminal दोबारा खोलें, या Pi Windows गाइड के अनुसार `shellPath` सेट करें। |

## उन्नत सेटअप

Images, reasoning levels या बड़े context के लिए मॉडल की वास्तविक क्षमताओं के अनुसार `input`, `reasoning`, `contextWindow` और `maxTokens` सेट करें। [मॉडल चयन गाइड](/hi/faq/model-calling/model-selection-guide) देखें।

## तकनीकी विवरण

`providers` और `--provider`, Pi client के configuration fields हैं; `bettertoken` इस उदाहरण का local name है। Pi पहले `--api-key`, फिर `auth.json` में saved credentials और उसके बाद `models.json` का `apiKey` उपयोग करता है। उसी नाम के पुराने credentials हों तो Pi में `/logout` से संबंधित entry हटाकर फिर कनेक्ट करें।

### Pi के आधिकारिक संदर्भ

* [इंस्टॉलेशन और quickstart](https://pi.dev/docs/latest/quickstart)
* [Custom URL और मॉडल](https://pi.dev/docs/latest/models#configure-a-compatible-endpoint)
* [Command-line संदर्भ](https://pi.dev/docs/latest/cli)
* [Windows सेटअप](https://pi.dev/docs/latest/windows)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.