@cognipeer/agent-sdk 0.8.9 → 0.8.11

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
@@ -2024,6 +2024,177 @@ function extractMessageText2(message) {
2024
2024
  return "";
2025
2025
  }
2026
2026
 
2027
+ // src/smart/toolArgCoercion.ts
2028
+ var PLACEHOLDER_TEXT = /* @__PURE__ */ new Set(["", "null", "undefined", "none", "nil", "n/a", "na"]);
2029
+ var ENVELOPE_KEYS = ["input", "args", "arguments", "params", "parameters", "payload"];
2030
+ function defOf(schema) {
2031
+ const def = schema?._def;
2032
+ return def && typeof def === "object" ? def : null;
2033
+ }
2034
+ function isPlaceholder(value) {
2035
+ return typeof value === "string" && PLACEHOLDER_TEXT.has(value.trim().toLowerCase());
2036
+ }
2037
+ function parseJsonish(value) {
2038
+ const text = value.trim();
2039
+ if (!text.startsWith("{") && !text.startsWith("[")) return { ok: false };
2040
+ try {
2041
+ return { ok: true, value: JSON.parse(text) };
2042
+ } catch {
2043
+ return { ok: false };
2044
+ }
2045
+ }
2046
+ function safeParses(schema, value) {
2047
+ try {
2048
+ return schema.safeParse(value).success === true;
2049
+ } catch {
2050
+ return false;
2051
+ }
2052
+ }
2053
+ function coerceToolArgs(schema, value) {
2054
+ try {
2055
+ return coerceNode(schema, value, 0);
2056
+ } catch {
2057
+ return value;
2058
+ }
2059
+ }
2060
+ function coerceNode(schema, value, depth) {
2061
+ if (depth > 12) return value;
2062
+ const def = defOf(schema);
2063
+ if (!def) return value;
2064
+ switch (def.typeName) {
2065
+ case "ZodOptional":
2066
+ case "ZodNullable": {
2067
+ if (value === void 0 || value === null) return value;
2068
+ if (isPlaceholder(value)) return void 0;
2069
+ return coerceNode(def.innerType, value, depth + 1);
2070
+ }
2071
+ case "ZodDefault":
2072
+ case "ZodCatch":
2073
+ case "ZodReadonly":
2074
+ case "ZodBranded":
2075
+ return coerceNode(def.innerType, value, depth + 1);
2076
+ case "ZodEffects":
2077
+ return coerceNode(def.schema, value, depth + 1);
2078
+ case "ZodPipeline":
2079
+ return coerceNode(def.in, value, depth + 1);
2080
+ case "ZodLazy":
2081
+ return coerceNode(def.getter(), value, depth + 1);
2082
+ case "ZodObject":
2083
+ return coerceObject(def, value, depth);
2084
+ case "ZodRecord": {
2085
+ const unwrapped = unwrapJsonString(value);
2086
+ if (!unwrapped || typeof unwrapped !== "object" || Array.isArray(unwrapped)) return unwrapped ?? value;
2087
+ const out = {};
2088
+ for (const [key, entry] of Object.entries(unwrapped)) {
2089
+ out[key] = def.valueType ? coerceNode(def.valueType, entry, depth + 1) : entry;
2090
+ }
2091
+ return out;
2092
+ }
2093
+ case "ZodArray": {
2094
+ const unwrapped = unwrapJsonString(value);
2095
+ const items = Array.isArray(unwrapped) ? unwrapped : unwrapped === void 0 || unwrapped === null ? unwrapped : [unwrapped];
2096
+ if (!Array.isArray(items)) return items;
2097
+ return items.map((item) => coerceNode(def.type, item, depth + 1));
2098
+ }
2099
+ case "ZodTuple": {
2100
+ const unwrapped = unwrapJsonString(value);
2101
+ if (!Array.isArray(unwrapped)) return unwrapped ?? value;
2102
+ const items = def.items ?? [];
2103
+ return unwrapped.map((item, index) => items[index] ? coerceNode(items[index], item, depth + 1) : item);
2104
+ }
2105
+ case "ZodNumber": {
2106
+ if (typeof value === "number") return value;
2107
+ if (typeof value === "string" && value.trim() !== "") {
2108
+ const parsed = Number(value.trim());
2109
+ if (Number.isFinite(parsed)) return parsed;
2110
+ }
2111
+ if (typeof value === "boolean") return value ? 1 : 0;
2112
+ return value;
2113
+ }
2114
+ case "ZodBoolean": {
2115
+ if (typeof value === "boolean") return value;
2116
+ if (typeof value === "string") {
2117
+ const text = value.trim().toLowerCase();
2118
+ if (text === "true" || text === "yes" || text === "1") return true;
2119
+ if (text === "false" || text === "no" || text === "0") return false;
2120
+ }
2121
+ if (value === 1) return true;
2122
+ if (value === 0) return false;
2123
+ return value;
2124
+ }
2125
+ case "ZodString": {
2126
+ if (typeof value === "string") return value;
2127
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
2128
+ if (value && typeof value === "object") {
2129
+ try {
2130
+ return JSON.stringify(value);
2131
+ } catch {
2132
+ return value;
2133
+ }
2134
+ }
2135
+ return value;
2136
+ }
2137
+ case "ZodEnum": {
2138
+ if (typeof value !== "string") return value;
2139
+ const values = def.values ?? [];
2140
+ if (values.includes(value)) return value;
2141
+ const match = values.find((option) => option.toLowerCase() === value.trim().toLowerCase());
2142
+ return match ?? value;
2143
+ }
2144
+ case "ZodNativeEnum": {
2145
+ if (typeof value !== "string") return value;
2146
+ const values = Object.values(def.values ?? {}).filter((option) => typeof option === "string");
2147
+ if (values.includes(value)) return value;
2148
+ return values.find((option) => option.toLowerCase() === value.trim().toLowerCase()) ?? value;
2149
+ }
2150
+ case "ZodUnion":
2151
+ case "ZodDiscriminatedUnion": {
2152
+ const options = def.options ? Array.isArray(def.options) ? def.options : Array.from(def.options.values()) : [];
2153
+ for (const option of options) {
2154
+ const candidate = coerceNode(option, value, depth + 1);
2155
+ if (safeParses(option, candidate)) return candidate;
2156
+ }
2157
+ return value;
2158
+ }
2159
+ default:
2160
+ return value;
2161
+ }
2162
+ }
2163
+ function unwrapJsonString(value) {
2164
+ if (typeof value !== "string") return value;
2165
+ if (isPlaceholder(value)) return void 0;
2166
+ const parsed = parseJsonish(value);
2167
+ return parsed.ok ? parsed.value : value;
2168
+ }
2169
+ function coerceObject(def, value, depth) {
2170
+ const unwrapped = unwrapJsonString(value);
2171
+ if (!unwrapped || typeof unwrapped !== "object" || Array.isArray(unwrapped)) return unwrapped ?? value;
2172
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape ?? {};
2173
+ const shapeKeys = Object.keys(shape);
2174
+ let source = unwrapped;
2175
+ if (depth === 0 && shapeKeys.length > 0) {
2176
+ const keys = Object.keys(source);
2177
+ if (keys.length === 1 && !shapeKeys.includes(keys[0]) && ENVELOPE_KEYS.includes(keys[0].toLowerCase())) {
2178
+ const inner = unwrapJsonString(source[keys[0]]);
2179
+ if (inner && typeof inner === "object" && !Array.isArray(inner)) {
2180
+ source = inner;
2181
+ }
2182
+ }
2183
+ }
2184
+ const out = {};
2185
+ for (const [key, entry] of Object.entries(source)) {
2186
+ const field = shape[key];
2187
+ if (!field) {
2188
+ out[key] = entry;
2189
+ continue;
2190
+ }
2191
+ const coerced = coerceNode(field, entry, depth + 1);
2192
+ if (coerced === void 0) continue;
2193
+ out[key] = coerced;
2194
+ }
2195
+ return out;
2196
+ }
2197
+
2027
2198
  // src/smart/toolResponses.ts
