@cognipeer/agent-sdk 0.10.2 → 0.10.4

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
@@ -513,7 +513,7 @@ function getModelCapabilities(model) {
513
513
  return {
514
514
  provider,
515
515
  structuredOutput: supportsNativeStructuredOutput(provider) ? "native" : "tool_based",
516
- strictToolCalling: requiresStrictToolCalling(provider),
516
+ strictToolCalling: requiresStrictToolCalling(provider) && isOpenAIHostedEndpoint(model._lc),
517
517
  streaming: true
518
518
  };
519
519
  }
@@ -556,6 +556,17 @@ function supportsNativeStructuredOutput(provider) {
556
556
  function requiresStrictToolCalling(provider) {
557
557
  return ["openai"].includes(provider);
558
558
  }
559
+ function isOpenAIHostedEndpoint(lcModel) {
560
+ if (!lcModel) return true;
561
+ const baseURL = lcModel.clientConfig?.baseURL ?? lcModel.configuration?.baseURL ?? lcModel.baseURL;
562
+ if (typeof baseURL !== "string" || baseURL.trim() === "") return true;
563
+ try {
564
+ const host = new URL(baseURL).hostname.toLowerCase();
565
+ return host === "api.openai.com" || host.endsWith(".openai.azure.com") || host.endsWith(".cognitiveservices.azure.com");
566
+ } catch {
567
+ return false;
568
+ }
569
+ }
559
570
 
560
571
  // src/model.ts
561
572
  function isSmartModel(m) {
@@ -2520,13 +2531,19 @@ function resolveCapabilities(provider) {
2520
2531
  switch (provider) {
2521
2532
  case "openai":
2522
2533
  case "azure":
2523
- case "openai-compatible":
2524
2534
  return {
2525
2535
  structuredOutput: "native",
2526
2536
  strictToolCalling: true,
2527
2537
  streaming: true,
2528
2538
  provider
2529
2539
  };
2540
+ case "openai-compatible":
2541
+ return {
2542
+ structuredOutput: "native",
2543
+ strictToolCalling: false,
2544
+ streaming: true,
2545
+ provider
2546
+ };
2530
2547
  case "anthropic":
2531
2548
  return {
2532
2549
  structuredOutput: "tool_based",
@@ -3855,6 +3872,187 @@ Identical to an earlier ${duplicate.toolName} result. Use get_tool_response with
3855
3872
  }
3856
3873
  return notApplied4(output);
3857
3874
  }
3875
+ var identity = (value) => value;
3876
+ function describeLike(schema, source, suffix) {
3877
+ const description = [source.description, suffix].filter(Boolean).join(" ");
3878
+ return description ? schema.describe(description) : schema;
3879
+ }
3880
+ function jsonString(source) {
3881
+ return {
3882
+ schema: describeLike(zod.z.string(), source, "(a JSON value, encoded as a string)"),
3883
+ restore: (value) => {
3884
+ if (typeof value !== "string") return value;
3885
+ try {
3886
+ return JSON.parse(value);
3887
+ } catch {
3888
+ return value;
3889
+ }
3890
+ }
3891
+ };
3892
+ }
3893
+ function unwrapOptional(schema) {
3894
+ const def = schema._def;
3895
+ if (def?.typeName === "ZodOptional") return { inner: def.innerType, optional: true };
3896
+ if (def?.typeName === "ZodDefault") return { inner: def.innerType, optional: true };
3897
+ return { inner: schema, optional: false };
3898
+ }
3899
+ function isZodSchema2(schema) {
3900
+ return Boolean(schema) && typeof schema.safeParse === "function" && Boolean(schema._def);
3901
+ }
3902
+ function toStrictCompatible(schema) {
3903
+ const def = schema?._def;
3904
+ switch (def?.typeName) {
3905
+ case "ZodObject": {
3906
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
3907
+ const keys = Object.keys(shape ?? {});
3908
+ const open = def.unknownKeys === "passthrough" || def.catchall && def.catchall._def?.typeName !== "ZodNever";
3909
+ if (keys.length === 0 && open) return jsonString(schema);
3910
+ const nextShape = {};
3911
+ const restores = {};
3912
+ for (const key of keys) {
3913
+ const field = shape[key];
3914
+ const { inner, optional } = unwrapOptional(field);
3915
+ const child = toStrictCompatible(inner);
3916
+ const childSchema = describeLike(child.schema, field.description ? field : inner);
3917
+ nextShape[key] = optional ? childSchema.nullable() : childSchema;
3918
+ restores[key] = { restore: child.restore, optional };
3919
+ }
3920
+ return {
3921
+ schema: describeLike(zod.z.object(nextShape), schema),
3922
+ restore: (value) => {
3923
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
3924
+ const out = {};
3925
+ for (const [key, raw] of Object.entries(value)) {
3926
+ const entry = restores[key];
3927
+ if (raw === null && entry?.optional) continue;
3928
+ out[key] = entry ? entry.restore(raw) : raw;
3929
+ }
3930
+ return out;
3931
+ }
3932
+ };
3933
+ }
3934
+ case "ZodOptional":
3935
+ case "ZodDefault": {
3936
+ const child = toStrictCompatible(def.innerType);
3937
+ return {
3938
+ schema: describeLike(child.schema.nullable(), schema),
3939
+ restore: (value) => value === null ? void 0 : child.restore(value)
3940
+ };
3941
+ }
3942
+ case "ZodNullable": {
3943
+ const child = toStrictCompatible(def.innerType);
3944
+ return {
3945
+ schema: describeLike(child.schema.nullable(), schema),
3946
+ restore: (value) => value === null ? null : child.restore(value)
3947
+ };
3948
+ }
3949
+ case "ZodArray": {
3950
+ const child = toStrictCompatible(def.type);
3951
+ return {
3952
+ schema: describeLike(zod.z.array(child.schema), schema),
3953
+ restore: (value) => Array.isArray(value) ? value.map(child.restore) : value
3954
+ };
3955
+ }
3956
+ case "ZodUnion":
3957
+ case "ZodDiscriminatedUnion": {
3958
+ const rawOptions = def.options instanceof Map ? [...def.options.values()] : def.options;
3959
+ const options = rawOptions.map(toStrictCompatible);
3960
+ if (options.length === 1) return options[0];
3961
+ if (options.every((option, index) => option.schema === rawOptions[index])) {
3962
+ return { schema, restore: identity };
3963
+ }
3964
+ return {
3965
+ schema: describeLike(zod.z.union(options.map((option) => option.schema)), schema),
3966
+ restore: (value) => {
3967
+ const candidates = options.map((option) => option.restore(value));
3968
+ const index = candidates.findIndex((candidate, i) => rawOptions[i].safeParse(candidate).success);
3969
+ return candidates[index >= 0 ? index : 0];
3970
+ }
3971
+ };
3972
+ }
3973
+ case "ZodEffects":
3974
+ return toStrictCompatible(def.schema);
3975
+ case "ZodRecord":
3976
+ case "ZodAny":
3977
+ case "ZodUnknown":
3978
+ return jsonString(schema);
3979
+ default:
3980
+ return { schema, restore: identity };
3981
+ }
3982
+ }
3983
+ function topLevelObject(transform) {
3984
+ if (transform.schema._def?.typeName === "ZodObject") return transform;
3985
+ return {
3986
+ schema: zod.z.object({
3987
+ input: transform.schema.describe(
3988
+ transform.schema.description ?? "The tool arguments as a JSON object, encoded as a string"
3989
+ )
3990
+ }),
3991
+ restore: (value) => {
3992
+ const input = value && typeof value === "object" ? value.input : void 0;
3993
+ const restored = transform.restore(input);
3994
+ return restored && typeof restored === "object" ? restored : {};
3995
+ }
3996
+ };
3997
+ }
3998
+ function toStrictToolSchema(schema) {
3999
+ return topLevelObject(toStrictCompatible(schema));
4000
+ }
4001
+ function restoreToolCalls(message, restorers) {
4002
+ if (!message || typeof message !== "object" || restorers.size === 0) return message;
4003
+ const restoreList = (calls) => {
4004
+ if (!Array.isArray(calls) || calls.length === 0) return calls;
4005
+ return calls.map((call) => {
4006
+ const fn = call?.function;
4007
+ const name = call?.name ?? fn?.name;
4008
+ const restore = name ? restorers.get(name) : void 0;
4009
+ if (!restore) return call;
4010
+ let next = call;
4011
+ if (call.args && typeof call.args === "object") next = { ...next, args: restore(call.args) };
4012
+ if (fn && typeof fn.arguments === "string") {
4013
+ try {
4014
+ next = { ...next, function: { ...fn, arguments: JSON.stringify(restore(JSON.parse(fn.arguments))) } };
4015
+ } catch {
4016
+ }
4017
+ }
4018
+ return next;
4019
+ });
4020
+ };
4021
+ const m = message;
4022
+ const hasDirect = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
4023
+ const hasKwargs = Array.isArray(m.additional_kwargs?.tool_calls) && m.additional_kwargs.tool_calls.length > 0;
4024
+ if (!hasDirect && !hasKwargs) return message;
4025
+ return {
4026
+ ...message,
4027
+ ...hasDirect ? { tool_calls: restoreList(m.tool_calls) } : {},
4028
+ ...hasKwargs ? { additional_kwargs: { ...m.additional_kwargs, tool_calls: restoreList(m.additional_kwargs.tool_calls) } } : {}
4029
+ };
4030
+ }
4031
+ var strictViews = /* @__PURE__ */ new WeakMap();
4032
+ function prepareStrictToolMenu(tools) {
4033
+ const restorers = /* @__PURE__ */ new Map();
4034
+ const menu = tools.map((tool) => {
4035
+ const t = tool;
4036
+ if (!t || typeof t.name !== "string" || !isZodSchema2(t.schema)) return tool;
4037
+ const cached = strictViews.get(tool);
4038
+ if (cached && cached.schema === t.schema) {
4039
+ restorers.set(t.name, cached.restore);
4040
+ return cached.view;
4041
+ }
4042
+ try {
4043
+ const transform = toStrictToolSchema(t.schema);
4044
+ const view = Object.create(tool);
4045
+ view.schema = transform.schema;
4046
+ view.__lcTool = void 0;
4047
+ strictViews.set(tool, { schema: t.schema, view, restore: transform.restore });
4048
+ restorers.set(t.name, transform.restore);
4049
+ return view;
4050
+ } catch {
4051
+ return tool;
4052
+ }
4053
+ });
4054
+ return { menu, restorers };
4055
+ }
3858
4056
 
3859
4057
  // src/nodes/agentCore.ts
3860
4058
  function createAgentCoreNode(opts) {
@@ -3875,10 +4073,17 @@ function createAgentCoreNode(opts) {
3875
4073
  };
3876
4074
  let tools = runtime.tools ?? [];
3877
4075
  const shouldUseStrictToolCalling = Boolean(
3878
- runtime.responseFormat && runtime.model?.capabilities?.strictToolCalling
4076
+ runtime.model?.capabilities?.strictToolCalling
3879
4077
  );
4078
+ let strictRestorers = /* @__PURE__ */ new Map();
4079
+ const wireMenu = (menu) => {
4080
+ if (!shouldUseStrictToolCalling) return menu;
4081
+ const prepared = prepareStrictToolMenu(menu);
4082
+ strictRestorers = prepared.restorers;
4083
+ return prepared.menu;
4084
+ };
3880
4085
  const bindToolMenu = (menu) => runtime.model?.bindTools ? runtime.model.bindTools(
3881
- menu,
4086
+ wireMenu(menu),
3882
4087
  shouldUseStrictToolCalling ? { strict: true } : void 0
3883
4088
  ) : runtime.model;
3884
4089
  const menuMutationReachesProvider = typeof runtime.model?.bindTools === "function";
@@ -3889,7 +4094,8 @@ function createAgentCoreNode(opts) {
3889
4094
  const computeTraceToolDefinitions = (menu) => {
3890
4095
  if (!traceSession || !traceSession.resolvedConfig.logData || menu.length === 0) return void 0;
3891
4096
  try {
3892
- return menu.map((tool) => {
4097
+ const wire = shouldUseStrictToolCalling ? prepareStrictToolMenu(menu).menu : menu;
4098
+ return wire.map((tool) => {
3893
4099
  const def = toToolDefinition(tool, shouldUseStrictToolCalling ? true : void 0);
3894
4100
  return { name: def.name, description: def.description || void 0, parameters: def.parameters };
3895
4101
  });
@@ -4195,6 +4401,9 @@ ${append}`;
4195
4401
  throw err;
4196
4402
  }
4197
4403
  }
4404
+ if (shortCircuited === void 0 && strictRestorers.size > 0) {
4405
+ response = restoreToolCalls(response, strictRestorers);
4406
+ }
4198
4407
  if (!host?.has("postModelCall")) break;
4199
4408
  const postGate = await host.runGate("postModelCall", {
4200
4409
  message: response,
@@ -6156,6 +6365,9 @@ function isSyntheticSummaryMessage(message) {
6156
6365
  }
6157
6366
  return false;
6158
6367
  }
6368
+ function isCompactedToolContent(content) {
6369
+ return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
6370
+ }
6159
6371
 
6160
6372
  // src/structuredOutput/manager.ts
6161
6373
  var StructuredOutputManager = class {
@@ -8072,6 +8284,10 @@ function collectRecentTurns(messages, lastTurnsToKeep) {
8072
8284
  function renderStructuredSummary(summary) {
8073
8285
  if (!summary) return "";
8074
8286
  const lines = ["Context summary:"];
8287
+ if (summary.user_directives && summary.user_directives.length > 0) {
8288
+ lines.push("User directives (still in force \u2014 follow them):");
8289
+ lines.push(...summary.user_directives.map((directive) => `- ${directive}`));
8290
+ }
8075
8291
  if (summary.stable_facts.length > 0) {
8076
8292
  lines.push("Stable facts:");
8077
8293
  lines.push(...summary.stable_facts.map((fact) => `- ${fact.key}: ${fact.value}`));
@@ -8147,17 +8363,46 @@ function clampToBudget(messages, maxContextTokens) {
8147
8363
  }
8148
8364
  return working;
8149
8365
  }
8366
+ function collectSummaryOnlyBody(body, hasSummary, lastTurnsToKeep) {
8367
+ if (!hasSummary) {
8368
+ return collectRecentTurns(body, Math.max(1, lastTurnsToKeep));
8369
+ }
8370
+ let boundary = -1;
8371
+ for (let index = body.length - 1; index >= 0; index -= 1) {
8372
+ if (isSyntheticSummaryMessage(body[index])) {
8373
+ boundary = index;
8374
+ break;
8375
+ }
8376
+ }
8377
+ let lastUserIndex = -1;
8378
+ for (let index = body.length - 1; index >= 0; index -= 1) {
8379
+ if (body[index].role === "user") {
8380
+ lastUserIndex = index;
8381
+ break;
8382
+ }
8383
+ }
8384
+ const keep = /* @__PURE__ */ new Set();
8385
+ const firstUserIndex = body.findIndex((message) => message.role === "user");
8386
+ if (firstUserIndex >= 0) keep.add(firstUserIndex);
8387
+ const verbatimFrom = Math.min(lastUserIndex >= 0 ? lastUserIndex : body.length, boundary + 1);
8388
+ for (let index = Math.max(0, verbatimFrom); index < body.length; index += 1) {
8389
+ if (!isSyntheticSummaryMessage(body[index])) keep.add(index);
8390
+ }
8391
+ return body.filter((_, index) => keep.has(index));
8392
+ }
8150
8393
  function buildModelMessages(state, config) {
8151
8394
  const rawMessages = state.messages || [];
8152
8395
  if (config.context.policy === "raw") {
8153
8396
  return clampToBudget(rawMessages, config.limits.maxContextTokens);
8154
8397
  }
8155
- const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
8156
8398
  const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
8157
8399
  const summaryText = renderStructuredSummary(latestSummary);
8158
8400
  const memoryText = renderMemoryBlock(state.memoryFacts);
8159
- const systemMessage2 = recentMessages[0]?.role === "system" ? recentMessages[0] : void 0;
8160
- const body = systemMessage2 ? recentMessages.slice(1) : recentMessages;
8401
+ const systemMessage2 = rawMessages[0]?.role === "system" ? rawMessages[0] : void 0;
8402
+ const body = config.context.policy === "summary_only" ? collectSummaryOnlyBody(systemMessage2 ? rawMessages.slice(1) : rawMessages, Boolean(summaryText), config.context.lastTurnsToKeep) : (() => {
8403
+ const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
8404
+ return recentMessages[0]?.role === "system" ? recentMessages.slice(1) : recentMessages;
8405
+ })();
8161
8406
  const syntheticContextMessages = [];
8162
8407
  if (summaryText) {
8163
8408
  syntheticContextMessages.push({ role: "system", name: "context_summary", content: summaryText });
@@ -8168,7 +8413,7 @@ function buildModelMessages(state, config) {
8168
8413
  const assembled = [
8169
8414
  ...systemMessage2 ? [systemMessage2] : [],
8170
8415
  ...syntheticContextMessages,
8171
- ...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
8416
+ ...body
8172
8417
  ];
8173
8418
  return clampToBudget(assembled, config.limits.maxContextTokens);
8174
8419
  }
@@ -8213,6 +8458,7 @@ function extractJsonObject(text) {
8213
8458
  }
8214
8459
  function normalizeStructuredSummary(input, fallbackText) {
8215
8460
  const summary = {
8461
+ user_directives: Array.isArray(input?.user_directives) ? input.user_directives.map((directive) => String(directive ?? "").trim()).filter(Boolean) : [],
8216
8462
  stable_facts: Array.isArray(input?.stable_facts) ? input.stable_facts.filter((fact) => fact && typeof fact === "object").map((fact) => ({
8217
8463
  key: String(fact.key || "unknown"),
8218
8464
  value: String(fact.value || ""),
@@ -8273,7 +8519,7 @@ function extractCanonicalFacts(messages) {
8273
8519
  return [...facts.values()];
8274
8520
  }
8275
8521
  function isSummarizedToolPlaceholder(content) {
8276
- return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
8522
+ return isCompactedToolContent(content);
8277
8523
  }
8278
8524
  function collectLatestTurnToolCallIds(messages) {
8279
8525
  const ids = /* @__PURE__ */ new Set();
@@ -8332,11 +8578,16 @@ function runIntegrityCheck(previous, current) {
8332
8578
  const previousKeys = new Set((previous?.stable_facts || []).map((fact) => fact.key));
8333
8579
  const currentKeys = new Set(current.stable_facts.map((fact) => fact.key));
8334
8580
  const obsoleteKeys = new Set(current.discarded_obsolete);
8335
- const criticalFactLoss = [...previousKeys].some((key) => !obsoleteKeys.has(key) && !currentKeys.has(key));
8581
+ const currentDirectives = new Set(current.user_directives || []);
8582
+ const lostDirectives = (previous?.user_directives || []).filter((directive) => !currentDirectives.has(directive) && !obsoleteKeys.has(directive));
8583
+ const criticalFactLoss = [...previousKeys].some((key) => !obsoleteKeys.has(key) && !currentKeys.has(key)) || lostDirectives.length > 0;
8336
8584
  const obsoleteFactRevived = current.stable_facts.some((fact) => obsoleteKeys.has(fact.key));
8337
8585
  if (criticalFactLoss) {
8338
8586
  notes.push("Missing previously retained facts; merged forward during integrity repair.");
8339
8587
  }
8588
+ if (lostDirectives.length > 0) {
8589
+ notes.push(`Dropped ${lostDirectives.length} user directive(s); merged forward during integrity repair.`);
8590
+ }
8340
8591
  if (obsoleteFactRevived) {
8341
8592
  notes.push("Obsolete facts reappeared; removed during integrity repair.");
8342
8593
  }
@@ -8359,7 +8610,13 @@ function repairStructuredSummary(previous, current, integrity) {
8359
8610
  }
8360
8611
  }
8361
8612
  const filteredFacts = integrity.obsoleteFactRevived ? nextFacts.filter((fact) => !current.discarded_obsolete.includes(fact.key)) : nextFacts;
8362
- return { ...current, stable_facts: filteredFacts };
8613
+ const directives = [...current.user_directives || []];
8614
+ for (const directive of previous.user_directives || []) {
8615
+ if (!directives.includes(directive) && !current.discarded_obsolete.includes(directive)) {
8616
+ directives.push(directive);
8617
+ }
8618
+ }
8619
+ return { ...current, user_directives: directives, stable_facts: filteredFacts };
8363
8620
  }
8364
8621
  function createContextSummarizeNode(opts) {
8365
8622
  return async (state) => {
@@ -8433,6 +8690,7 @@ function createContextSummarizeNode(opts) {
8433
8690
 
8434
8691
  Return exactly one JSON object with this schema:
8435
8692
  {
8693
+ "user_directives": [string],
8436
8694
  "stable_facts": [{ "key": string, "value": string, "confidence": number }],
8437
8695
  "active_goals": [string],
8438
8696
  "open_questions": [string],
@@ -8441,6 +8699,7 @@ Return exactly one JSON object with this schema:
8441
8699
  }
8442
8700
 
8443
8701
  Rules:
8702
+ - user_directives: standing instructions the user gave about HOW to work or answer for the rest of the conversation (language, format, tone, scope, things to always or never do) that still apply. NOT the tasks or questions themselves \u2014 "read the logs" is a task (an active goal), "always answer in Turkish" is a directive. Copy each directive close to verbatim; never merge, soften or drop one. Carry forward every directive from the previous structured summary unless the user explicitly revoked it \u2014 then put its exact text in discarded_obsolete.
8444
8703
  - Keep stable_facts only for facts that future turns must remember.
8445
8704
  - Put invalidated or superseded fact keys in discarded_obsolete.
8446
8705
  - Preserve active_goals still relevant to the user.
@@ -8508,6 +8767,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
8508
8767
  durationMs = Date.now() - startTime;
8509
8768
  structuredSummary = normalizeStructuredSummary(void 0, previousSummary || conversationText.slice(0, 800));
8510
8769
  structuredSummary = mergeStableFacts(structuredSummary, canonicalFacts);
8770
+ structuredSummary.user_directives = [...previousStructuredSummary?.user_directives || []];
8511
8771
  integrity = { passed: true, criticalFactLoss: false, obsoleteFactRevived: false, notes: ["Fallback summary generated locally."] };
8512
8772
  summaryText = renderStructuredSummary(structuredSummary);
8513
8773
  const errorEvent = {
@@ -8742,6 +9002,21 @@ var todoUpdateItemSchema = zod.z.object({
8742
9002
  status: todoStatusSchema.optional(),
8743
9003
  evidence: zod.z.string().max(300).optional()
8744
9004
  });
9005
+ var todoItemWireSchema = zod.z.object({
9006
+ id: zod.z.number().int().min(1).describe("Sequential id starting from 1 (write) or an existing id (update)"),
9007
+ step: zod.z.string().min(1).optional(),
9008
+ title: zod.z.string().min(1).optional(),
9009
+ description: zod.z.string().min(1).optional(),
9010
+ owner: zod.z.string().min(1).optional(),
9011
+ exitCriteria: zod.z.string().min(1).optional(),
9012
+ status: todoStatusSchema.optional().describe("Required for every item on write"),
9013
+ evidence: zod.z.string().max(300).optional()
9014
+ });
9015
+ function describeTodoIssue(issue) {
9016
+ if (!issue) return void 0;
9017
+ const path2 = issue.path.length > 0 ? `todoList[${issue.path[0]}]${issue.path.slice(1).map((p) => `.${String(p)}`).join("")}` : "todoList";
9018
+ return `${path2}: ${issue.message}`;
9019
+ }
8745
9020
  function normalizeTodoItem(item, existing) {
8746
9021
  const id = item.id ?? existing?.id;
8747
9022
  const step = item.step || item.title || item.description || existing?.step || existing?.title || existing?.description || `Step ${id}`;
@@ -8858,7 +9133,7 @@ function createPlanTool(stateRef, toolName, description) {
8858
9133
  schema: zod.z.object({
8859
9134
  operation: zod.z.enum(["write", "read", "update"]),
8860
9135
  expectedVersion: zod.z.number().int().min(0).optional(),
8861
- todoList: zod.z.array(zod.z.union([todoWriteItemSchema, todoUpdateItemSchema])).optional()
9136
+ todoList: zod.z.array(todoItemWireSchema).optional()
8862
9137
  }),
8863
9138
  func: async ({ operation, expectedVersion, todoList }) => {
8864
9139
  const toolStateRef = manageTodo._stateRef;
@@ -8924,7 +9199,10 @@ function createPlanTool(stateRef, toolName, description) {
8924
9199
  return {
8925
9200
  status: "error",
8926
9201
  operation,
8927
- error: parsed.error.issues[0]?.message || "Invalid todoList for write.",
9202
+ // The wire schema has `status` optional (one shape for write and
9203
+ // update), so a missing one is caught here — named, so the model
9204
+ // can fix the call.
9205
+ error: describeTodoIssue(parsed.error.issues[0]) || "Invalid todoList for write.",
8928
9206
  version: currentVersion,
8929
9207
  adherenceScore: stateRef.adherenceScore || 0
8930
9208
  };
@@ -8947,7 +9225,7 @@ function createPlanTool(stateRef, toolName, description) {
8947
9225
  return {
8948
9226
  status: "error",
8949
9227
  operation,
8950
- error: parsed.error.issues[0]?.message || "Invalid todoList for update.",
9228
+ error: describeTodoIssue(parsed.error.issues[0]) || "Invalid todoList for update.",
8951
9229
  version: currentVersion,
8952
9230
  adherenceScore: stateRef.adherenceScore || 0
8953
9231
  };
@@ -16607,6 +16885,7 @@ exports.httpSink = httpSink;
16607
16885
  exports.inMemoryCheckpointStore = inMemoryCheckpointStore;
16608
16886
  exports.inMemoryConversationStore = inMemoryConversationStore;
16609
16887
  exports.isHookImplemented = isHookImplemented;
16888
+ exports.isOpenAIHostedEndpoint = isOpenAIHostedEndpoint;
16610
16889
  exports.isSmartModel = isSmartModel;
16611
16890
  exports.isValidIban = isValidIban;
16612
16891
  exports.isValidLuhn = isValidLuhn;
@@ -16635,6 +16914,7 @@ exports.portkeyGateway = portkeyGateway;
16635
16914
  exports.portkeyGuardrail = portkeyGuardrail;
16636
16915
  exports.preopenSkills = preopenSkills;
16637
16916
  exports.preopenToolCallId = preopenToolCallId;
16917
+ exports.prepareStrictToolMenu = prepareStrictToolMenu;
16638
16918
  exports.promptInjectionGuard = promptInjectionGuard;
16639
16919
  exports.rateLimit = rateLimit;
16640
16920
  exports.readMemoryFacts = readMemoryFacts;
@@ -16654,6 +16934,7 @@ exports.resolveToolApprovalState = resolveToolApprovalState;
16654
16934
  exports.resolveUserQuestionState = resolveUserQuestionState;
16655
16935
  exports.responseCache = responseCache;
16656
16936
  exports.restoreSnapshot = restoreSnapshot;
16937
+ exports.restoreToolCalls = restoreToolCalls;
16657
16938
  exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
16658
16939
  exports.scoreItemsByRelevance = scoreItemsByRelevance;
16659
16940
  exports.searchSkills = searchSkills;
@@ -16664,6 +16945,8 @@ exports.setTokenCounter = setTokenCounter;
16664
16945
  exports.startStreamingSession = startStreamingSession;
16665
16946
  exports.summarizeObject = summarizeObject;
16666
16947
  exports.textFromContent = textFromContent;
16948
+ exports.toStrictCompatible = toStrictCompatible;
16949
+ exports.toStrictToolSchema = toStrictToolSchema;
16667
16950
  exports.tokenize = tokenize;
16668
16951
  exports.toolPolicy = toolPolicy;
16669
16952
  exports.traceSessionToOtlp = traceSessionToOtlp;