@zqagent/core 0.3.10 → 0.3.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.
Files changed (37) hide show
  1. package/dist/{TurnEngine-BPKhWuSI.d.cts → TurnEngine-BSciNywD.d.cts} +23 -4
  2. package/dist/{TurnEngine-DtGEuVLT.d.ts → TurnEngine-BU4R7q_0.d.ts} +23 -4
  3. package/dist/index.cjs +144 -21
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +53 -4
  6. package/dist/index.d.ts +53 -4
  7. package/dist/index.js +142 -21
  8. package/dist/index.js.map +1 -1
  9. package/dist/internal/engine/FileLogHook.d.cts +2 -1
  10. package/dist/internal/engine/FileLogHook.d.ts +2 -1
  11. package/dist/internal/llmConfig.cjs +15 -0
  12. package/dist/internal/llmConfig.cjs.map +1 -1
  13. package/dist/internal/llmConfig.d.cts +15 -0
  14. package/dist/internal/llmConfig.d.ts +15 -0
  15. package/dist/internal/llmConfig.js +15 -0
  16. package/dist/internal/llmConfig.js.map +1 -1
  17. package/dist/internal/providers/diagnostics.cjs +39 -5
  18. package/dist/internal/providers/diagnostics.cjs.map +1 -1
  19. package/dist/internal/providers/diagnostics.d.cts +35 -3
  20. package/dist/internal/providers/diagnostics.d.ts +35 -3
  21. package/dist/internal/providers/diagnostics.js +34 -4
  22. package/dist/internal/providers/diagnostics.js.map +1 -1
  23. package/dist/internal/providers/models.cjs.map +1 -1
  24. package/dist/internal/providers/models.js.map +1 -1
  25. package/dist/internal/update/controller.cjs +2 -2
  26. package/dist/internal/update/controller.cjs.map +1 -1
  27. package/dist/internal/update/controller.js +1 -1
  28. package/dist/internal/update/platform.cjs +2 -2
  29. package/dist/internal/update/platform.cjs.map +1 -1
  30. package/dist/internal/update/platform.js +1 -1
  31. package/dist/tools/explore.cjs +76 -4
  32. package/dist/tools/explore.cjs.map +1 -1
  33. package/dist/tools/explore.d.cts +2 -1
  34. package/dist/tools/explore.d.ts +2 -1
  35. package/dist/tools/explore.js +76 -4
  36. package/dist/tools/explore.js.map +1 -1
  37. package/package.json +4 -3
@@ -1,5 +1,6 @@
1
1
  import { T as TokenUsage, M as Message, a as ToolSchema, R as ReasoningEffort, S as StreamChunk, b as MessageAttachment, c as StoredAttachment } from './types-BYyXWWPW.cjs';
2
2
  import { a as ToolMetadata, T as ToolRegistry } from './ToolRegistry-DouDvn9E.cjs';
3
+ import { ApiMode } from './internal/providers/diagnostics.cjs';
3
4
  import { ChatCompletionMessageParam } from 'openai/resources/chat/completions.js';
4
5
  import { RequestOptions } from 'openai/core.mjs';
5
6
  import { ModelCapability } from '@zqagent/shared/model-capabilities';
