@jeffreycao/copilot-api 2.2.10 → 2.2.12

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 CHANGED
@@ -264,6 +264,42 @@ enabled = false
264
264
  >
265
265
  > For third-party models that do not support `tool_search`, we recommend disabling features.apps. Otherwise, each prompt may consume an additional 20,000 or more tokens.
266
266
 
267
+ ### If Codex Is Not Signed In to a GPT Account
268
+
269
+ ```toml
270
+ [model_providers.copilot_api]
271
+ name = "OpenAI"
272
+ base_url = "http://localhost:4141"
273
+ requires_openai_auth = false
274
+ supports_websockets = false
275
+ wire_api = "responses"
276
+ request_max_retries = 3
277
+ stream_max_retries = 3
278
+ stream_idle_timeout_ms = 300000
279
+
280
+ [model_providers.copilot_api.auth]
281
+ command = "powershell.exe"
282
+ args = [
283
+ "-NoProfile",
284
+ "-NonInteractive",
285
+ "-Command",
286
+ "[Console]::Out.Write($env:GITHUB_COPILOT_API_KEY)"
287
+ ]
288
+ ```
289
+
290
+ macOS, replace the `auth` block with:
291
+
292
+ ```toml
293
+ [model_providers.copilot_api.auth]
294
+ command = "/bin/zsh"
295
+ args = [
296
+ "-c",
297
+ "printf '%s' \"$GITHUB_COPILOT_API_KEY\""
298
+ ]
299
+ ```
300
+
301
+ Without this configuration, Codex cannot fetch `/v1/models` while not signed in to a GPT account, so custom models are unavailable in the model picker.
302
+
267
303
  When a Codex client (`User-Agent` starts with `codex`) requests the top-level `GET /v1/models`, the gateway merges native Codex models with models available through the Messages adapter. The latter advertise `use_responses_lite: true`: `/v1/responses` uses **Responses → Messages** for Anthropic providers, while OpenAI-compatible providers and Chat-only Copilot models reuse the existing Messages route for **Responses → Messages → Chat Completions**, then translate streaming or JSON results back to Responses.
268
304
 
269
305
  The merged catalog is what Codex shows in its model picker, including the models exposed by your configured providers:
package/README.zh-CN.md CHANGED
@@ -280,6 +280,42 @@ enabled = false
280
280
  >
281
281
  > 对于不支持 `tool_search` 的第三方模型,我们建议禁用 features.apps。否则,每个提示可能会额外消耗 20,000 多个 token。
282
282
 
283
+ ### Codex 未登录 GPT 账号时
284
+
285
+ ```toml
286
+ [model_providers.copilot_api]
287
+ name = "OpenAI"
288
+ base_url = "http://localhost:4141"
289
+ requires_openai_auth = false
290
+ supports_websockets = false
291
+ wire_api = "responses"
292
+ request_max_retries = 3
293
+ stream_max_retries = 3
294
+ stream_idle_timeout_ms = 300000
295
+
296
+ [model_providers.copilot_api.auth]
297
+ command = "powershell.exe"
298
+ args = [
299
+ "-NoProfile",
300
+ "-NonInteractive",
301
+ "-Command",
302
+ "[Console]::Out.Write($env:GITHUB_COPILOT_API_KEY)"
303
+ ]
304
+ ```
305
+
306
+ macOS 将 `auth` 段替换为:
307
+
308
+ ```toml
309
+ [model_providers.copilot_api.auth]
310
+ command = "/bin/zsh"
311
+ args = [
312
+ "-c",
313
+ "printf '%s' \"$GITHUB_COPILOT_API_KEY\""
314
+ ]
315
+ ```
316
+
317
+ 未按上述方式配置时,Codex 未登录 GPT 账号拉不到 `/v1/models`,无法选择自定义模型。
318
+
283
319
  Codex 客户端(`User-Agent` 以 `codex` 开头)请求顶层 `GET /v1/models` 时,网关会把原生 Codex 模型与可通过 Messages 适配的模型合并返回。后者会声明 `use_responses_lite: true`:调用 `/v1/responses` 后,Anthropic provider 走 **Responses → Messages**,OpenAI 兼容 provider 以及只支持 Chat 的 Copilot 模型则复用现有 Messages 路由继续走 **Responses → Messages → Chat Completions**,最终统一翻译回 Responses(包括流式事件)。
284
320
 
