@prestyj/ai 5.16.1 → 5.17.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.js CHANGED
@@ -235,6 +235,9 @@ function providerGuidance(provider, message, statusCode) {
235
235
  if (statusCode === 401 || lower.includes("unauthorized") || lower.includes("invalid api key")) {
236
236
  return `Authentication failed with ${name}. Re-authenticate to refresh your credentials.`;
237
237
  }
238
+ if (lower.includes("requires a newer version")) {
239
+ return `${name} needs a newer EZ Coder to serve this model. Update EZ Coder to the latest version and retry, or switch to another ${name} model via the model selector.`;
240
+ }
238
241
  if (lower.includes("overloaded") || lower.includes("engine_overloaded")) {
239
242
  return `${name}'s servers are overloaded right now. Retry in a moment \u2014 not a EZ Coder issue.`;
240
243
  }
@@ -502,6 +505,108 @@ function normalizeRootForAnthropic(schema) {
502
505
  return out;
503
506
  }
504
507
 
508
+ // src/utils/strict-tool-schema.ts
509
+ var UnsupportedStrictSchemaError = class extends Error {
510
+ };
511
+ var UNSUPPORTED_KEYS = [
512
+ "$ref",
513
+ "$defs",
514
+ "definitions",
515
+ "allOf",
516
+ "oneOf",
517
+ "patternProperties",
518
+ "dependentSchemas",
519
+ "dependencies",
520
+ "unevaluatedProperties",
521
+ "propertyNames",
522
+ "contains",
523
+ "prefixItems",
524
+ "not",
525
+ "if",
526
+ "then",
527
+ "else"
528
+ ];
529
+ function isSchemaObject(value) {
530
+ return typeof value === "object" && value !== null && !Array.isArray(value);
531
+ }
532
+ function isStructured(value) {
533
+ if (!isSchemaObject(value)) return false;
534
+ const types = typeof value.type === "string" ? [value.type] : Array.isArray(value.type) ? value.type : [];
535
+ return types.includes("object") || types.includes("array") || value.properties !== void 0 || value.items !== void 0;
536
+ }
537
+ function allowsNull(schema) {
538
+ if (!isSchemaObject(schema)) return false;
539
+ if (schema.type === "null" || Array.isArray(schema.type) && schema.type.includes("null"))
540
+ return true;
541
+ if (schema.const === null || Array.isArray(schema.enum) && schema.enum.includes(null))
542
+ return true;
543
+ return Array.isArray(schema.anyOf) && schema.anyOf.some((variant) => allowsNull(variant));
544
+ }
545
+ function makeNodeStrict(schema) {
546
+ if (!isSchemaObject(schema)) {
547
+ throw new UnsupportedStrictSchemaError("boolean schemas are unsupported");
548
+ }
549
+ for (const key of UNSUPPORTED_KEYS) {
550
+ if (schema[key] !== void 0) {
551
+ throw new UnsupportedStrictSchemaError(`${key} schemas are unsupported`);
552
+ }
553
+ }
554
+ if (schema.anyOf !== void 0) {
555
+ if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) {
556
+ throw new UnsupportedStrictSchemaError("anyOf must contain at least one schema");
557
+ }
558
+ for (const variant of schema.anyOf) {
559
+ if (isStructured(variant)) {
560
+ throw new UnsupportedStrictSchemaError("object and array unions are unsupported");
561
+ }
562
+ makeNodeStrict(variant);
563
+ }
564
+ }
565
+ if (schema.items !== void 0) {
566
+ if (Array.isArray(schema.items)) {
567
+ throw new UnsupportedStrictSchemaError("tuple schemas are unsupported");
568
+ }
569
+ makeNodeStrict(schema.items);
570
+ }
571
+ const isObjectSchema = schema.type === "object";
572
+ if (schema.properties !== void 0 && !isObjectSchema) {
573
+ throw new UnsupportedStrictSchemaError("properties require type object");
574
+ }
575
+ if (!isObjectSchema) return;
576
+ if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
577
+ throw new UnsupportedStrictSchemaError(
578
+ "schema-valued or true additionalProperties is unsupported"
579
+ );
580
+ }
581
+ if (schema.properties !== void 0 && !isSchemaObject(schema.properties)) {
582
+ throw new UnsupportedStrictSchemaError("object properties must be a schema map");
583
+ }
584
+ const properties = schema.properties ?? {};
585
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
586
+ for (const [key, property] of Object.entries(properties)) {
587
+ makeNodeStrict(property);
588
+ if (!required.has(key) && !allowsNull(property)) {
589
+ properties[key] = { anyOf: [property, { type: "null" }] };
590
+ }
591
+ }
592
+ schema.required = Object.keys(properties);
593
+ schema.additionalProperties = false;
594
+ }
595
+ function supportsStrictToolSampling(provider) {
596
+ return provider === "openai";
597
+ }
598
+ function makeStrictToolSchema(schema) {
599
+ const cloned = structuredClone(schema);
600
+ if (!isSchemaObject(cloned)) {
601
+ throw new UnsupportedStrictSchemaError("root schema must be an object");
602
+ }
603
+ makeNodeStrict(cloned);
604
+ if (cloned.type !== "object") {
605
+ throw new UnsupportedStrictSchemaError("root schema must have type object");
606
+ }
607
+ return cloned;
608
+ }
609
+
505
610
  // src/providers/reasoning-field.ts
