@armadra/agent 0.6.1 → 0.6.2

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/CHANGELOG.zh-CN.md +12 -0
  3. package/dist/agent/session-settings.d.ts +4 -1
  4. package/dist/agent/session-settings.js +7 -2
  5. package/dist/ai/apis/chatgpt-backend.d.ts +7 -2
  6. package/dist/ai/apis/chatgpt-backend.js +12 -4
  7. package/dist/ai/providers/discovered-cache.d.ts +22 -11
  8. package/dist/ai/providers/discovered-cache.js +56 -12
  9. package/dist/ai/providers/registry.js +7 -6
  10. package/dist/ai/types.d.ts +5 -0
  11. package/dist/auth/chatgpt/backend-client.d.ts +11 -2
  12. package/dist/auth/chatgpt/backend-client.js +38 -6
  13. package/dist/auth/chatgpt/cli.d.ts +2 -1
  14. package/dist/auth/chatgpt/cli.js +14 -7
  15. package/dist/auth/chatgpt/follow.d.ts +16 -0
  16. package/dist/auth/chatgpt/follow.js +51 -0
  17. package/dist/auth/chatgpt/presets.d.ts +8 -0
  18. package/dist/auth/chatgpt/presets.js +12 -0
  19. package/dist/auth/testing/fake-oauth.d.ts +4 -1
  20. package/dist/auth/testing/fake-oauth.js +24 -1
  21. package/dist/bundle/ama.cjs +341 -180
  22. package/dist/cli/compose-providers.d.ts +2 -1
  23. package/dist/cli/compose-providers.js +6 -3
  24. package/dist/cli/startup-steps.js +4 -1
  25. package/dist/cli/subcommands/models-discover.d.ts +4 -2
  26. package/dist/cli/subcommands/models-discover.js +40 -8
  27. package/dist/config/json-schema.js +1 -0
  28. package/dist/config/key-docs.js +7 -1
  29. package/dist/config/schema-w6.d.ts +1 -1
  30. package/dist/config/schema-w6.js +2 -1
  31. package/dist/config/types-w6.d.ts +5 -0
  32. package/dist/i18n/catalog.d.ts +7 -0
  33. package/dist/i18n/messages/auth.d.ts +12 -0
  34. package/dist/i18n/messages/auth.js +20 -0
  35. package/dist/i18n/messages/config-keys.d.ts +2 -0
  36. package/dist/i18n/messages/config-keys.js +2 -0
  37. package/dist/i18n/messages/config.d.ts +2 -0
  38. package/docs/en/providers.md +8 -4
  39. package/docs/providers.md +25 -10
  40. package/package.json +1 -1
@@ -41,7 +41,7 @@ var AMA_VERSION;
41
41
  var init_version = __esm({
42
42
  "src/version.ts"() {
43
43
  "use strict";
44
- AMA_VERSION = true ? "0.6.1" : readPackageVersion();
44
+ AMA_VERSION = true ? "0.6.2" : readPackageVersion();
45
45
  }
46
46
  });
47
47
 