285
321
  合并后的模型列表会直接展示在 Codex 的模型选择界面中,包含各 provider 暴露的模型:
package/dist/main.js CHANGED
@@ -30,7 +30,7 @@ if (isMcpFastPath(process.argv)) {
30
30
  const { auth } = await import("./auth-C-RWNXGU.js");
31
31
  const { debug } = await import("./debug-41w6Whae.js");
32
32
  const { mcp } = await import("./mcp-fpSlKZxK.js");
33
- const { start } = await import("./start-tknmnmUA.js");
33
+ const { start } = await import("./start-CJ6z_8Pn.js");
34
34
  await runMain(defineCommand({
35
35
  meta: {
36
36
  name: "copilot-api",
@@ -576,9 +576,19 @@ const builtinProviderModelRegistry = new class BuiltinProviderModelRegistry {
576
576
  inputModalities: ["text"],
577
577
  maxOutputTokens: 64e3,
578
578
  pricing: {
579
- cachedInput: .02,
580
- input: 1,
581
- output: 2
579
+ cachedInput: .1,
580
+ input: 3,
581
+ output: 9
582
+ }
583
+ },
584
+ "deepseek-v4-flash-vision-exp": {
585
+ contextWindow: 1e6,
586
+ inputModalities: ["text", "image"],
587
+ maxOutputTokens: 64e3,
588
+ pricing: {
589
+ cachedInput: .1,
590
+ input: 3,
591
+ output: 9
582
592
  }
583
593
  },
584
594
  "deepseek-v4-pro": {
@@ -586,9 +596,9 @@ const builtinProviderModelRegistry = new class BuiltinProviderModelRegistry {
586
596
  inputModalities: ["text"],
587
597
  maxOutputTokens: 64e3,
588
598
  pricing: {
589
- cachedInput: .025,
590
- input: 3,
591
- output: 6
599
+ cachedInput: .3,
600
+ input: 9,
601
+ output: 27
592
602
  }
593
603
  }
594
604
  },
@@ -661,19 +671,34 @@ const builtinProviderModelRegistry = new class BuiltinProviderModelRegistry {
661
671
  inputModalities: ["text"],
662
672
  maxOutputTokens: 64e3,
663
673
  pricing: {
664
- cachedInput: .0028,
665
- input: .14,
666
- output: .28
674
+ cachedInput: .007,
675
+ input: .22,
676
+ output: .66
667
677
  }
668
678
  },
679
+ "deepseek-v4-flash-vision-exp": {
680
+ contextWindow: 1e6,
681
+ inputModalities: ["text", "image"],
682
+ maxOutputTokens: 384e3,
683
+ pricing: {
684
+ cachedInput: .007,
685
+ input: .22,
686
+ output: .66
687
+ },
688
+ reasoningEfforts: [
689
+ "low",
690
+ "high",
691
+ "max"
692
+ ]
693
+ },
669
694
  "deepseek-v4-pro": {
670
695
  contextWindow: 1e6,
671
696
  inputModalities: ["text"],
672
697
  maxOutputTokens: 64e3,
673
698
  pricing: {
674
- cachedInput: .0145,
675
- input: 1.74,
676
- output: 3.48
699
+ cachedInput: .022,
700
+ input: .66,
701
+ output: 1.98
677
702
  }
678
703
  },
679
704
  "kimi-k2.7-code": {
@@ -781,6 +806,21 @@ const builtinProviderModelRegistry = new class BuiltinProviderModelRegistry {
781
806
  maxInputTokens: 512e3,
782
807
  output: 2.4
783
808
  }] }
809
+ },
810
+ "ox-alpha-free": {
811
+ contextWindow: 1e6,
812
+ inputModalities: ["text", "image"],
813
+ maxOutputTokens: 131072,
814
+ pricing: {
815
+ cachedInput: 0,
816
+ input: 0,
817
+ output: 0
818
+ },
819
+ reasoningEfforts: [
820
+ "low",
821
+ "high",
822
+ "max"
823
+ ]
784
824
  }
785
825
  },
786
826
  kimi: {
@@ -8440,6 +8480,14 @@ const MESSAGES_COMPACTION_PROMPT = [
8440
8480
  "",
8441
8481
  compactTextOnlyGuard
8442
8482
  ].join("\n");
8483
+ const MESSAGES_TOOL_CALL_TIPS = [
8484
+ "# Tool Call Tips",
8485
+ "- Do NOT call `exec_command` directly; that tool does not exist. Use `functions__exec` to run commands instead.",
8486
+ "- The functions__exec tool accepts parameters only as {\"input\":\"...\"}; put the complete executable code inside input, including properly constructed tools.exec_command(...) calls and text(...) output handling.",
8487
+ "- Construct all tools.exec_command(...) arguments strictly according to its tool definition, and use OS/shell-compatible commands for Windows, Linux, and macOS.",
8488
+ "- Always assign the awaited tools.exec_command(...) call to a variable, then forward its output with text(result.output) and inspect result.exit_code; unforwarded output is silently dropped and makes results look empty.",
8489
+ "- Read files with the OS-native command (Get-Content/Test-Path on Windows PowerShell, cat/ls on POSIX), quote paths containing spaces, and verify the forwarded output is non-empty before concluding a file was read."
8490
+ ].join("\n");
8443
8491
  const COMPACTION_REPLAY_PROMPT = "The previous conversation was compacted. Continue from this handoff summary:\n\n";
8444
8492
  const MAX_DEVELOPER_PROMPTS = 5;
8445
8493
  const TOOL_NAME_PATTERN = /^[A-Za-z0-9_-]{1,64}$/u;
@@ -8460,7 +8508,7 @@ var ResponsesMessagesTranslationError = class extends Error {
8460
8508
  function translateResponsesToMessages(payload, options) {
8461
8509
  const registry = createToolRegistry(payload);
8462
8510
  const normalized = normalizeResponsesInput(payload.input);
8463
- const { messages, system } = translateInputToAnthropic(normalized.input, registry, payload.instructions, payload.input);
8511
+ const { messages, system } = translateInputToAnthropic(normalized.input, registry, payload.instructions, payload.input, options.toolCallTips ?? false);
8464
8512
  if (normalized.compaction) messages.push({
8465
8513
  role: "user",
8466
8514
  content: MESSAGES_COMPACTION_PROMPT
@@ -8649,17 +8697,11 @@ function registerMessagesTool(registration, registry) {
8649
8697
  const originalKey = createOriginalToolKey(registration);
8650
8698
  const existing = registry.byOriginal.get(originalKey);
8651
8699
  if (existing) return existing;
8652
- const alias = createToolAlias(registration.namespace ? `${registration.namespace.replaceAll(".", "_")}__${registration.name}` : registration.name, originalKey, registry);
8653
- const descriptor = {
8654
- alias,
8655
- kind: registration.kind,
8656
- name: registration.name,
8657
- ...registration.namespace ? { namespace: registration.namespace } : {}
8658
- };
8659
- registry.byAlias.set(alias, descriptor);
8700
+ const descriptor = createMessagesToolDescriptor(registration, registry);
8701
+ registry.byAlias.set(descriptor.alias, descriptor);
8660
8702
  registry.byOriginal.set(originalKey, descriptor);
8661
8703
  registry.tools.push({
8662
- name: alias,
8704
+ name: descriptor.alias,
8663
8705
  ...registration.description ? { description: registration.description } : {},
8664
8706
  input_schema: registration.kind === "custom" ? CUSTOM_TOOL_INPUT_SCHEMA : registration.parameters ?? {
8665
8707
  type: "object",
@@ -8669,7 +8711,16 @@ function registerMessagesTool(registration, registry) {
8669
8711
  });
8670
8712
  return descriptor;
8671
8713
  }
8672
- function translateInputToAnthropic(input, registry, instructions, originalInput) {
8714
+ function createMessagesToolDescriptor(registration, registry) {
8715
+ const originalKey = createOriginalToolKey(registration);
8716
+ return {
8717
+ alias: createToolAlias(registration.namespace ? `${registration.namespace.replaceAll(".", "_")}__${registration.name}` : registration.name, originalKey, registry),
8718
+ kind: registration.kind,
8719
+ name: registration.name,
8720
+ ...registration.namespace ? { namespace: registration.namespace } : {}
8721
+ };
8722
+ }
8723
+ function translateInputToAnthropic(input, registry, instructions, originalInput, toolCallTips) {
8673
8724
  const messages = [];
8674
8725
  const system = [];
8675
8726
  if (instructions?.trim()) system.push({
@@ -8677,20 +8728,29 @@ function translateInputToAnthropic(input, registry, instructions, originalInput)
8677
8728
  text: instructions
8678
8729
  });
8679
8730
  appendDeveloperPrompts(system, originalInput);
8680
- if (typeof input === "string") {
8681
- messages.push({
8682
- role: "user",
8683
- content: input
8684
- });
8685
- return {
8686
- messages,
8687
- system
8688
- };
8689
- }
8690
- if (!Array.isArray(input)) return {
8731
+ if (typeof input === "string") messages.push({
8732
+ role: "user",
8733
+ content: input
8734
+ });
8735
+ else if (Array.isArray(input)) translateInputItems(input, messages, system, registry);
8736
+ if (toolCallTips) appendToolCallTips(system);
8737
+ return {
8691
8738
  messages,
8692
8739
  system
8693
8740
  };
8741
+ }
8742
+ function appendToolCallTips(system) {
8743
+ const lastSystemBlock = system.at(-1);
8744
+ if (!lastSystemBlock) {
8745
+ system.push({
8746
+ type: "text",
8747
+ text: MESSAGES_TOOL_CALL_TIPS
8748
+ });
8749
+ return;
8750
+ }
8751
+ lastSystemBlock.text = `${lastSystemBlock.text}\n\n${MESSAGES_TOOL_CALL_TIPS}`;
8752
+ }
8753
+ function translateInputItems(input, messages, system, registry) {
8694
8754
  let userMessageSeen = false;
8695
8755
  for (const item of input) {
8696
8756
  const type = getItemType(item);
@@ -8726,10 +8786,6 @@ function translateInputToAnthropic(input, registry, instructions, originalInput)
8726
8786
  default: throw new ResponsesMessagesTranslationError(`Responses Messages fallback does not support input item type '${type}'`);
8727
8787
  }
8728
8788
  }
8729
- return {
8730
- messages,
8731
- system
8732
- };
8733
8789
  }
8734
8790
  function translateInputMessage(item, messages, system, userMessageSeen) {
8735
8791
  if (!isRecord(item)) throw new ResponsesMessagesTranslationError("Invalid Responses message item");
@@ -8794,11 +8850,12 @@ function translateInputReasoning(item, messages) {
8794
8850
  }
8795
8851
  function translateInputToolCall(item, kind, messages, registry) {
8796
8852
  if (!isRecord(item)) throw new ResponsesMessagesTranslationError("Invalid Responses tool call item");
8797
- const descriptor = registerMessagesTool({
8853
+ const toolIdentity = {
8798
8854
  kind,
8799
8855
  name: requireStringField(item, "name", `${kind}_tool_call`),
8800
8856
  namespace: getOptionalStringField(item, "namespace") ?? void 0
8801
- }, registry);
8857
+ };
8858
+ const descriptor = registry.byOriginal.get(createOriginalToolKey(toolIdentity)) ?? createMessagesToolDescriptor(toolIdentity, registry);
8802
8859
  const input = kind === "custom" ? { input: getStringField(item, "input") ?? "" } : parseFunctionArguments(getStringField(item, "arguments") ?? "{}", `${kind}_tool_call.arguments`);
8803
8860
  appendAssistantBlock(messages, {
8804
8861
  type: "tool_use",
@@ -9938,13 +9995,15 @@ async function handleResponsesViaMessages(c, options) {
9938
9995
  model: options.publicModel
9939
9996
  }, {
9940
9997
  model: options.targetModel,
9941
- publicModel: options.publicModel
9998
+ publicModel: options.publicModel,
9999
+ toolCallTips: isCodexUserAgent(c.req.header("user-agent"))
9942
10000
  });
9943
10001
  const context = translation;
9944
10002
  debugJson(logger$3, "Translated Messages request:", {
9945
10003
  payload: translation.messagesPayload,
9946
10004
  publicModel: options.publicModel,
9947
- targetModel: options.targetModel
10005
+ targetModel: options.targetModel,
10006
+ userAgent: c.req.header("user-agent") ?? ""
9948
10007
  });
9949
10008
  const messagesResponse = await responsesMessagesDependencies.handleCompletionPayload(c, translation.messagesPayload, {
9950
10009
  compactType: translation.compaction ? 1 : void 0,
@@ -10514,4 +10573,4 @@ server.route("/:provider/images", providerImageRoutes);
10514
10573
  //#endregion
10515
10574
  export { server };
10516
10575
 
10517
- //# sourceMappingURL=server-DEEWMydw.js.map
10576
+ //# sourceMappingURL=server-C3DnUZoh.js.map