Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ See [SPONSORS.md](./SPONSORS.md).
<td width="180"><a href="https://www.packyapi.com/register?aff=k5KT"><img src="assets/sponsors/packycode.png" alt="PackyCode" width="150"></a></td>
<td>Thanks to <a href="https://www.packyapi.com/register?aff=k5KT">PackyCode</a> for sponsoring this project! PackyCode is a stable, high-performance API relay provider, offering relay services for Claude Code, Codex, Gemini, and more. With automatic failover, smart routing, and unlimited concurrency, it turns AI into a real productivity tool. <a href="https://www.packyapi.com/register?aff=k5KT">Register via this link</a> and get started! Pick <code>PackyCode</code> in the Add provider picker or run <code>ocx provider add packycode</code>.<br><sub>PackyCode 是一家稳定、高效的 API 中转服务商,提供 Claude Code、Codex、Gemini 等多种中转服务。具备自动故障转移、智能路由和无限并发等多种功能,让 AI 编程成为真正的生产力工具。<a href="https://www.packyapi.com/register?aff=k5KT">点此链接注册</a>,立即开始使用!</sub></td>
</tr>
<tr>
<td width="180"><a href="https://tokenlab.sh/r/OPENCODEX"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/sponsors/tokenlab-dark.png"><img src="assets/sponsors/tokenlab-light.png" alt="TokenLab" width="150"></picture></a></td>
<td>Thanks to <a href="https://tokenlab.sh/r/OPENCODEX">TokenLab</a> for sponsoring this project! TokenLab gives coding agents one API key for leading models, supporting OpenAI Responses and Chat Completions, Anthropic Messages, and Gemini's native API formats, with streaming and tool calling. It also provides an MCP server and agent Skills for easy integration. Choose your delivery mode and pay as you go. Pick <code>TokenLab</code> in the Add provider picker or run <code>ocx provider add tokenlab</code>.<br><sub>TokenLab 为编程智能体提供统一的多模型 API,一枚 API Key 即可接入主流模型,支持 OpenAI Responses、Chat Completions、Anthropic Messages 和 Gemini 原生 API 格式,以及流式输出和工具调用。同时提供 MCP 服务器和 Agent Skills,方便接入现有工作流;交付模式可选,按量付费。</sub></td>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</tr>
</tbody>
</table>

