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
32 changes: 32 additions & 0 deletions docs-site/src/content/docs/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,38 @@ Create a key in [Novita's key manager](https://novita.ai/settings/key-management
> hosts and schemas and are not routed by this preset.
> Live discovery for this preset is capped at a 1 MiB response and 256 raw model rows.

### Official CodeBuddy Code CLI (Global & CN)

OpenCodex provides official adapter support for Tencent Cloud's CodeBuddy Code CLI via the `codebuddy` (Global) and `codebuddy-cn` (China) presets.

```json
{
"providers": {
"codebuddy": {
"adapter": "codebuddy",
"baseUrl": "https://www.codebuddy.ai",
"apiKey": "${CODEBUDDY_API_KEY}"
},
"codebuddy-cn": {
"adapter": "codebuddy",
"baseUrl": "https://www.codebuddy.cn",
"apiKey": "${CODEBUDDY_CN_API_KEY}"
}
}
}
```

- **Prerequisites:** Install the official CodeBuddy CLI globally:
```bash
npm install -g @tencent-ai/codebuddy-code
```
- **Authentication:** Obtain your official API key from the vendor console:
- Global: [CodeBuddy Global API Keys](https://www.codebuddy.ai/profile/keys)
- CN: [CodeBuddy CN API Keys](https://copilot.tencent.com/profile/keys)
- **Region Isolation:** `codebuddy` and `codebuddy-cn` use separate canonical endpoints (`https://www.codebuddy.ai` and `https://www.codebuddy.cn`) and isolated child environments (`CODEBUDDY_INTERNET_ENVIRONMENT=public` vs `internal`). Credentials are strictly region-scoped and never exchanged across environments. Overriding the canonical base URL fails closed.
- **Tool Ownership:** In v1, the CLI is spawned with `--tools ""` and `--strict-mcp-config`, ensuring Codex maintains exclusive tool ownership. The provider operates in text and reasoning mode; client tool execution is not delegated to the vendor CLI.
- **Entitlements and Billing:** The provider uses the same vendor-documented CodeBuddy account/CLI authentication surface. Availability and billing of free, promotional, trial, or subscription credits remain determined by the user's CodeBuddy account entitlement.

### A6API credit quota

A custom `openai-chat` provider using `authMode: "key"` and the canonical
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Providers can expose a built-in shorthand, such as `agy` for `google-antigravity

| Field | Type | Meaning |
| --- | --- | --- |
| `adapter` | `string` | One of `openai-chat`, `openai-responses`, `anthropic`, `google`, `kiro`, `cursor`, `ollama-native`, `azure-openai` (or alias `azure`). |
| `adapter` | `string` | One of `openai-chat`, `openai-responses`, `anthropic`, `google`, `kiro`, `cursor`, `ollama-native`, `azure-openai` (or alias `azure`), `codebuddy`. |
| `baseUrl` | `string` | Upstream API base URL. Most built-in fixed endpoints ignore a mismatch; collision-safe key presets preserve an older same-named custom destination. |
| `requestPacing?` | `{ enabled, requestsPerMinute?, minIntervalMs?, models? }` | Optional client-side outbound request-start pacing, separate from upstream usage, billing, and rate-limit indicators. RPM is converted to an even interval; `minIntervalMs` may impose a longer interval. Provider limits apply across all models, while `models` entries use exact upstream model IDs (for example `nvidia/llama-3.1-nemotron-ultra-253b-v1`) and can only add delay. Queue waits do not consume the upstream response-header timeout. HTTP, Responses WebSocket, and explicit adapter `fetchResponse`/`runTurn` dispatches are covered. |
| `upstreamHttpVersion?` | `"auto" \| "http1.1" \| "h1" \| "http2" \| "h2"` | Pin the HTTP version used for upstream requests to this provider. Defaults to `auto`, which lets Bun negotiate. An explicit pin requires an HTTPS target and fails locally when it cannot be honored. Set `http1.1` when a provider's HTTP/2 SSE stream stalls instead of delivering events — the symptom is a long-running streaming request that produces nothing and eventually times out. For Cursor, `http1.1`/`h1` selects its `RunSSE` + `BidiAppend` compatibility transport for inference and also pins live model discovery. Management `POST`/`PATCH` accept `null` to clear it back to `auto`. |
Expand Down
72 changes: 37 additions & 35 deletions scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,11 @@
"artifacts-prune.test.ts": "images",
"artifacts-ssrf.test.ts": "images",
"aside-client.test.ts": "providers",
"aside-profiles-routes.test.ts": "server",
"aside-profiles.test.ts": "clients",
"aside-profile-paths.test.ts": "clients",
"aside-profile-identity.test.ts": "clients",
"aside-profile-paths.test.ts": "clients",
"aside-profile-sync-owner.test.ts": "clients",
"aside-profiles-routes.test.ts": "server",
"aside-profiles.test.ts": "clients",
"assert-mergeable-review.test.ts": "ci-workflows",
"auto-compact-budget.test.ts": "providers",
"autostart-health.test.ts": "service",
Expand Down Expand Up @@ -336,6 +336,7 @@
"cli-help.test.ts": "cli",
"cli-json-contract.test.ts": "cli",
"cli-management-auth.test.ts": "cli",
"cli-models-price.test.ts": "cli",
"cli-models-reasoning.test.ts": "cli",
"cli-models-runtime-dispatch.test.ts": "cli",
"cli-models.test.ts": "cli",
Expand All @@ -357,17 +358,19 @@
"client-config-export.test.ts": "config",
"client-config-new-clients.test.ts": "config",
"client-connect.test.ts": "clients",
"client-injection-guard.test.ts": "codex-integration",
"client-lifecycle-lock.test.ts": "clients",
"client-export-modality-enum.test.ts": "clients",
"client-fingerprint.test.ts": "clients",
"client-hub-relay.test.ts": "clients",
"client-injection-guard.test.ts": "codex-integration",
"client-lifecycle-lock.test.ts": "clients",
"client-machine-listener.test.ts": "clients",
"cline-pass-deepseek-v4-tool-replay.test.ts": "providers",
"cline-pass-provider.test.ts": "providers",
"cline-pass-reasoning-efforts.test.ts": "providers",
"cline-provider.test.ts": "providers",
"closed-pr-branch-cleanup.test.ts": "ci-workflows",
"codebuddy-adapter.test.ts": "providers",
"codebuddy-protocol.test.ts": "providers",
"codex-account-delete-atomicity.test.ts": "codex-integration",
"codex-account-label.test.ts": "codex-integration",
"codex-account-mode-state.test.ts": "gui",
Expand Down Expand Up @@ -455,9 +458,9 @@
"codex-prompt-lock.test.ts": "codex-integration",
"codex-prompt-route.test.ts": "codex-integration",
"codex-prompt-text-probe.test.ts": "codex-integration",
"codex-quota-parser-parity.test.ts": "codex-integration",
"codex-quota-auto-refresh.test.ts": "codex-integration",
"codex-quota-auto-refresh-main-admission.test.ts": "codex-integration",
"codex-quota-auto-refresh.test.ts": "codex-integration",
"codex-quota-parser-parity.test.ts": "codex-integration",
"codex-quota-prime.test.ts": "codex-integration",
"codex-quota-rejection.test.ts": "codex-integration",
"codex-refresh.test.ts": "codex-integration",
Expand Down Expand Up @@ -597,9 +600,9 @@
"desktop-3p-guard.test.ts": "clients",
"desktop-3p-removal.test.ts": "clients",
"desktop-3p.test.ts": "clients",
"desktop-remote-store.test.ts": "clients",
"desktop-app-restart.test.ts": "clients",
"desktop-profile.test.ts": "clients",
"desktop-remote-store.test.ts": "clients",
"destination-policy-resolved.test.ts": "routing",
"digitalocean-scaleway-provider.test.ts": "providers",
"docs-429-failover-claims.test.ts": "ci-workflows",
Expand All @@ -618,12 +621,12 @@
"empty-completion-guard.test.ts": "responses",
"empty-completion-hardening.test.ts": "responses",
"empty-tool-output-annotation.test.ts": "adapters",
"exec-tool-result-normalize.test.ts": "adapters",
"ensure-desired-integrations-race.test.ts": "cli",
"error-fidelity.test.ts": "server",
"errors-adapter-failure.test.ts": "server",
"eventstream-decoder.test.ts": "responses",
"exa-web-search.test.ts": "providers",
"exec-tool-result-normalize.test.ts": "adapters",
"expand-user-path.test.ts": "config",
"fast-row-ingress.test.ts": "providers",
"fast-row-listing.test.ts": "codex-integration",
Expand Down Expand Up @@ -690,6 +693,8 @@
"identity-neutralize.test.ts": "adapters",
"init-backup-cleanup.test.ts": "service",
"init-eof.test.ts": "service",
"initial-model-selection.test.ts": "providers",
"initial-selection-write-fence.test.ts": "providers",
"injection-model-api.test.ts": "codex-integration",
"input-admission.test.ts": "server",
"install-scripts.test.ts": "ci-workflows",
Expand Down Expand Up @@ -789,13 +794,13 @@
"loopback-listener-admission.test.ts": "server",
"loopback-listener-integration.test.ts": "server",
"macos-serial-lanes.test.ts": "ci-workflows",
"management-api-logs-metrics.test.ts": "server",
"main-account-hard-lock-auth.test.ts": "codex-integration",
"main-account-hard-lock-policy.test.ts": "codex-integration",
"main-account-hard-lock-recovery.test.ts": "codex-integration",
"main-quota-evidence-validation.test.ts": "codex-integration",
"main-quota-provenance.test.ts": "codex-integration",
"main-quota-window-observation.test.ts": "codex-integration",
"management-api-logs-metrics.test.ts": "server",
"management-client-config-route.test.ts": "server",
"management-integration-journal-delete.test.ts": "server",
"management-integration-routes.test.ts": "server",
Expand All @@ -812,11 +817,15 @@
"minimax-reasoning-split.test.ts": "providers",
"model-cache-generation-tombstone.test.ts": "codex-integration",
"model-cache.test.ts": "codex-integration",
"model-costs-management-api.test.ts": "server",
"model-discovery-management-api.test.ts": "server",
"model-display-names-management-api.test.ts": "codex-integration",
"model-metadata-sync.test.ts": "codex-integration",
"model-pinned-effort-config.test.ts": "config",
"model-pinned-effort.test.ts": "codex-integration",
"model-presets.test.ts": "providers",
"model-rename-migration.test.ts": "providers",
"model-selection-guidance.test.ts": "cli",
"model-visibility-management-api.test.ts": "codex-integration",
"models-page-groups.test.ts": "gui",
"models-workspace-tabs.test.ts": "gui",
Expand Down Expand Up @@ -850,9 +859,6 @@
"native-profile-startup.test.ts": "codex-integration",
"native-profile-store.test.ts": "codex-integration",
"new-model-policy.test.ts": "providers",
"initial-model-selection.test.ts": "providers",
"initial-selection-write-fence.test.ts": "providers",
"model-selection-guidance.test.ts": "cli",
"nous-oauth-live.test.ts": "providers",
"nous-oauth.test.ts": "providers",
"novita-provider.test.ts": "providers",
Expand Down Expand Up @@ -923,9 +929,9 @@
"opencode-go-session-header.test.ts": "providers",
"opencode-zen-deepseek-reasoning.test.ts": "providers",
"opencode-zen-rate-limit.test.ts": "providers",
"orcarouter-provider.test.ts": "providers",
"openrouter-provider-routing.test.ts": "providers",
"optional-shutdown-hooks.test.ts": "lib",
"orcarouter-provider.test.ts": "providers",
"outbound-body-guard.test.ts": "server",
"owned-service-home.test.ts": "server",
"package-tree-integrity.test.ts": "ci-workflows",
Expand Down Expand Up @@ -991,17 +997,6 @@
"quota-scoring.test.ts": "usage",
"qwen-cloud-endpoints.test.ts": "gui",
"qwen38-preserve-reasoning.test.ts": "providers",
"reserve-availability.test.ts": "codex-integration",
"reserve-auth-context.test.ts": "codex-integration",
"reserve-catalog.test.ts": "codex-integration",
"reserve-catalog-lifecycle.test.ts": "codex-integration",
"reserve-claude-policy.test.ts": "server",
"reserve-dispatch.test.ts": "codex-integration",
"reserve-dispatch-ws.test.ts": "responses",
"reserve-helper-boundary.test.ts": "codex-integration",
"reserve-ingress.test.ts": "server",
"reserve-passive-revocation.test.ts": "codex-integration",
"reserve-quota-scope.test.ts": "codex-integration",
"rate-limit-reset-credits.test.ts": "gui",
"rate-limit-retry.test.ts": "providers",
"raycast-client.test.ts": "clients",
Expand All @@ -1016,7 +1011,6 @@
"release-helper.test.ts": "ci-workflows",
"release-notes.test.ts": "ci-workflows",
"release-version-line.test.ts": "ci-workflows",
"version-line.test.ts": "ci-workflows",
"remote-catalog.test.ts": "clients",
"remove-tree-helper.test.ts": "lib",
"repo-hygiene.test.ts": "ci-workflows",
Expand All @@ -1027,20 +1021,31 @@
"request-log-estimate-cap.test.ts": "usage",
"request-log.test.ts": "usage",
"request-pacing.test.ts": "usage",
"reserve-auth-context.test.ts": "codex-integration",
"reserve-availability.test.ts": "codex-integration",
"reserve-catalog-lifecycle.test.ts": "codex-integration",
"reserve-catalog.test.ts": "codex-integration",
"reserve-claude-policy.test.ts": "server",
"reserve-dispatch-ws.test.ts": "responses",
"reserve-dispatch.test.ts": "codex-integration",
"reserve-helper-boundary.test.ts": "codex-integration",
"reserve-ingress.test.ts": "server",
"reserve-passive-revocation.test.ts": "codex-integration",
"reserve-quota-scope.test.ts": "codex-integration",
"response-model-identity.test.ts": "server",
"responses-account-label.test.ts": "responses",
"responses-compaction-routing.test.ts": "responses",
"responses-compaction.test.ts": "responses",
"responses-context-overflow.test.ts": "responses",
"responses-custom-tool-guidance.test.ts": "responses",
"responses-custom-tool-repair.test.ts": "responses",
"responses-forward-incomplete-quota.test.ts": "responses",
"responses-function-tool-repair.test.ts": "responses",
"responses-fetch-helpers-boundary.test.ts": "responses",
"responses-field-backfill.test.ts": "responses",
"responses-forward-dangling-call.test.ts": "responses",
"responses-forward-incomplete-quota.test.ts": "responses",
"responses-forward-posit-continuation.test.ts": "responses",
"responses-forward-prompt-envelope.test.ts": "responses",
"responses-function-tool-repair.test.ts": "responses",
"responses-image-gen-repair.test.ts": "responses",
"responses-inbound-store-default.test.ts": "responses",
"responses-item-id-repair.test.ts": "responses",
Expand Down Expand Up @@ -1127,8 +1132,8 @@
"service.test.ts": "service",
"session-affinity.test.ts": "server",
"session-lane-recall-harness.test.ts": "server",
"settings-oauth-open-browser.test.ts": "config",
"settings-main-account-hard-lock.test.ts": "config",
"settings-oauth-open-browser.test.ts": "config",
"settings-startup-health-seam.test.ts": "config",
"settings-stream-mode.test.ts": "config",
"shutdown-drain.test.ts": "service",
Expand Down Expand Up @@ -1234,11 +1239,13 @@
"usage-shape-extraction.test.ts": "usage",
"usage-summary.test.ts": "usage",
"usage-surfaces.test.ts": "usage",
"usage-time-range.test.ts": "usage",
"user-cost-overlay-coderabbit-regressions.test.ts": "usage",
"user-cost-overlay-live-reconcile.test.ts": "usage",
"user-cost-overlay-provider-delete.test.ts": "usage",
"v2-agent-message-failfast.test.ts": "server",
"vercel-gateway-provider-routing.test.ts": "providers",
"version-line.test.ts": "ci-workflows",
"vertex-catalog.test.ts": "adapters/google",
"vision-anthropic.test.ts": "vision",
"vision-backend-union.test.ts": "vision",
Expand Down Expand Up @@ -1299,12 +1306,7 @@
"zhipu-bigmodel-provider.test.ts": "providers",
"zz-ci-api-usage-isolation.test.ts": "ci-workflows",
"zz-ci-storage-policy-isolation.test.ts": "ci-workflows",
"zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows",
"cli-models-price.test.ts": "cli",
"model-costs-management-api.test.ts": "server",
"usage-time-range.test.ts": "usage",
"model-pinned-effort.test.ts": "codex-integration",
"model-pinned-effort-config.test.ts": "config"
"zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows"
},
"migrated": [
"adapters",
Expand Down
85 changes: 85 additions & 0 deletions src/adapters/codebuddy/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig } from "../../types";
import type { AdapterRequest, ProviderAdapter } from "../base";
import { mapReasoningEffort } from "../../reasoning-effort";
import { buildSystemPrompt } from "../coding-agent/protocol";
import { baseScopedEnv, runCodingAgentTurn, type CodingAgentDeps, type SpawnFn } from "../coding-agent/turn";
import { CODEBUDDY_PROFILES, type CodeBuddyProfile } from "./profiles";

export type { SpawnFn } from "../coding-agent/turn";
export type CodeBuddyAdapterDeps = CodingAgentDeps;

/**
* Build the scoped child-process environment for a CodeBuddy turn (§六/§十四).
*
* The region switch and credential are layered on top of the shared base env, which never inherits a
* parent `CODEBUDDY_*`. `CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS=1` matches the vendor SDK's own
* single-shot behavior (a `-p` turn stops at the first result and cannot receive cross-turn
* background push-back).
*/
export function buildChildEnv(profile: CodeBuddyProfile, apiKey: string): Record<string, string> {
return {
...baseScopedEnv(),
CODEBUDDY_API_KEY: apiKey,
CODEBUDDY_INTERNET_ENVIRONMENT: profile.internetEnvironment,
CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS: "1",
};
}

/**
* Build the headless CLI arguments (§七/§十一).
*
* Tool ownership stays with Codex: `--tools ""` disables every built-in tool and `--strict-mcp-config`
* (with no `--mcp-config`) blocks MCP tools, so the CLI can neither read, write, exec, nor browse the
* workspace. `-y/--dangerously-skip-permissions` is deliberately NOT passed, so any operation that
* would require authorization is blocked. The turn is a single text/reasoning pass over stream-json;
* Codex's tool catalog is not advertised in v1 (the control-protocol tool bridge is a fast-follow).
*/
export function buildArgs(profile: CodeBuddyProfile, parsed: OcxParsedRequest, provider: OcxProviderConfig): string[] {
const args: string[] = [
"-p",
"--output-format", "stream-json",
"--input-format", "stream-json",
"--include-partial-messages",
"--verbose",
"--no-session-persistence",
"--tools", "",
"--strict-mcp-config",
"--max-turns", "1",
"--model", parsed.modelId,
];
const effort = mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning);
if (effort) args.push("--effort", effort);
const system = buildSystemPrompt(parsed);
if (system) args.push("--append-system-prompt", system);
Comment on lines +52 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move the system prompt out of the Windows command line

When the globally installed CLI resolves to its normal npm .cmd shim on Windows, commandInvocation serializes every argument into cmd.exe /c; placing the full Codex system/developer prompt here therefore exceeds cmd.exe's 8,191-character limit for ordinary long agent instructions, causing the spawn to fail before CodeBuddy receives the stdin conversation. It also exposes potentially sensitive prompt content through process command-line metadata. Pass the prompt through a supported file/stdin mechanism instead of argv.

AGENTS.md reference: AGENTS.md:L357-L363

Useful? React with 👍 / 👎.

// profile is retained for symmetry with the region-isolated design and future per-region flags.
void profile;
return args;
}

/** Create the shared CodeBuddy adapter: region profile selects Global vs CN, one turn runs tools-disabled. */
export function createCodeBuddyAdapter(provider: OcxProviderConfig, deps: CodeBuddyAdapterDeps = {}): ProviderAdapter {
return {
name: "codebuddy",

// runTurn owns the turn; buildRequest/parseStream are the disabled HTTP path (mirrors cursor).
buildRequest(): AdapterRequest {
return { url: provider.baseUrl, method: "POST", headers: {}, body: "" };
},
async *parseStream(): AsyncGenerator<AdapterEvent> {
yield { type: "error", message: "CodeBuddy adapter uses runTurn; the fetch/parseStream path is disabled." };
},

async runTurn(parsed, incoming, emit): Promise<void> {
await runCodingAgentTurn({
profiles: CODEBUDDY_PROFILES,
provider,
parsed,
incoming,
emit,
buildArgs: (resolved, req, prov) => buildArgs(resolved as CodeBuddyProfile, req, prov),
buildEnv: (resolved, apiKey) => buildChildEnv(resolved as CodeBuddyProfile, apiKey),
deps,
});
},
};
}
Loading
Loading