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
6 changes: 6 additions & 0 deletions docs-site/src/content/docs/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ ccx logout <provider>
| `cursor` | `cursor` | `https://api2.cursor.sh` | Experimental unofficial PKCE login **or** a pasted dashboard user API key. Same unofficial AgentService/Run protocol either way; not a public OpenAI chat-completions API. |
| `github-copilot` | `openai-chat` | `https://api.githubcopilot.com` | Experimental. GitHub device flow + `copilot_internal` exchange (VS Code OAuth client). Requires an active Copilot subscription; not an official third-party API. |

If an xAI OAuth request to the Grok subscription proxy reports that the Grok CLI client version is
outdated, update CodexCommander to a release with the current xAI compatibility profile. Routed
requests advertise CodexCommander's pinned client version; they do not launch the local `grok`
executable, so updating that executable alone does not change the request fingerprint. xAI API-key
requests use `api.x.ai` and do not use the Grok subscription-proxy fingerprint.

For the canonical Kimi Coding Plan presets (`kimi` account login and `kimi-code` API key),
CodexCommander forwards only a caller-supplied stable `prompt_cache_key` to the Chat Completions request;
it never generates one. Kimi documents a stable session/task key as required to improve Code Plan
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codexcommander",
"version": "0.1.20",
"version": "0.1.21",
"private": true,
"description": "CodexCommander — universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code",
"type": "module",
Expand Down
6 changes: 4 additions & 2 deletions src/providers/xai-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { resolveGithubCopilotTransport } from "./github-copilot-transport";

export const XAI_GROK_CLI_BASE_URL = "https://cli-chat-proxy.grok.com/v1";

const XAI_GROK_COMPATIBILITY_VERSION = "1.0.52";

export const XAI_GROK_COMPATIBILITY = {
version: "0.2.93",
userAgent: "codexcommander-grok/0.2.93",
version: XAI_GROK_COMPATIBILITY_VERSION,
userAgent: `codexcommander-grok/${XAI_GROK_COMPATIBILITY_VERSION}`,
headers: {
clientIdentifier: "x-grok-client-identifier",
clientVersion: "x-grok-client-version",
Expand Down
12 changes: 12 additions & 0 deletions tests/xai-transport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,18 @@ describe("xAI outbound compatibility headers", () => {
test("OAuth snapshot is exact", async () => {
const { effective, seen } = await capture("oauth");
expect(effective.baseUrl).toBe(XAI_GROK_CLI_BASE_URL);
// Keep this literal independent of the imported profile constant so a stale
// fingerprint cannot make both implementation and expectation pass together.
const outgoingVersion = seen[0]!.get("x-grok-client-version")!;
expect(XAI_GROK_CLIENT_VERSION).toBe("1.0.52");
expect(outgoingVersion).toBe("1.0.52");
expect(seen[0]!.get("user-agent")).toBe(`codexcommander-grok/${outgoingVersion}`);
const actual = outgoingVersion.split(".").map(Number);
const minimum = [1, 0, 13];
const atLeastMinimum = actual[0]! > minimum[0]!
|| (actual[0] === minimum[0] && actual[1]! > minimum[1]!)
|| (actual[0] === minimum[0] && actual[1] === minimum[1] && actual[2]! >= minimum[2]!);
expect(atLeastMinimum).toBe(true);
expect(lower(seen[0])).toEqual({
authorization: "Bearer oauth-token",
"content-type": "application/json",
Expand Down
Loading