Expand Down
9 changes: 4 additions & 5 deletions SPONSORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ sponsor receives:
policy. A second-language blurb (for example Chinese) may run alongside the English one.
- A built-in provider preset (`ocx provider add <id>`) shipped in a public npm release,
listed near the top of the provider picker in the dashboard and CLI and marked as a sponsor
there. (The registry field and picker ordering that back this land with the first sponsor
preset; today the picker follows registry order.)
there. The dashboard picker, `ocx init` and `ocx provider presets` list sponsor rows Main
before Standard, then alphabetically by label, an order no sponsor can buy.
- A detailed entry on the [providers page](https://opencodex.me/guides/providers/) of the docs
site.
- Maintenance: if a release breaks the preset or its adapter, the maintainer fixes it; issues
Expand All @@ -66,9 +66,8 @@ and the placements themselves:
The README says nothing else about sponsorship; tiers, pricing, and contact channels live only on
this page.

The translated READMEs under [`readme/`](./readme) carry one linking line right after their
own quick-start block instead of duplicating the section, so a sponsor change is one edit in
English.
The translated READMEs under [`readme/`](./readme) carry the same sponsor section, with each
row's thanks line and blurb translated, so a sponsor change updates every README together.

## Pricing

Expand Down
Binary file added assets/sponsors/tokenlab-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sponsors/tokenlab-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions desktop/src-tauri/src/provider_icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const ALIASES: &[(&str, &str)] = &[
("orcarouter", "orcarouter.svg"),
("orcarouter-oauth", "orcarouter.svg"),
("packycode", "packycode.svg"),
("tokenlab", "tokenlab.svg"),
("parallel", "parallel.svg"),
("sambanova", "sambanova.svg"),
("scaleway", "scaleway.svg"),
Expand Down Expand Up @@ -131,6 +132,7 @@ fn paint(file: &str) -> &'static str {
| "packycode.svg"
| "siliconflow.svg"
| "synthetic.svg"
| "tokenlab.svg"
| "vercel-ai-gateway-color.svg"
| "zenmux.svg" => "mask",
"baseten.svg" | "kilo.svg" | "sambanova.svg" | "venice.svg" | "zai.svg" => "plate",
Expand Down Expand Up @@ -200,6 +202,7 @@ fn svg(file: &str) -> Option<&'static str> {
"stepfun-color.svg" => svg!("stepfun-color.svg"),
"synthetic.svg" => svg!("synthetic.svg"),
"together.svg" => svg!("together.svg"),
"tokenlab.svg" => svg!("tokenlab.svg"),
"umans.svg" => svg!("umans.svg"),
"venice.svg" => svg!("venice.svg"),
"vercel-ai-gateway-color.svg" => svg!("vercel-ai-gateway-color.svg"),
Expand Down
13 changes: 13 additions & 0 deletions devlog/_plan/260929_tokenlab_sponsor/000_roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# TokenLab — preset merge and third Standard sponsor

TokenLab (TOKENLAB AI INC.) signed up as a Standard sponsor on 2026-09-29 (DocuSign envelope sent
21:08 KST; USD 1,200 / 3 months, term starts at the npm release that ships the preset). Two units:

| Doc | Work phase | Outcome |
|-----|-----------|---------|
| [010](./010_merge_6221.md) | wp1 | #6221 (fork `hedging8563`, ordinary API-key preset) merged into `dev` on green exact-head CI |
| [020](./020_sponsor_pr.md) | wp2 | Separate maintainer PR: sponsor field, dashboard sponsor surface, README row #3, docs, assets |

The sponsor PR stays unmerged for owner review. The Responses-first proposal in TokenLab's asset pack
(`integration-notes.md`) is out of scope for both units: it changes the upstream protocol and needs
its own evidence and PR.
37 changes: 37 additions & 0 deletions devlog/_plan/260929_tokenlab_sponsor/010_merge_6221.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 010 — Merge #6221 (TokenLab API-key preset)

## State at plan time

- Head repo `hedging8563/opencodex`, branch `codex/tokenlab-provider`, draft, `maintainerCanModify`.
- Branch updated onto `dev` with `gh pr update-branch` → head `6a9e571202`.
- Fork runs `Cross-platform CI` (36566988054) and `React Doctor` (36566988033) approved by the maintainer.
- Admission gap recorded in the PR body: routing/resale authorization evidence. The owner's
sponsorship agreement with the operator (§2.2: sourcing and delivery mode are TokenLab's
responsibility, not audited or guaranteed by opencodex) is the maintainer decision that closes it;
no upstream endorsement claim is added.

## Steps

0. Head moved to `fb565b7c48`: the `dev` union failed `docs-provider-preset-counts` (16 assertions,
localized 99/82 counts). Recounted the anchored lines; the test passes locally 18/18.
1. Wait for every required check on `6a9e571202` to complete successfully. A red, skipped or
older-head result blocks merge; fix forward only if the failure is in this diff.
2. Mark the PR ready (`gh pr ready 6221`).
3. Post a maintainer-integration comment: owner instruction, exact head SHA, check list, and the
admission decision above.
4. Squash-merge with the admin bypass (`gh pr merge 6221 --squash --admin`); the squash keeps the
PR author as commit author.
5. Verify `dev` contains the squash commit and `src/providers/registry/entries-extended.ts` carries
the `tokenlab` entry.

## Not in this unit

Sponsor field, README, logos — see 020.

## Outcome (2026-09-29)

Merged as `f6cddd7d69` at 12:51 UTC from head `fb565b7c48`: 24 checks passed, 7 skipped by path
conditions (Cross-platform CI 36567400620, React Doctor). CodeRabbit's assertive review found nothing
actionable. The readiness gate re-drafted the PR on `ready`; the maintainer ticked the last two boxes
after that review and recorded it on the PR. A full local `bun run test` cannot run from a worktree
under `~/.codex`: the harness refuses to delete temporary directories inside the real Codex home.
63 changes: 63 additions & 0 deletions devlog/_plan/260929_tokenlab_sponsor/020_sponsor_pr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 020 — TokenLab third Standard sponsor PR

Branch `codex/tokenlab-sponsor`, started on the #6221 head and rebased onto `dev` after 010 lands.
Pattern: #3914 (OrcaRouter, mechanism) and #3915 (PackyCode, second sponsor). Assets come from
TokenLab's corrected pack (`TokenLab-OpenCodex-assets-corrected.zip`), artwork unchanged.

## Diff

- `src/providers/registry/entries-extended.ts` — the `tokenlab` entry gains
`sponsor: { tier: "standard", url: "https://tokenlab.sh/?utm_source=opencodex&utm_medium=readme" }`
with a comment naming SPONSORS.md and the signing date. No routing, default or discovery change.
- `assets/sponsors/tokenlab-light.png`, `assets/sponsors/tokenlab-dark.png` — the pack's 500×125
lockups, unchanged (`-light` = for light page backgrounds, as in the pack). Listed in
`package.json` `files` beside the OrcaRouter/PackyCode logos.
- `README.md` — third row of the `sponsors:standard` table, in signing order after PackyCode.
Logo in `<picture>` with a `prefers-color-scheme: dark` source so the dark lockup shows in
GitHub dark mode; the `<img>` fallback is the light lockup (npm). Text: "Thanks to TokenLab for
sponsoring this project!", the sponsor's English blurb verbatim, then the picker /
`ocx provider add tokenlab` line.
- `readme/README.{ko,ja,zh-CN,zh-TW,ru,fr,tr}.md` — the same row, translated like the existing
rows, image paths `../assets/...`. Keep the README drift gate green.
- `gui/public/provider-icons/tokenlab.svg` — the pack's symbol mark; `gui/src/provider-icons.ts`
maps `tokenlab` to it, sets the display name, and applies dark-mode treatment like other
monochrome marks.
- `gui/src/components/provider-workspace/ProviderSponsor.tsx` — replace the hardcoded
OrcaRouter/PackyCode ternaries with a small brand table so a sponsor is one row; add TokenLab.
i18n keys `pws.sponsor.tokenlabTitle` / `pws.sponsor.tokenlabDescription` in every
`gui/src/i18n/*.ts` locale (the closed catalog must stay exhaustive).
- `docs-site/src/content/docs/guides/providers.md` — sponsor paragraph after PackyCode, and the
base-URL table row if #6221 has not already added it. Translated locales must not contradict it.
- Tests — `tests/providers/sponsor-presets.test.ts` stays generic; the GUI sponsor overview test
covers the TokenLab card. Respect the file-size ratchet: move rather than grow capped files.

## Verification

## Audit folds (reviewer, NEAR-PASS)

- `desktop/src-tauri/src/provider_icons.rs`: `("tokenlab", "tokenlab.svg")` in `ALIASES`, the same paint
arm as `MASKED_PROVIDER_ICONS`, and `svg!("tokenlab.svg")` (`gui/tests/provider-icons-native.test.ts`).
- `readme/i18n-manifest.json`: refresh all seven `sourceSha256` values to the new LF-normalized README hash
(`docs-readme-translation-parity.test.ts`).
- `<picture>` is gate-compatible: only `src=`/`href=` are asset-tracked, so each locale's `<img src>` must be
`../assets/sponsors/tokenlab-light.png`; include the dark `<source>` too.
- Icon provenance row in `gui/public/provider-icons/README.md`; `structure/dashboard-and-usage.md` owns the
`ProviderSponsor` description — update it for the brand table.
- Docs: extend the existing TokenLab section in `guides/providers.md` with the sponsor link; do not add a
second paragraph.
- `SPONSORS.md`: fix the stale "picker follows registry order" and "translated READMEs carry one linking
line" sentences.
- Branch: after #6221 squashes, move only the sponsor commits onto `dev`
(`git rebase --onto origin/dev fb565b7c48`).

## Verification (commands)

Focused: sponsor-presets, provider-registry-parity, tokenlab-provider, README drift/translation
gates, GUI sponsor tests, `bun run typecheck`, `bun run lint:gui`, `bun run privacy:scan`,
`bun run structure:check`, `bun run build:gui`. Then `bun run test` or the documented focused
exception. Screenshot of the dashboard sponsor card and picker uploaded to the `pr-assets` branch
and linked by SHA in the PR description, never committed to the PR branch.

## Out of scope

Responses-first adapter and the `X-TokenLab-Delivery-Policy` header (pack `integration-notes.md`).
7 changes: 5 additions & 2 deletions docs-site/src/content/docs/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,9 @@ region-pinned EU routes, is at [opper.ai/models](https://opper.ai/models). Opper
| Cloudflare AI Gateway | `https://gateway.ai.cloudflare.com/v1/{account-id}/{gateway}/anthropic` |
| …and more | opencode zen, Vercel AI Gateway, Venice, NanoGPT, Synthetic, Qianfan, Alibaba, Parallel, ZenMux, LiteLLM |

**TokenLab** is an OpenAI-compatible API gateway operated by TOKENLAB AI INC.
**TokenLab** ([sponsor](https://github.com/lidge-jun/opencodex/blob/main/SPONSORS.md)) is an
OpenAI-compatible API gateway at [tokenlab.sh](https://tokenlab.sh/r/OPENCODEX),
operated by TOKENLAB AI INC.
Create a workspace [API key](https://tokenlab.sh/dashboard/api?tab=keys), then run
`ocx provider add tokenlab` or select **TokenLab** in the dashboard's **Add provider** picker.
The preset uses [Chat Completions](https://docs.tokenlab.sh/quickstart) and discovers models at
Expand All @@ -566,7 +568,8 @@ policy. Use a valid key with a funded workspace for inference. `gpt-5.6-terra` i
default; choose another discovered model if your key does not allow it. The provider and model
prefixes remain separate: `tokenlab/gpt-5.6-terra` sends `gpt-5.6-terra` upstream.
TokenLab's [terms](https://tokenlab.sh/tos) and [privacy policy](https://tokenlab.sh/privacy-policy)
apply to requests sent to this service.
apply to requests sent to this service. The preset pins the row near the top of the Add provider
picker and marks it as a sponsor, and nothing else about routing or defaults changes.

The MiniMax and MiniMax (CN) provider cards can also show Coding Plan quota when the configured
key has an active plan. The dashboard reads the plan's 5-hour window and, when present, weekly
Expand Down
9 changes: 9 additions & 0 deletions gui/public/provider-icons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,12 @@ committing it.
gradient is the brand, so it must never be masked.

- `factory-droid.svg` — Factory Docs favicon, fetched 2026-09-28 from `https://docs.factory.ai/favicon.svg`; unmodified first-party asset for Factory Droid.

## TokenLab (2026-09-29)

- `tokenlab.svg` — TokenLab's "Specimen Split" symbol, `logos/tokenlab-symbol.svg` from the
sponsor asset pack TokenLab supplied for its Standard sponsorship (`SPONSORS.md`), committed
byte for byte (416 bytes, MD5 `fcb8c1325a34ed52b1dc89eabf08a0e6`), `<title>`/`<desc>` included
since they do not affect rendering. `viewBox="0 0 48 48"`, one `#151714` ink, so it is
**masked** like `packycode.svg`: as an image it vanishes on the dark tile. The pack's reverse
symbol (`#F5F5F1`) is the same geometry and is not needed once the mark follows the theme.
8 changes: 8 additions & 0 deletions gui/public/provider-icons/tokenlab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 25 additions & 9 deletions gui/src/components/provider-workspace/ProviderSponsor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import { useT } from "../../i18n/shared";
import { useT, type TKey } from "../../i18n/shared";
import { IconExternal } from "../../icons";
import type { WorkspaceItem } from "../../provider-workspace/catalog";
import { matchingWorkspacePreset, type CatalogPreset } from "../provider-catalog/provider-presets";

type SponsorBrand = { name: string; title: TKey; description: TKey };

const ORCAROUTER: SponsorBrand = {
name: "OrcaRouter", title: "pws.sponsor.orcaTitle", description: "pws.sponsor.orcaDescription",
};

/**
* One row per sponsor preset id. The registry `sponsor` field decides whether a card shows;
* this table only supplies the brand name and localized copy, so a preset flagged as a sponsor
* without a row here still renders nothing rather than borrowing another sponsor's words.
*/
const SPONSOR_BRANDS: Readonly<Record<string, SponsorBrand>> = {
orcarouter: ORCAROUTER,
"orcarouter-oauth": ORCAROUTER,
packycode: { name: "PackyCode", title: "pws.sponsor.packyTitle", description: "pws.sponsor.packyDescription" },
tokenlab: { name: "TokenLab", title: "pws.sponsor.tokenlabTitle", description: "pws.sponsor.tokenlabDescription" },
};

function webLink(value?: string): string | undefined {
if (!value) return undefined;
try {
Expand All @@ -16,25 +34,23 @@ function webLink(value?: string): string | undefined {
export default function ProviderSponsor({ item, preset }: { item: WorkspaceItem; preset?: CatalogPreset }) {
const t = useT();
if (!preset?.sponsor || !matchingWorkspacePreset(item, [preset])) return null;
const brand = preset.id === "orcarouter" || preset.id === "orcarouter-oauth"
? "OrcaRouter" : preset.id === "packycode" ? "PackyCode" : undefined;
const brand = Object.hasOwn(SPONSOR_BRANDS, preset.id) ? SPONSOR_BRANDS[preset.id] : undefined;
if (!brand) return null;
const orca = brand === "OrcaRouter";
const visit = webLink(preset.sponsorUrl);
const dashboard = webLink(preset.dashboardUrl);

return <section className="pws-sponsor" aria-label={`${brand} · ${t("modal.badge.sponsor")}`}>
return <section className="pws-sponsor" aria-label={`${brand.name} · ${t("modal.badge.sponsor")}`}>
<div className="pws-sponsor-copy">
<div className="pws-sponsor-byline">
<span>{brand}</span>
<span>{brand.name}</span>
<span className="pws-sponsor-badge">{t("modal.badge.sponsor")}</span>
</div>
<h3>{t(orca ? "pws.sponsor.orcaTitle" : "pws.sponsor.packyTitle")}</h3>
<p>{t(orca ? "pws.sponsor.orcaDescription" : "pws.sponsor.packyDescription")}</p>
<h3>{t(brand.title)}</h3>
<p>{t(brand.description)}</p>
</div>
{(visit || dashboard) && <div className="pws-sponsor-actions">
{visit && <a className="btn btn-primary" href={visit} target="_blank" rel="noopener noreferrer">
{t("pws.sponsor.visit", { provider: brand })}<IconExternal width={14} height={14} aria-hidden="true" />
{t("pws.sponsor.visit", { provider: brand.name })}<IconExternal width={14} height={14} aria-hidden="true" />
</a>}
{dashboard && dashboard !== visit && <a className="pws-sponsor-console" href={dashboard} target="_blank" rel="noopener noreferrer">
{t("pws.sponsor.console")}<IconExternal width={13} height={13} aria-hidden="true" />
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2456,6 +2456,8 @@ export const de: Record<TKey, string> = {
"pws.sponsor.orcaDescription": "Ein OpenAI-kompatibles Gateway mit adaptivem Routing und automatischem Failover.",
"pws.sponsor.packyTitle": "Claude Code, Codex und Gemini an einem Ort",
"pws.sponsor.packyDescription": "Ein API-Relay für Ihre KI-Programmierwerkzeuge. Starten Sie mit einem Token der Codex-Gruppe.",
"pws.sponsor.tokenlabTitle": "Ein API-Schlüssel für führende Modelle",
"pws.sponsor.tokenlabDescription": "Responses, Chat Completions, Streaming und Tool-Aufrufe für Coding-Agenten, mit wählbarem Bereitstellungsmodus und nutzungsbasierter Abrechnung.",
"pws.sponsor.visit": "{provider} entdecken",
"pws.sponsor.console": "Konsole öffnen",
"modal.invalidPreset": "Diese integrierte Anbietervorlage ist unvollständig. Starten Sie den Proxy neu und versuchen Sie es erneut.",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,8 @@ export const en = {
"pws.sponsor.orcaDescription": "An OpenAI-compatible gateway with adaptive routing and automatic failover.",
"pws.sponsor.packyTitle": "Claude Code, Codex and Gemini in one place",
"pws.sponsor.packyDescription": "An API relay for your AI coding tools. Start with a Codex-group token.",
"pws.sponsor.tokenlabTitle": "One API key for leading models",
"pws.sponsor.tokenlabDescription": "Responses, Chat Completions, streaming and tool calling for coding agents, with your choice of delivery mode and pay-as-you-go billing.",
"pws.sponsor.visit": "Explore {provider}",
"pws.sponsor.console": "Open console",
"modal.invalidPreset": "This built-in provider preset is incomplete. Restart the proxy and try again.",
Expand Down
Loading
Loading