@codeworksh/aikit 0.10.0 → 0.11.0-dev.20261012155220

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 (34) hide show
  1. package/cli.mjs +3 -3
  2. package/{copilot-bFammM5T.mjs → copilot-JLgwmznn.mjs} +2 -2
  3. package/{copilot-bFammM5T.mjs.map → copilot-JLgwmznn.mjs.map} +1 -1
  4. package/{copilot-headers-01-kLz8g.mjs → copilot-headers-BvQ3FFn-.mjs} +2 -2
  5. package/{copilot-headers-01-kLz8g.mjs.map → copilot-headers-BvQ3FFn-.mjs.map} +1 -1
  6. package/{failure-CN0horoO.mjs → failure-DFQNKc-O.mjs} +23 -6
  7. package/failure-DFQNKc-O.mjs.map +1 -0
  8. package/{github-copilot-eDhLBMfL.mjs → github-copilot-C7oJ2Tfp.mjs} +2 -2
  9. package/{github-copilot-eDhLBMfL.mjs.map → github-copilot-C7oJ2Tfp.mjs.map} +1 -1
  10. package/github-copilot-CLJx-bcP.mjs +3 -0
  11. package/index.d.mts +46 -6
  12. package/index.mjs +238 -16
  13. package/index.mjs.map +1 -1
  14. package/llm/failure.mjs +1 -1
  15. package/{model-Czo0SKj0.mjs → model-D-FoGzVN.mjs} +5 -3
  16. package/model-D-FoGzVN.mjs.map +1 -0
  17. package/{model-yhqJA3dm.d.mts → model-DCfjY0fS.d.mts} +2 -2
  18. package/{modelgen-BHm-jA64.mjs → modelgen-D6UBM1fq.mjs} +5 -5
  19. package/modelgen-D6UBM1fq.mjs.map +1 -0
  20. package/modelgen.d.mts +1 -1
  21. package/modelgen.mjs +1 -1
  22. package/oauth/github/copilot.mjs +1 -1
  23. package/openai-codex-CIBVNhQx.mjs +2 -0
  24. package/{openai-codex-MpxV35tx.mjs → openai-codex-Dj0oh0UV.mjs} +26 -15
  25. package/openai-codex-Dj0oh0UV.mjs.map +1 -0
  26. package/package.json +1 -1
  27. package/{registry-CZtcfRPL.mjs → registry-CfGgGfSs.mjs} +4 -4
  28. package/{registry-CZtcfRPL.mjs.map → registry-CfGgGfSs.mjs.map} +1 -1
  29. package/failure-CN0horoO.mjs.map +0 -1
  30. package/github-copilot-gMaBI_-X.mjs +0 -3
  31. package/model-Czo0SKj0.mjs.map +0 -1
  32. package/modelgen-BHm-jA64.mjs.map +0 -1
  33. package/openai-codex-CvdfMYoU.mjs +0 -2
  34. package/openai-codex-MpxV35tx.mjs.map +0 -1
package/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { C as NamedError, _ as optionsKey, a as KnownProviderEnumSchema, c as calculateCost, d as getModels, f as getProviders, h as modelsAreEqual, i as KnownProviderEnum, l as clampThinkingLevel, m as model_exports, n as APIMethodEnumSchema, r as ActiveThinkingLevel, s as ThinkingBudgets$1, t as APIMethodEnum, u as getModel, v as registry, y as thinkingTokenBudgetField } from "./model-Czo0SKj0.mjs";
3
- import { C as ToolCallSchema, D as transformMessages, E as resolveJsonSchemaConstraint, S as AssistantMessageSchema, T as message_exports, g as shortHash, n as createOpenAICodex, r as openaiCodex, v as openAICodexTools, w as createAssistantMessage$1, x as resolveOpenAICodexToolConstraint } from "./openai-codex-MpxV35tx.mjs";
4
- import { r as normalize, t as failure_exports } from "./failure-CN0horoO.mjs";
5
- import { i as packageForModel, o as resolveLanguageModel, r as loadProviderFactory } from "./registry-CZtcfRPL.mjs";
6
- import { i as githubCopilot, r as createGitHubCopilot } from "./github-copilot-eDhLBMfL.mjs";
2
+ import { a as KnownProviderEnumSchema, b as thinkingTokenBudgetField, d as getModel, f as getModels, g as modelsAreEqual, h as model_exports, i as KnownProviderEnum, l as calculateCost, n as APIMethodEnumSchema, p as getProviders, r as ActiveThinkingLevel, s as ThinkingBudgets$1, t as APIMethodEnum, u as clampThinkingLevel, v as optionsKey, w as NamedError, y as registry } from "./model-D-FoGzVN.mjs";
3
+ import { C as ToolCallSchema, E as transformMessages, S as AssistantMessageSchema, T as message_exports, g as shortHash, n as createOpenAICodex, r as openaiCodex, v as openAICodexTools, w as createAssistantMessage$1, x as resolveOpenAICodexToolConstraint } from "./openai-codex-Dj0oh0UV.mjs";
4
+ import { r as normalize, t as failure_exports } from "./failure-DFQNKc-O.mjs";
5
+ import { i as packageForModel, o as resolveLanguageModel, r as loadProviderFactory } from "./registry-CfGgGfSs.mjs";
6
+ import { i as githubCopilot, r as createGitHubCopilot } from "./github-copilot-C7oJ2Tfp.mjs";
7
7
  import Type$2, { Type, Type as Type$1 } from "typebox";
