@prestyj/ai 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -324,6 +324,9 @@ function providerGuidance(provider, message, statusCode) {
324
324
  if (lower.includes("context_length_exceeded") || lower.includes("prompt is too long")) {
325
325
  return `Context window for this ${name} model is full. Compact the conversation to shrink history, or start a new session.`;
326
326
  }
327
+ if (lower.includes("many-image request") || lower.includes("image dimensions") && lower.includes("max allowed size")) {
328
+ return `An image in conversation history exceeds ${name}'s many-image limit. Restart EZ Coder so restored images are resized, then retry; if it persists, start a new session.`;
329
+ }
327
330
  if (statusCode === 413 || lower.includes("request_too_large") || lower.includes("request exceeds the maximum size")) {
328
331
  return `The request to ${name} is too large. Compact the conversation to shrink history, or start a new session.`;
329
332
  }
@@ -820,9 +823,14 @@ function toAnthropicMessages(messages, cacheControl) {
820
823
  continue;
821
824
  }
822
825
  if (msg.role === "user") {
826
+ if (typeof msg.content === "string") {
827
+ if (msg.content === "") continue;
828
+ } else if (!msg.content.some((p) => !(p.type === "text" && p.text === ""))) {
829
+ continue;
830
+ }
823
831
  out.push({
824
832
  role: "user",
825
- content: typeof msg.content === "string" ? msg.content : msg.content.map((part) => {
833
+ content: typeof msg.content === "string" ? msg.content : msg.content.filter((part) => !(part.type === "text" && part.text === "")).map((part) => {
826
834
  if (part.type === "text") return { type: "text", text: part.text };
827
835
  if (part.type === "video") {
828
836
  return {
@@ -847,6 +855,7 @@ function toAnthropicMessages(messages, cacheControl) {
847
855
  continue;
848
856
  }
849
857
  if (msg.role === "assistant") {
858
+ if (typeof msg.content === "string" && msg.content === "") continue;
850
859
  const content = typeof msg.content === "string" ? msg.content : toAnthropicAssistantContent(msg.content, msgIdx > trajectoryStartIdx, idMap);
851
860
  if (Array.isArray(content) && content.length === 0) continue;
852
861
  out.push({ role: "assistant", content });
@@ -967,7 +976,7 @@ function remapToolCallId(id, idMap) {
967
976
  if (!id.startsWith("toolu_")) return id;
968
977
  const existing = idMap.get(id);
969
978
  if (existing) return existing;
970
- const mapped = `call_${id.slice(5)}`;
979
+ const mapped = `call_${id.slice(6)}`;
971
980
  idMap.set(id, mapped);
972
981
  return mapped;
973
982
  }
@@ -1578,6 +1587,12 @@ async function* runStream(options) {
1578
1587
  statusCode: 504
1579
1588
  });
1580
1589
  }
1590
+ if (stopReason === null) {
1591
+ throw new ProviderError("anthropic", "Stream ended before completion (no stop_reason).", {
1592
+ statusCode: 504,
1593
+ cause: { partialContent: contentParts, outputTokens }
1594
+ });
1595
+ }
1581
1596
  const normalizedStop = normalizeAnthropicStopReason(stopReason);
1582
1597
  const response = {
1583
1598
  message: {
@@ -1844,6 +1859,17 @@ function getEnvironment() {
1844
1859
  }
1845
1860
 
1846
1861
  // src/providers/openai.ts
1862
+ function toKimiK3Effort(level) {
1863
+ switch (level) {
1864
+ case "low":
1865
+ return "low";
1866
+ case "medium":
1867
+ case "high":
1868
+ return "high";
1869
+ default:
1870
+ return "max";
1871
+ }
1872
+ }
1847
1873
  function extractOpenAIUsage(usage) {
1848
1874
  let cacheRead = 0;
1849
1875
  let cacheWrite = 0;
@@ -1900,6 +1926,7 @@ async function* runStream2(options) {
1900
1926
  const client = createClient2(options);
1901
1927
  const isKimiK3 = options.provider === "moonshot" && options.model === "kimi-k3";
1902
1928
  const isManagedKimiK3 = isKimiK3 && options.baseUrl?.replace(/\/+$/, "").endsWith("/coding/v1") === true;
1929
+ const k3Effort = options.thinking ? toKimiK3Effort(options.thinking) : void 0;
1903
1930
  const isKimiK27 = options.provider === "moonshot" && options.model.startsWith("kimi-k2.7-code");
1904
1931
  const hasFixedKimiSampling = isKimiK3 || isKimiK27;
1905
1932
  const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" && !isKimiK3 && !isKimiK27 || options.provider === "xiaomi";
@@ -1914,9 +1941,11 @@ async function* runStream2(options) {
1914
1941
  }
1915
1942
  const messages = toOpenAIMessages(downgradedMessages, {
1916
1943
  provider: options.provider,
1917
- // K3 and K2.7 preserve reasoning even when the user hides thinking in the
1918
- // UI; keep assistant tool-call history wire-valid in that display mode.
1919
- thinking: isKimiK3 || isKimiK27 || !!options.thinking,
1944
+ // K2.7 preserves reasoning even when the user hides thinking in the UI;
1945
+ // keep assistant tool-call history wire-valid in that display mode. A
1946
+ // disabled K3 must NOT carry placeholder reasoning_content (mirrors the
1947
+ // official CLI: reasoning is preserved only while thinking is enabled).
1948
+ thinking: isKimiK27 || !!options.thinking,
1920
1949
  supportsImages: options.supportsImages
1921
1950
  });
1922
1951
  const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
@@ -1949,9 +1978,11 @@ async function* runStream2(options) {
1949
1978
  if (isKimiK3) {
1950
1979
  const paramsAny = params;
1951
1980
  if (isManagedKimiK3) {
1952
- paramsAny.thinking = { type: "enabled", effort: "max", keep: "all" };
1981
+ paramsAny.thinking = k3Effort ? { type: "enabled", effort: k3Effort, keep: "all" } : { type: "disabled" };
1982
+ } else if (k3Effort) {
1983
+ paramsAny.reasoning_effort = k3Effort;
1953
1984
  } else {
1954
- paramsAny.reasoning_effort = "max";
1985
+ paramsAny.thinking = { type: "disabled" };
1955
1986
  }
1956
1987
  }
1957
1988
  if (usesThinkingParam) {
@@ -2057,6 +2088,12 @@ async function* runStream2(options) {
2057
2088
  statusCode: 504
2058
2089
  });
2059
2090
  }
2091
+ if (finishReason === null) {
2092
+ throw new ProviderError(providerName, "Stream ended before completion (no finish_reason).", {
2093
+ statusCode: 504,
2094
+ cause: { partialText: textAccum, outputTokens }
2095
+ });
2096
+ }
2060
2097
  if (thinkingAccum) {
2061
2098
  contentParts.push({ type: "thinking", text: thinkingAccum });
2062
2099
  }