@withbuddi/buddi 0.1.0-pre.19 → 0.1.0-pre.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/cli/dist/commands.js +1 -1
- package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
- package/node_modules/@buddi/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/main.js +12 -2
- package/node_modules/@buddi/cli/dist/main.js.map +1 -1
- package/node_modules/@buddi/cli/dist/status.d.ts +10 -0
- package/node_modules/@buddi/cli/dist/status.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/status.js +4 -0
- package/node_modules/@buddi/cli/dist/status.js.map +1 -1
- package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.js +7 -1
- package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
- package/node_modules/@buddi/core/dist/provider-accounts.d.ts +7 -1
- package/node_modules/@buddi/core/dist/provider-accounts.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/provider-accounts.js +14 -1
- package/node_modules/@buddi/core/dist/provider-accounts.js.map +1 -1
- package/node_modules/@buddi/core/dist/provider.d.ts +6 -0
- package/node_modules/@buddi/core/dist/provider.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/provider.js.map +1 -1
- package/node_modules/@buddi/core/migrations/046_ollama_device_key.sql +7 -0
- package/node_modules/@buddi/core/migrations/047_reported_context_windows.sql +5 -0
- package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/gateway/dist/codex-accounts.d.ts +24 -11
- package/node_modules/@buddi/gateway/dist/codex-accounts.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/codex-accounts.js +151 -215
- package/node_modules/@buddi/gateway/dist/codex-accounts.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts +1 -0
- package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.js +1 -0
- package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/ollama-accounts.d.ts +87 -0
- package/node_modules/@buddi/gateway/dist/ollama-accounts.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/ollama-accounts.js +179 -0
- package/node_modules/@buddi/gateway/dist/ollama-accounts.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/provider-accounts.d.ts +47 -1
- package/node_modules/@buddi/gateway/dist/provider-accounts.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/provider-accounts.js +182 -25
- package/node_modules/@buddi/gateway/dist/provider-accounts.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/context-budget.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/context-budget.js +10 -3
- package/node_modules/@buddi/gateway/dist/surfaces/context-budget.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.js +16 -13
- package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
- package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/runtime/dist/codex-direct.d.ts +55 -0
- package/node_modules/@buddi/runtime/dist/codex-direct.d.ts.map +1 -0
- package/node_modules/@buddi/runtime/dist/codex-direct.js +334 -0
- package/node_modules/@buddi/runtime/dist/codex-direct.js.map +1 -0
- package/node_modules/@buddi/runtime/dist/codex-oauth.d.ts +66 -0
- package/node_modules/@buddi/runtime/dist/codex-oauth.d.ts.map +1 -0
- package/node_modules/@buddi/runtime/dist/codex-oauth.js +210 -0
- package/node_modules/@buddi/runtime/dist/codex-oauth.js.map +1 -0
- package/node_modules/@buddi/runtime/dist/codex-profile.d.ts +19 -0
- package/node_modules/@buddi/runtime/dist/codex-profile.d.ts.map +1 -0
- package/node_modules/@buddi/runtime/dist/codex-profile.js +99 -0
- package/node_modules/@buddi/runtime/dist/codex-profile.js.map +1 -0
- package/node_modules/@buddi/runtime/dist/context-window.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/context-window.js +4 -0
- package/node_modules/@buddi/runtime/dist/context-window.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.d.ts +24 -0
- package/node_modules/@buddi/runtime/dist/delegate.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.js +87 -11
- package/node_modules/@buddi/runtime/dist/delegate.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/index.d.ts +4 -4
- package/node_modules/@buddi/runtime/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/index.js +5 -5
- package/node_modules/@buddi/runtime/dist/index.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.d.ts +7 -0
- package/node_modules/@buddi/runtime/dist/loop.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.js +48 -8
- package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/ollama-signing.d.ts +52 -0
- package/node_modules/@buddi/runtime/dist/ollama-signing.d.ts.map +1 -0
- package/node_modules/@buddi/runtime/dist/ollama-signing.js +154 -0
- package/node_modules/@buddi/runtime/dist/ollama-signing.js.map +1 -0
- package/node_modules/@buddi/runtime/dist/openai.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/openai.js +21 -7
- package/node_modules/@buddi/runtime/dist/openai.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/provider-models.d.ts +2 -0
- package/node_modules/@buddi/runtime/dist/provider-models.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/provider-models.js +8 -3
- package/node_modules/@buddi/runtime/dist/provider-models.js.map +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/packages/cli/dist/.tsbuildinfo +1 -1
- package/packages/cli/dist/commands.js +1 -1
- package/packages/cli/dist/commands.js.map +1 -1
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +12 -2
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/cli/dist/status.d.ts +10 -0
- package/packages/cli/dist/status.d.ts.map +1 -1
- package/packages/cli/dist/status.js +4 -0
- package/packages/cli/dist/status.js.map +1 -1
- package/packages/core/dist/.tsbuildinfo +1 -1
- package/packages/core/dist/agents/catalog.d.ts.map +1 -1
- package/packages/core/dist/agents/catalog.js +7 -1
- package/packages/core/dist/agents/catalog.js.map +1 -1
- package/packages/core/dist/provider-accounts.d.ts +7 -1
- package/packages/core/dist/provider-accounts.d.ts.map +1 -1
- package/packages/core/dist/provider-accounts.js +14 -1
- package/packages/core/dist/provider-accounts.js.map +1 -1
- package/packages/core/dist/provider.d.ts +6 -0
- package/packages/core/dist/provider.d.ts.map +1 -1
- package/packages/core/dist/provider.js.map +1 -1
- package/packages/core/migrations/046_ollama_device_key.sql +7 -0
- package/packages/core/migrations/047_reported_context_windows.sql +5 -0
- package/packages/gateway/dist/.tsbuildinfo +1 -1
- package/packages/gateway/dist/codex-accounts.d.ts +24 -11
- package/packages/gateway/dist/codex-accounts.d.ts.map +1 -1
- package/packages/gateway/dist/codex-accounts.js +151 -215
- package/packages/gateway/dist/codex-accounts.js.map +1 -1
- package/packages/gateway/dist/index.d.ts +1 -0
- package/packages/gateway/dist/index.d.ts.map +1 -1
- package/packages/gateway/dist/index.js +1 -0
- package/packages/gateway/dist/index.js.map +1 -1
- package/packages/gateway/dist/ollama-accounts.d.ts +87 -0
- package/packages/gateway/dist/ollama-accounts.d.ts.map +1 -0
- package/packages/gateway/dist/ollama-accounts.js +179 -0
- package/packages/gateway/dist/ollama-accounts.js.map +1 -0
- package/packages/gateway/dist/provider-accounts.d.ts +47 -1
- package/packages/gateway/dist/provider-accounts.d.ts.map +1 -1
- package/packages/gateway/dist/provider-accounts.js +182 -25
- package/packages/gateway/dist/provider-accounts.js.map +1 -1
- package/packages/gateway/dist/surfaces/context-budget.d.ts.map +1 -1
- package/packages/gateway/dist/surfaces/context-budget.js +10 -3
- package/packages/gateway/dist/surfaces/context-budget.js.map +1 -1
- package/packages/gateway/dist/web/server.d.ts.map +1 -1
- package/packages/gateway/dist/web/server.js +16 -13
- package/packages/gateway/dist/web/server.js.map +1 -1
- package/packages/install/dist/.tsbuildinfo +1 -1
- package/packages/runtime/dist/.tsbuildinfo +1 -1
- package/packages/runtime/dist/codex-direct.d.ts +55 -0
- package/packages/runtime/dist/codex-direct.d.ts.map +1 -0
- package/packages/runtime/dist/codex-direct.js +334 -0
- package/packages/runtime/dist/codex-direct.js.map +1 -0
- package/packages/runtime/dist/codex-oauth.d.ts +66 -0
- package/packages/runtime/dist/codex-oauth.d.ts.map +1 -0
- package/packages/runtime/dist/codex-oauth.js +210 -0
- package/packages/runtime/dist/codex-oauth.js.map +1 -0
- package/packages/runtime/dist/codex-profile.d.ts +19 -0
- package/packages/runtime/dist/codex-profile.d.ts.map +1 -0
- package/packages/runtime/dist/codex-profile.js +99 -0
- package/packages/runtime/dist/codex-profile.js.map +1 -0
- package/packages/runtime/dist/context-window.d.ts.map +1 -1
- package/packages/runtime/dist/context-window.js +4 -0
- package/packages/runtime/dist/context-window.js.map +1 -1
- package/packages/runtime/dist/delegate.d.ts +24 -0
- package/packages/runtime/dist/delegate.d.ts.map +1 -1
- package/packages/runtime/dist/delegate.js +87 -11
- package/packages/runtime/dist/delegate.js.map +1 -1
- package/packages/runtime/dist/index.d.ts +4 -4
- package/packages/runtime/dist/index.d.ts.map +1 -1
- package/packages/runtime/dist/index.js +5 -5
- package/packages/runtime/dist/index.js.map +1 -1
- package/packages/runtime/dist/loop.d.ts +7 -0
- package/packages/runtime/dist/loop.d.ts.map +1 -1
- package/packages/runtime/dist/loop.js +48 -8
- package/packages/runtime/dist/loop.js.map +1 -1
- package/packages/runtime/dist/ollama-signing.d.ts +52 -0
- package/packages/runtime/dist/ollama-signing.d.ts.map +1 -0
- package/packages/runtime/dist/ollama-signing.js +154 -0
- package/packages/runtime/dist/ollama-signing.js.map +1 -0
- package/packages/runtime/dist/openai.d.ts.map +1 -1
- package/packages/runtime/dist/openai.js +21 -7
- package/packages/runtime/dist/openai.js.map +1 -1
- package/packages/runtime/dist/provider-models.d.ts +2 -0
- package/packages/runtime/dist/provider-models.d.ts.map +1 -1
- package/packages/runtime/dist/provider-models.js +8 -3
- package/packages/runtime/dist/provider-models.js.map +1 -1
- package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/.tsbuildinfo +1 -1
- package/packages/tools/email/dist/.tsbuildinfo +1 -1
- package/packages/tools/host/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/.tsbuildinfo +1 -1
- package/packages/tools/web/dist/.tsbuildinfo +1 -1
- package/packages/web/dist/assets/index-BRc5auXm.js +123 -0
- package/packages/web/dist/assets/{index-B727JQsO.css → index-DwUpotTR.css} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/node_modules/@buddi/runtime/dist/codex-app-server.d.ts +0 -20
- package/node_modules/@buddi/runtime/dist/codex-app-server.d.ts.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-app-server.js +0 -172
- package/node_modules/@buddi/runtime/dist/codex-app-server.js.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-policy.d.ts +0 -6
- package/node_modules/@buddi/runtime/dist/codex-policy.d.ts.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-policy.js +0 -79
- package/node_modules/@buddi/runtime/dist/codex-policy.js.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-rpc.d.ts +0 -34
- package/node_modules/@buddi/runtime/dist/codex-rpc.d.ts.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-rpc.js +0 -152
- package/node_modules/@buddi/runtime/dist/codex-rpc.js.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-session.d.ts +0 -30
- package/node_modules/@buddi/runtime/dist/codex-session.d.ts.map +0 -1
- package/node_modules/@buddi/runtime/dist/codex-session.js +0 -169
- package/node_modules/@buddi/runtime/dist/codex-session.js.map +0 -1
- package/packages/runtime/dist/codex-app-server.d.ts +0 -20
- package/packages/runtime/dist/codex-app-server.d.ts.map +0 -1
- package/packages/runtime/dist/codex-app-server.js +0 -172
- package/packages/runtime/dist/codex-app-server.js.map +0 -1
- package/packages/runtime/dist/codex-policy.d.ts +0 -6
- package/packages/runtime/dist/codex-policy.d.ts.map +0 -1
- package/packages/runtime/dist/codex-policy.js +0 -79
- package/packages/runtime/dist/codex-policy.js.map +0 -1
- package/packages/runtime/dist/codex-rpc.d.ts +0 -34
- package/packages/runtime/dist/codex-rpc.d.ts.map +0 -1
- package/packages/runtime/dist/codex-rpc.js +0 -152
- package/packages/runtime/dist/codex-rpc.js.map +0 -1
- package/packages/runtime/dist/codex-session.d.ts +0 -30
- package/packages/runtime/dist/codex-session.d.ts.map +0 -1
- package/packages/runtime/dist/codex-session.js +0 -169
- package/packages/runtime/dist/codex-session.js.map +0 -1
- package/packages/web/dist/assets/index-OA0xgibo.js +0 -123
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT subscription adapter: buddi's neutral request against OpenAI's Codex
|
|
3
|
+
* backend (`/backend-api/codex/responses`, the Responses API) with the
|
|
4
|
+
* account's own sign-in. No `codex` binary, no child process.
|
|
5
|
+
*
|
|
6
|
+
* Backend quirks, learned the hard way elsewhere and kept here:
|
|
7
|
+
* - `max_output_tokens` is refused, so an exact output cap cannot be honoured
|
|
8
|
+
* and a request asking for one is refused before it is sent;
|
|
9
|
+
* - `store: false`, and `reasoning.encrypted_content` is not requested: with
|
|
10
|
+
* no slot to replay it, asking for it makes tool continuations fail;
|
|
11
|
+
* - the answer always streams; without `onDelta` the stream is assembled.
|
|
12
|
+
*
|
|
13
|
+
* Provider error text is never copied into an error message: it can echo the
|
|
14
|
+
* request. Errors carry a status and a type so the loop classifies them.
|
|
15
|
+
*/
|
|
16
|
+
import { OPENAI_TOOL_NAME_MAX, ProviderError, markCutOff, toolNameMap, } from './anthropic.js';
|
|
17
|
+
import { providerCapabilities } from './capabilities.js';
|
|
18
|
+
import { parseToolArguments } from './openai.js';
|
|
19
|
+
import { MAX_CONTEXT_WINDOW_TOKENS, MIN_CONTEXT_WINDOW_TOKENS } from './context-window.js';
|
|
20
|
+
import { SseParser, frameJson } from './sse.js';
|
|
21
|
+
import { defaultHttpTransport } from './transport.js';
|
|
22
|
+
export const CODEX_BASE_URL = 'https://chatgpt.com/backend-api';
|
|
23
|
+
export const CODEX_DEFAULT_MODEL = 'gpt-5.5';
|
|
24
|
+
export const CODEX_FALLBACK_MODELS = ['gpt-6-astra', 'gpt-6-sol', 'gpt-6-luna', 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.5'];
|
|
25
|
+
/** The client version the model list is asked for; the backend filters by it. */
|
|
26
|
+
const CLIENT_VERSION = '0.156.1';
|
|
27
|
+
/** Wire names the backend reserves for its own tools. */
|
|
28
|
+
const RESERVED_TOOL_NAMES = ['request_user_input', 'skills'];
|
|
29
|
+
export const CODEX_MODEL_UNAVAILABLE = 'The selected model is not available for this ChatGPT account. Choose a supported model in agent settings.';
|
|
30
|
+
function base(url) {
|
|
31
|
+
const b = (url ?? CODEX_BASE_URL).replace(/\/+$/, '');
|
|
32
|
+
return b.endsWith('/codex') ? b.slice(0, -'/codex'.length) : b;
|
|
33
|
+
}
|
|
34
|
+
function headers(accessToken, accountId, accept) {
|
|
35
|
+
return {
|
|
36
|
+
authorization: `Bearer ${accessToken}`, 'chatgpt-account-id': accountId, originator: 'buddi',
|
|
37
|
+
'openai-beta': 'responses=experimental', accept, 'content-type': 'application/json',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function record(value) {
|
|
41
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
42
|
+
}
|
|
43
|
+
/** buddi's history as Responses input items. Tool calls and results are top-level items. */
|
|
44
|
+
export function codexInput(req, names) {
|
|
45
|
+
const items = [];
|
|
46
|
+
for (const message of req.messages) {
|
|
47
|
+
for (const block of message.content) {
|
|
48
|
+
switch (block.type) {
|
|
49
|
+
case 'text':
|
|
50
|
+
items.push({ type: 'message', role: message.role, content: [{ type: message.role === 'user' ? 'input_text' : 'output_text', text: block.text }] });
|
|
51
|
+
break;
|
|
52
|
+
case 'image':
|
|
53
|
+
items.push({ type: 'message', role: message.role, content: [{ type: 'input_image', image_url: `data:${block.mime};base64,${block.data}` }] });
|
|
54
|
+
break;
|
|
55
|
+
case 'tool_use': {
|
|
56
|
+
const name = names.get(block.name);
|
|
57
|
+
if (!name)
|
|
58
|
+
throw new Error('ChatGPT cannot replay a tool that is no longer granted.');
|
|
59
|
+
items.push({ type: 'function_call', call_id: block.id, name, arguments: JSON.stringify(block.input ?? {}) });
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'tool_result':
|
|
63
|
+
items.push({ type: 'function_call_output', call_id: block.tool_use_id, output: block.is_error ? `[Buddi tool failed]\n${block.content}` : block.content });
|
|
64
|
+
break;
|
|
65
|
+
case 'thinking':
|
|
66
|
+
break; // Not replayed: the backend keeps no reasoning state with store:false.
|
|
67
|
+
default:
|
|
68
|
+
throw new Error(`ChatGPT subscription cannot replay ${block.type} content.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return items;
|
|
73
|
+
}
|
|
74
|
+
/** Classify a failure without echoing provider text. */
|
|
75
|
+
export function codexError(status, code, message, retryAt = null) {
|
|
76
|
+
const make = (s, type, text) => new ProviderError({ status: s, type, message: text, retryAt });
|
|
77
|
+
if (/model.{0,200}(?:not supported|unsupported|not available|does not exist)/i.test(message) && (status === 400 || status === 404 || status === 0)) {
|
|
78
|
+
return make(400, 'model_not_supported', CODEX_MODEL_UNAVAILABLE);
|
|
79
|
+
}
|
|
80
|
+
if (status === 401 || /invalid_api_key|token_expired|unauthorized/i.test(code)) {
|
|
81
|
+
return make(401, 'authentication_error', 'ChatGPT rejected this account’s sign-in. Reconnect the account in Settings → Model accounts.');
|
|
82
|
+
}
|
|
83
|
+
if (status === 429 || /usage_limit|rate_limit/i.test(code)) {
|
|
84
|
+
return make(429, 'rate_limit_error', 'Your ChatGPT plan’s limit is reached. Wait for it to reset, or use another account.');
|
|
85
|
+
}
|
|
86
|
+
if (/context_length|context_window/i.test(code))
|
|
87
|
+
return make(400, 'context_window_exceeded', 'The conversation is longer than this model accepts.');
|
|
88
|
+
if (status >= 500)
|
|
89
|
+
return make(status, 'provider_error', `ChatGPT’s backend failed (HTTP ${status}).`);
|
|
90
|
+
if (status >= 400)
|
|
91
|
+
return make(status, 'invalid_request_error', `ChatGPT refused the request (HTTP ${status}${code ? `; ${code.slice(0, 60)}` : ''}).`);
|
|
92
|
+
return make(0, code === 'transport_error' ? 'transport_error' : 'provider_error', code === 'transport_error' ? 'The ChatGPT stream was cut off.' : 'The ChatGPT turn did not complete.');
|
|
93
|
+
}
|
|
94
|
+
async function httpError(res) {
|
|
95
|
+
let code = '';
|
|
96
|
+
let message = '';
|
|
97
|
+
try {
|
|
98
|
+
const data = record(JSON.parse(await res.text()));
|
|
99
|
+
const error = record(data.error);
|
|
100
|
+
const detail = record(data.detail);
|
|
101
|
+
const c = error.code ?? error.type ?? detail.code ?? data.code;
|
|
102
|
+
code = typeof c === 'string' && /^[A-Za-z0-9_.-]{1,80}$/.test(c) ? c : '';
|
|
103
|
+
const m = error.message ?? data.detail ?? data.message;
|
|
104
|
+
message = typeof m === 'string' ? m.slice(0, 2000) : '';
|
|
105
|
+
}
|
|
106
|
+
catch { /* status is enough */ }
|
|
107
|
+
const retryAfter = res.headers?.get?.('retry-after');
|
|
108
|
+
const retryAt = retryAfter && /^\d{1,6}$/.test(retryAfter) ? new Date(Date.now() + Number(retryAfter) * 1000).toISOString() : null;
|
|
109
|
+
return codexError(res.status, code, message, retryAt);
|
|
110
|
+
}
|
|
111
|
+
/** The Responses SSE vocabulary, assembled into buddi's content blocks. */
|
|
112
|
+
export class CodexStreamAssembly {
|
|
113
|
+
names;
|
|
114
|
+
onDelta;
|
|
115
|
+
#parser = new SseParser();
|
|
116
|
+
#items = [];
|
|
117
|
+
#usage = { input: 0, output: 0 };
|
|
118
|
+
#model;
|
|
119
|
+
#incomplete = false;
|
|
120
|
+
#completed = false;
|
|
121
|
+
failure;
|
|
122
|
+
spoke = false;
|
|
123
|
+
constructor(names, onDelta) {
|
|
124
|
+
this.names = names;
|
|
125
|
+
this.onDelta = onDelta;
|
|
126
|
+
}
|
|
127
|
+
push(text) {
|
|
128
|
+
if (this.failure)
|
|
129
|
+
return;
|
|
130
|
+
for (const frame of this.#parser.push(text))
|
|
131
|
+
this.#event(frameJson(frame));
|
|
132
|
+
}
|
|
133
|
+
#item(id, make) {
|
|
134
|
+
let item = this.#items.find(i => i.id === id && i.block.type === make().type);
|
|
135
|
+
if (!item) {
|
|
136
|
+
item = { id, block: make() };
|
|
137
|
+
this.#items.push(item);
|
|
138
|
+
}
|
|
139
|
+
return item;
|
|
140
|
+
}
|
|
141
|
+
#event(event) {
|
|
142
|
+
if (!event || this.failure)
|
|
143
|
+
return;
|
|
144
|
+
const type = event.type;
|
|
145
|
+
const itemId = typeof event.item_id === 'string' ? event.item_id : '';
|
|
146
|
+
switch (type) {
|
|
147
|
+
case 'response.output_item.added': {
|
|
148
|
+
const item = record(event.item);
|
|
149
|
+
if (item.type === 'function_call' && typeof item.id === 'string')
|
|
150
|
+
this.#tool(item);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case 'response.output_text.delta': {
|
|
154
|
+
if (typeof event.delta !== 'string' || event.delta === '')
|
|
155
|
+
return;
|
|
156
|
+
const item = this.#item(itemId, () => ({ type: 'text', text: '' }));
|
|
157
|
+
item.block.text += event.delta;
|
|
158
|
+
this.spoke = true;
|
|
159
|
+
this.onDelta?.({ kind: 'text', text: event.delta });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
case 'response.reasoning_summary_text.delta':
|
|
163
|
+
case 'response.reasoning_text.delta': {
|
|
164
|
+
if (typeof event.delta !== 'string' || event.delta === '')
|
|
165
|
+
return;
|
|
166
|
+
const item = this.#item(itemId, () => ({ type: 'thinking', text: '' }));
|
|
167
|
+
item.block.text += event.delta;
|
|
168
|
+
this.spoke = true;
|
|
169
|
+
this.onDelta?.({ kind: 'thinking', text: event.delta });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
case 'response.reasoning_summary_part.added': {
|
|
173
|
+
// A new summary paragraph inside the same reasoning item.
|
|
174
|
+
const item = this.#items.find(i => i.id === itemId && i.block.type === 'thinking');
|
|
175
|
+
if (item && item.block.text !== '')
|
|
176
|
+
item.block.text += '\n\n';
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
case 'response.function_call_arguments.delta': {
|
|
180
|
+
const item = this.#items.find(i => i.id === itemId && i.block.type === 'tool_use');
|
|
181
|
+
if (item && typeof event.delta === 'string') {
|
|
182
|
+
item.args = (item.args ?? '') + event.delta;
|
|
183
|
+
item.gotArgs = true;
|
|
184
|
+
}
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
case 'response.output_item.done': {
|
|
188
|
+
const done = record(event.item);
|
|
189
|
+
if (done.type !== 'function_call')
|
|
190
|
+
return;
|
|
191
|
+
const item = this.#tool(done);
|
|
192
|
+
if (item && !item.gotArgs && typeof done.arguments === 'string')
|
|
193
|
+
item.args = done.arguments;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
case 'response.completed':
|
|
197
|
+
case 'response.incomplete': {
|
|
198
|
+
const response = record(event.response);
|
|
199
|
+
const usage = record(response.usage);
|
|
200
|
+
if (typeof usage.input_tokens === 'number')
|
|
201
|
+
this.#usage.input = usage.input_tokens;
|
|
202
|
+
if (typeof usage.output_tokens === 'number')
|
|
203
|
+
this.#usage.output = usage.output_tokens;
|
|
204
|
+
if (typeof response.model === 'string')
|
|
205
|
+
this.#model = response.model;
|
|
206
|
+
if (type === 'response.incomplete' || response.status === 'incomplete')
|
|
207
|
+
this.#incomplete = true;
|
|
208
|
+
this.#completed = true;
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
case 'response.failed': {
|
|
212
|
+
const error = record(record(event.response).error);
|
|
213
|
+
this.failure = codexError(0, typeof error.code === 'string' ? error.code : '', typeof error.message === 'string' ? error.message : '');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
case 'error': {
|
|
217
|
+
const error = Object.keys(record(event.error)).length ? record(event.error) : event;
|
|
218
|
+
this.failure = codexError(0, typeof error.code === 'string' ? error.code : '', typeof error.message === 'string' ? error.message : '');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
default:
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
#tool(item) {
|
|
225
|
+
const id = typeof item.id === 'string' ? item.id : typeof item.call_id === 'string' ? item.call_id : '';
|
|
226
|
+
const existing = this.#items.find(i => i.id === id && i.block.type === 'tool_use');
|
|
227
|
+
if (existing)
|
|
228
|
+
return existing;
|
|
229
|
+
const wire = typeof item.name === 'string' ? item.name : '';
|
|
230
|
+
const name = this.names.get(wire);
|
|
231
|
+
if (!name) {
|
|
232
|
+
this.failure = new ProviderError({ status: 0, type: 'provider_error', message: 'ChatGPT asked for a tool outside this turn’s grant.' });
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
const entry = { id, block: { type: 'tool_use', id: typeof item.call_id === 'string' ? item.call_id : id, name, input: {} }, args: '' };
|
|
236
|
+
this.#items.push(entry);
|
|
237
|
+
return entry;
|
|
238
|
+
}
|
|
239
|
+
finish(fallbackModel) {
|
|
240
|
+
for (const frame of this.#parser.end())
|
|
241
|
+
this.#event(frameJson(frame));
|
|
242
|
+
if (this.failure)
|
|
243
|
+
throw this.failure;
|
|
244
|
+
if (!this.#completed)
|
|
245
|
+
throw codexError(0, 'transport_error', '');
|
|
246
|
+
const content = [];
|
|
247
|
+
for (const item of this.#items) {
|
|
248
|
+
if (item.block.type === 'tool_use')
|
|
249
|
+
content.push({ ...item.block, input: parseToolArguments(item.args) });
|
|
250
|
+
else if (item.block.type === 'text' || item.block.type === 'thinking') {
|
|
251
|
+
if (item.block.text !== '')
|
|
252
|
+
content.push(item.block);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const stopReason = this.#incomplete ? 'max_tokens' : content.some(b => b.type === 'tool_use') ? 'tool_use' : 'end_turn';
|
|
256
|
+
return { content: markCutOff(content, stopReason), stopReason, usage: this.#usage, model: this.#model ?? fallbackModel };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
export function createCodexDirectAdapter(options) {
|
|
260
|
+
const transport = options.transport ?? defaultHttpTransport;
|
|
261
|
+
const url = `${base(options.baseUrl)}/codex/responses`;
|
|
262
|
+
return {
|
|
263
|
+
capabilities: { ...providerCapabilities('openai'), nativeWebSearch: false, usageReporting: true, parallelToolCalls: true },
|
|
264
|
+
async complete(req) {
|
|
265
|
+
req.signal?.throwIfAborted();
|
|
266
|
+
if (req.maxTokens !== undefined) {
|
|
267
|
+
throw new ProviderError({ status: 0, type: 'unsupported_request', message: 'A ChatGPT subscription account cannot enforce an exact output-token cap.' });
|
|
268
|
+
}
|
|
269
|
+
const mapping = toolNameMap(req.tools, OPENAI_TOOL_NAME_MAX, RESERVED_TOOL_NAMES);
|
|
270
|
+
const names = new Map([...mapping].map(([wire, original]) => [original, wire]));
|
|
271
|
+
const body = {
|
|
272
|
+
model: options.model, store: false, stream: true, instructions: req.system,
|
|
273
|
+
input: codexInput(req, names),
|
|
274
|
+
tools: req.tools.map(tool => ({ type: 'function', name: names.get(tool.name), description: tool.description, parameters: tool.input_schema, strict: false })),
|
|
275
|
+
tool_choice: 'auto', parallel_tool_calls: true,
|
|
276
|
+
};
|
|
277
|
+
if (req.thinking === 'on')
|
|
278
|
+
body.reasoning = { effort: 'medium', summary: 'auto' };
|
|
279
|
+
const assembly = new CodexStreamAssembly(mapping, req.onDelta);
|
|
280
|
+
await req.onDispatch?.();
|
|
281
|
+
req.signal?.throwIfAborted();
|
|
282
|
+
let res;
|
|
283
|
+
try {
|
|
284
|
+
res = await transport(url, {
|
|
285
|
+
method: 'POST', headers: headers(options.accessToken, options.accountId, 'text/event-stream'), body: JSON.stringify(body),
|
|
286
|
+
idleTimeoutMs: options.timeoutMs ?? 120_000,
|
|
287
|
+
...(req.signal ? { signal: req.signal } : {}),
|
|
288
|
+
onChunk: (text, status) => { if (status >= 200 && status < 300)
|
|
289
|
+
assembly.push(text); },
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
req.signal?.throwIfAborted();
|
|
294
|
+
throw new ProviderError({ status: 0, type: 'transport_error', message: assembly.spoke ? 'The ChatGPT stream was cut off.' : 'Could not reach ChatGPT.', cause: error });
|
|
295
|
+
}
|
|
296
|
+
if (!res.ok)
|
|
297
|
+
throw await httpError(res);
|
|
298
|
+
return assembly.finish(options.model);
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/** The account's models, from the backend; the known list when it will not say. */
|
|
303
|
+
export async function listCodexModels(options) {
|
|
304
|
+
const fallback = { models: CODEX_FALLBACK_MODELS.map(id => ({ id, name: id, isDefault: id === CODEX_DEFAULT_MODEL })), truncated: false };
|
|
305
|
+
try {
|
|
306
|
+
const res = await (options.transport ?? defaultHttpTransport)(`${base(options.baseUrl)}/codex/models?client_version=${CLIENT_VERSION}`, {
|
|
307
|
+
method: 'GET', headers: headers(options.accessToken, options.accountId, 'application/json'),
|
|
308
|
+
signal: AbortSignal.timeout(20_000), maxBytes: 4 * 1024 * 1024,
|
|
309
|
+
});
|
|
310
|
+
if (!res.ok)
|
|
311
|
+
return fallback;
|
|
312
|
+
const data = record(await res.json());
|
|
313
|
+
if (!Array.isArray(data.models))
|
|
314
|
+
return fallback;
|
|
315
|
+
const listed = data.models.map(record)
|
|
316
|
+
.filter(m => m.visibility === 'list' && typeof m.slug === 'string' && m.slug.trim() && m.slug.length <= 150 && !/[\x00-\x1f\x7f\s]/.test(m.slug))
|
|
317
|
+
.sort((a, b) => (typeof a.priority === 'number' ? a.priority : 1e9) - (typeof b.priority === 'number' ? b.priority : 1e9));
|
|
318
|
+
const models = new Map();
|
|
319
|
+
for (const m of listed.slice(0, 1000)) {
|
|
320
|
+
const id = m.slug;
|
|
321
|
+
const label = typeof m.display_name === 'string' && m.display_name.length <= 200 && !/[\x00-\x1f\x7f]/.test(m.display_name) ? m.display_name : id;
|
|
322
|
+
const window = m.context_window;
|
|
323
|
+
const contextWindow = typeof window === 'number' && Number.isInteger(window) && window > 0
|
|
324
|
+
? Math.min(MAX_CONTEXT_WINDOW_TOKENS, Math.max(MIN_CONTEXT_WINDOW_TOKENS, window)) : undefined;
|
|
325
|
+
if (!models.has(id))
|
|
326
|
+
models.set(id, { id, name: label, isDefault: models.size === 0, ...(contextWindow ? { contextWindow } : {}) });
|
|
327
|
+
}
|
|
328
|
+
return models.size ? { models: [...models.values()], truncated: listed.length > 1000 } : fallback;
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return fallback;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=codex-direct.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-direct.js","sourceRoot":"","sources":["../src/codex-direct.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT subscription sign-in: the device-code OAuth the Codex CLI uses,
|
|
3
|
+
* done by buddi itself. No `codex` binary, no owner `~/.codex`.
|
|
4
|
+
*
|
|
5
|
+
* The flow differs from RFC 8628: the usercode call returns a
|
|
6
|
+
* `device_auth_id`, polls are keyed by it (403/404 mean "not yet"), and an
|
|
7
|
+
* approval returns an authorization code plus a server-made PKCE verifier,
|
|
8
|
+
* which are exchanged at `/oauth/token` with the device redirect. Refresh
|
|
9
|
+
* tokens rotate and are single use: the caller persists every rotated pair.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here puts a response body, a token or a code into an error message.
|
|
12
|
+
*/
|
|
13
|
+
import { type HttpTransport } from './transport.js';
|
|
14
|
+
export declare const CODEX_ISSUER = "https://auth.openai.com";
|
|
15
|
+
export declare const CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
16
|
+
export declare const CODEX_DEVICE_REDIRECT = "https://auth.openai.com/deviceauth/callback";
|
|
17
|
+
export declare const CODEX_VERIFY_URL = "https://auth.openai.com/codex/device";
|
|
18
|
+
/** The server gives no expiry for a device code; the Codex CLI waits 15 minutes. */
|
|
19
|
+
export declare const CODEX_DEVICE_TIMEOUT_MS: number;
|
|
20
|
+
export interface CodexTokens {
|
|
21
|
+
version: 1;
|
|
22
|
+
state: 'ready' | 'refreshing';
|
|
23
|
+
accessToken: string;
|
|
24
|
+
refreshToken: string;
|
|
25
|
+
idToken?: string;
|
|
26
|
+
accountId: string;
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
}
|
|
29
|
+
export interface CodexDeviceStart {
|
|
30
|
+
deviceAuthId: string;
|
|
31
|
+
userCode: string;
|
|
32
|
+
verificationUrl: string;
|
|
33
|
+
intervalMs: number;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
}
|
|
36
|
+
export type CodexDevicePoll = 'pending' | 'slow_down' | {
|
|
37
|
+
code: string;
|
|
38
|
+
verifier: string;
|
|
39
|
+
} | {
|
|
40
|
+
denied: string;
|
|
41
|
+
};
|
|
42
|
+
export declare function codexAccountId(token: string | undefined): string | undefined;
|
|
43
|
+
/** Epoch ms from the `exp` claim, or 0 (treat as expired) when absent. */
|
|
44
|
+
export declare function codexTokenExpiry(token: string | undefined): number;
|
|
45
|
+
/**
|
|
46
|
+
* buddi's envelope, or the legacy vault value (Codex's own `auth.json`, as the
|
|
47
|
+
* old runner stored it, possibly hex-encoded by macOS `security -w`),
|
|
48
|
+
* converted to the envelope.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readCodexTokens(raw: string): CodexTokens;
|
|
51
|
+
/** The envelope as Codex's `auth.json`, for a staged private profile. */
|
|
52
|
+
export declare function codexAuthJson(tokens: CodexTokens, now?: () => number): string;
|
|
53
|
+
export declare class CodexOAuthProtocol {
|
|
54
|
+
#private;
|
|
55
|
+
readonly transport: HttpTransport;
|
|
56
|
+
readonly now: () => number;
|
|
57
|
+
constructor(transport?: HttpTransport, now?: () => number);
|
|
58
|
+
startDevice(): Promise<CodexDeviceStart>;
|
|
59
|
+
pollDevice(deviceAuthId: string, userCode: string): Promise<CodexDevicePoll>;
|
|
60
|
+
exchange(input: {
|
|
61
|
+
code: string;
|
|
62
|
+
verifier: string;
|
|
63
|
+
}): Promise<CodexTokens>;
|
|
64
|
+
refresh(tokens: CodexTokens): Promise<CodexTokens>;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=codex-oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-oauth.d.ts","sourceRoot":"","sources":["../src/codex-oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE1E,eAAO,MAAM,YAAY,4BAA4B,CAAC;AACtD,eAAO,MAAM,eAAe,iCAAiC,CAAC;AAI9D,eAAO,MAAM,qBAAqB,gDAAwC,CAAC;AAC3E,eAAO,MAAM,gBAAgB,yCAAiC,CAAC;AAC/D,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAGnD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CACtC;AACD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CACxG;AACD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAqBhH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI5E;AACD,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGlE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CA2BxD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,eAAW,GAAG,MAAM,CAMzE;AAED,qBAAa,kBAAkB;;IACjB,QAAQ,CAAC,SAAS,EAAE,aAAa;IAAyB,QAAQ,CAAC,GAAG;gBAA7D,SAAS,GAAE,aAAoC,EAAW,GAAG,eAAW;IAUvF,WAAW,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAiBxC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAwClF,QAAQ,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzE,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAGnD"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT subscription sign-in: the device-code OAuth the Codex CLI uses,
|
|
3
|
+
* done by buddi itself. No `codex` binary, no owner `~/.codex`.
|
|
4
|
+
*
|
|
5
|
+
* The flow differs from RFC 8628: the usercode call returns a
|
|
6
|
+
* `device_auth_id`, polls are keyed by it (403/404 mean "not yet"), and an
|
|
7
|
+
* approval returns an authorization code plus a server-made PKCE verifier,
|
|
8
|
+
* which are exchanged at `/oauth/token` with the device redirect. Refresh
|
|
9
|
+
* tokens rotate and are single use: the caller persists every rotated pair.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here puts a response body, a token or a code into an error message.
|
|
12
|
+
*/
|
|
13
|
+
import { defaultHttpTransport } from './transport.js';
|
|
14
|
+
export const CODEX_ISSUER = 'https://auth.openai.com';
|
|
15
|
+
export const CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
|
|
16
|
+
const USERCODE_URL = `${CODEX_ISSUER}/api/accounts/deviceauth/usercode`;
|
|
17
|
+
const DEVICE_TOKEN_URL = `${CODEX_ISSUER}/api/accounts/deviceauth/token`;
|
|
18
|
+
const TOKEN_URL = `${CODEX_ISSUER}/oauth/token`;
|
|
19
|
+
export const CODEX_DEVICE_REDIRECT = `${CODEX_ISSUER}/deviceauth/callback`;
|
|
20
|
+
export const CODEX_VERIFY_URL = `${CODEX_ISSUER}/codex/device`;
|
|
21
|
+
/** The server gives no expiry for a device code; the Codex CLI waits 15 minutes. */
|
|
22
|
+
export const CODEX_DEVICE_TIMEOUT_MS = 15 * 60_000;
|
|
23
|
+
const AUTH_CLAIM = 'https://api.openai.com/auth';
|
|
24
|
+
const INVALID = 'Invalid ChatGPT credential. Reconnect this account.';
|
|
25
|
+
function validToken(value) {
|
|
26
|
+
return typeof value === 'string' && value.length > 0 && value.length <= 16384 && !/[\s\x00-\x1f\x7f]/.test(value);
|
|
27
|
+
}
|
|
28
|
+
function validId(value) {
|
|
29
|
+
return typeof value === 'string' && value.length > 0 && value.length <= 200 && /^[A-Za-z0-9._:-]+$/.test(value);
|
|
30
|
+
}
|
|
31
|
+
/** A JWT's payload, unverified: the claims are routing hints, the token itself is the credential. */
|
|
32
|
+
function jwtPayload(token) {
|
|
33
|
+
if (!token)
|
|
34
|
+
return null;
|
|
35
|
+
try {
|
|
36
|
+
const part = token.split('.')[1];
|
|
37
|
+
if (!part || part.length > 16384)
|
|
38
|
+
return null;
|
|
39
|
+
const value = JSON.parse(Buffer.from(part, 'base64url').toString('utf8'));
|
|
40
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function codexAccountId(token) {
|
|
47
|
+
const auth = jwtPayload(token)?.[AUTH_CLAIM];
|
|
48
|
+
const id = auth && typeof auth === 'object' ? auth.chatgpt_account_id : undefined;
|
|
49
|
+
return validId(id) ? id : undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Epoch ms from the `exp` claim, or 0 (treat as expired) when absent. */
|
|
52
|
+
export function codexTokenExpiry(token) {
|
|
53
|
+
const exp = jwtPayload(token)?.exp;
|
|
54
|
+
return typeof exp === 'number' && Number.isFinite(exp) && exp > 0 ? exp * 1000 : 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* buddi's envelope, or the legacy vault value (Codex's own `auth.json`, as the
|
|
58
|
+
* old runner stored it, possibly hex-encoded by macOS `security -w`),
|
|
59
|
+
* converted to the envelope.
|
|
60
|
+
*/
|
|
61
|
+
export function readCodexTokens(raw) {
|
|
62
|
+
try {
|
|
63
|
+
if (typeof raw !== 'string' || Buffer.byteLength(raw) > 128 * 1024)
|
|
64
|
+
throw new Error();
|
|
65
|
+
let value = raw;
|
|
66
|
+
if (/^(?:[0-9a-f]{2})+$/i.test(value))
|
|
67
|
+
value = new TextDecoder('utf-8', { fatal: true }).decode(Buffer.from(value, 'hex'));
|
|
68
|
+
if (Buffer.byteLength(value) > 64 * 1024)
|
|
69
|
+
throw new Error();
|
|
70
|
+
const data = JSON.parse(value);
|
|
71
|
+
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
72
|
+
throw new Error();
|
|
73
|
+
if (data.version === 1) {
|
|
74
|
+
const t = data;
|
|
75
|
+
if (!['ready', 'refreshing'].includes(t.state) || !validToken(t.accessToken) || !validToken(t.refreshToken) ||
|
|
76
|
+
(t.idToken !== undefined && !validToken(t.idToken)) || !validId(t.accountId) ||
|
|
77
|
+
!Number.isFinite(t.expiresAt) || t.expiresAt < 0)
|
|
78
|
+
throw new Error();
|
|
79
|
+
return { version: 1, state: t.state, accessToken: t.accessToken, refreshToken: t.refreshToken,
|
|
80
|
+
...(t.idToken ? { idToken: t.idToken } : {}), accountId: t.accountId, expiresAt: t.expiresAt };
|
|
81
|
+
}
|
|
82
|
+
const tokens = data.tokens;
|
|
83
|
+
if (!tokens || typeof tokens !== 'object' || data.OPENAI_API_KEY ||
|
|
84
|
+
(data.auth_mode !== undefined && data.auth_mode !== 'chatgpt') ||
|
|
85
|
+
!validToken(tokens.access_token) || !validToken(tokens.refresh_token) ||
|
|
86
|
+
(tokens.id_token !== undefined && tokens.id_token !== null && !validToken(tokens.id_token)))
|
|
87
|
+
throw new Error();
|
|
88
|
+
const idToken = typeof tokens.id_token === 'string' ? tokens.id_token : undefined;
|
|
89
|
+
const accountId = validId(tokens.account_id) ? tokens.account_id : codexAccountId(tokens.access_token) ?? codexAccountId(idToken);
|
|
90
|
+
if (!accountId)
|
|
91
|
+
throw new Error();
|
|
92
|
+
return { version: 1, state: 'ready', accessToken: tokens.access_token, refreshToken: tokens.refresh_token,
|
|
93
|
+
...(idToken ? { idToken } : {}), accountId, expiresAt: codexTokenExpiry(tokens.access_token) };
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new Error(INVALID);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** The envelope as Codex's `auth.json`, for a staged private profile. */
|
|
100
|
+
export function codexAuthJson(tokens, now = Date.now) {
|
|
101
|
+
return JSON.stringify({
|
|
102
|
+
auth_mode: 'chatgpt', OPENAI_API_KEY: null,
|
|
103
|
+
tokens: { id_token: tokens.idToken ?? null, access_token: tokens.accessToken, refresh_token: tokens.refreshToken, account_id: tokens.accountId },
|
|
104
|
+
last_refresh: new Date(now()).toISOString(),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
export class CodexOAuthProtocol {
|
|
108
|
+
transport;
|
|
109
|
+
now;
|
|
110
|
+
constructor(transport = defaultHttpTransport, now = Date.now) {
|
|
111
|
+
this.transport = transport;
|
|
112
|
+
this.now = now;
|
|
113
|
+
}
|
|
114
|
+
async #post(url, body, type) {
|
|
115
|
+
return this.transport(url, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: { 'content-type': type === 'json' ? 'application/json' : 'application/x-www-form-urlencoded', accept: 'application/json' },
|
|
118
|
+
body, signal: AbortSignal.timeout(20_000), maxBytes: 65536,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async startDevice() {
|
|
122
|
+
let res;
|
|
123
|
+
try {
|
|
124
|
+
res = await this.#post(USERCODE_URL, JSON.stringify({ client_id: CODEX_CLIENT_ID }), 'json');
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new Error('Could not reach ChatGPT sign-in. Check the network and try again.');
|
|
128
|
+
}
|
|
129
|
+
if (res.status === 404)
|
|
130
|
+
throw new Error('Device code sign-in is not enabled on this ChatGPT account. Turn it on in ChatGPT settings, under Security.');
|
|
131
|
+
try {
|
|
132
|
+
if (!res.ok)
|
|
133
|
+
throw new Error();
|
|
134
|
+
const data = await res.json();
|
|
135
|
+
const userCode = data.user_code ?? data.usercode;
|
|
136
|
+
if (!validId(data.device_auth_id) || typeof userCode !== 'string' || !/^[A-Za-z0-9-]{4,32}$/.test(userCode))
|
|
137
|
+
throw new Error();
|
|
138
|
+
const interval = typeof data.interval === 'string' ? Number(data.interval.trim()) : data.interval;
|
|
139
|
+
const seconds = typeof interval === 'number' && Number.isFinite(interval) && interval > 0 && interval <= 60 ? interval : 5;
|
|
140
|
+
return { deviceAuthId: data.device_auth_id, userCode, verificationUrl: CODEX_VERIFY_URL,
|
|
141
|
+
intervalMs: seconds * 1000, expiresAt: this.now() + CODEX_DEVICE_TIMEOUT_MS };
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
throw new Error('ChatGPT sign-in could not start. Try again in a moment.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async pollDevice(deviceAuthId, userCode) {
|
|
148
|
+
let res;
|
|
149
|
+
try {
|
|
150
|
+
res = await this.#post(DEVICE_TOKEN_URL, JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }), 'json');
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return 'pending';
|
|
154
|
+
} // A network blip is not a denial; the deadline still bounds the wait.
|
|
155
|
+
if (res.ok) {
|
|
156
|
+
const data = await res.json().catch(() => null);
|
|
157
|
+
if (data && validToken(data.authorization_code) && validToken(data.code_verifier))
|
|
158
|
+
return { code: data.authorization_code, verifier: data.code_verifier };
|
|
159
|
+
return { denied: 'ChatGPT sent an unexpected sign-in response. Start again.' };
|
|
160
|
+
}
|
|
161
|
+
if (res.status === 403 || res.status === 404)
|
|
162
|
+
return 'pending';
|
|
163
|
+
let code;
|
|
164
|
+
try {
|
|
165
|
+
const error = JSON.parse(await res.text()).error;
|
|
166
|
+
code = error && typeof error === 'object' ? error.code : error;
|
|
167
|
+
}
|
|
168
|
+
catch { /* not JSON */ }
|
|
169
|
+
if (code === 'deviceauth_authorization_pending' || code === 'authorization_pending')
|
|
170
|
+
return 'pending';
|
|
171
|
+
if (code === 'slow_down')
|
|
172
|
+
return 'slow_down';
|
|
173
|
+
if (res.status === 429)
|
|
174
|
+
return 'slow_down';
|
|
175
|
+
return { denied: code === 'access_denied' || code === 'expired_token' ? 'Sign-in was declined or expired on ChatGPT. Start again.' : 'ChatGPT did not approve the sign-in. Start again.' };
|
|
176
|
+
}
|
|
177
|
+
async #token(body, previous) {
|
|
178
|
+
try {
|
|
179
|
+
const res = await this.#post(TOKEN_URL, new URLSearchParams({ client_id: CODEX_CLIENT_ID, ...body }).toString(), 'form');
|
|
180
|
+
if (!res.ok)
|
|
181
|
+
throw new Error();
|
|
182
|
+
const data = await res.json();
|
|
183
|
+
if (!validToken(data.access_token))
|
|
184
|
+
throw new Error();
|
|
185
|
+
const refreshToken = data.refresh_token === undefined || data.refresh_token === null || data.refresh_token === '' ? previous?.refreshToken : data.refresh_token;
|
|
186
|
+
if (!validToken(refreshToken))
|
|
187
|
+
throw new Error();
|
|
188
|
+
const idToken = validToken(data.id_token) ? data.id_token : previous?.idToken;
|
|
189
|
+
const accountId = codexAccountId(data.access_token) ?? codexAccountId(idToken) ?? previous?.accountId;
|
|
190
|
+
if (!accountId)
|
|
191
|
+
throw new Error();
|
|
192
|
+
const expiresIn = data.expires_in;
|
|
193
|
+
const expiresAt = typeof expiresIn === 'number' && Number.isFinite(expiresIn) && expiresIn > 0 && expiresIn <= 366 * 86400
|
|
194
|
+
? this.now() + expiresIn * 1000 : codexTokenExpiry(data.access_token);
|
|
195
|
+
if (!expiresAt)
|
|
196
|
+
throw new Error();
|
|
197
|
+
return { version: 1, state: 'ready', accessToken: data.access_token, refreshToken, ...(idToken ? { idToken } : {}), accountId, expiresAt };
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
throw new Error(previous ? 'ChatGPT token refresh failed. Reconnect this account.' : 'ChatGPT sign-in could not complete. Start a fresh sign-in.');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exchange(input) {
|
|
204
|
+
return this.#token({ grant_type: 'authorization_code', code: input.code, code_verifier: input.verifier, redirect_uri: CODEX_DEVICE_REDIRECT });
|
|
205
|
+
}
|
|
206
|
+
refresh(tokens) {
|
|
207
|
+
return this.#token({ grant_type: 'refresh_token', refresh_token: tokens.refreshToken, scope: 'openid profile email' }, tokens);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=codex-oauth.js.map
|