@@ -3622,6 +3622,7 @@ var init_config_keys = __esm({
3622
3622
  "auth.chatgpt.clientId": "OAuth client id",
3623
3623
  "auth.chatgpt.issuer": "Authorization server (override with AMA_CHATGPT_ISSUER for tests)",
3624
3624
  "auth.chatgpt.originator": "originator request header for the codex flavor",
3625
+ "auth.chatgpt.codexClientVersion": "Codex CLI version sent as client_version when listing codex-flavor models (the backend hides models newer than it); AMA_CHATGPT_CODEX_CLIENT_VERSION overrides",
3625
3626
  "auth.chatgpt.redirectPorts": "Local callback ports, tried in order; 0 = any free port",
3626
3627
  skills: "Skills",
3627
3628
  "skills.dirs": "Extra skill directories; accumulated across levels",
@@ -3740,6 +3741,7 @@ var init_config_keys = __esm({
3740
3741
  "auth.chatgpt.clientId": "OAuth 客户端 id",
3741
3742
  "auth.chatgpt.issuer": "授权服务器(测试用 AMA_CHATGPT_ISSUER 覆盖)",
3742
3743
  "auth.chatgpt.originator": "codex flavor 的 originator 请求头",
3744
+ "auth.chatgpt.codexClientVersion": "codex flavor 列模型时作为 client_version 发送的 Codex CLI 版本号(后端不给比它新的模型);AMA_CHATGPT_CODEX_CLIENT_VERSION 优先",
3743
3745
  "auth.chatgpt.redirectPorts": "本地回调端口,依次尝试;0 = 任意空闲端口",
3744
3746
  skills: "Skill",
3745
3747
  "skills.dirs": "追加的 Skill 目录;各层累加",
@@ -5114,7 +5116,13 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5114
5116
  siwcLimitHint: "Tip: set a weekly limit for ama in ChatGPT → Settings → Usage → App limits. For personal use only; never share one sign-in between several people.",
5115
5117
  freePlanHint: (plan2) => `Note: the "${plan2}" plan may not include subscription usage for ama.`,
5116
5118
  modelHint: "Use it with --model chatgpt/<model>; list the models your account can use with ama models discover chatgpt.",
5117
- modelsCached: (count2) => `Your account can use ${count2} model(s); pick one with /model or --model chatgpt/<model>.`
5119
+ modelsCached: (count2) => `Your account can use ${count2} model(s); pick one with /model or --model chatgpt/<model>.`,
5120
+ siwcEligibilityHint: "Whether this account can share its plan usage with ama is only confirmed on the first request.",
5121
+ codexNoModels: (version) => `The codex backend returned no models. codexClientVersion (${version}) may be too old: set a newer Codex CLI version with ama config set auth.chatgpt.codexClientVersion <version>, then run ama models discover chatgpt.`
5122
+ },
5123
+ request: {
5124
+ notEligible: "this ChatGPT account cannot share plan usage with ama (403 subscription_sharing_user_not_eligible). Possible causes:\n 1. Plan: plan usage is shared with Plus / Pro only\n 2. Workspace account: Team / Enterprise / Edu workspaces may not offer it\n 3. Region restriction, or not yet rolled out during the preview (most likely when a Pro account still gets this error)\nYou can sign in the other way instead: ama auth login chatgpt --flavor codex",
5125
+ flavorMismatch: (current3, ref, pinned) => `signed in with ${current3}, but ${ref} pins the @${pinned} channel. Drop @${pinned} so the channel follows the sign-in, or run ama auth login chatgpt --flavor ${pinned}`
5118
5126
  },
5119
5127
  errors: {
5120
5128
  portsBusy: (ports, codex) => `callback port ${ports} is in use: finish the other sign-in first, or use --paste${codex ? " / --device" : ""}`,
@@ -5215,7 +5223,13 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5215
5223
  siwcLimitHint: "提示:可在 ChatGPT → 设置 → Usage → App limits 给 ama 设周上限。仅限本人使用,不要让多人共用一个登录。",
5216
5224
  freePlanHint: (plan2) => `注意:「${plan2}」计划可能不含给 ama 用的订阅额度。`,
5217
5225
  modelHint: "用 --model chatgpt/<模型> 使用;账户可用的模型用 ama models discover chatgpt 查看。",
5218
- modelsCached: (count2) => `账户可用 ${count2} 个模型,用 /model 或 --model chatgpt/<模型> 选择。`
5226
+ modelsCached: (count2) => `账户可用 ${count2} 个模型,用 /model 或 --model chatgpt/<模型> 选择。`,
5227
+ siwcEligibilityHint: "这个账户能否把套餐额度共享给 ama,要到首次请求时才能确认。",
5228
+ codexNoModels: (version) => `codex 后端没有返回模型,可能是 codexClientVersion(${version})过旧:用 ama config set auth.chatgpt.codexClientVersion <版本> 设为较新的 Codex CLI 版本,再运行 ama models discover chatgpt。`
5229
+ },
5230
+ request: {
5231
+ notEligible: "这个 ChatGPT 账户不能把套餐额度共享给 ama(403 subscription_sharing_user_not_eligible)。可能的原因:\n 1. 账户套餐:额度共享只对 Plus / Pro 开放\n 2. 工作空间账户:Team / Enterprise / Edu 工作空间可能未开放\n 3. 地区受限,或预览期尚未开放(Pro 账户仍报此错时最可能是这一条)\n可以改用另一种登录方式:ama auth login chatgpt --flavor codex",
5232
+ flavorMismatch: (current3, ref, pinned) => `当前以 ${current3} 方式登录,但 ${ref} 显式指定了 @${pinned} 渠道。去掉 @${pinned} 让渠道跟随登录方式,或运行 ama auth login chatgpt --flavor ${pinned}`
5219
5233
  },
5220
5234
  errors: {
5221
5235
  portsBusy: (ports, codex) => `回调端口 ${ports} 被占用:请先结束其它登录,或用 --paste${codex ? " / --device" : ""}`,
@@ -6410,7 +6424,8 @@ function validateConfigW6(c, config) {
6410
6424
  if (chatgpt === void 0 || !c.object(chatgpt, cp)) return;
6411
6425
  c.keys(chatgpt, cp, CHATGPT_AUTH_KEYS);
6412
6426
  c.oneOf(chatgpt, "flavor", cp, CHATGPT_FLAVORS);
6413
- for (const key of ["clientId", "issuer", "originator"]) c.string(chatgpt, key, cp);
6427
+ for (const key of ["clientId", "issuer", "originator", "codexClientVersion"])
6428
+ c.string(chatgpt, key, cp);
6414
6429
  checkPorts(c, chatgpt, "redirectPorts", cp);
6415
6430
  });
6416
6431
  }
@@ -6477,6 +6492,7 @@ var init_schema_w6 = __esm({
6477
6492
  "clientId",
6478
6493
  "issuer",
6479
6494
  "originator",
6495
+ "codexClientVersion",
6480
6496
  "redirectPorts"
6481
6497
  ];
6482
6498
  }
@@ -9695,6 +9711,113 @@ var init_channels = __esm({
9695
9711
  }
9696
9712
  });
9697
9713
 
9714
+ // src/auth/chatgpt/presets.ts
9715
+ function nonEmpty2(value) {
9716
+ const trimmed = value?.trim();
9717
+ return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
9718
+ }
9719
+ function chatgptBaseUrl(flavor, env = process.env) {
9720
+ return nonEmpty2(env["AMA_CHATGPT_BASE_URL"]) ?? CHATGPT_BASE_URLS[flavor];
9721
+ }
9722
+ function codexClientVersion(config, env = process.env) {
9723
+ return nonEmpty2(env["AMA_CHATGPT_CODEX_CLIENT_VERSION"]) ?? nonEmpty2(config?.codexClientVersion) ?? DEFAULT_CODEX_CLIENT_VERSION;
9724
+ }
9725
+ function resolveChatGptPreset(flavor, overrides = {}) {
9726
+ const env = overrides.env ?? process.env;
9727
+ const config = overrides.config;
9728
+ const issuer = (nonEmpty2(env["AMA_CHATGPT_ISSUER"]) ?? nonEmpty2(config?.issuer) ?? DEFAULT_ISSUER).replace(/\/+$/, "");
9729
+ const sameFlavor = overrides.entry?.flavor === flavor ? overrides.entry : void 0;
9730
+ const explicitClient = nonEmpty2(env["AMA_CHATGPT_CLIENT_ID"]) ?? nonEmpty2(config?.clientId);
9731
+ const ports = overrides.port !== void 0 ? [overrides.port] : config?.redirectPorts !== void 0 && config.redirectPorts.length > 0 ? [...config.redirectPorts] : void 0;
9732
+ if (flavor === "siwc") {
9733
+ const issued = sameFlavor?.clientId !== SIWC_REGISTRATION_CLIENT_ID ? sameFlavor?.clientId : void 0;
9734
+ const clientId = explicitClient ?? issued ?? SIWC_REGISTRATION_CLIENT_ID;
9735
+ return {
9736
+ flavor,
9737
+ issuer,
9738
+ clientId,
9739
+ registering: clientId === SIWC_REGISTRATION_CLIENT_ID,
9740
+ authorizeUrl: `${issuer}/api/accounts/authorize`,
9741
+ tokenUrl: `${issuer}/api/accounts/oauth/token`,
9742
+ scopes: [
9743
+ "openid",
9744
+ "profile",
9745
+ "email",
9746
+ "offline_access",
9747
+ "resource.invoke",
9748
+ SIWC_REQUIRED_SCOPE
9749
+ ],
9750
+ // 端口可变(scheme / host / path 不变):1455 被占用就用任意空闲端口
9751
+ redirectPorts: ports ?? [1455, 0],
9752
+ resource: SIWC_RESOURCE,
9753
+ refreshEncoding: "form",
9754
+ baseUrl: chatgptBaseUrl(flavor, env),
9755
+ verifyIdToken: true,
9756
+ requiredScope: SIWC_REQUIRED_SCOPE,
9757
+ device: false,
9758
+ revoke: true
9759
+ };
9760
+ }
9761
+ return {
9762
+ flavor,
9763
+ issuer,
9764
+ clientId: explicitClient ?? CODEX_CLIENT_ID,
9765
+ registering: false,
9766
+ authorizeUrl: `${issuer}/oauth/authorize`,
9767
+ tokenUrl: `${issuer}/oauth/token`,
9768
+ scopes: ["openid", "profile", "email", "offline_access"],
9769
+ // 公开客户端只登记了这两个端口;被占用不抢占
9770
+ redirectPorts: ports ?? [1455, 1457],
9771
+ refreshEncoding: "json",
9772
+ baseUrl: chatgptBaseUrl(flavor, env),
9773
+ verifyIdToken: false,
9774
+ device: true,
9775
+ revoke: false,
9776
+ originator: nonEmpty2(config?.originator) ?? DEFAULT_ORIGINATOR
9777
+ };
9778
+ }
9779
+ function authorizeUrl(preset, input2) {
9780
+ const params = new URLSearchParams({
9781
+ response_type: "code",
9782
+ client_id: preset.clientId,
9783
+ redirect_uri: input2.redirectUri,
9784
+ scope: preset.scopes.join(" "),
9785
+ code_challenge: input2.challenge,
9786
+ code_challenge_method: "S256",
9787
+ state: input2.state
9788
+ });
9789
+ if (preset.flavor === "siwc") {
9790
+ params.set("nonce", input2.nonce);
9791
+ if (preset.resource !== void 0) params.set("resource", preset.resource);
9792
+ if (input2.hostId !== void 0) params.set("ext_agent_host_id", input2.hostId);
9793
+ if (preset.registering) params.set("agent_name_hint", AGENT_NAME_HINT);
9794
+ } else {
9795
+ params.set("id_token_add_organizations", "true");
9796
+ params.set("codex_cli_simplified_flow", "true");
9797
+ if (preset.originator !== void 0) params.set("originator", preset.originator);
9798
+ }
9799
+ return `${preset.authorizeUrl}?${params.toString()}`;
9800
+ }
9801
+ var CHATGPT_PROVIDER_ID, DEFAULT_ISSUER, SIWC_REGISTRATION_CLIENT_ID, CODEX_CLIENT_ID, SIWC_RESOURCE, SIWC_REQUIRED_SCOPE, AGENT_NAME_HINT, DEFAULT_ORIGINATOR, DEFAULT_CODEX_CLIENT_VERSION, CHATGPT_BASE_URLS;
9802
+ var init_presets = __esm({
9803
+ "src/auth/chatgpt/presets.ts"() {
9804
+ "use strict";
9805
+ CHATGPT_PROVIDER_ID = "chatgpt";
9806
+ DEFAULT_ISSUER = "https://auth.openai.com";
9807
+ SIWC_REGISTRATION_CLIENT_ID = "dynamic_agent_client";
9808
+ CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
9809
+ SIWC_RESOURCE = "https://api.openai.com/v1";
9810
+ SIWC_REQUIRED_SCOPE = "chatgpt.tokens.use.direct";
9811
+ AGENT_NAME_HINT = "ama";
9812
+ DEFAULT_ORIGINATOR = "codex_cli_rs";
9813
+ DEFAULT_CODEX_CLIENT_VERSION = "0.160.0";
9814
+ CHATGPT_BASE_URLS = {
9815
+ siwc: "https://api.openai.com/v1",
9816
+ codex: "https://chatgpt.com/backend-api/codex"
9817
+ };
9818
+ }
9819
+ });
9820
+
9698
9821
  // src/ai/providers/catalog-data.ts
9699
9822
  var CATALOG_SOURCES;
9700
9823
  var init_catalog_data = __esm({
@@ -11802,11 +11925,12 @@ async function resolveModel(args, registry2, manager, defaultModel, deps, intera
11802
11925
  } else {
11803
11926
  const change = lastEntry(manager, (e) => e.type === "model_change");
11804
11927
  if (change?.type === "model_change") {
11928
+ const channel = change.provider === CHATGPT_PROVIDER_ID ? void 0 : change.channel;
11805
11929
  const found = registry2.findModel(
11806
11930
  formatModelRef({
11807
11931
  provider: change.provider,
11808
11932
  id: change.modelId,
11809
- ...change.channel !== void 0 ? { channel: change.channel } : {}
11933
+ ...channel !== void 0 ? { channel } : {}
11810
11934
  })
11811
11935
  );
11812
11936
  if (found.ok) choice3 = { model: found.model, provider: found.provider };
@@ -11883,6 +12007,7 @@ var init_startup_steps = __esm({
11883
12007
  "use strict";
11884
12008
  init_suggest();
11885
12009
  init_channels();
12010
+ init_presets();
11886
12011
  import_node_fs14 = require("node:fs");
11887
12012
  import_node_path16 = require("node:path");
11888
12013
  init_errors();
@@ -16579,7 +16704,7 @@ function resolvePreset(input2) {
16579
16704
  return { preset, codemode, builtin: names.sort(), warnings };
16580
16705
  }
16581
16706
  var CODEMODE_TOOL, PRESET_TOOLS, PresetToolRegistry;
16582
- var init_presets = __esm({
16707
+ var init_presets2 = __esm({
16583
16708
  "src/tools/presets.ts"() {
16584
16709
  "use strict";
16585
16710
  init_capability();
@@ -16939,7 +17064,7 @@ var init_tool_runner = __esm({
16939
17064
  import_node_path35 = require("node:path");
16940
17065
  init_loop_guard();
16941
17066
  init_schema2();
16942
- init_presets();
17067
+ init_presets2();
16943
17068
  init_registry();
16944
17069
  init_truncate();
16945
17070
  ABORTED_TOOL_TEXT = "aborted by user";
@@ -24127,9 +24252,72 @@ var init_session_extensions = __esm({
24127
24252
  }
24128
24253
  });
24129
24254
 
24255
+ // src/auth/oauth/live.ts
24256
+ function registerLiveToken(token, context) {
24257
+ live.delete(token);
24258
+ live.set(token, context);
24259
+ while (live.size > MAX_LIVE) {
24260
+ const oldest = live.keys().next().value;
24261
+ if (oldest === void 0) break;
24262
+ live.delete(oldest);
24263
+ }
24264
+ }
24265
+ function liveToken(token) {
24266
+ return token === void 0 ? void 0 : live.get(token);
24267
+ }
24268
+ var MAX_LIVE, live;
24269
+ var init_live = __esm({
24270
+ "src/auth/oauth/live.ts"() {
24271
+ "use strict";
24272
+ MAX_LIVE = 32;
24273
+ live = /* @__PURE__ */ new Map();
24274
+ }
24275
+ });
24276
+
24277
+ // src/auth/chatgpt/follow.ts
24278
+ function backendOf(compat) {
24279
+ if (typeof compat !== "object" || compat === null) return void 0;
24280
+ const value = compat.chatgptBackend;
24281
+ return value === "siwc" || value === "codex" ? value : void 0;
24282
+ }
24283
+ function followChatGptLogin(model, provider, apiKey) {
24284
+ const current3 = backendOf(model.compat);
24285
+ if (current3 === void 0 || model.channelPinned === true) return model;
24286
+ const flavor = liveToken(apiKey)?.flavor;
24287
+ if (flavor === void 0 || flavor === current3) return model;
24288
+ const channels = provider?.channels ?? [];
24289
+ const target = channels.find((c) => backendOf(c.compat) === flavor) ?? channels.find((c) => c.name === flavor);
24290
+ if (target === void 0) return model;
24291
+ const previous = channels.find((c) => c.name === model.channel);
24292
+ const headers2 = { ...model.headers };
24293
+ for (const name of Object.keys(previous?.headers ?? {})) delete headers2[name];
24294
+ Object.assign(headers2, target.headers);
24295
+ const next = {
24296
+ ...model,
24297
+ api: target.api,
24298
+ baseUrl: target.baseUrl,
24299
+ channel: target.name,
24300
+ compat: { ...model.compat, ...target.compat, chatgptBackend: flavor }
24301
+ };
24302
+ if (Object.keys(headers2).length > 0) next.headers = headers2;
24303
+ else delete next.headers;
24304
+ return next;
24305
+ }
24306
+ var init_follow = __esm({
24307
+ "src/auth/chatgpt/follow.ts"() {
24308
+ "use strict";
24309
+ init_live();
24310
+ }
24311
+ });
24312
+
24130
24313
  // src/agent/session-settings.ts
24131
24314
  function providerStream(providers) {
24132
- return (model, context, streamOptions) => {
24315
+ return (requested, context, streamOptions) => {
24316
+ const model = followChatGptLogin(
24317
+ requested,
24318
+ providers.get(requested.provider),
24319
+ streamOptions.apiKey
24320
+ );
24133
24321
  const api = providers.getApi(model.api);
24134
24322
  if (api === void 0) {
24135
24323
  throw new AmaError("provider_not_found", `no implementation registered for api ${model.api}`);
@@ -24141,6 +24329,7 @@ var SessionSettings;
24141
24329
  var init_session_settings = __esm({
24142
24330
  "src/agent/session-settings.ts"() {
24143
24331
  "use strict";
24332
+ init_follow();
24144
24333
  init_errors();
24145
24334
  init_session_sync();
24146
24335
  SessionSettings = class {
@@ -33625,7 +33814,7 @@ var init_compose_session = __esm({
33625
33814
  init_expand();
33626
33815
  init_index_prompt();
33627
33816
  init_templates();
33628
- init_presets();
33817
+ init_presets2();
33629
33818
  init_compose_store();
33630
33819
  init_compose_extensions();
33631
33820
  init_compose_memory();
@@ -34299,10 +34488,20 @@ var init_token_store = __esm({
34299
34488
  function discoveredCachePath(dataDir, provider) {
34300
34489
  return (0, import_node_path66.join)(dataDir, "models", "discovered", `${provider}.json`);
34301
34490
  }
34302
- function isEntry(value) {
34303
- if (typeof value !== "object" || value === null) return false;
34304
- const { id, name } = value;
34305
- return typeof id === "string" && id !== "" && (name === void 0 || typeof name === "string");
34491
+ function toEntry(value) {
34492
+ if (typeof value !== "object" || value === null) return void 0;
34493
+ const raw = value;
34494
+ const { id, name, contextWindow, input: input2, reasoningLevels } = raw;
34495
+ if (typeof id !== "string" || id === "") return void 0;
34496
+ const out = { id };
34497
+ if (typeof name === "string" && name !== "") out.name = name;
34498
+ if (typeof contextWindow === "number" && Number.isInteger(contextWindow) && contextWindow > 0)
34499
+ out.contextWindow = contextWindow;
34500
+ if (Array.isArray(input2) && input2.includes("text"))
34501
+ out.input = ["text", "image"].filter((x) => input2.includes(x));
34502
+ if (Array.isArray(reasoningLevels) && reasoningLevels.every((x) => typeof x === "string"))
34503
+ out.reasoningLevels = reasoningLevels;
34504
+ return out;
34306
34505
  }
34307
34506
  function readDiscoveredCache(dataDir, provider) {
34308
34507
  let parsed;
@@ -34319,7 +34518,7 @@ function readDiscoveredCache(dataDir, provider) {
34319
34518
  provider,
34320
34519
  fetchedAt: typeof file.fetchedAt === "string" ? file.fetchedAt : "",
34321
34520
  ...typeof file.flavor === "string" ? { flavor: file.flavor } : {},
34322
- models: file.models.filter(isEntry).map((m) => m.name ? { id: m.id, name: m.name } : { id: m.id })
34521
+ models: file.models.map(toEntry).filter((m) => m !== void 0)
34323
34522
  };
34324
34523
  }
34325
34524
  function writeDiscoveredCache(dataDir, provider, input2, now = Date.now()) {
@@ -34329,7 +34528,7 @@ function writeDiscoveredCache(dataDir, provider, input2, now = Date.now()) {
34329
34528
  provider,
34330
34529
  fetchedAt: new Date(now).toISOString(),
34331
34530
  ...input2.flavor !== void 0 ? { flavor: input2.flavor } : {},
34332
- models: input2.models.map((m) => m.name ? { id: m.id, name: m.name } : { id: m.id })
34531
+ models: input2.models.map(toEntry).filter((m) => m !== void 0)
34333
34532
  };
34334
34533
  (0, import_node_fs44.mkdirSync)((0, import_node_path66.dirname)(path), { recursive: true, mode: 448 });
34335
34534
  const tmp = `${path}.${process.pid}.tmp`;
@@ -34344,10 +34543,32 @@ function clearDiscoveredCache(dataDir, provider) {
34344
34543
  (0, import_node_fs44.rmSync)(path, { force: true });
34345
34544
  return true;
34346
34545
  }
34546
+ function thinkingMapOf(levels) {
34547
+ const map = {
34548
+ off: levels.includes("none") ? "none" : null
34549
+ };
34550
+ for (const level of EFFORT_LEVELS) map[level] = levels.includes(level) ? level : null;
34551
+ return map;
34552
+ }
34553
+ function withBackendMetadata(model, cached, matched) {
34554
+ if (model.contextWindow === void 0 && cached.contextWindow !== void 0)
34555
+ model.contextWindow = cached.contextWindow;
34556
+ if (matched) return;
34557
+ if (cached.input !== void 0) model.input = [...cached.input];
34558
+ const efforts = (cached.reasoningLevels ?? []).filter((x) => x !== "none");
34559
+ if (efforts.length > 0) {
34560
+ model.reasoning = true;
34561
+ model.thinkingLevelMap = thinkingMapOf(cached.reasoningLevels ?? []);
34562
+ }
34563
+ }
34347
34564
  function discoveredModels(file, provider, modelsDev) {
34348
34565
  return file.models.map((m) => {
34349
- const { entry } = enrichEntry(m.name ? { id: m.id, name: m.name } : { id: m.id }, modelsDev);
34566
+ const { entry, metadata } = enrichEntry(
34567
+ m.name ? { id: m.id, name: m.name } : { id: m.id },
34568
+ modelsDev
34569
+ );
34350
34570
  const model = withCustomDefaults(entry, provider.id, provider.api);
34571
+ withBackendMetadata(model, m, metadata.match !== void 0);
34351
34572
  const names = (provider.channels ?? []).map((c) => c.name);
34352
34573
  if (names.length > 0) {
34353
34574
  const own = file.flavor !== void 0 && names.includes(file.flavor) ? file.flavor : void 0;
@@ -34356,18 +34577,20 @@ function discoveredModels(file, provider, modelsDev) {
34356
34577
  return model;
34357
34578
  });
34358
34579
  }
34359
- function mergeDiscoveredModels(registry2, dataDir, modelsDev) {
34580
+ function mergeDiscoveredModels(registry2, dataDir, modelsDev, loginFlavor = () => void 0) {
34360
34581
  const merged = [];
34361
34582
  for (const provider of registry2.list()) {
34362
34583
  if (provider.models.length > 0 || !provider.requiresApiKey) continue;
34363
34584
  const file = readDiscoveredCache(dataDir, provider.id);
34364
34585
  if (file === void 0 || file.models.length === 0) continue;
34586
+ const flavor = loginFlavor(provider.id);
34587
+ if (flavor !== void 0 && file.flavor !== void 0 && file.flavor !== flavor) continue;
34365
34588
  registry2.addModels(provider.id, discoveredModels(file, provider, modelsDev), "discovered");
34366
34589
  merged.push(provider.id);
34367
34590
  }
34368
34591
  return merged;
34369
34592
  }
34370
- var import_node_fs44, import_node_path66, DISCOVERED_CACHE_VERSION;
34593
+ var import_node_fs44, import_node_path66, DISCOVERED_CACHE_VERSION, EFFORT_LEVELS;
34371
34594
  var init_discovered_cache = __esm({
34372
34595
  "src/ai/providers/discovered-cache.ts"() {
34373
34596
  "use strict";
@@ -34376,6 +34599,7 @@ var init_discovered_cache = __esm({
34376
34599
  init_catalog2();
34377
34600
  init_enrich();
34378
34601
  DISCOVERED_CACHE_VERSION = 1;
34602
+ EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
34379
34603
  }
34380
34604
  });
34381
34605
 
@@ -34464,109 +34688,6 @@ var init_chatgpt_rate_limits = __esm({
34464
34688
  }
34465
34689
  });
34466
34690
 
34467
- // src/auth/chatgpt/presets.ts
34468
- function nonEmpty2(value) {
34469
- const trimmed = value?.trim();
34470
- return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
34471
- }
34472
- function chatgptBaseUrl(flavor, env = process.env) {
34473
- return nonEmpty2(env["AMA_CHATGPT_BASE_URL"]) ?? CHATGPT_BASE_URLS[flavor];
34474
- }
34475
- function resolveChatGptPreset(flavor, overrides = {}) {
34476
- const env = overrides.env ?? process.env;
34477
- const config = overrides.config;
34478
- const issuer = (nonEmpty2(env["AMA_CHATGPT_ISSUER"]) ?? nonEmpty2(config?.issuer) ?? DEFAULT_ISSUER).replace(/\/+$/, "");
34479
- const sameFlavor = overrides.entry?.flavor === flavor ? overrides.entry : void 0;
34480
- const explicitClient = nonEmpty2(env["AMA_CHATGPT_CLIENT_ID"]) ?? nonEmpty2(config?.clientId);
34481
- const ports = overrides.port !== void 0 ? [overrides.port] : config?.redirectPorts !== void 0 && config.redirectPorts.length > 0 ? [...config.redirectPorts] : void 0;
34482
- if (flavor === "siwc") {
34483
- const issued = sameFlavor?.clientId !== SIWC_REGISTRATION_CLIENT_ID ? sameFlavor?.clientId : void 0;
34484
- const clientId = explicitClient ?? issued ?? SIWC_REGISTRATION_CLIENT_ID;
34485
- return {
34486
- flavor,
34487
- issuer,
34488
- clientId,
34489
- registering: clientId === SIWC_REGISTRATION_CLIENT_ID,
34490
- authorizeUrl: `${issuer}/api/accounts/authorize`,
34491
- tokenUrl: `${issuer}/api/accounts/oauth/token`,
34492
- scopes: [
34493
- "openid",
34494
- "profile",
34495
- "email",
34496
- "offline_access",
34497
- "resource.invoke",
34498
- SIWC_REQUIRED_SCOPE
34499
- ],
34500
- // 端口可变(scheme / host / path 不变):1455 被占用就用任意空闲端口
34501
- redirectPorts: ports ?? [1455, 0],
34502
- resource: SIWC_RESOURCE,
34503
- refreshEncoding: "form",
34504
- baseUrl: chatgptBaseUrl(flavor, env),
34505
- verifyIdToken: true,
34506
- requiredScope: SIWC_REQUIRED_SCOPE,
34507
- device: false,
34508
- revoke: true
34509
- };
34510
- }
34511
- return {
34512
- flavor,
34513
- issuer,
34514
- clientId: explicitClient ?? CODEX_CLIENT_ID,
34515
- registering: false,
34516
- authorizeUrl: `${issuer}/oauth/authorize`,
34517
- tokenUrl: `${issuer}/oauth/token`,
34518
- scopes: ["openid", "profile", "email", "offline_access"],
34519
- // 公开客户端只登记了这两个端口;被占用不抢占
34520
- redirectPorts: ports ?? [1455, 1457],
34521
- refreshEncoding: "json",
34522
- baseUrl: chatgptBaseUrl(flavor, env),
34523
- verifyIdToken: false,
34524
- device: true,
34525
- revoke: false,
34526
- originator: nonEmpty2(config?.originator) ?? DEFAULT_ORIGINATOR
34527
- };
34528
- }
34529
- function authorizeUrl(preset, input2) {
34530
- const params = new URLSearchParams({
34531
- response_type: "code",
34532
- client_id: preset.clientId,
34533
- redirect_uri: input2.redirectUri,
34534
- scope: preset.scopes.join(" "),
34535
- code_challenge: input2.challenge,
34536
- code_challenge_method: "S256",
34537
- state: input2.state
34538
- });
34539
- if (preset.flavor === "siwc") {
34540
- params.set("nonce", input2.nonce);
34541
- if (preset.resource !== void 0) params.set("resource", preset.resource);
34542
- if (input2.hostId !== void 0) params.set("ext_agent_host_id", input2.hostId);
34543
- if (preset.registering) params.set("agent_name_hint", AGENT_NAME_HINT);
34544
- } else {
34545
- params.set("id_token_add_organizations", "true");
34546
- params.set("codex_cli_simplified_flow", "true");
34547
- if (preset.originator !== void 0) params.set("originator", preset.originator);
34548
- }
34549
- return `${preset.authorizeUrl}?${params.toString()}`;
34550
- }
34551
- var CHATGPT_PROVIDER_ID, DEFAULT_ISSUER, SIWC_REGISTRATION_CLIENT_ID, CODEX_CLIENT_ID, SIWC_RESOURCE, SIWC_REQUIRED_SCOPE, AGENT_NAME_HINT, DEFAULT_ORIGINATOR, CHATGPT_BASE_URLS;
34552
- var init_presets2 = __esm({
34553
- "src/auth/chatgpt/presets.ts"() {
34554
- "use strict";
34555
- CHATGPT_PROVIDER_ID = "chatgpt";
34556
- DEFAULT_ISSUER = "https://auth.openai.com";
34557
- SIWC_REGISTRATION_CLIENT_ID = "dynamic_agent_client";
34558
- CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
34559
- SIWC_RESOURCE = "https://api.openai.com/v1";
34560
- SIWC_REQUIRED_SCOPE = "chatgpt.tokens.use.direct";
34561
- AGENT_NAME_HINT = "ama";
34562
- DEFAULT_ORIGINATOR = "codex_cli_rs";
34563
- CHATGPT_BASE_URLS = {
34564
- siwc: "https://api.openai.com/v1",
34565
- codex: "https://chatgpt.com/backend-api/codex"
34566
- };
34567
- }
34568
- });
34569
-
34570
34691
  // src/auth/oauth/token-client.ts
34571
34692
  function oauthErrorCode(body) {
34572
34693
  try {
@@ -34832,6 +34953,7 @@ var init_key_docs = __esm({
34832
34953
  "src/config/key-docs.ts"() {
34833
34954
  "use strict";
34834
34955
  init_http();
34956
+ init_presets();
34835
34957
  init_i18n();
34836
34958
  init_declarations();
34837
34959
  init_merge();
@@ -34854,7 +34976,12 @@ var init_key_docs = __esm({
34854
34976
  subagents: "read"
34855
34977
  },
34856
34978
  auth: {
34857
- chatgpt: { flavor: "siwc", issuer: "https://auth.openai.com", originator: "codex_cli_rs" }
34979
+ chatgpt: {
34980
+ flavor: "siwc",
34981
+ issuer: "https://auth.openai.com",
34982
+ originator: "codex_cli_rs",
34983
+ codexClientVersion: DEFAULT_CODEX_CLIENT_VERSION
34984
+ }
34858
34985
  },
34859
34986
  checkpoints: { ...DEFAULT_CHECKPOINTS_CONFIG },
34860
34987
  sandbox: { enabled: "auto", bash: "off", network: "deny", writable: [] },
@@ -35146,6 +35273,7 @@ function w6Sections() {
35146
35273
  clientId: str3(),
35147
35274
  issuer: str3(),
35148
35275
  originator: str3(),
35276
+ codexClientVersion: str3(),
35149
35277
  redirectPorts: {
35150
35278
  type: "array",
35151
35279
  items: { type: "integer", minimum: 0, maximum: 65535 }
@@ -36168,28 +36296,6 @@ var init_openai_compat = __esm({
36168
36296
  }
36169
36297
  });
36170
36298
 
36171
- // src/auth/oauth/live.ts
36172
- function registerLiveToken(token, context) {
36173
- live.delete(token);
36174
- live.set(token, context);
36175
- while (live.size > MAX_LIVE) {
36176
- const oldest = live.keys().next().value;
36177
- if (oldest === void 0) break;
36178
- live.delete(oldest);
36179
- }
36180
- }
36181
- function liveToken(token) {
36182
- return token === void 0 ? void 0 : live.get(token);
36183
- }
36184
- var MAX_LIVE, live;
36185
- var init_live = __esm({
36186
- "src/auth/oauth/live.ts"() {
36187
- "use strict";
36188
- MAX_LIVE = 32;
36189
- live = /* @__PURE__ */ new Map();
36190
- }
36191
- });
36192
-
36193
36299
  // src/auth/oauth/refresh.ts
36194
36300
  function authExpiredError(provider) {
36195
36301
  return new AmaError(
@@ -36288,7 +36394,7 @@ var init_refresh = __esm({
36288
36394
  "src/auth/oauth/refresh.ts"() {
36289
36395
  "use strict";
36290
36396
  init_errors();
36291
- init_presets2();
36397
+ init_presets();
36292
36398
  init_token_client();
36293
36399
  init_token_store();
36294
36400
  REFRESH_MARGIN_MS = 5 * 6e4;
@@ -36342,8 +36448,10 @@ function chatgptPrecheck(model, compat, apiKey) {
36342
36448
  if (live2 === void 0) return;
36343
36449
  if (live2.needsLogin === true) throw authExpiredError(live2.provider);
36344
36450
  if (live2.flavor !== compat.chatgptBackend) {
36451
+ const pinned = String(compat.chatgptBackend);
36452
+ const ref = `${model.provider}/${model.id}@${pinned}`;
36345
36453
  throw new Error(
36346
- `chatgpt_flavor_mismatch: logged in with ${live2.flavor} but ${model.provider}/${model.id} uses the ${String(compat.chatgptBackend)} channel; run \`ama auth login ${live2.provider} --flavor ${String(compat.chatgptBackend)}\` or switch channel`
36454
+ `chatgpt_flavor_mismatch: ${msg().auth.request.flavorMismatch(live2.flavor, ref, pinned)}`
36347
36455
  );
36348
36456
  }
36349
36457
  }
@@ -36427,9 +36535,7 @@ function recoverChatGptError(error2, model, compat, options, apiKey, tried) {
36427
36535
  if (backend === "siwc" && error2.status === 403 && code === "subscription_sharing_user_not_eligible")
36428
36536
  return {
36429
36537
  kind: "fail",
36430
- error: new Error(
36431
- "not_eligible: this ChatGPT account cannot share plan usage with ama (403 subscription_sharing_user_not_eligible)"
36432
- )
36538
+ error: new Error(`not_eligible: ${msg().auth.request.notEligible}`)
36433
36539
  };
36434
36540
  if (backend === "siwc" && error2.status === 400 && code === "subscription_sharing_unsupported_capability" && !tried.has("strip")) {
36435
36541
  const param = typeof body["param"] === "string" ? body["param"].split(/[.[]/)[0] : void 0;
@@ -36455,6 +36561,7 @@ var init_chatgpt_backend = __esm({
36455
36561
  "use strict";
36456
36562
  init_live();
36457
36563
  init_refresh();
36564
+ init_i18n();
36458
36565
  init_chatgpt_rate_limits();
36459
36566
  SIWC_FORBIDDEN_FIELDS = [
36460
36567
  "background",
@@ -38733,8 +38840,8 @@ var init_registry2 = __esm({
38733
38840
  candidates: available.filter(Boolean).map((c) => `${provider.id}/${model.id}@${c}`)
38734
38841
  };
38735
38842
  }
38736
- if (channel === model.channel) return { ok: true, model, provider };
38737
- return { ok: true, model: this.materialize(provider, model, channel), provider };
38843
+ const picked = channel === model.channel ? model : this.materialize(provider, model, channel);
38844
+ return { ok: true, model: { ...picked, channelPinned: true }, provider };
38738
38845
  }
38739
38846
  /**
38740
38847
  * `provider/model`、`provider/model@渠道` 或裸模型 id。`@` 先按渠道解析(id 里本来就带 `@` 且已登记的
@@ -38763,9 +38870,9 @@ var init_registry2 = __esm({
38763
38870
  const open2 = this.relayed.has(provider.id) || this.openTables.has(provider.id);
38764
38871
  const relayed = provider.models.length === 0 || open2;
38765
38872
  if (synthesize && relayed && id.length > 0) {
38766
- const synthesized = this.synthesize(provider, id);
38767
- if (channel !== void 0 && provider.channels?.some((c) => c.name === channel))
38768
- synthesized.channels = [.../* @__PURE__ */ new Set([...synthesized.channels ?? [], channel])];
38873
+ const known = provider.channels?.some((c) => c.name === channel) ? channel : void 0;
38874
+ const synthesized = this.synthesize(provider, id, known);
38875
+ if (known) synthesized.channels = [.../* @__PURE__ */ new Set([...synthesized.channels ?? [], known])];
38769
38876
  return { ok: true, model: synthesized, provider };
38770
38877
  }
38771
38878
  return { ok: false, reason: "not_found", candidates: this.similar(id, provider.id) };
@@ -46723,7 +46830,7 @@ var init_tool = __esm({
46723
46830
  import_node_fs65 = require("node:fs");
46724
46831
  import_node_os13 = require("node:os");
46725
46832
  import_node_path88 = require("node:path");
46726
- init_presets();
46833
+ init_presets2();
46727
46834
  init_capability();
46728
46835
  init_declarations();
46729
46836
  init_host_side();
@@ -46873,7 +46980,7 @@ var init_codemode_notice = __esm({
46873
46980
  "use strict";
46874
46981
  import_node_fs66 = require("node:fs");
46875
46982
  import_node_path89 = require("node:path");
46876
- init_presets();
46983
+ init_presets2();
46877
46984
  init_i18n();
46878
46985
  NOTICES_FILE = "notices.json";
46879
46986
  KEY = "codemodeNonStrictDefault";
@@ -46959,12 +47066,15 @@ async function buildProviderRegistry(input2, options = {}) {
46959
47066
  }
46960
47067
  if (provider !== void 0) registry2 = make({ provider, apiKey: cli.apiKey });
46961
47068
  }
46962
- if (dataDir !== void 0)
47069
+ if (dataDir !== void 0) {
47070
+ const flavor = readOAuthEntry(input2.authFile, CHATGPT_PROVIDER_ID)?.flavor;
46963
47071
  mergeDiscoveredModels(
46964
47072
  registry2,
46965
47073
  dataDir,
46966
- lazyIndex(() => loadModelsDevIndex(dataDir))
47074
+ lazyIndex(() => loadModelsDevIndex(dataDir)),
47075
+ (id) => id === CHATGPT_PROVIDER_ID ? flavor : void 0
46967
47076
  );
47077
+ }
46968
47078
  const probe = options.probeLocal ?? env[NO_LOCAL_PROBE_ENV] !== "1";
46969
47079
  if (probe && config.defaultModel === void 0 && !anyKeyConfigured(registry2)) {
46970
47080
  await probeLocalProviders(registry2, options.probeTimeoutMs ?? LOCAL_PROBE_TIMEOUT_MS);
@@ -46999,7 +47109,7 @@ var init_compose_providers = __esm({
46999
47109
  init_discovered_cache();
47000
47110
  init_enrich();
47001
47111
  init_token_store();
47002
- init_presets2();
47112
+ init_presets();
47003
47113
  LOCAL_PROBE_TIMEOUT_MS = 300;
47004
47114
  NO_LOCAL_PROBE_ENV = "AMA_NO_LOCAL_PROBE";
47005
47115
  }
@@ -47741,7 +47851,7 @@ var init_model_items = __esm({
47741
47851
  "src/modes/interactive/model-items.ts"() {
47742
47852
  "use strict";
47743
47853
  init_model_visibility();
47744
- init_presets2();
47854
+ init_presets();
47745
47855
  init_i18n();
47746
47856
  HINT_PREFIX = "ama:hint:";
47747
47857
  }
@@ -48951,7 +49061,7 @@ var init_startup_screen = __esm({
48951
49061
  init_builtin3();
48952
49062
  import_node_path92 = require("node:path");
48953
49063
  init_channels();
48954
- init_presets();
49064
+ init_presets2();
48955
49065
  init_i18n();
48956
49066
  init_version();
48957
49067
  }
@@ -54723,7 +54833,7 @@ var init_status_area = __esm({
54723
54833
  init_info();
54724
54834
  init_bash();
54725
54835
  init_detect();
54726
- init_presets();
54836
+ init_presets2();
54727
54837
  init_tui2();
54728
54838
  init_status_bar();
54729
54839
  init_status_line();
@@ -57271,7 +57381,7 @@ var init_compose2 = __esm({
57271
57381
  init_bash();
57272
57382
  import_node_path99 = require("node:path");
57273
57383
  init_paths();
57274
- init_presets();
57384
+ init_presets2();
57275
57385
  init_registry();
57276
57386
  init_tool2();
57277
57387
  init_codemode_notice();
@@ -58811,8 +58921,7 @@ init_discovered_cache();
58811
58921
 
58812
58922
  // src/auth/chatgpt/backend-client.ts
58813
58923
  init_chatgpt_rate_limits();
58814
- init_version();
58815
- init_presets2();
58924
+ init_presets();
58816
58925
  var BACKEND_TIMEOUT_MS = 15e3;
58817
58926
  function headers(auth) {
58818
58927
  const out = {
@@ -58829,9 +58938,29 @@ function listed(item) {
58829
58938
  const visibility = item["visibility"];
58830
58939
  return visibility === void 0 || visibility === "list";
58831
58940
  }
58941
+ function codexMetadata(item) {
58942
+ const out = {};
58943
+ const window2 = item["context_window"];
58944
+ if (typeof window2 === "number" && Number.isInteger(window2) && window2 > 0)
58945
+ out.contextWindow = window2;
58946
+ const modalities = item["input_modalities"];
58947
+ if (Array.isArray(modalities)) {
58948
+ const input2 = ["text", "image"].filter((x) => modalities.includes(x));
58949
+ if (input2.includes("text")) out.input = input2;
58950
+ }
58951
+ const levels = item["supported_reasoning_levels"];
58952
+ if (Array.isArray(levels)) {
58953
+ const efforts = levels.map(
58954
+ (level) => typeof level === "string" ? level : typeof level === "object" && level !== null ? level["effort"] : void 0
58955
+ ).filter((x) => typeof x === "string" && x !== "");
58956
+ if (efforts.length > 0) out.reasoningLevels = [...new Set(efforts)];
58957
+ }
58958
+ return out;
58959
+ }
58832
58960
  async function listChatGptModels(fetchFn, baseUrl, auth) {
58833
58961
  const base4 = baseUrl.replace(/\/+$/, "");
58834
- const url = auth.flavor === "codex" ? `${base4}/models?client_version=${encodeURIComponent(AMA_VERSION)}` : `${base4}/models`;
58962
+ const version = auth.clientVersion ?? DEFAULT_CODEX_CLIENT_VERSION;
58963
+ const url = auth.flavor === "codex" ? `${base4}/models?client_version=${encodeURIComponent(version)}` : `${base4}/models`;
58835
58964
  const response = await fetchFn(url, {
58836
58965
  headers: headers(auth),
58837
58966
  signal: AbortSignal.timeout(BACKEND_TIMEOUT_MS)
@@ -58846,7 +58975,11 @@ async function listChatGptModels(fetchFn, baseUrl, auth) {
58846
58975
  if (typeof id !== "string" || id === "" || seen.has(id)) continue;
58847
58976
  seen.add(id);
58848
58977
  const name = item["display_name"];
58849
- out.push(typeof name === "string" && name !== "" ? { id, name } : { id });
58978
+ out.push({
58979
+ id,
58980
+ ...typeof name === "string" && name !== "" ? { name } : {},
58981
+ ...auth.flavor === "codex" ? codexMetadata(item) : {}
58982
+ });
58850
58983
  }
58851
58984
  return out;
58852
58985
  }
@@ -59299,7 +59432,7 @@ function readOrCreateHostId(dataDir) {
59299
59432
  }
59300
59433
 
59301
59434
  // src/auth/chatgpt/login.ts
59302
- init_presets2();
59435
+ init_presets();
59303
59436
  var DEFAULT_ACCESS_TTL_S = 3600;
59304
59437
  function flowPreset(preset, hostId) {
59305
59438
  return {
@@ -59412,7 +59545,7 @@ async function revokeChatGpt(fetchFn, entry, overrides = {}) {
59412
59545
  }
59413
59546
 
59414
59547
  // src/auth/chatgpt/cli.ts
59415
- init_presets2();
59548
+ init_presets();
59416
59549
  init_quota_text();
59417
59550
  function userAuthConfig(io) {
59418
59551
  try {
@@ -59564,14 +59697,18 @@ async function runLogin(args, io, deps = {}) {
59564
59697
  if (entry.planType === "free") io.stdout(`${m.freePlanHint(entry.planType)}
59565
59698
  `);
59566
59699
  if (flavor === "siwc") io.stdout(`${m.siwcLimitHint}
59700
+ ${m.siwcEligibilityHint}
59567
59701
  `);
59568
59702
  const count2 = await cacheModels(io, entry, config, deps);
59569
- io.stdout(`${count2 === void 0 ? m.modelHint : m.modelsCached(count2)}
59703
+ const done = count2 === 0 && flavor === "codex" ? m.codexNoModels(codexClientVersion(config, io.env)) : count2 === void 0 || count2 === 0 ? m.modelHint : m.modelsCached(count2);
59704
+ io.stdout(`${done}
59570
59705
  `);
59571
59706
  return ExitCode.Ok;
59572
59707
  }
59573
59708
  async function cacheModels(io, entry, config, deps) {
59709
+ const dataDir = resolveDataDir({ env: io.env });
59574
59710
  try {
59711
+ clearDiscoveredCache(dataDir, CHATGPT_PROVIDER_ID);
59575
59712
  const models = await listChatGptModels(
59576
59713
  deps.fetch ?? fetch,
59577
59714
  chatgptBaseUrl(entry.flavor, io.env),
@@ -59579,11 +59716,10 @@ async function cacheModels(io, entry, config, deps) {
59579
59716
  flavor: entry.flavor,
59580
59717
  accessToken: entry.accessToken,
59581
59718
  accountId: entry.accountId,
59582
- originator: config?.originator
59719
+ originator: config?.originator,
59720
+ clientVersion: codexClientVersion(config, io.env)
59583
59721
  }
59584
59722
  );
59585
- if (models.length === 0) return void 0;
59586
- const dataDir = resolveDataDir({ env: io.env });
59587
59723
  writeDiscoveredCache(dataDir, CHATGPT_PROVIDER_ID, { models, flavor: entry.flavor });
59588
59724
  return models.length;
59589
59725
  } catch {
@@ -59790,7 +59926,7 @@ init_types2();
59790
59926
  init_capability();
59791
59927
  init_registry2();
59792
59928
  init_auth_file();
59793
- init_presets();
59929
+ init_presets2();
59794
59930
  init_registry();
59795
59931
  init_args();
59796
59932
  init_default_model();
@@ -60424,7 +60560,7 @@ init_types_w6();
60424
60560
 
60425
60561
  // src/auth/chatgpt/doctor.ts
60426
60562
  init_i18n();
60427
- init_presets2();
60563
+ init_presets();
60428
60564
  init_quota_text();
60429
60565
  async function oauthDoctorLines(provider, entry, options = {}) {
60430
60566
  const m = msg().auth;
@@ -60891,7 +61027,7 @@ var CACHE_PROBE_ACTION = {
60891
61027
 
60892
61028
  // src/cli/subcommands/models-discover.ts
60893
61029
  init_http();
60894
- init_presets2();
61030
+ init_presets();
60895
61031
  init_live();
60896
61032
  init_registry2();
60897
61033
  init_discovered_cache();
@@ -61160,11 +61296,18 @@ async function discoverModels(provider, apiKey, options = {}) {
61160
61296
  flavor,
61161
61297
  accessToken: apiKey,
61162
61298
  accountId: live2?.accountId,
61163
- originator: channel?.headers?.["originator"]
61299
+ originator: channel?.headers?.["originator"],
61300
+ clientVersion: options.codexClientVersion
61164
61301
  });
61165
61302
  return models.map((m) => {
61166
61303
  const model = withCustomDefaults({ id: m.id }, provider.id, provider.api);
61167
61304
  if (m.name !== void 0) model.name = m.name;
61305
+ if (m.contextWindow !== void 0) model.contextWindow = m.contextWindow;
61306
+ if (m.input !== void 0) model.input = m.input;
61307
+ if (m.reasoningLevels?.some((x) => x !== "none") === true) {
61308
+ model.reasoning = true;
61309
+ model.thinkingLevelMap = thinkingMapOf(m.reasoningLevels);
61310
+ }
61168
61311
  return model;
61169
61312
  });
61170
61313
  }
@@ -61279,7 +61422,9 @@ async function run6(ctx) {
61279
61422
  }
61280
61423
  let found;
61281
61424
  try {
61282
- found = await discoverModels(provider, key.apiKey);
61425
+ found = await discoverModels(provider, key.apiKey, {
61426
+ codexClientVersion: codexClientVersion(ctx.level.merged.config.auth?.chatgpt, io.env)
61427
+ });
61283
61428
  } catch (error2) {
61284
61429
  io.stderr(m.listFailed(provider.id, error2.message));
61285
61430
  return ExitCode.RuntimeError;
@@ -61345,14 +61490,30 @@ async function run6(ctx) {
61345
61490
  }
61346
61491
  return ExitCode.Ok;
61347
61492
  }
61493
+ function cacheEntry(m) {
61494
+ const entry = { id: m.id };
61495
+ if (m.name !== m.id) entry.name = m.name;
61496
+ if (m.contextWindow !== void 0) entry.contextWindow = m.contextWindow;
61497
+ if (m.input.length !== 1 || m.input[0] !== "text") entry.input = [...m.input];
61498
+ if (m.reasoning && m.thinkingLevelMap !== void 0)
61499
+ entry.reasoningLevels = Object.entries(m.thinkingLevelMap).flatMap(
61500
+ ([level, value]) => typeof value !== "string" ? [] : level === "off" ? ["none"] : [level]
61501
+ );
61502
+ return entry;
61503
+ }
61348
61504
  function cacheChatGpt(ctx, found, apiKey) {
61505
+ const flavor = liveToken(apiKey)?.flavor;
61349
61506
  try {
61350
- const flavor = liveToken(apiKey)?.flavor;
61351
- const models = found.map((m) => ({ id: m.id, ...m.name !== m.id ? { name: m.name } : {} }));
61507
+ const models = found.map(cacheEntry);
61352
61508
  const path = writeDiscoveredCache(ctx.level.dataDir, CHATGPT_PROVIDER_ID, { models, flavor });
61353
61509
  ctx.io.stdout(msg().subcommands.discover.cached(path));
61354
61510
  } catch (error2) {
61355
61511
  ctx.io.stderr(`ama: ${error2.message}
61512
+ `);
61513
+ }
61514
+ if (found.length === 0 && flavor === "codex") {
61515
+ const version = codexClientVersion(ctx.level.merged.config.auth?.chatgpt, ctx.io.env);
61516
+ ctx.io.stderr(`${msg().auth.login.codexNoModels(version)}
61356
61517
  `);
61357
61518
  }
61358
61519
  }