506
611
  var REASONING_FIELD_ALIASES = [
507
612
  "reasoning_content",
@@ -982,7 +1087,7 @@ function toOpenAIMessages(messages, options) {
982
1087
  (part) => {
983
1088
  if (part.type === "text") return { type: "text", text: part.text };
984
1089
  if (part.type === "video") {
985
- const videoUrl = part.fileId ? { url: `ms://${part.fileId}`, id: part.fileId } : { url: `data:${part.mediaType};base64,${part.data}` };
1090
+ const videoUrl = options?.provider === "moonshot" && part.fileId ? { url: `ms://${part.fileId}`, id: part.fileId } : { url: `data:${part.mediaType};base64,${part.data}` };
986
1091
  return {
987
1092
  type: "video_url",
988
1093
  video_url: videoUrl
@@ -1086,15 +1191,28 @@ function toOpenAIMessages(messages, options) {
1086
1191
  }
1087
1192
  return out;
1088
1193
  }
1089
- function toOpenAITools(tools) {
1090
- return tools.map((tool) => ({
1091
- type: "function",
1092
- function: {
1093
- name: tool.name,
1094
- description: tool.description,
1095
- parameters: resolveToolSchema(tool)
1194
+ function toOpenAITools(tools, opts) {
1195
+ return tools.map((tool) => {
1196
+ let parameters = resolveToolSchema(tool);
1197
+ let strict;
1198
+ if (opts?.strict) {
1199
+ try {
1200
+ parameters = makeStrictToolSchema(parameters);
1201
+ strict = true;
1202
+ } catch (error) {
1203
+ if (!(error instanceof UnsupportedStrictSchemaError)) throw error;
1204
+ }
1096
1205
  }
1097
- }));
1206
+ return {
1207
+ type: "function",
1208
+ function: {
1209
+ name: tool.name,
1210
+ description: tool.description,
1211
+ parameters,
1212
+ ...strict ? { strict } : {}
1213
+ }
1214
+ };
1215
+ });
1098
1216
  }
1099
1217
  function toOpenAIToolChoice(choice) {
1100
1218
  if (choice === "auto") return "auto";
@@ -1921,7 +2039,7 @@ async function* runStream2(options) {
1921
2039
  const k3Effort = options.thinking ? toKimiK3Effort(options.thinking) : void 0;
1922
2040
  const isKimiK27 = options.provider === "moonshot" && options.model.startsWith("kimi-k2.7-code");
1923
2041
  const hasFixedKimiSampling = isKimiK3 || isKimiK27;
1924
- const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" && !isKimiK3 && !isKimiK27 || options.provider === "xiaomi";
2042
+ const usesThinkingParam = options.provider === "deepseek" || options.provider === "glm" || options.provider === "moonshot" && !isKimiK3 && !isKimiK27 || options.provider === "xiaomi";
1925
2043
  const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
1926
2044
  const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
1927
2045
  if (options.provider === "moonshot") {
@@ -1947,19 +2065,23 @@ async function* runStream2(options) {
1947
2065
  model: options.model,
1948
2066
  messages,
1949
2067
  stream: useStreaming,
1950
- ...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
2068
+ ...options.maxTokens ? options.provider === "deepseek" || options.provider === "glm" || options.provider === "moonshot" ? { max_tokens: options.maxTokens } : { max_completion_tokens: options.maxTokens } : {},
1951
2069
  ...effectiveTemp != null && !options.thinking && !hasFixedKimiSampling ? { temperature: effectiveTemp } : {},
1952
2070
  ...options.topP != null && !hasFixedKimiSampling ? { top_p: options.topP } : {},
1953
2071
  ...options.stop ? { stop: options.stop } : {},
1954
2072
  ...options.thinking && !usesThinkingParam && !isKimiK3 && !isKimiK27 && !isLocal ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking, options.model) } : {},
1955
- ...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
2073
+ ...options.tools?.length ? {
2074
+ tools: toOpenAITools(options.tools, {
2075
+ strict: supportsStrictToolSampling(options.provider)
2076
+ })
2077
+ } : {},
1956
2078
  ...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
1957
2079
  ...useStreaming ? { stream_options: { include_usage: true } } : {}
1958
2080
  };
1959
2081
  if (options.provider === "openai" || options.provider === "moonshot") {
1960
2082
  const paramsAny = params;
1961
2083
  paramsAny.prompt_cache_key = normalizePromptCacheKey(options.promptCacheKey ?? "ezcoder");
1962
- if (options.provider === "openai" && options.model.startsWith("gpt-5.6")) {
2084
+ if (options.provider === "openai" && (options.model.startsWith("gpt-5.6") || options.model.startsWith("gpt-6"))) {
1963
2085
  paramsAny.prompt_cache_options = { mode: "implicit", ttl: "30m" };
1964
2086
  } else if (!isKimiK3 && (options.cacheRetention ?? "short") === "long") {
1965
2087
  paramsAny.prompt_cache_retention = "24h";
@@ -1970,6 +2092,9 @@ async function* runStream2(options) {
1970
2092
  options.thinking
1971
2093
  );
1972
2094
  }
2095
+ if (options.provider === "sakana" && options.model === "fugu-ultra" && (options.thinking === "max" || options.thinking === "ultra")) {
2096
+ params.reasoning_effort = "max";
2097
+ }
1973
2098
  if (options.provider === "openai" && options.serviceTier) {
1974
2099
  params.service_tier = options.serviceTier;
1975
2100
  }
@@ -1986,7 +2111,9 @@ async function* runStream2(options) {
1986
2111
  if (usesThinkingParam) {
1987
2112
  if (options.thinking) {
1988
2113
  params.thinking = { type: "enabled" };
1989
- if (options.provider === "glm") {
2114
+ if (options.provider === "deepseek") {
2115
+ params.reasoning_effort = options.thinking === "low" ? "low" : options.thinking === "medium" || options.thinking === "high" ? "high" : "max";
2116
+ } else if (options.provider === "glm") {
1990
2117
  params.reasoning_effort = toGlmReasoningEffort(
1991
2118
  options.thinking
1992
2119
  );
@@ -2381,7 +2508,7 @@ function extractRequestIdFromMessage(message) {
2381
2508
 
2382
2509
  // src/providers/openai-codex.ts
2383
2510
  var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
2384
- var CODEX_CLIENT_VERSION = "0.144.1";
2511
+ var CODEX_CLIENT_VERSION = "0.153.4";
2385
2512
  var CODEX_REQUEST_COMPRESSION_MIN_BYTES = 16 * 1024;
2386
2513
  var zstdInitPromise;
2387
2514
  async function encodeCodexRequest(body) {
@@ -2427,7 +2554,7 @@ async function encodeCodexRequest(body) {
2427
2554
  }
2428
2555
  }
2429
2556
  function usesResponsesLite(model) {
2430
- return model.startsWith("gpt-5.6-");
2557
+ return model.startsWith("gpt-5.6-") || model.startsWith("gpt-6-");
2431
2558
  }
2432
2559
  function outputTextKey(itemId, contentIndex) {
2433
2560
  return `${itemId ?? ""}:${contentIndex ?? 0}`;
@@ -2481,8 +2608,10 @@ async function* runStream3(options) {
2481
2608
  body.temperature = options.temperature;
2482
2609
  }
2483
2610
  body.reasoning = {
2611
+ // GPT-5.6/6 require at least low; older models still support thinking off.
2612
+ // Apply the floor here for every caller, including one-off prompt rewrites.
2484
2613
  // `ultra` is a client orchestration preset, not a Codex API effort.
2485
- effort: options.thinking === "ultra" ? "max" : options.thinking ?? "none",
2614
+ effort: options.thinking === "ultra" ? "max" : options.thinking ?? (responsesLite ? "low" : "none"),
2486
2615
  summary: "auto",
2487
2616
  ...responsesLite ? { context: "all_turns" } : {}
2488
2617
  };
@@ -2527,14 +2656,10 @@ async function* runStream3(options) {
2527
2656
  const usageLimit = codexUsageLimitError(parsed.errorObj, response.status, requestId);
2528
2657
  if (usageLimit) throw usageLimit;
2529
2658
  let hint;
2530
- if (response.status === 400 && text.includes("not supported")) {
2531
- if (options.model === "gpt-5.5-pro") {
2532
- hint = "Use gpt-5.5 instead. OpenAI's Codex model catalog does not list gpt-5.5-pro.";
2533
- } else {
2534
- hint = "This model is not available through Codex for the authenticated account. Switch to a model listed for OpenAI Codex via the model selector, or check your Codex usage limits.";
2535
- }
2659
+ if (response.status === 400 && message === `The '${options.model}' model is not supported when using Codex with a ChatGPT account.`) {
2660
+ 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.";
2536
2661
  } else if (response.status === 404 && text.includes("does not exist")) {
2537
- hint = "This model is not in the current OpenAI Codex catalog for this account. Switch to gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, or gpt-5.5 via the model selector.";
2662
+ hint = "This model is not in OpenAI's current catalog for your ChatGPT account. Switch to GPT-6 Astra, GPT-5.6 Sol, GPT-5.6 Terra, or GPT-5.6 Luna via the model selector.";
2538
2663
  }
2539
2664
  throw new ProviderError("openai", message, {
2540
2665
  statusCode: response.status,
@@ -2907,13 +3032,23 @@ function toCodexInput(messages, options) {
2907
3032
  return { system, input };
2908
3033
  }
2909
3034
  function toCodexTools(tools) {
2910
- return tools.map((tool) => ({
2911
- type: "function",
2912
- name: tool.name,
2913
- description: tool.description,
2914
- parameters: resolveToolSchema(tool),
2915
- strict: null
2916
- }));
3035
+ return tools.map((tool) => {
3036
+ let parameters = resolveToolSchema(tool);
3037
+ let strict = null;
3038
+ try {
3039
+ parameters = makeStrictToolSchema(parameters);
3040
+ strict = true;
3041
+ } catch (error) {
3042
+ if (!(error instanceof UnsupportedStrictSchemaError)) throw error;
3043
+ }
3044
+ return {
3045
+ type: "function",
3046
+ name: tool.name,
3047
+ description: tool.description,
3048
+ parameters,
3049
+ strict
3050
+ };
3051
+ });
2917
3052
  }
2918
3053
  function parseCodexErrorBody(text, statusCode) {
2919
3054
  if (!text) return {};
@@ -2974,6 +3109,8 @@ var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
2974
3109
  "gemini-3-flash",
2975
3110
  "gemini-3.1-flash-lite",
2976
3111
  "gemini-3.7-flash",
3112
+ "gemini-3.8-flash",
3113
+ "gemini-3.5-flash-lite",
2977
3114
  "gemini-2.5-pro",
2978
3115
  "gemini-2.5-flash",
2979
3116
  "gemma-4-31b-it",
@@ -2997,12 +3134,20 @@ var ACCOUNT_GATED_MODELS = /* @__PURE__ */ new Set([
2997
3134
  "gemini-3.5-flash",
2998
3135
  "gemini-3.1-pro-preview",
2999
3136
  "gemini-3.1-pro-preview-customtools",
3000
- "gemini-3.7-flash"
3137
+ "gemini-3.7-flash",
3138
+ "gemini-3.8-flash",
3139
+ "gemini-3.5-flash-lite"
3001
3140
  ]);
3002
3141
  function accountGatedMessage(model) {
3142
+ if (model === "gemini-3.8-flash" || model === "gemini-3.5-flash-lite") {
3143
+ return `${model} is not available through Code Assist for this account. Public Gemini API availability does not guarantee Code Assist OAuth access.`;
3144
+ }
3003
3145
  return `Your Google account isn't entitled to "${model}" over Gemini Code Assist OAuth, so the API reports it as not found. This is an account-access limit, not a ezcoder bug.`;
3004
3146
  }
3005
- function accountGatedHint() {
3147
+ function accountGatedHint(model) {
3148
+ if (model === "gemini-3.8-flash" || model === "gemini-3.5-flash-lite") {
3149
+ return "Use /model to select Gemini 3.1 Flash Lite, or retry once Google enables this model through Code Assist for your account.";
3150
+ }
3006
3151
  return `Newer Gemini models (3.7 Flash, 3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin \u2014 free/personal accounts usually can't call them. Switch to Gemini 3.1 Flash Lite (it works on this account) with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
3007
3152
  }
3008
3153
  function formatErrorMessage(status, body, model) {
@@ -3328,7 +3473,7 @@ async function fetchCodeAssist(plan, options) {
3328
3473
  throw new ProviderError("gemini", message, {
3329
3474
  statusCode: response.status,
3330
3475
  ...resetsAt !== void 0 ? { resetsAt } : {},
3331
- ...accountGated ? { hint: accountGatedHint() } : {}
3476
+ ...accountGated ? { hint: accountGatedHint(options.model) } : {}
3332
3477
  });
3333
3478
  }
3334
3479
  return response;