@@ -344,22 +345,40 @@ declare class OpenAIProvider implements ProviderClient {
344
345
  private _logDir?;
345
346
  /** 服务端点 baseURL(用于识别 DeepSeek 等特定供应商) */
346
347
  private _baseURL;
347
- /** 模型 → API 模式缓存:某模型不支持 Responses 后,后续直走 Chat */
348
- private _modeByModel;
348
+ /**
349
+ * 本实例的 API 模式。
350
+ *
351
+ * 显式配置 > 全局 `OPENAI_FORCE_API_MODE` > auto(先 Responses 再降级)。
352
+ * 早先只有全局环境变量一种表达方式,一个节点挂两家供应商时无法各自指定。
353
+ */
354
+ private _apiMode;
349
355
  constructor(opts: {
350
356
  apiKey?: string;
351
357
  baseURL?: string;
352
358
  /** LLM 请求日志根目录,按日期分目录,不传则不记录 */
353
359
  logDir?: string;
360
+ /**
361
+ * 单次请求超时(毫秒)。缺省/非法时回落到 `OPENAI_TIMEOUT_MS`,再回落 10 分钟。
362
+ *
363
+ * 必须能按供应商设置:推理模型的合理预算与普通模型差一个数量级,共用一个全局值
364
+ * 只能二选一(慢模型被掐断,或快模型失败时干等十分钟)。
365
+ */
366
+ timeoutMs?: number | null;
367
+ /**
368
+ * API 模式(auto / responses / chat)。缺省时读 `OPENAI_FORCE_API_MODE`,再缺省 auto。
369
+ */
370
+ apiMode?: ApiMode | null;
354
371
  });
355
372
  /**
356
373
  * 解析指定模型的 API 模式。
357
374
  *
358
- * 优先级:环境变量 OPENAI_FORCE_API_MODE(responses|chat)强制指定
359
- * > 运行时降级缓存(该模型曾因"不支持"失败而缓存为 chat)
375
+ * 优先级:本实例的显式配置(responses|chat)
376
+ * > 运行时降级缓存(该端点+模型曾因"不支持"失败而缓存为 chat)
360
377
  * > 默认 responses(Responses 优先)。
361
378
  */
362
379
  private _resolveMode;
380
+ /** 记录「该端点+模型不支持 Responses」,后续同进程内的请求直走 Chat */
381
+ private _markChatMode;
363
382
  /**
364
383
  * Responses 失败的分类(决定「能不能改走 Chat Completions」以及要不要缓存降级)。
365
384
  *
@@ -1,5 +1,6 @@
1
1
  import { T as TokenUsage, M as Message, a as ToolSchema, R as ReasoningEffort, S as StreamChunk, b as MessageAttachment, c as StoredAttachment } from './types-BYyXWWPW.js';
2
2
  import { a as ToolMetadata, T as ToolRegistry } from './ToolRegistry-Cy0fQxrb.js';
3
+ import { ApiMode } from './internal/providers/diagnostics.js';
3
4
  import { ChatCompletionMessageParam } from 'openai/resources/chat/completions.js';
4
5
  import { RequestOptions } from 'openai/core.mjs';
5
6
  import { ModelCapability } from '@zqagent/shared/model-capabilities';
@@ -344,22 +345,40 @@ declare class OpenAIProvider implements ProviderClient {
344
345
  private _logDir?;
345
346
  /** 服务端点 baseURL(用于识别 DeepSeek 等特定供应商) */
346
347
  private _baseURL;
347
- /** 模型 → API 模式缓存:某模型不支持 Responses 后,后续直走 Chat */
348
- private _modeByModel;
348
+ /**
349
+ * 本实例的 API 模式。
350
+ *
351
+ * 显式配置 > 全局 `OPENAI_FORCE_API_MODE` > auto(先 Responses 再降级)。
352
+ * 早先只有全局环境变量一种表达方式,一个节点挂两家供应商时无法各自指定。
353
+ */
354
+ private _apiMode;
349
355
  constructor(opts: {
350
356
  apiKey?: string;
351
357
  baseURL?: string;
352
358
  /** LLM 请求日志根目录,按日期分目录,不传则不记录 */
353
359
  logDir?: string;
360
+ /**
361
+ * 单次请求超时(毫秒)。缺省/非法时回落到 `OPENAI_TIMEOUT_MS`,再回落 10 分钟。
362
+ *
363
+ * 必须能按供应商设置:推理模型的合理预算与普通模型差一个数量级,共用一个全局值
364
+ * 只能二选一(慢模型被掐断,或快模型失败时干等十分钟)。
365
+ */
366
+ timeoutMs?: number | null;
367
+ /**
368
+ * API 模式(auto / responses / chat)。缺省时读 `OPENAI_FORCE_API_MODE`,再缺省 auto。
369
+ */
370
+ apiMode?: ApiMode | null;
354
371
  });
355
372
  /**
356
373
  * 解析指定模型的 API 模式。
357
374
  *
358
- * 优先级:环境变量 OPENAI_FORCE_API_MODE(responses|chat)强制指定
359
- * > 运行时降级缓存(该模型曾因"不支持"失败而缓存为 chat)
375
+ * 优先级:本实例的显式配置(responses|chat)
376
+ * > 运行时降级缓存(该端点+模型曾因"不支持"失败而缓存为 chat)
360
377
  * > 默认 responses(Responses 优先)。
361
378
  */
362
379
  private _resolveMode;
380
+ /** 记录「该端点+模型不支持 Responses」,后续同进程内的请求直走 Chat */
381
+ private _markChatMode;
363
382
  /**
364
383
  * Responses 失败的分类(决定「能不能改走 Chat Completions」以及要不要缓存降级)。
365
384
  *
package/dist/index.cjs CHANGED
@@ -125,6 +125,8 @@ __export(src_exports, {
125
125
  registerTerminalTools: () => registerTerminalTools,
126
126
  registerTodoTool: () => registerTodoTool,
127
127
  registerWebTools: () => registerWebTools,
128
+ repairToolCallHistory: () => repairToolCallHistory,
129
+ repairToolCallHistoryDetailed: () => repairToolCallHistoryDetailed,
128
130
  resetFfmpegCache: () => resetFfmpegCache,
129
131
  resetSandboxCache: () => resetSandboxCache,
130
132
  resolveMedia: () => resolveMedia,
@@ -345,10 +347,22 @@ function authErrorHints(message, code = "") {
345
347
  "\u51ED\u636E\u65E0\u6548\uFF1A\u82E5\u7528\u7684\u662F\u300C\u5FD7\u524D\u5927\u6A21\u578B\uFF08\u5185\u7F6E\uFF09\u300D\uFF0C\u5728\u8282\u70B9\u8BBE\u7F6E\u7684\u6A21\u578B\u9875\u70B9\u300C\u5237\u65B0\u5185\u7F6E\u6A21\u578B\u300D\u91CD\u65B0\u9886\u53D6 Key\uFF08\u5728\u63A7\u5236\u53F0\u91CD\u7F6E\u8FC7 Key \u540E\u9700\u8981\u8FD9\u4E00\u6B65\uFF09\uFF1B\u82E5\u662F\u81EA\u586B\u7684\u4F9B\u5E94\u5546\uFF0C\u8BF7\u68C0\u67E5 Key \u662F\u5426\u6B63\u786E\u6216\u5DF2\u8FC7\u671F"
346
348
  ];
347
349
  }
350
+ function toolCallHistoryHints(message, code = "") {
351
+ const text = `${message} ${code}`;
352
+ if (!/tool_calls|tool[_ ]?call[_ ]?id/i.test(text) || !/must be followed by tool messages|insufficient tool messages|no tool output found|tool messages responding/i.test(
353
+ text
354
+ )) {
355
+ return [];
356
+ }
357
+ return [
358
+ "\u8FD9\u4E0D\u662F\u6A21\u578B\u6216\u4F59\u989D\u95EE\u9898\uFF1A\u4F1A\u8BDD\u5386\u53F2\u91CC\u6709\u4E00\u6761\u300C\u5DE5\u5177\u8C03\u7528\u6CA1\u6709\u62FF\u5230\u7ED3\u679C\u300D\u7684\u8BB0\u5F55\uFF08\u901A\u5E38\u662F\u4E0A\u6B21\u5728\u5DE5\u5177\u6267\u884C\u4E2D\u6309\u4E86 Ctrl+C\uFF0C\u6216\u8FDB\u7A0B\u88AB\u4E2D\u65AD\uFF09",
359
+ "\u5F15\u64CE\u5DF2\u81EA\u52A8\u6E05\u7406\u5E76\u91CD\u8BD5\uFF1B\u5982\u679C\u4ECD\u62A5\u540C\u6837\u7684\u9519\u8BEF\uFF0C\u7528 /new \u5F00\u4E00\u4E2A\u65B0\u4F1A\u8BDD\u5373\u53EF\uFF08\u65E7\u4F1A\u8BDD\u7684\u5386\u53F2\u91CC\u8FD8\u7559\u7740\u8FD9\u6761\u8BB0\u5F55\uFF09"
360
+ ];
361
+ }
348
362
  function paramErrorHints(message, code = "") {
349
363
  const text = `${message} ${code}`;
350
364
  const hints = [];
351
- if (/not[_\s]*(activated|enabled|purchased)|arrearage|quota|subscription|insufficient|未开通|欠费|额度|余额不足/i.test(
365
+ if (/not[_\s]*(activated|enabled|purchased)|arrearage|quota|subscription|billing|未开通|欠费|额度|余额不足|insufficient[_\s]*(quota|balance|credit|funds)/i.test(
352
366
  text
353
367
  )) {
354
368
  hints.push(
@@ -372,9 +386,23 @@ function paramErrorHints(message, code = "") {
372
386
  }
373
387
  return hints;
374
388
  }
375
- function llmTimeoutMs() {
389
+ var DEFAULT_LLM_TIMEOUT_MS = 6e5;
390
+ function normLlmTimeoutMs(v) {
391
+ if (v === null || v === void 0 || v === "") return null;
392
+ const n = Number(v);
393
+ if (!Number.isFinite(n) || n <= 0) return null;
394
+ return Math.min(Math.round(n), 30 * 6e4);
395
+ }
396
+ function llmTimeoutMs(explicit) {
397
+ const fromArg = normLlmTimeoutMs(explicit);
398
+ if (fromArg) return fromArg;
376
399
  const n = Number(process.env.OPENAI_TIMEOUT_MS);
377
- return Number.isFinite(n) && n > 0 ? n : 6e5;
400
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_LLM_TIMEOUT_MS;
401
+ }
402
+ function normApiMode(v) {
403
+ const s = typeof v === "string" ? v.trim().toLowerCase() : "";
404
+ if (s === "auto" || s === "responses" || s === "chat") return s;
405
+ return null;
378
406
  }
379
407
  function llmStreamIdleMs() {
380
408
  const n = Number(process.env.OPENAI_STREAM_IDLE_MS);
@@ -2220,6 +2248,76 @@ function applyToolResultBudget(tool, result, opts = {}) {
2220
2248
  return { content, truncated: true, savedPath };
2221
2249
  }
2222
2250
 
2251
+ // src/engine/history.ts
2252
+ function repairToolCallHistoryDetailed(messages) {
2253
+ const out = [];
2254
+ let droppedCalls = 0;
2255
+ let droppedResults = 0;
2256
+ let droppedMessages = 0;
2257
+ let i = 0;
2258
+ while (i < messages.length) {
2259
+ const m = messages[i];
2260
+ if (m.role === "tool") {
2261
+ droppedResults += 1;
2262
+ i += 1;
2263
+ continue;
2264
+ }
2265
+ const calls = m.role === "assistant" ? m.tool_calls : void 0;
2266
+ if (!calls?.length) {
2267
+ if (m.role === "assistant" && m.tool_calls) {
2268
+ const { tool_calls, ...rest } = m;
2269
+ void tool_calls;
2270
+ out.push(rest);
2271
+ } else {
2272
+ out.push(m);
2273
+ }
2274
+ i += 1;
2275
+ continue;
2276
+ }
2277
+ const responders = /* @__PURE__ */ new Map();
2278
+ const notices = [];
2279
+ let j = i + 1;
2280
+ while (j < messages.length) {
2281
+ const t = messages[j];
2282
+ if (t.role === "notice") {
2283
+ notices.push(t);
2284
+ j += 1;
2285
+ continue;
2286
+ }
2287
+ if (t.role !== "tool") break;
2288
+ if (t.tool_call_id && !responders.has(t.tool_call_id)) {
2289
+ responders.set(t.tool_call_id, t);
2290
+ }
2291
+ j += 1;
2292
+ }
2293
+ const kept = calls.filter((tc) => tc.id && responders.has(tc.id));
2294
+ droppedCalls += calls.length - kept.length;
2295
+ droppedResults += responders.size - kept.length;
2296
+ if (kept.length === 0) {
2297
+ const { tool_calls, ...rest } = m;
2298
+ void tool_calls;
2299
+ if ((rest.content ?? "").trim() !== "") out.push(rest);
2300
+ else droppedMessages += 1;
2301
+ out.push(...notices);
2302
+ } else {
2303
+ out.push(kept.length === calls.length ? m : { ...m, tool_calls: kept });
2304
+ for (const tc of kept) out.push(responders.get(tc.id));
2305
+ out.push(...notices);
2306
+ }
2307
+ i = j;
2308
+ }
2309
+ const unchanged = out.length === messages.length && out.every((m, idx) => m === messages[idx]);
2310
+ return {
2311
+ messages: unchanged ? messages : out,
2312
+ droppedCalls,
2313
+ droppedResults,
2314
+ droppedMessages
2315
+ };
2316
+ }
2317
+ function repairToolCallHistory(messages) {
2318
+ return repairToolCallHistoryDetailed(messages).messages;
2319
+ }
2320
+
2223
2321
  // src/engine/TurnEngine.ts