8
- import { jsonSchema, streamText } from "ai";
8
+ import { APICallError } from "@ai-sdk/provider";
9
+ import { RetryError, jsonSchema, streamText } from "ai";
9
10
  import { parse } from "partial-json";
10
11
  import Schema from "typebox/schema";
11
12
  import Value from "typebox/value";
@@ -368,6 +369,8 @@ const HelperOptions = Type$1.Object({
368
369
  sessionId: Type$1.Optional(Type$1.String()),
369
370
  apiKey: Type$1.Optional(Type$1.String()),
370
371
  timeoutMs: Type$1.Optional(Type$1.Number()),
372
+ /** Abort a stream that goes this long without a chunk, so a dead connection fails instead of waiting out `timeoutMs`. */
373
+ idleTimeoutMs: Type$1.Optional(Type$1.Number()),
371
374
  maxRetries: Type$1.Optional(Type$1.Number()),
372
375
  signal: Type$1.Optional(Type$1.Unsafe({})),
373
376
  onPayload: Type$1.Optional(Type$1.Unsafe({})),
@@ -728,7 +731,7 @@ function disabledProviderOptions(model) {
728
731
  if (!model.reasoning) return {};
729
732
  const key = optionsKey(model);
730
733
  if (key === "anthropic" || key === "google-vertex-anthropic") {
731
- if (model.thinkingLevelMap?.off === null) return {};
734
+ if (model.thinkingLevelMap?.off === null) return { [key]: { effort: ANTHROPIC_DEFAULT_EFFORT } };
732
735
  return { [key]: { thinking: { type: "disabled" } } };
733
736
  }
734
737
  if (key === "github-copilot") {
@@ -755,6 +758,8 @@ function googleDisabledThinkingConfig(model) {
755
758
  if (model.compat?.supportsThinkingLevel) return { thinkingLevel: model.thinkingLevelMap?.off ?? "minimal" };
756
759
  return { thinkingBudget: 0 };
757
760
  }
761
+ /** The effort Anthropic applies when a request names none. */
762
+ const ANTHROPIC_DEFAULT_EFFORT = "high";
758
763
  /**
759
764
  * The effort level an adaptive Claude model reasons at.
760
765
  *
@@ -827,6 +832,18 @@ function reasoningProviderOptions(model, plan) {
827
832
  }
828
833
  return {};
829
834
  }
835
+ /**
836
+ * The provider-native thinking value a request carried, read off the exact body the
837
+ * adapter sent. Adapters drop efforts they believe a model rejects, so the options
838
+ * aikit hands them can say more than the wire did.
839
+ */
840
+ function providerThinkingLevel(body) {
841
+ const value = field(body, "reasoning", "effort") ?? field(body, "reasoning_effort") ?? field(body, "generationConfig", "thinkingConfig", "thinkingLevel") ?? (field(body, "thinking", "type") === "disabled" ? void 0 : field(body, "output_config", "effort"));
842
+ return typeof value === "string" ? value : void 0;
843
+ }
844
+ function field(value, ...keys) {
845
+ return keys.reduce((at, key) => typeof at === "object" && at !== null ? at[key] : void 0, value);
846
+ }
830
847
  //#endregion
831
848
  //#region src/utils/jsonparse.ts
832
849
  /**
@@ -932,14 +949,170 @@ function sanitizeSurrogates(text) {
932
949
  return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
933
950
  }
934
951
  //#endregion
952
+ //#region src/llm/strict.ts
953
+ var UnsupportedStrictSchemaError = class extends Error {};
954
+ const UNSUPPORTED_KEYWORDS = [
955
+ "$ref",
956
+ "$defs",
957
+ "definitions",
958
+ "allOf",
959
+ "oneOf",
960
+ "patternProperties",
961
+ "dependentSchemas",
962
+ "dependencies",
963
+ "unevaluatedProperties",
964
+ "propertyNames",
965
+ "contains",
966
+ "prefixItems",
967
+ "not",
968
+ "if",
969
+ "then",
970
+ "else"
971
+ ];
972
+ const ANTHROPIC_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
973
+ "minimum",
974
+ "maximum",
975
+ "exclusiveMinimum",
976
+ "exclusiveMaximum",
977
+ "multipleOf",
978
+ "maxItems",
979
+ "uniqueItems",
980
+ "minContains",
981
+ "maxContains",
982
+ "minProperties",
983
+ "maxProperties"
984
+ ]);
985
+ const ANTHROPIC_STRING_FORMATS = /* @__PURE__ */ new Set([
986
+ "date-time",
987
+ "time",
988
+ "date",
989
+ "duration",
990
+ "email",
991
+ "hostname",
992
+ "uri",
993
+ "ipv4",
994
+ "ipv6",
995
+ "uuid"
996
+ ]);
997
+ const isAnthropicUnsupportedKeyword = (key, value) => {
998
+ if (ANTHROPIC_UNSUPPORTED_KEYWORDS.has(key)) return true;
999
+ if (key === "minItems") return value !== 0 && value !== 1;
1000
+ if (key === "format") return typeof value !== "string" || !ANTHROPIC_STRING_FORMATS.has(value);
1001
+ return false;
1002
+ };
1003
+ function isJsonSchemaObject(value) {
1004
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1005
+ }
1006
+ function isNullSchema(schema) {
1007
+ return isJsonSchemaObject(schema) && schema.type === "null";
1008
+ }
1009
+ /** `X` of an `anyOf: [X, null]` schema. */
1010
+ function nullableVariant(schema) {
1011
+ if (!isJsonSchemaObject(schema) || !Array.isArray(schema.anyOf)) return;
1012
+ const variants = schema.anyOf.filter((variant) => !isNullSchema(variant));
1013
+ return variants.length === 1 ? variants[0] : void 0;
1014
+ }
1015
+ function isStructuredSchema(schema) {
1016
+ if (!isJsonSchemaObject(schema)) return false;
1017
+ const types = typeof schema.type === "string" ? [schema.type] : Array.isArray(schema.type) ? schema.type : [];
1018
+ return types.includes("object") || types.includes("array") || schema.properties !== void 0 || schema.items !== void 0;
1019
+ }
1020
+ const CONSTRAINING_KEYWORDS = [
1021
+ "type",
1022
+ "const",
1023
+ "enum",
1024
+ "anyOf",
1025
+ "allOf",
1026
+ "oneOf",
1027
+ "not",
1028
+ "$ref",
1029
+ "properties",
1030
+ "items"
1031
+ ];
1032
+ function schemaAllowsNull(schema) {
1033
+ if (schema === true) return true;
1034
+ if (!isJsonSchemaObject(schema)) return false;
1035
+ if (CONSTRAINING_KEYWORDS.every((key) => schema[key] === void 0)) return true;
1036
+ if (schema.type === "null" || Array.isArray(schema.type) && schema.type.includes("null")) return true;
1037
+ if (schema.const === null || Array.isArray(schema.enum) && schema.enum.includes(null)) return true;
1038
+ return Array.isArray(schema.anyOf) && schema.anyOf.some((variant) => schemaAllowsNull(variant));
1039
+ }
1040
+ function makeNodeStrict(schema, isUnsupportedKeyword) {
1041
+ if (!isJsonSchemaObject(schema)) throw new UnsupportedStrictSchemaError("boolean schemas are unsupported");
1042
+ for (const key of UNSUPPORTED_KEYWORDS) if (schema[key] !== void 0) throw new UnsupportedStrictSchemaError(`${key} schemas are unsupported`);
1043
+ if (isUnsupportedKeyword) {
1044
+ for (const [key, value] of Object.entries(schema)) if (isUnsupportedKeyword(key, value)) throw new UnsupportedStrictSchemaError(`${key}: ${JSON.stringify(value)} is unsupported`);
1045
+ }
1046
+ if (schema.anyOf !== void 0) {
1047
+ if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) throw new UnsupportedStrictSchemaError("anyOf must contain at least one schema");
1048
+ const nullable = nullableVariant(schema) !== void 0;
1049
+ for (const variant of schema.anyOf) {
1050
+ if (!nullable && isStructuredSchema(variant)) throw new UnsupportedStrictSchemaError("object and array unions are unsupported");
1051
+ makeNodeStrict(variant, isUnsupportedKeyword);
1052
+ }
1053
+ }
1054
+ if (schema.items !== void 0) {
1055
+ if (Array.isArray(schema.items)) throw new UnsupportedStrictSchemaError("tuple schemas are unsupported");
1056
+ makeNodeStrict(schema.items, isUnsupportedKeyword);
1057
+ }
1058
+ const isObjectSchema = schema.type === "object";
1059
+ if (schema.properties !== void 0 && !isObjectSchema) throw new UnsupportedStrictSchemaError("properties require type object");
1060
+ if (!isObjectSchema) return;
1061
+ if (schema.additionalProperties !== void 0 && typeof schema.additionalProperties !== "boolean") throw new UnsupportedStrictSchemaError("schema-valued additionalProperties is unsupported");
1062
+ if (schema.properties !== void 0 && !isJsonSchemaObject(schema.properties)) throw new UnsupportedStrictSchemaError("object properties must be a schema map");
1063
+ if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== "string"))) throw new UnsupportedStrictSchemaError("object required must be a string array");
1064
+ const properties = schema.properties ?? {};
1065
+ const propertyNames = Object.keys(properties);
1066
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
1067
+ if ([...required].some((key) => !propertyNames.includes(key))) throw new UnsupportedStrictSchemaError("required contains an unknown property");
1068
+ for (const [key, property] of Object.entries(properties)) {
1069
+ makeNodeStrict(property, isUnsupportedKeyword);
1070
+ if (!required.has(key) && !schemaAllowsNull(property)) properties[key] = { anyOf: [property, { type: "null" }] };
1071
+ }
1072
+ schema.required = propertyNames;
1073
+ schema.additionalProperties = false;
1074
+ }
1075
+ /**
1076
+ * Convert a tool's parameter schema to the subset strict constrained sampling accepts: every object closed and
1077
+ * every property required, with formerly optional properties made nullable. Callers strip those nulls again
1078
+ * before validation (see `normalizeOptionalNulls`).
1079
+ */
1080
+ function makeStrictJsonSchema(schema, isUnsupportedKeyword) {
1081
+ const cloned = structuredClone(schema);
1082
+ if (!isJsonSchemaObject(cloned) || cloned.type !== "object") throw new UnsupportedStrictSchemaError("root schema must have type object");
1083
+ makeNodeStrict(cloned, isUnsupportedKeyword);
1084
+ return cloned;
1085
+ }
1086
+ /**
1087
+ * The strict parameter schema to send for a JSON-schema constrained tool, or `undefined` to send it non-strict.
1088
+ * A `"prefer"` tool whose schema the model's strict mode cannot express falls back to non-strict; a `"require"`
1089
+ * tool throws instead.
1090
+ */
1091
+ function resolveStrictParameters(tool, model) {
1092
+ const config = tool.constrainedSampling;
1093
+ if (!config || config.type !== "json_schema") return;
1094
+ if (model?.compat?.supportsStrictMode ?? true) {
1095
+ const isAnthropic = model?.protocol === KnownProviderEnum.anthropic || model?.protocol === KnownProviderEnum.googleVertexAnthropic;
1096
+ try {
1097
+ return makeStrictJsonSchema(tool.parameters, isAnthropic ? isAnthropicUnsupportedKeyword : void 0);
1098
+ } catch (error) {
1099
+ if (!(error instanceof UnsupportedStrictSchemaError)) throw error;
1100
+ if (config.strict !== "require") return;
1101
+ throw new Error(`tool "${tool.name}" requires JSON-schema constrained sampling, but ${error.message}.`);
1102
+ }
1103
+ }
1104
+ if (config.strict === "require") throw new Error(`tool "${tool.name}" requires JSON-schema constrained sampling, but strict tools are unsupported.`);
1105
+ }
1106
+ //#endregion
935
1107
  //#region src/llm/transform.ts
