@prestyj/ai 5.27.0 → 5.28.1

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/index.js CHANGED
@@ -1033,7 +1033,7 @@ function isAdaptiveThinkingModel(model) {
1033
1033
  function toAnthropicThinking(level, maxTokens, model) {
1034
1034
  if (isAdaptiveThinkingModel(model)) {
1035
1035
  let effort = level;
1036
- if (effort === "xhigh" && !/opus-5|opus-4-8|opus-4-7/.test(model)) {
1036
+ if (effort === "xhigh" && !/opus-5|opus-4[-.]8|opus-4[-.]7|sonnet-5[-.]5/.test(model)) {
1037
1037
  effort = "high";
1038
1038
  }
1039
1039
  return {
@@ -2036,7 +2036,7 @@ async function* runStream2(options) {
2036
2036
  const endpointKey = reasoningFieldKey(providerName, options.baseUrl, options.model);
2037
2037
  const client = createClient2(options);
2038
2038
  const isLocal = options.provider === "local";
2039
- const isKimiK3 = options.provider === "moonshot" && options.model === "kimi-k3";
2039
+ const isKimiK3 = options.provider === "moonshot" && (options.model === "kimi-k3" || options.model === "kimi-for-coding");
2040
2040
  const isManagedKimiK3 = isKimiK3 && options.baseUrl?.replace(/\/+$/, "").endsWith("/coding/v1") === true;
2041
2041
  const k3Effort = options.thinking ? toKimiK3Effort(options.thinking) : void 0;
2042
2042
  const isKimiK27 = options.provider === "moonshot" && options.model.startsWith("kimi-k2.7-code");
@@ -2510,7 +2510,7 @@ function extractRequestIdFromMessage(message) {
2510
2510
 
2511
2511
  // src/providers/openai-codex.ts
2512
2512
  var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
2513
- var CODEX_CLIENT_VERSION = "0.155.1";
2513
+ var CODEX_CLIENT_VERSION = "0.159.1";
2514
2514
  var CODEX_REQUEST_COMPRESSION_MIN_BYTES = 16 * 1024;
2515
2515
  var zstdInitPromise;
2516
2516
  async function encodeCodexRequest(body) {
@@ -2556,7 +2556,7 @@ async function encodeCodexRequest(body) {
2556
2556
  }
2557
2557
  }
2558
2558
  function usesResponsesLite(model) {
2559
- return model.startsWith("gpt-5.6-") || model.startsWith("gpt-6-");
2559
+ return model.startsWith("gpt-5.6-") || model.startsWith("gpt-6-") || model.startsWith("gpt-6.");
2560
2560
  }
2561
2561
  function outputTextKey(itemId, contentIndex) {
2562
2562
  return `${itemId ?? ""}:${contentIndex ?? 0}`;
@@ -2678,7 +2678,7 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2678
2678
  if (response.status === 400 && message === `The '${options.model}' model is not supported when using Codex with a ChatGPT account.`) {
2679
2679
  hint = "This model is not available through your ChatGPT account. Switch to a model listed for OpenAI via the model selector, or check your ChatGPT usage limits.";
2680
2680
  } else if (response.status === 404 && text.includes("does not exist")) {
2681
- hint = "This model is not in OpenAI's current catalog for your ChatGPT account. Switch to GPT-6 Astra, GPT-6 Sol, or GPT-6 Luna via the model selector.";
2681
+ hint = "This model is not in OpenAI's current catalog for your ChatGPT account. Switch to GPT-6 Astra, GPT-6.1 Sol, or GPT-6 Luna via the model selector.";
2682
2682
  }
2683
2683
  throw new ProviderError("openai", message, {
2684
2684
  statusCode: response.status,
@@ -2692,6 +2692,8 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2692
2692
  const contentParts = [];
2693
2693
  let textAccum = "";
2694
2694
  const toolCalls = /* @__PURE__ */ new Map();
2695
+ const finishedToolCalls = /* @__PURE__ */ new Set();
2696
+ let terminal;
2695
2697
  const orderedItems = [];
2696
2698
  const outputItemTypes = /* @__PURE__ */ new Map();
2697
2699
  const outputTextByPart = /* @__PURE__ */ new Map();
@@ -2835,6 +2837,7 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2835
2837
  for (const [key, tc] of toolCalls) {
2836
2838
  if (key.endsWith(`|${itemId}`)) {
2837
2839
  tc.argsJson = argsStr;
2840
+ finishedToolCalls.add(key);
2838
2841
  break;
2839
2842
  }
2840
2843
  }
@@ -2860,6 +2863,7 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2860
2863
  const id = `${callId}|${itemId}`;
2861
2864
  const tc = toolCalls.get(id);
2862
2865
  if (tc) {
2866
+ finishedToolCalls.add(id);
2863
2867
  orderedItems.push({ kind: "tool", id });
2864
2868
  const args = parseToolArguments(tc.argsJson);
2865
2869
  yield {
@@ -2871,8 +2875,17 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2871
2875
  }
2872
2876
  }
2873
2877
  }
2874
- if (type === "response.completed" || type === "response.done") {
2878
+ if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
2875
2879
  const resp = event.response;
2880
+ if (type === "response.incomplete" || resp?.status === "incomplete") {
2881
+ const details = resp?.incomplete_details;
2882
+ terminal = {
2883
+ status: "incomplete",
2884
+ reason: typeof details?.reason === "string" ? details.reason : void 0
2885
+ };
2886
+ } else {
2887
+ terminal = { status: "completed" };
2888
+ }
2876
2889
  const usage = resp?.usage;
2877
2890
  if (usage) {
2878
2891
  cacheRead = usage.input_tokens_details?.cached_tokens ?? 0;
@@ -2882,6 +2895,25 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2882
2895
  }
2883
2896
  }
2884
2897
  }
2898
+ if (!terminal) {
2899
+ throw new ProviderError("openai", "Stream ended before completion (no response.completed).", {
2900
+ statusCode: 504
2901
+ });
2902
+ }
2903
+ const droppedToolCalls = [...toolCalls.keys()].filter((id) => !finishedToolCalls.has(id)).length;
2904
+ if (terminal.status === "completed") {
2905
+ for (const [id, tc] of toolCalls) {
2906
+ if (!finishedToolCalls.has(id)) {
2907
+ throw new ProviderError(
2908
+ "openai",
2909
+ `Codex reply completed with an unfinished tool call: ${tc.name} (${id}).`,
2910
+ { statusCode: 502 }
2911
+ );
2912
+ }
2913
+ }
2914
+ } else {
2915
+ providerDiag("codex_incomplete", { reason: terminal.reason ?? null, droppedToolCalls });
2916
+ }
2885
2917
  const seenTool = /* @__PURE__ */ new Set();
2886
2918
  let textInserted = false;
2887
2919
  for (const entry of orderedItems) {
@@ -2908,7 +2940,7 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2908
2940
  contentParts.push({ type: "text", text: textAccum });
2909
2941
  }
2910
2942
  for (const [id, tc] of toolCalls) {
2911
- if (seenTool.has(id)) continue;
2943
+ if (seenTool.has(id) || !finishedToolCalls.has(id)) continue;
2912
2944
  seenTool.add(id);
2913
2945
  contentParts.push({
2914
2946
  type: "tool_call",
@@ -2917,8 +2949,15 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2917
2949
  args: parseToolArguments(tc.argsJson)
2918
2950
  });
2919
2951
  }
2952
+ if (droppedToolCalls > 0) {
2953
+ let last = contentParts.at(-1);
2954
+ while (last?.type === "raw" && isEncryptedReasoning(last.data)) {
2955
+ contentParts.pop();
2956
+ last = contentParts.at(-1);
2957
+ }
2958
+ }
2920
2959
  const hasToolCalls = contentParts.some((p) => p.type === "tool_call");
2921
- const stopReason = hasToolCalls ? "tool_use" : "end_turn";
2960
+ const stopReason = terminal.status === "incomplete" ? incompleteStopReason(terminal.reason) : hasToolCalls ? "tool_use" : "end_turn";
2922
2961
  const streamResponse = {
2923
2962
  message: {
2924
2963
  role: "assistant",
@@ -2935,6 +2974,11 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2935
2974
  yield { type: "done", stopReason };
2936
2975
  return streamResponse;
2937
2976
  }
2977
+ function incompleteStopReason(reason) {
2978
+ if (reason === "max_output_tokens") return "max_tokens";
2979
+ if (reason === "content_filter") return "refusal";
2980
+ return "error";
2981
+ }
2938
2982
  async function* parseSSE(body) {
2939
2983
  for await (const event of readSseStream(body)) {
2940
2984
  const data = event.data.trim();
@@ -4070,6 +4114,8 @@ var CIRCULAR = "[CIRCULAR]";
4070
4114
  var SENSITIVE_NAME = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|key|auth(?:orization)?|bearer|cookie|credential|private[_-]?key|password|passwd|secret)(?:$|[_-])/i;
4071
4115
  var ENV_SECRET_ASSIGNMENT = /\b((?:[A-Z0-9]+_)*(?:API_?KEY|ACCESS_TOKEN|REFRESH_TOKEN|TOKEN|KEY|AUTH|AUTHORIZATION|BEARER|CREDENTIALS?|PASSWORD|PASSWD|SECRET))\b(\s*[=:]\s*)(["']?)(?!\$|process\.env|os\.environ|import\.meta|env\.)(?=[^\s,"';}]*\d)([^\s,"';}=$][^\s,"';}]{7,})\3/g;
4072
4116
  var COMPACT_SECRET_ASSIGNMENT = /\b((?:[a-z0-9]+[_-])*(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|auth|authorization|credentials?|password|passwd|secret)|(?:[a-z0-9]+[_-])+key)=(["']?)(?!\$)([^\s,"'&;}=][^\s,"'&;}]{7,})\2/gi;
4117
+ var URL_USERINFO = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/?#@:"'`<>]*:[^\s/?#"'`<>]+@/gi;
4118
+ var URL_USERINFO_TO_FIRST_AT = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]*:[^\s/@]+@/gi;
4073
4119
  function escaped(value) {
4074
4120
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4075
4121
  }
@@ -4093,7 +4139,8 @@ function redactText(text, options = {}) {
4093
4139
  /-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/g,
4094
4140
  REDACTED
4095
4141
  );
4096
- result = result.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi, `$1${REDACTED}@`);
4142
+ result = result.replace(URL_USERINFO, `$1${REDACTED}@`);
4143
+ result = result.replace(URL_USERINFO_TO_FIRST_AT, `$1${REDACTED}@`);
4097
4144
  result = result.replace(
4098
4145
  /\b(authorization\s*[:=]\s*)(?:bearer|basic)\s+[^\s,;]+/gi,
4099
4146
  `$1${REDACTED}`
@@ -4137,7 +4184,7 @@ function isMediaObject(value) {
4137
4184
  function redactValue(value, options = {}) {
4138
4185
  const maxDepth = options.maxDepth ?? 20;
4139
4186
  const maxEntries = options.maxEntries ?? 1e4;
4140
- const seen = /* @__PURE__ */ new WeakSet();
4187
+ const ancestors = /* @__PURE__ */ new WeakSet();
4141
4188
  let entries = 0;
4142
4189
  const visit = (current, depth, sensitive = false) => {
4143
4190
  if (typeof current === "string") {
@@ -4151,8 +4198,15 @@ function redactValue(value, options = {}) {
4151
4198
  if (isBinary(current)) return current;
4152
4199
  if (current instanceof Date) return new Date(current.getTime());
4153
4200
  if (depth >= maxDepth) return TRUNCATED;
4154
- if (seen.has(current)) return CIRCULAR;
4155
- seen.add(current);
4201
+ if (ancestors.has(current)) return CIRCULAR;
4202
+ ancestors.add(current);
4203
+ try {
4204
+ return cloneObject(current, depth);
4205
+ } finally {
4206
+ ancestors.delete(current);
4207
+ }
4208
+ };
4209
+ const cloneObject = (current, depth) => {
4156
4210
  if (current instanceof Error) {
4157
4211
  const error = {
4158
4212
  name: current.name,