2224
2322
  var crypto = __toESM(require("crypto"), 1);
2225
2323
  var fs3 = __toESM(require("fs"), 1);
@@ -2758,6 +2856,7 @@ ${notice}` : text,
2758
2856
  attachments = routed.attachments;
2759
2857
  this.taskId = taskId;
2760
2858
  this._turnStartTime = Date.now();
2859
+ this.messages = repairToolCallHistory(this.messages);
2761
2860
  this.messages.push({
2762
2861
  role: "user",
2763
2862
  content: userInput,
@@ -3759,7 +3858,7 @@ ${notice}` : text,
3759
3858
  /** 过滤 notice + 剥离 display-only 字段,得到最终发送视图 */
3760
3859
  _finalizeOutbound(sourceMessages) {
3761
3860
  const _STRIP = /* @__PURE__ */ new Set(["source", "_display", "ts", "reasoning", "usage", "attachmentRefs"]);
3762
- return sourceMessages.filter((m) => m.role !== "notice").map((m) => {
3861
+ const stripped = sourceMessages.filter((m) => m.role !== "notice").map((m) => {
3763
3862
  if (m.role === "tool") {
3764
3863
  return {
3765
3864
  role: "tool",
@@ -3768,15 +3867,16 @@ ${notice}` : text,
3768
3867
  };
3769
3868
  }
3770
3869
  const staleAttachments = Boolean(m.attachments?.length) && (m.ts ?? 0) < this._turnStartTime;
3771
- const stripped = {};
3870
+ const plain = {};
3772
3871
  for (const [k, v] of Object.entries(m)) {
3773
3872
  if (staleAttachments && k === "attachments") continue;
3774
3873
  if (!_STRIP.has(k)) {
3775
- stripped[k] = v;
3874
+ plain[k] = v;
3776
3875
  }
3777
3876
  }
3778
- return stripped;
3877
+ return plain;
3779
3878
  });
3879
+ return repairToolCallHistory(stripped);
3780
3880
  }
3781
3881
  /** 软阈值(token 数):达到它只淘汰旧工具结果 */
3782
3882
  _softTriggerTokens() {
@@ -4529,6 +4629,11 @@ var ResponsesApiError = class extends Error {
4529
4629
  type;
4530
4630
  requestId;
4531
4631
  };
4632
+ var NO_AUTH_KEY = "not-needed";
4633
+ var degradedModes = /* @__PURE__ */ new Map();
4634
+ function modeKey(baseURL, model) {
4635
+ return `${baseURL}::${model}`;
4636
+ }
4532
4637
  var OpenAIProvider = class {
4533
4638
  /** OpenAI SDK 客户端 */
4534
4639
  client;
@@ -4536,23 +4641,31 @@ var OpenAIProvider = class {
4536
4641
  _logDir;
4537
4642
  /** 服务端点 baseURL(用于识别 DeepSeek 等特定供应商) */
4538
4643
  _baseURL;
4539
- /** 模型 → API 模式缓存:某模型不支持 Responses 后,后续直走 Chat */
4540
- _modeByModel = /* @__PURE__ */ new Map();
4644
+ /**
4645
+ * 本实例的 API 模式。
4646
+ *
4647
+ * 显式配置 > 全局 `OPENAI_FORCE_API_MODE` > auto(先 Responses 再降级)。
4648
+ * 早先只有全局环境变量一种表达方式,一个节点挂两家供应商时无法各自指定。
4649
+ */
4650
+ _apiMode;
4541
4651
  constructor(opts) {
4652
+ const explicitKey = opts.apiKey !== void 0;
4542
4653
  const apiKey = cleanLlmValue(opts.apiKey ?? process.env.OPENAI_API_KEY);
4543
4654
  const baseURL = normalizeBaseURL(opts.baseURL ?? process.env.OPENAI_BASE_URL);
4544
- if (!apiKey) {
4655
+ if (!apiKey && !explicitKey) {
4545
4656
  throw new Error(sanitizeEmoji("\u274C \u672A\u8BBE\u7F6E OPENAI_API_KEY \u73AF\u5883\u53D8\u91CF"));
4546
4657
  }
4658
+ const effectiveKey = apiKey ?? NO_AUTH_KEY;
4547
4659
  this._baseURL = baseURL ?? "";
4660
+ this._apiMode = normApiMode(opts.apiMode) ?? normApiMode(process.env.OPENAI_FORCE_API_MODE) ?? "auto";
4548
4661
  const agent = socksAgent();
4549
4662
  const proxyHint = unsupportedProxyHint();
4550
4663
  if (proxyHint) console.warn(`[llm] ${proxyHint}`);
4551
4664
  const baseFetch = agent ? makeSocksFetch(agent) : ((input, init) => globalThis.fetch(input, init));
4552
4665
  this.client = new import_openai.default({
4553
- apiKey,
4666
+ apiKey: effectiveKey,
4554
4667
  ...baseURL ? { baseURL } : {},
4555
- timeout: llmTimeoutMs(),
4668
+ timeout: llmTimeoutMs(opts.timeoutMs),
4556
4669
  maxRetries: llmMaxRetries(),
4557
4670
  // 类型:SDK 期望 (RequestInfo, RequestInit) => Promise<Response>,
4558
4671
  // node-fetch 的 Response 与 DOM Response 结构不同,此处显式放宽
@@ -4569,14 +4682,17 @@ var OpenAIProvider = class {
4569
4682
  /**
4570
4683
  * 解析指定模型的 API 模式。
4571
4684
  *
4572
- * 优先级:环境变量 OPENAI_FORCE_API_MODE(responses|chat)强制指定
4573
- * > 运行时降级缓存(该模型曾因"不支持"失败而缓存为 chat)
4685
+ * 优先级:本实例的显式配置(responses|chat)
4686
+ * > 运行时降级缓存(该端点+模型曾因"不支持"失败而缓存为 chat)
4574
4687
  * > 默认 responses(Responses 优先)。
4575
4688
  */
4576
4689
  _resolveMode(model) {
4577
- const forced = process.env.OPENAI_FORCE_API_MODE?.toLowerCase();
4578
- if (forced === "responses" || forced === "chat") return forced;
4579
- return this._modeByModel.get(model) ?? "responses";
4690
+ if (this._apiMode !== "auto") return this._apiMode;
4691
+ return degradedModes.get(modeKey(this._baseURL, model)) ?? "responses";
4692
+ }
4693
+ /** 记录「该端点+模型不支持 Responses」,后续同进程内的请求直走 Chat */
4694
+ _markChatMode(model) {
4695
+ degradedModes.set(modeKey(this._baseURL, model), "chat");
4580
4696
  }
4581
4697
  /**
4582
4698
  * Responses 失败的分类(决定「能不能改走 Chat Completions」以及要不要缓存降级)。
@@ -4652,7 +4768,7 @@ var OpenAIProvider = class {
4652
4768
  } catch (err) {
4653
4769
  const kind = this._responsesFailureKind(err, true);
4654
4770
  if (kind) {
4655
- if (kind === "endpoint") this._modeByModel.set(model, "chat");
4771
+ if (kind === "endpoint") this._markChatMode(model);
4656
4772
  console.warn(
4657
4773
  `[llm] ${model} Responses API \u4E0D\u53EF\u7528(${kind})\uFF0C\u6539\u7528 Chat Completions (${String(
4658
4774
  err?.message ?? err
@@ -4726,7 +4842,7 @@ var OpenAIProvider = class {
4726
4842
  } catch (err) {
4727
4843
  const kind = this._responsesFailureKind(err, true);
4728
4844
  if (kind) {
4729
- if (kind === "endpoint") this._modeByModel.set(model, "chat");
4845
+ if (kind === "endpoint") this._markChatMode(model);
4730
4846
  console.warn(
4731
4847
  `[llm] ${model} Responses API \u4E0D\u53EF\u7528(${kind})\uFF0C\u6539\u7528 Chat Completions (${String(
4732
4848
  err?.message ?? err
@@ -4772,7 +4888,7 @@ var OpenAIProvider = class {
4772
4888
  } catch (err) {
4773
4889
  const kind = emitted ? null : this._responsesFailureKind(err, false);
4774
4890
  if (!kind) throw enrichLlmError(err, this._baseURL);
4775
- if (kind === "endpoint") this._modeByModel.set(ctx.model, "chat");
4891
+ if (kind === "endpoint") this._markChatMode(ctx.model);
4776
4892
  console.warn(
4777
4893
  `[llm] ${ctx.model} Responses \u6D41\u5185\u5931\u8D25(${kind})\uFF0C\u6539\u7528 Chat Completions (${String(
4778
4894
  err?.message ?? err
@@ -7296,6 +7412,9 @@ var ConsoleHook = class {
7296
7412
  for (const hint of authErrorHints(error, errorType)) {
7297
7413
  cliLog(` \u{1F4A1} ${hint}`);
7298
7414
  }
7415
+ for (const hint of toolCallHistoryHints(error, errorType)) {
7416
+ cliLog(` \u{1F4A1} ${hint}`);
7417
+ }
7299
7418
  for (const hint of paramErrorHints(error)) {
7300
7419
  cliLog(` \u{1F4A1} ${hint}`);
7301
7420
  }
@@ -13298,6 +13417,8 @@ function createDefaultEngine(opts) {
13298
13417
  mode = "interactive" /* INTERACTIVE */,
13299
13418
  maxIterations = DEFAULT_MAX_ITERATIONS,
13300
13419
  reasoningEffort,
13420
+ timeoutMs,
13421
+ apiMode,
13301
13422
  allowedCommands = [],
13302
13423
  shellPolicy = "approve",
13303
13424
  sandbox,
@@ -13318,7 +13439,7 @@ function createDefaultEngine(opts) {
13318
13439
  } = opts;
13319
13440
  const envEffort = process.env.OPENAI_REASONING_EFFORT?.toLowerCase();
13320
13441
  const effectiveEffort = reasoningEffort ?? (envEffort === "low" || envEffort === "medium" || envEffort === "high" ? envEffort : void 0);
13321
- const effectiveProvider = provider ?? new OpenAIProvider({ logDir });
13442
+ const effectiveProvider = provider ?? new OpenAIProvider({ logDir, timeoutMs, apiMode });
13322
13443
  const sandboxPlan = resolveSandbox({ ...sandbox, workspace });
13323
13444
  const registry = new ToolRegistry();
13324
13445
  const conflictGuard = new ConflictGuard();
@@ -13489,6 +13610,8 @@ function createDefaultEngine(opts) {
13489
13610
  registerTerminalTools,
13490
13611
  registerTodoTool,
13491
13612
  registerWebTools,
13613
+ repairToolCallHistory,
13614
+ repairToolCallHistoryDetailed,
13492
13615
  resetFfmpegCache,
13493
13616
  resetSandboxCache,
13494
13617
  resolveMedia,