topchester-ai 0.53.0 → 0.54.0

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/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as runTopchesterCli } from "./cli-CqFhOvlt.mjs";
2
+ import { t as runTopchesterCli } from "./cli-D1d-I3Fi.mjs";
3
3
  //#region src/bin.ts
4
4
  await runTopchesterCli();
5
5
  //#endregion
@@ -127,13 +127,13 @@ function extractAccountIdFromClaims(claims) {
127
127
  const flatClaim = getStringProperty(claims, "chatgpt_account_id");
128
128
  if (flatClaim) return flatClaim;
129
129
  const authClaims = claims["https://api.openai.com/auth"];
130
- if (isPlainObject$2(authClaims)) {
130
+ if (isPlainObject$3(authClaims)) {
131
131
  const namespacedClaim = getStringProperty(authClaims, "chatgpt_account_id");
132
132
  if (namespacedClaim) return namespacedClaim;
133
133
  }
134
134
  const organizations = claims.organizations;
135
135
  if (Array.isArray(organizations)) {
136
- const firstOrganization = organizations.find(isPlainObject$2);
136
+ const firstOrganization = organizations.find(isPlainObject$3);
137
137
  const organizationId = firstOrganization ? getStringProperty(firstOrganization, "id") : void 0;
138
138
  if (organizationId) return organizationId;
139
139
  }
@@ -143,7 +143,7 @@ function parseJwtClaims(token) {
143
143
  if (!parts || parts.length !== 3 || !parts[1]) return;
144
144
  try {
145
145
  const parsed = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
146
- return isPlainObject$2(parsed) ? parsed : void 0;
146
+ return isPlainObject$3(parsed) ? parsed : void 0;
147
147
  } catch {
148
148
  return;
149
149
  }
@@ -190,7 +190,7 @@ async function readJsonObject(response, label) {
190
190
  } catch (error) {
191
191
  throw new CodexAuthError("invalid_response", `Invalid Codex ${label}: ${formatErrorMessage$4(error)}.`);
192
192
  }
193
- if (!isPlainObject$2(parsed)) throw new CodexAuthError("invalid_response", `Invalid Codex ${label}: expected an object.`);
193
+ if (!isPlainObject$3(parsed)) throw new CodexAuthError("invalid_response", `Invalid Codex ${label}: expected an object.`);
194
194
  return parsed;
195
195
  }
196
196
  function isPendingDeviceAuthResponse(response) {
@@ -214,7 +214,7 @@ function optionalPositiveNumber(value) {
214
214
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
215
215
  return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
216
216
  }
217
- function isPlainObject$2(value) {
217
+ function isPlainObject$3(value) {
218
218
  return typeof value === "object" && value !== null && !Array.isArray(value);
219
219
  }
220
220
  function formatErrorMessage$4(error) {
@@ -325,13 +325,13 @@ async function getAuthStoreStatus(options = {}) {
325
325
  }
326
326
  }
327
327
  function parseAuthStore(path, value) {
328
- if (!isPlainObject$1(value)) throw new AuthStoreError(path, "<root>: expected an object");
328
+ if (!isPlainObject$2(value)) throw new AuthStoreError(path, "<root>: expected an object");
329
329
  if (value.version !== 1) throw new AuthStoreError(path, "version: expected 1");
330
- if (!isPlainObject$1(value.providers)) throw new AuthStoreError(path, "providers: expected an object");
330
+ if (!isPlainObject$2(value.providers)) throw new AuthStoreError(path, "providers: expected an object");
331
331
  const providers = {};
332
332
  for (const [providerId, providerRecord] of Object.entries(value.providers)) {
333
333
  if (!providerId) throw new AuthStoreError(path, "providers: provider id must not be empty");
334
- if (!isPlainObject$1(providerRecord)) throw new AuthStoreError(path, `providers.${providerId}: expected an object`);
334
+ if (!isPlainObject$2(providerRecord)) throw new AuthStoreError(path, `providers.${providerId}: expected an object`);
335
335
  providers[providerId] = parseProviderRecord(path, providerId, providerRecord);
336
336
  }
337
337
  return {
@@ -392,7 +392,7 @@ async function setModeIfSupported(path, mode) {
392
392
  throw error;
393
393
  });
394
394
  }
395
- function isPlainObject$1(value) {
395
+ function isPlainObject$2(value) {
396
396
  return typeof value === "object" && value !== null && !Array.isArray(value);
397
397
  }
398
398
  function isNodeError$4(error) {
@@ -5335,6 +5335,7 @@ function createCodexProviderFetch(options = {}) {
5335
5335
  const providerId = options.providerId ?? "codex";
5336
5336
  const upstreamFetch = options.fetch ?? fetch;
5337
5337
  return (async (input, init) => {
5338
+ const request = await rewriteCodexRequest(input, init);
5338
5339
  const auth = await resolveCodexAuth({
5339
5340
  ...options,
5340
5341
  providerId,
@@ -5344,10 +5345,13 @@ function createCodexProviderFetch(options = {}) {
5344
5345
  headers.delete("authorization");
5345
5346
  headers.set("Authorization", `Bearer ${auth.accessToken}`);
5346
5347
  if (auth.accountId) headers.set("ChatGPT-Account-Id", auth.accountId);
5347
- return upstreamFetch(rewriteCodexRequestUrl(input), {
5348
- ...init,
5348
+ const response = await upstreamFetch(request.input, {
5349
+ ...request.init,
5349
5350
  headers
5350
5351
  });
5352
+ if (request.responseMode === "chat-json") return codexResponsesSseToChatJson(response);
5353
+ if (request.responseMode === "chat-sse") return codexResponsesSseToChatSse(response);
5354
+ return response;
5351
5355
  });
5352
5356
  }
5353
5357
  function rewriteCodexRequestUrl(input) {
@@ -5360,6 +5364,193 @@ function rewriteCodexRequestUrl(input) {
5360
5364
  }
5361
5365
  return input;
5362
5366
  }
5367
+ async function rewriteCodexRequest(input, init) {
5368
+ const rewrittenUrl = rewriteCodexRequestUrl(input);
5369
+ const body = await readJsonBody(init?.body);
5370
+ if (!isChatCompletionsBody(body)) return {
5371
+ input: rewrittenUrl,
5372
+ ...init ? { init } : {}
5373
+ };
5374
+ const stream = body.stream === true;
5375
+ const codexBody = chatCompletionsBodyToCodexResponsesBody(body);
5376
+ const headers = new Headers(init?.headers);
5377
+ headers.set("Content-Type", "application/json");
5378
+ return {
5379
+ input: rewrittenUrl,
5380
+ init: {
5381
+ ...init,
5382
+ headers,
5383
+ body: JSON.stringify(codexBody)
5384
+ },
5385
+ responseMode: stream ? "chat-sse" : "chat-json"
5386
+ };
5387
+ }
5388
+ function chatCompletionsBodyToCodexResponsesBody(body) {
5389
+ const instructions = body.messages.filter((message) => message.role === "system" || message.role === "developer").map((message) => messageContentToText(message.content)).filter((text) => text.trim().length > 0).join("\n\n");
5390
+ const input = body.messages.filter((message) => message.role !== "system" && message.role !== "developer").map(chatMessageToResponseInputItem).filter((item) => item !== void 0);
5391
+ return {
5392
+ model: body.model,
5393
+ instructions: instructions || "You are a helpful assistant.",
5394
+ input,
5395
+ store: false,
5396
+ stream: true,
5397
+ ...typeof body.temperature === "number" ? { temperature: body.temperature } : {},
5398
+ ...typeof body.top_p === "number" ? { top_p: body.top_p } : {},
5399
+ ...typeof body.max_tokens === "number" ? { max_output_tokens: body.max_tokens } : {}
5400
+ };
5401
+ }
5402
+ function chatMessageToResponseInputItem(message) {
5403
+ const text = messageContentToText(message.content);
5404
+ if (!text.trim()) return;
5405
+ return {
5406
+ type: "message",
5407
+ role: message.role === "assistant" ? "assistant" : "user",
5408
+ content: [{
5409
+ type: message.role === "assistant" ? "output_text" : "input_text",
5410
+ text
5411
+ }]
5412
+ };
5413
+ }
5414
+ async function codexResponsesSseToChatJson(response) {
5415
+ if (!response.ok) return response;
5416
+ const parsed = parseCodexResponsesSse(await response.text());
5417
+ const headers = new Headers(response.headers);
5418
+ headers.set("Content-Type", "application/json");
5419
+ return new Response(JSON.stringify({
5420
+ id: parsed.id ?? "codex-response",
5421
+ object: "chat.completion",
5422
+ created: parsed.created ?? Math.floor(Date.now() / 1e3),
5423
+ model: parsed.model ?? "codex",
5424
+ choices: [{
5425
+ index: 0,
5426
+ finish_reason: "stop",
5427
+ message: {
5428
+ role: "assistant",
5429
+ content: parsed.text
5430
+ }
5431
+ }],
5432
+ ...parsed.usage ? { usage: parsed.usage } : {}
5433
+ }), {
5434
+ status: response.status,
5435
+ statusText: response.statusText,
5436
+ headers
5437
+ });
5438
+ }
5439
+ async function codexResponsesSseToChatSse(response) {
5440
+ if (!response.ok) return response;
5441
+ const parsed = parseCodexResponsesSse(await response.text());
5442
+ const encoder = new TextEncoder();
5443
+ const id = parsed.id ?? "codex-response";
5444
+ const created = parsed.created ?? Math.floor(Date.now() / 1e3);
5445
+ const model = parsed.model ?? "codex";
5446
+ const chunks = [
5447
+ {
5448
+ id,
5449
+ object: "chat.completion.chunk",
5450
+ created,
5451
+ model,
5452
+ choices: [{
5453
+ index: 0,
5454
+ delta: { role: "assistant" },
5455
+ finish_reason: null
5456
+ }]
5457
+ },
5458
+ ...(parsed.text.match(/[\s\S]{1,2048}/gu) ?? []).map((delta) => ({
5459
+ id,
5460
+ object: "chat.completion.chunk",
5461
+ created,
5462
+ model,
5463
+ choices: [{
5464
+ index: 0,
5465
+ delta: { content: delta },
5466
+ finish_reason: null
5467
+ }]
5468
+ })),
5469
+ {
5470
+ id,
5471
+ object: "chat.completion.chunk",
5472
+ created,
5473
+ model,
5474
+ choices: [{
5475
+ index: 0,
5476
+ delta: {},
5477
+ finish_reason: "stop"
5478
+ }],
5479
+ ...parsed.usage ? { usage: parsed.usage } : {}
5480
+ }
5481
+ ];
5482
+ const stream = new ReadableStream({ start(controller) {
5483
+ for (const chunk of chunks) controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
5484
+ controller.enqueue(encoder.encode("data: [DONE]\n\n"));
5485
+ controller.close();
5486
+ } });
5487
+ const headers = new Headers(response.headers);
5488
+ headers.set("Content-Type", "text/event-stream");
5489
+ return new Response(stream, {
5490
+ status: response.status,
5491
+ statusText: response.statusText,
5492
+ headers
5493
+ });
5494
+ }
5495
+ function parseCodexResponsesSse(source) {
5496
+ let text = "";
5497
+ let response;
5498
+ for (const event of source.split(/\n\n/u)) {
5499
+ const dataLines = event.split(/\r?\n/u).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
5500
+ if (dataLines.length === 0) continue;
5501
+ const data = dataLines.join("\n");
5502
+ if (data === "[DONE]") continue;
5503
+ const parsed = safeJsonParse(data);
5504
+ if (!isPlainObject$1(parsed)) continue;
5505
+ if (parsed.type === "response.output_text.delta" && typeof parsed.delta === "string") text += parsed.delta;
5506
+ if (parsed.type === "response.completed" && isPlainObject$1(parsed.response)) response = parsed.response;
5507
+ }
5508
+ return {
5509
+ ...typeof response?.id === "string" ? { id: response.id } : {},
5510
+ ...typeof response?.created_at === "number" ? { created: response.created_at } : {},
5511
+ ...typeof response?.model === "string" ? { model: response.model } : {},
5512
+ text,
5513
+ ...normalizeCodexUsage(response?.usage)
5514
+ };
5515
+ }
5516
+ function normalizeCodexUsage(usage) {
5517
+ if (!isPlainObject$1(usage)) return {};
5518
+ const promptTokens = typeof usage.input_tokens === "number" ? usage.input_tokens : void 0;
5519
+ const completionTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : void 0;
5520
+ const totalTokens = typeof usage.total_tokens === "number" ? usage.total_tokens : void 0;
5521
+ return { usage: {
5522
+ ...promptTokens === void 0 ? {} : { prompt_tokens: promptTokens },
5523
+ ...completionTokens === void 0 ? {} : { completion_tokens: completionTokens },
5524
+ ...totalTokens === void 0 ? {} : { total_tokens: totalTokens }
5525
+ } };
5526
+ }
5527
+ async function readJsonBody(body) {
5528
+ if (typeof body !== "string") return;
5529
+ return safeJsonParse(body);
5530
+ }
5531
+ function safeJsonParse(source) {
5532
+ try {
5533
+ return JSON.parse(source);
5534
+ } catch {
5535
+ return;
5536
+ }
5537
+ }
5538
+ function isChatCompletionsBody(value) {
5539
+ return isPlainObject$1(value) && typeof value.model === "string" && Array.isArray(value.messages) && value.messages.every((message) => isPlainObject$1(message) && typeof message.role === "string");
5540
+ }
5541
+ function messageContentToText(content) {
5542
+ if (typeof content === "string") return content;
5543
+ if (!Array.isArray(content)) return "";
5544
+ return content.map((part) => {
5545
+ if (!isPlainObject$1(part)) return "";
5546
+ if (typeof part.text === "string") return part.text;
5547
+ if (typeof part.content === "string") return part.content;
5548
+ return "";
5549
+ }).filter(Boolean).join("\n");
5550
+ }
5551
+ function isPlainObject$1(value) {
5552
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5553
+ }
5363
5554
  async function resolveCodexAuth(options = {}) {
5364
5555
  const providerId = options.providerId ?? "codex";
5365
5556
  const record = (await readAuthStore({ path: options.authStorePath })).providers[providerId];
@@ -6197,7 +6388,8 @@ const openRouterProviderDefaults = {
6197
6388
  };
6198
6389
  const codexProviderDefaults = {
6199
6390
  type: "openai-compatible",
6200
- baseURL: CODEX_BACKEND_BASE_URL
6391
+ baseURL: CODEX_BACKEND_BASE_URL,
6392
+ toolProtocol: "text-json"
6201
6393
  };
6202
6394
  const codexStarterModelChoices = [
6203
6395
  "codex/gpt-5.5",
@@ -15650,4 +15842,4 @@ function formatDryRunSyncStatus(status) {
15650
15842
  //#endregion
15651
15843
  export { runTopchesterCli as t };
15652
15844
 
15653
- //# sourceMappingURL=cli-CqFhOvlt.mjs.map
15845
+ //# sourceMappingURL=cli-D1d-I3Fi.mjs.map