936
- function createAssistantMessage(model) {
1108
+ function createAssistantMessage(model, thinkingLevel) {
937
1109
  return createAssistantMessage$1({
938
1110
  role: "assistant",
939
1111
  parts: [],
940
1112
  protocol: model.protocol,
941
1113
  provider: model.provider,
942
1114
  model: model.id,
1115
+ thinkingLevel,
943
1116
  usage: {
944
1117
  input: 0,
945
1118
  output: 0,
@@ -1188,13 +1361,13 @@ function convertTools(tools, model) {
1188
1361
  if (!tools || tools.length === 0) return;
1189
1362
  const result = {};
1190
1363
  for (const tool of tools) {
1191
- const jsonSchemaConstraint = resolveJsonSchemaConstraint(tool, model?.compat);
1364
+ const strictParameters = resolveStrictParameters(tool, model);
1192
1365
  const grammarConstraint = model?.protocol === KnownProviderEnum.openaiCodex ? resolveOpenAICodexToolConstraint(tool, model.compat) : void 0;
1193
1366
  result[tool.name] = {
1194
1367
  description: tool.description,
1195
- inputSchema: jsonSchema(tool.parameters),
1196
- ...jsonSchemaConstraint ? { strict: true } : {},
1197
- ...grammarConstraint?.type === "grammar" ? { providerOptions: { "openai-codex": { grammar: grammarConstraint } } } : {}
1368
+ inputSchema: jsonSchema(strictParameters ?? tool.parameters),
1369
+ ...strictParameters ? { strict: true } : {},
1370
+ ...grammarConstraint ? { providerOptions: { "openai-codex": { grammar: grammarConstraint } } } : {}
1198
1371
  };
1199
1372
  }
1200
1373
  return result;
@@ -1490,6 +1663,9 @@ function handlePart(part, output, model, stream, pricing) {
1490
1663
  case "tool-call":
1491
1664
  finalizeToolCall(output, part, stream);
1492
1665
  break;
1666
+ case "start-step":
1667
+ stampProviderThinkingLevel(output, part.request.body);
1668
+ break;
1493
1669
  case "finish-step":
1494
1670
  output.responseId ||= part.response.id;
1495
1671
  if (part.response.modelId && part.response.modelId !== model.id) output.responseModel ||= part.response.modelId;
@@ -1508,6 +1684,15 @@ function handlePart(part, output, model, stream, pricing) {
1508
1684
  case "error": throw part.error instanceof Error ? part.error : new Error(formatThrownError(part.error));
1509
1685
  }
1510
1686
  }
1687
+ function stampProviderThinkingLevel(output, body) {
1688
+ const level = providerThinkingLevel(body);
1689
+ if (level !== void 0) output.providerThinkingLevel = level;
1690
+ }
1691
+ /** A request the provider refused never streams a `start-step`; its body travels on the error. */
1692
+ function rejectedRequestBody(error) {
1693
+ if (RetryError.isInstance(error)) return rejectedRequestBody(error.lastError);
1694
+ return APICallError.isInstance(error) ? error.requestBodyValues : void 0;
1695
+ }
1511
1696
  function resolvePricing(model, pricing) {
1512
1697
  return serviceTierCostMultiplier(model, servedServiceTier(model, pricing.requestedServiceTier, pricing.providerMetadata));
1513
1698
  }
@@ -1531,11 +1716,21 @@ function resolveMaxOutputTokens(model, plan) {
1531
1716
  if (plan.maxTokens === void 0) return void 0;
1532
1717
  return isAnthropicMessagesModel(model) && !model.compat?.forceAdaptiveThinking ? plan.maxTokens - plan.budget : plan.maxTokens;
1533
1718
  }
1719
+ /** A bare number is a total ceiling only; the idle timeout has to be spelled per chunk. */
1720
+ function resolveTimeout(options) {
1721
+ const { timeoutMs, idleTimeoutMs } = options;
1722
+ if (timeoutMs === void 0 && idleTimeoutMs === void 0) return void 0;
1723
+ return compact({
1724
+ totalMs: timeoutMs,
1725
+ firstChunkMs: idleTimeoutMs,
1726
+ chunkMs: idleTimeoutMs
1727
+ });
1728
+ }
1534
1729
  const stream$1 = (model, context, options) => {
1535
1730
  const stream = new AssistantMessageEventStream();
1536
1731
  const runtimeOptions = applyDefaultMaxTokens(model, options ?? {});
1537
1732
  (async () => {
1538
- const output = createAssistantMessage(model);
1733
+ const output = createAssistantMessage(model, runtimeOptions.reasoning ?? "off");
1539
1734
  try {
1540
1735
  const plan = resolvePlan(model, context, runtimeOptions);
1541
1736
  const languageModel = await resolveAISDKLanguageModel(model, runtimeOptions, plan.budget);
@@ -1554,8 +1749,9 @@ const stream$1 = (model, context, options) => {
1554
1749
  maxOutputTokens: resolveMaxOutputTokens(model, plan),
1555
1750
  temperature: runtimeOptions.temperature,
1556
1751
  providerOptions,
1752
+ include: { requestBody: true },
1557
1753
  abortSignal: runtimeOptions.signal,
1558
- timeout: runtimeOptions.timeoutMs,
1754
+ timeout: resolveTimeout(runtimeOptions),
1559
1755
  maxRetries: runtimeOptions.maxRetries,
1560
1756
  headers: runtimeOptions.headers,
1561
1757
  onError: () => {}
@@ -1584,6 +1780,7 @@ const stream$1 = (model, context, options) => {
1584
1780
  delete block.partialJson;
1585
1781
  }
1586
1782
  output.time.completed = Date.now();
1783
+ stampProviderThinkingLevel(output, rejectedRequestBody(error));
1587
1784
  output.stopReason = runtimeOptions.signal?.aborted ? "aborted" : "error";
1588
1785
  if (output.stopReason === "aborted") output.errorMessage = formatThrownError(error);
1589
1786
  else {
@@ -1656,6 +1853,29 @@ function errorPath(error) {
1656
1853
  return "root";
1657
1854
  }
1658
1855
  /**
1856
+ * Drop `null` from optional properties whose schema does not accept null, in place. Strict constrained sampling
1857
+ * makes every property required and nullable, so the model answers an omitted optional argument with `null`.
1858
+ */
1859
+ function normalizeOptionalNulls(value, schema) {
1860
+ const variant = nullableVariant(schema);
1861
+ if (variant !== void 0) return normalizeOptionalNulls(value, variant);
1862
+ const node = schema;
1863
+ if (Array.isArray(value)) {
1864
+ if (Array.isArray(node.items)) {
1865
+ for (const [index, item] of value.entries()) if (node.items[index]) normalizeOptionalNulls(item, node.items[index]);
1866
+ } else if (node.items) for (const item of value) normalizeOptionalNulls(item, node.items);
1867
+ return;
1868
+ }
1869
+ if (typeof value !== "object" || value === null || !node.properties) return;
1870
+ const object = value;
1871
+ const required = new Set(node.required ?? []);
1872
+ for (const [key, property] of Object.entries(node.properties)) {
1873
+ if (!(key in object)) continue;
1874
+ if (object[key] === null && !required.has(key) && typeof property.$ref !== "string" && !schemaAllowsNull(property)) delete object[key];
1875
+ else normalizeOptionalNulls(object[key], property);
1876
+ }
1877
+ }
1878
+ /**
1659
1879
  * Validates an arbitrary value against a TypeBox schema and returns the coerced value.
1660
1880
  */
1661
1881
  function validateSchema(schema, value, label) {
@@ -1688,9 +1908,11 @@ function validateToolCall(tools, toolExecution) {
1688
1908
  * Validates tool call arguments against the tool's TypeBox schema
1689
1909
  */
1690
1910
  function validateToolArguments(tool, toolExecution) {
1691
- return validateSchema(tool.parameters, toolExecution.rawArgs, `Tool "${toolExecution.name}"`);
1911
+ const args = structuredClone(toolExecution.rawArgs);
1912
+ normalizeOptionalNulls(args, tool.parameters);
1913
+ return validateSchema(tool.parameters, args, `Tool "${toolExecution.name}"`);
1692
1914
  }
1693
1915
  //#endregion
1694
- export { event_exports as Event, EventStream, failure_exports as Failure, message_exports as Message, model_exports as Model, protocol_exports as Protocol, ThinkingBudgets, Type, createAssistantMessageEventStream, createGitHubCopilot, createOpenAICodex, getEnvApiKey, githubCopilot, llm, openAICodexTools, openaiCodex, stream, validateSchema, validateToolArguments, validateToolCall };
1916
+ export { event_exports as Event, EventStream, failure_exports as Failure, message_exports as Message, model_exports as Model, protocol_exports as Protocol, ThinkingBudgets, Type, createAssistantMessageEventStream, createGitHubCopilot, createOpenAICodex, getEnvApiKey, githubCopilot, llm, normalizeOptionalNulls, openAICodexTools, openaiCodex, stream, validateSchema, validateToolArguments, validateToolCall };
1695
1917
 
1696
1918
  //# sourceMappingURL=index.mjs.map