2028
2199
  var CONTROL_PLANE_TOOL_NAMES = [
2029
2200
  "response",
@@ -2226,17 +2397,60 @@ Use get_tool_response with executionId "${refId}" only if you must recover the o
2226
2397
  }
2227
2398
  function validateToolArgs(tool, args) {
2228
2399
  const schema = tool.schema;
2229
- if (!schema || typeof schema.parse !== "function") {
2400
+ if (!schema || typeof schema.safeParse !== "function") {
2230
2401
  return { ok: true, value: args };
2231
2402
  }
2232
- try {
2233
- return { ok: true, value: schema.parse(args) };
2234
- } catch (error) {
2235
- if (error instanceof zod.ZodError) {
2236
- const message = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
2237
- return { ok: false, message };
2238
- }
2239
- return { ok: false, message: error instanceof Error ? error.message : String(error) };
2403
+ const direct = schema.safeParse(args);
2404
+ if (direct.success) {
2405
+ return { ok: true, value: direct.data };
2406
+ }
2407
+ const repaired = schema.safeParse(coerceToolArgs(schema, args));
2408
+ if (repaired.success) {
2409
+ return { ok: true, value: repaired.data, coerced: true };
2410
+ }
2411
+ const error = direct.error;
2412
+ if (error instanceof zod.ZodError) {
2413
+ const issues = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
2414
+ const expected = describeExpectedArgs(schema);
2415
+ return { ok: false, message: expected ? `${issues}. Expected arguments: ${expected}` : issues };
2416
+ }
2417
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
2418
+ }
2419
+ function describeExpectedArgs(schema) {
2420
+ const shape = typeof schema?._def?.shape === "function" ? schema._def.shape() : schema?._def?.shape;
2421
+ if (!shape || typeof shape !== "object") return null;
2422
+ const parts = Object.entries(shape).map(([key, field]) => {
2423
+ const { typeName, optional } = describeField(field);
2424
+ return `${key}${optional ? "?" : ""}: ${typeName}`;
2425
+ });
2426
+ return parts.length > 0 ? parts.join(", ") : null;
2427
+ }
2428
+ function describeField(field, depth = 0) {
2429
+ const def = field?._def;
2430
+ if (!def || depth > 6) return { typeName: "value", optional: false };
2431
+ switch (def.typeName) {
2432
+ case "ZodOptional":
2433
+ case "ZodNullable":
2434
+ case "ZodDefault":
2435
+ return { typeName: describeField(def.innerType, depth + 1).typeName, optional: true };
2436
+ case "ZodEffects":
2437
+ return { ...describeField(def.schema, depth + 1), optional: describeField(def.schema, depth + 1).optional };
2438
+ case "ZodObject":
2439
+ return { typeName: "object", optional: false };
2440
+ case "ZodArray":
2441
+ return { typeName: `array of ${describeField(def.type, depth + 1).typeName}`, optional: false };
2442
+ case "ZodRecord":
2443
+ return { typeName: "object", optional: false };
2444
+ case "ZodString":
2445
+ return { typeName: "string", optional: false };
2446
+ case "ZodNumber":
2447
+ return { typeName: "number", optional: false };
2448
+ case "ZodBoolean":
2449
+ return { typeName: "boolean", optional: false };
2450
+ case "ZodEnum":
2451
+ return { typeName: `one of ${(def.values ?? []).join("|")}`, optional: false };
2452
+ default:
2453
+ return { typeName: "value", optional: false };
2240
2454
  }
2241
2455
  }
2242
2456
 
@@ -4299,7 +4513,7 @@ var LEVEL_DEFAULTS = {
4299
4513
  };
4300
4514
  var VALID_LEVELS = ["minimal", "low", "medium", "high"];
4301
4515
  var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
4302
- var VALID_EFFORTS = ["minimal", "low", "medium", "high"];
4516
+ var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
4303
4517
  function validateReasoningConfig(input) {
4304
4518
  if (!input) return;
4305
4519
  if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
@@ -8793,12 +9007,19 @@ function parseSSEBlock(block) {
8793
9007
 
8794
9008
  // src/providers/utils/reasoning.ts
8795
9009
  var ANTHROPIC_EFFORT_BUDGET = {
9010
+ // 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
9011
+ // thinking block, which on Anthropic IS off — thinking there is opt-in.
9012
+ none: 0,
8796
9013
  minimal: 1024,
8797
9014
  low: 2048,
8798
9015
  medium: 8192,
8799
9016
  high: 16384
8800
9017
  };
8801
9018
  var GEMINI_EFFORT_BUDGET = {
9019
+ // 0 is Gemini's own documented spelling for "do not think", and unlike
9020
+ // Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
9021
+ // rather than falsiness.
9022
+ none: 0,
8802
9023
  minimal: 512,
8803
9024
  low: 1024,
8804
9025
  medium: 4096,
@@ -8874,14 +9095,15 @@ function clampBudget(budget, maxTokens) {
8874
9095
  }
8875
9096
  function normalizeEffort(effort) {
8876
9097
  if (!effort) return void 0;
8877
- const allowed = ["minimal", "low", "medium", "high"];
9098
+ const allowed = ["none", "minimal", "low", "medium", "high"];
8878
9099
  return allowed.includes(effort) ? effort : void 0;
8879
9100
  }
8880
9101
  function resolveBudget(reasoning, effortBudget) {
9102
+ const effort = normalizeEffort(reasoning.effort);
9103
+ if (effort === "none") return 0;
8881
9104
  if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
8882
9105
  return Math.floor(reasoning.budgetTokens);
8883
9106
  }
8884
- const effort = normalizeEffort(reasoning.effort);
8885
9107
  if (effort && effortBudget[effort]) return effortBudget[effort];
8886
9108
  return void 0;
8887
9109
  }
@@ -8970,12 +9192,21 @@ var OpenAIProvider = class extends BaseProvider {
8970
9192
  ...config.defaultHeaders,
8971
9193
  ...config.organization ? { "OpenAI-Organization": config.organization } : {}
8972
9194
  };
9195
+ this.responsesApi = config.responsesApi ?? "auto";
8973
9196
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
8974
9197
  }
8975
- /** True when the request targets a reasoning model (o-series / gpt-5) so we
8976
- * should route through the Responses API, which exposes `reasoning.effort`
8977
- * and reasoning summaries. Chat Completions silently drops these. */
9198
+ /** True when this request should go to the Responses API rather than Chat
9199
+ * Completions — which exposes `reasoning.effort` and reasoning summaries that
9200
+ * Chat Completions silently drops.
9201
+ *
9202
+ * `auto` (the default) keeps the historical rule: only when the request
9203
+ * carries a reasoning config AND the model name looks like an o-series/gpt-5
9204
+ * model. `never`/`always` let a caller state the answer instead, because the
9205
+ * name check is a guess and the two APIs differ in far more than reasoning —
9206
+ * see `responsesApi` in OpenAIProviderConfig. */
8978
9207
  useResponsesApi(request) {
9208
+ if (this.responsesApi === "never") return false;
9209
+ if (this.responsesApi === "always") return true;
8979
9210
  if (!request.reasoning) return false;
8980
9211
  return isReasoningModel(request.model || this.defaultModel);
8981
9212
  }
@@ -10838,7 +11069,7 @@ function fromNativeProvider(provider, options) {
10838
11069
  if (tools?.length) req.tools = tools;
10839
11070
  if (opts?.extra) req.extra = opts.extra;
10840
11071
  const reasoningOverride = invokeOptions?.reasoning;
10841
- const reasoningCfg = reasoningOverride ?? opts?.reasoning;
11072
+ const reasoningCfg = mergeReasoning(opts?.reasoning, reasoningOverride);
10842
11073
  if (reasoningCfg) req.reasoning = reasoningCfg;
10843
11074
  const tc = invokeOptions?.tool_choice ?? invokeOptions?.toolChoice;
10844
11075
  if (tc && tools?.length) {
@@ -10867,6 +11098,15 @@ function fromNativeProvider(provider, options) {
10867
11098
  return req;
10868
11099
  }
10869
11100
  }
11101
+ function mergeReasoning(base, override) {
11102
+ if (!base) return override;
11103
+ if (!override) return base;
11104
+ const merged = { ...base, ...override };
11105
+ if (base.providerExtras || override.providerExtras) {
11106
+ merged.providerExtras = { ...base.providerExtras, ...override.providerExtras };
11107
+ }
11108
+ return merged;
11109
+ }
10870
11110
  function toUnifiedMessage(msg) {
10871
11111
  const unified = {
10872
11112
  role: msg.role,
@@ -11033,6 +11273,43 @@ function convertToJsonSchema(schema, strict = false) {
11033
11273
  }
11034
11274
  return converted;
11035
11275
  }
11276
+ function simplifyOptionalNullableUnions(schema, required = null) {
11277
+ if (!schema || typeof schema !== "object") return schema;
11278
+ const clone2 = { ...schema };
11279
+ if (clone2.properties && typeof clone2.properties === "object") {
11280
+ const requiredKeys = new Set(Array.isArray(clone2.required) ? clone2.required : []);
11281
+ const properties = {};
11282
+ for (const [key, value] of Object.entries(clone2.properties)) {
11283
+ const child = simplifyOptionalNullableUnions(value, requiredKeys);
11284
+ properties[key] = requiredKeys.has(key) ? child : dropNullBranch(child);
11285
+ }
11286
+ clone2.properties = properties;
11287
+ }
11288
+ if (clone2.items) clone2.items = simplifyOptionalNullableUnions(clone2.items, required);
11289
+ for (const key of ["anyOf", "oneOf", "allOf"]) {
11290
+ if (Array.isArray(clone2[key])) {
11291
+ clone2[key] = clone2[key].map((entry) => simplifyOptionalNullableUnions(entry, required));
11292
+ }
11293
+ }
11294
+ return clone2;
11295
+ }
11296
+ function dropNullBranch(schema) {
11297
+ if (!schema || typeof schema !== "object") return schema;
11298
+ if (Array.isArray(schema.type) && schema.type.includes("null") && schema.type.length === 2) {
11299
+ return { ...schema, type: schema.type.find((entry) => entry !== "null") };
11300
+ }
11301
+ if (Array.isArray(schema.anyOf)) {
11302
+ const branches = schema.anyOf.filter((entry) => entry?.type !== "null");
11303
+ if (branches.length === 1 && branches.length !== schema.anyOf.length) {
11304
+ const { anyOf, ...rest } = schema;
11305
+ return { ...branches[0], ...rest };
11306
+ }
11307
+ if (branches.length !== schema.anyOf.length && branches.length > 1) {
11308
+ return { ...schema, anyOf: branches };
11309
+ }
11310
+ }
11311
+ return schema;
11312
+ }
11036
11313
  function normalizeStrictSchema(schema) {
11037
11314
  if (!schema || typeof schema !== "object") return schema;
11038
11315
  const clone2 = { ...schema };
@@ -11097,6 +11374,8 @@ function toToolDefinition(tool, strict) {
11097
11374
  parameters = convertToJsonSchema(rawSchema, useStrict);
11098
11375
  if (useStrict) {
11099
11376
  parameters = normalizeStrictSchema(parameters);
11377
+ } else {
11378
+ parameters = simplifyOptionalNullableUnions(parameters);
11100
11379
  }
11101
11380
  return { name, description, parameters, ...useStrict ? { strict: true } : {} };
11102
11381
  }
@@ -11269,6 +11548,7 @@ exports.canOpenSkill = canOpenSkill;
11269
11548
  exports.canSpawn = canSpawn;
11270
11549
  exports.captureSnapshot = captureSnapshot;
11271
11550
  exports.codePresenceRule = codePresenceRule;
11551
+ exports.coerceToolArgs = coerceToolArgs;
11272
11552
  exports.cognipeerSink = cognipeerSink;
11273
11553
  exports.collectToolRetentionDeclarations = collectToolRetentionDeclarations;
11274
11554
  exports.composeToolSets = composeToolSets;
@@ -11363,6 +11643,7 @@ exports.summarizeObject = summarizeObject;
11363
11643
  exports.tokenize = tokenize;
11364
11644
  exports.traceSessionToOtlp = traceSessionToOtlp;
11365
11645
  exports.validateReasoningConfig = validateReasoningConfig;
11646
+ exports.validateToolArgs = validateToolArgs;
11366
11647
  exports.withTools = withTools;
11367
11648
  exports.withinDepth = withinDepth;
11368
11649
  exports.writeSummaryFactsToMemory = writeSummaryFactsToMemory;