@opencow-ai/opencow-agent-sdk 0.4.2 → 0.4.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/cli.mjs CHANGED
@@ -57406,12 +57406,12 @@ function getOpus46CostTier(fastMode) {
57406
57406
  return COST_TIER_5_25;
57407
57407
  }
57408
57408
  function tokensToUSDCost(modelCosts, usage) {
57409
- return usage.input_tokens / 1e6 * modelCosts.inputTokens + usage.output_tokens / 1e6 * modelCosts.outputTokens + (usage.cache_read_input_tokens ?? 0) / 1e6 * modelCosts.promptCacheReadTokens + (usage.cache_creation_input_tokens ?? 0) / 1e6 * modelCosts.promptCacheWriteTokens + (usage.server_tool_use?.web_search_requests ?? 0) * modelCosts.webSearchRequests;
57409
+ return (usage?.input_tokens ?? 0) / 1e6 * modelCosts.inputTokens + (usage?.output_tokens ?? 0) / 1e6 * modelCosts.outputTokens + (usage?.cache_read_input_tokens ?? 0) / 1e6 * modelCosts.promptCacheReadTokens + (usage?.cache_creation_input_tokens ?? 0) / 1e6 * modelCosts.promptCacheWriteTokens + (usage?.server_tool_use?.web_search_requests ?? 0) * modelCosts.webSearchRequests;
57410
57410
  }
57411
57411
  function getModelCosts(model, usage) {
57412
57412
  const shortName = getCanonicalName(model);
57413
57413
  if (shortName === firstPartyNameToCanonical(CLAUDE_OPUS_4_6_CONFIG.firstParty)) {
57414
- const isFastMode = usage.speed === "fast";
57414
+ const isFastMode = usage?.speed === "fast";
57415
57415
  return getOpus46CostTier(isFastMode);
57416
57416
  }
57417
57417
  const costs = MODEL_COSTS[shortName];
@@ -84200,6 +84200,83 @@ function sanitizeTypeField(record2) {
84200
84200
  record2.type = filtered;
84201
84201
  }
84202
84202
  }
84203
+ function makeSchemaNullable(schema, style = "union") {
84204
+ if ("enum" in schema || "const" in schema)
84205
+ return schema;
84206
+ if (schema.nullable === true)
84207
+ return schema;
84208
+ const raw = schema.type;
84209
+ if (style === "nullable") {
84210
+ if (typeof raw === "string") {
84211
+ if (raw === "null")
84212
+ return schema;
84213
+ return { ...schema, nullable: true };
84214
+ }
84215
+ if (Array.isArray(raw)) {
84216
+ if (raw.includes("null"))
84217
+ return schema;
84218
+ return { ...schema, nullable: true };
84219
+ }
84220
+ return schema;
84221
+ }
84222
+ if (typeof raw === "string") {
84223
+ if (raw === "null")
84224
+ return schema;
84225
+ return { ...schema, type: [raw, "null"] };
84226
+ }
84227
+ if (Array.isArray(raw)) {
84228
+ if (raw.includes("null"))
84229
+ return schema;
84230
+ return { ...schema, type: [...raw, "null"] };
84231
+ }
84232
+ return schema;
84233
+ }
84234
+ function splitTypeArrayToAnyOf(schema) {
84235
+ if (!Array.isArray(schema.type) || schema.type.length < 2)
84236
+ return schema;
84237
+ const types = schema.type;
84238
+ const hasNull = types.includes("null");
84239
+ const nonNullTypes = types.filter((t) => t !== "null");
84240
+ if (hasNull && nonNullTypes.length === 1) {
84241
+ const { type: _type, ...rest } = schema;
84242
+ return { ...rest, type: nonNullTypes[0], nullable: true };
84243
+ }
84244
+ const ARRAY_KEYS = new Set(["items"]);
84245
+ const OBJECT_KEYS = new Set(["properties", "required", "additionalProperties"]);
84246
+ const TYPE_SPECIFIC_KEYS = new Set([...ARRAY_KEYS, ...OBJECT_KEYS]);
84247
+ const base2 = {};
84248
+ const structural = {};
84249
+ for (const [key, value] of Object.entries(schema)) {
84250
+ if (key === "type")
84251
+ continue;
84252
+ if (TYPE_SPECIFIC_KEYS.has(key)) {
84253
+ structural[key] = value;
84254
+ } else {
84255
+ base2[key] = value;
84256
+ }
84257
+ }
84258
+ const variants = nonNullTypes.map((t) => {
84259
+ const variant = { type: t };
84260
+ if (t === "array") {
84261
+ for (const k of ARRAY_KEYS) {
84262
+ if (k in structural)
84263
+ variant[k] = structural[k];
84264
+ }
84265
+ } else if (t === "object") {
84266
+ for (const k of OBJECT_KEYS) {
84267
+ if (k in structural)
84268
+ variant[k] = structural[k];
84269
+ }
84270
+ }
84271
+ return variant;
84272
+ });
84273
+ if (hasNull)
84274
+ base2.nullable = true;
84275
+ if (variants.length === 1) {
84276
+ return { ...base2, ...variants[0] };
84277
+ }
84278
+ return { ...base2, anyOf: variants };
84279
+ }
84203
84280
  function sanitizeSchemaForOpenAICompat(schema) {
84204
84281
  const stripped = stripSchemaKeywords(schema, OPENAI_INCOMPATIBLE_SCHEMA_KEYWORDS);
84205
84282
  if (!isSchemaRecord(stripped)) {
@@ -84516,7 +84593,7 @@ function convertAnthropicMessagesToResponsesInput(messages) {
84516
84593
  }
84517
84594
  return items.filter((item) => item.type !== "message" || item.content.length > 0);
84518
84595
  }
84519
- function enforceStrictSchema(schema) {
84596
+ function enforceStrictSchema(schema, topLevel = true) {
84520
84597
  const record2 = sanitizeSchemaForOpenAICompat(schema);
84521
84598
  if (record2.format === "uri") {
84522
84599
  delete record2.format;
@@ -84525,10 +84602,10 @@ function enforceStrictSchema(schema) {
84525
84602
  record2.additionalProperties = false;
84526
84603
  if (record2.properties && typeof record2.properties === "object" && !Array.isArray(record2.properties)) {
84527
84604
  const props = record2.properties;
84528
- const allKeys = Object.keys(props);
84605
+ const originalRequired = Array.isArray(record2.required) ? record2.required.filter((key) => typeof key === "string") : [];
84529
84606
  const enforcedProps = {};
84530
84607
  for (const [key, value] of Object.entries(props)) {
84531
- const strictValue = enforceStrictSchema(value);
84608
+ const strictValue = enforceStrictSchema(value, false);
84532
84609
  if (strictValue && typeof strictValue === "object" && strictValue.type === "object" && strictValue.additionalProperties === false && (!strictValue.properties || Object.keys(strictValue.properties).length === 0)) {
84533
84610
  continue;
84534
84611
  }
@@ -84536,20 +84613,27 @@ function enforceStrictSchema(schema) {
84536
84613
  }
84537
84614
  record2.properties = enforcedProps;
84538
84615
  record2.required = Object.keys(enforcedProps);
84616
+ if (topLevel) {
84617
+ for (const key of Object.keys(enforcedProps)) {
84618
+ if (!originalRequired.includes(key)) {
84619
+ enforcedProps[key] = makeSchemaNullable(enforcedProps[key]);
84620
+ }
84621
+ }
84622
+ }
84539
84623
  } else {
84540
84624
  record2.required = [];
84541
84625
  }
84542
84626
  }
84543
84627
  if ("items" in record2) {
84544
84628
  if (Array.isArray(record2.items)) {
84545
- record2.items = record2.items.map((item) => enforceStrictSchema(item));
84629
+ record2.items = record2.items.map((item) => enforceStrictSchema(item, false));
84546
84630
  } else {
84547
- record2.items = enforceStrictSchema(record2.items);
84631
+ record2.items = enforceStrictSchema(record2.items, false);
84548
84632
  }
84549
84633
  }
84550
84634
  for (const key of ["anyOf", "oneOf", "allOf"]) {
84551
84635
  if (key in record2 && Array.isArray(record2[key])) {
84552
- record2[key] = record2[key].map((item) => enforceStrictSchema(item));
84636
+ record2[key] = record2[key].map((item) => enforceStrictSchema(item, false));
84553
84637
  }
84554
84638
  }
84555
84639
  return record2;
@@ -85017,6 +85101,51 @@ var init_shim = __esm(() => {
85017
85101
  init_schema();
85018
85102
  });
85019
85103
 
85104
+ // src/providers/openai/capabilities.ts
85105
+ function supportsReasoningEffort(model) {
85106
+ return /^(o\d|gpt-5|gpt-4\.5)/i.test(model);
85107
+ }
85108
+ function isGeminiLikeModel(model) {
85109
+ const normalized = (model ?? "").trim().toLowerCase();
85110
+ return normalized.startsWith("gemini-") || normalized.includes("/gemini-");
85111
+ }
85112
+ function isGeminiTarget(model) {
85113
+ if (isEnvTruthy(getQueryEnvVar("CLAUDE_CODE_USE_GEMINI")))
85114
+ return true;
85115
+ return isGeminiLikeModel(model);
85116
+ }
85117
+ function supportsParallelToolCalls(model) {
85118
+ return !isGeminiTarget(model);
85119
+ }
85120
+ function getOpenAICompatMaxOutputTokens(model) {
85121
+ const max = getOpenAIMaxOutputTokens(model);
85122
+ if (max === undefined)
85123
+ return null;
85124
+ return { default: max, upperLimit: max };
85125
+ }
85126
+ function getOpenAICompatContextWindow(model) {
85127
+ return getOpenAIContextWindow(model) ?? null;
85128
+ }
85129
+ function openAICompatSupports(feature, model) {
85130
+ if (feature === "reasoning-effort")
85131
+ return supportsReasoningEffort(model);
85132
+ if (feature === "parallel-tool-calls")
85133
+ return supportsParallelToolCalls(model);
85134
+ return FEATURES_OPENAI_COMPAT.includes(feature);
85135
+ }
85136
+ var FEATURES_OPENAI_COMPAT;
85137
+ var init_capabilities2 = __esm(() => {
85138
+ init_openaiContextWindows();
85139
+ init_envUtils();
85140
+ init_state2();
85141
+ FEATURES_OPENAI_COMPAT = Object.freeze([
85142
+ "streaming",
85143
+ "tool-use",
85144
+ "image-input",
85145
+ "system-message-top-level"
85146
+ ]);
85147
+ });
85148
+
85020
85149
  // src/providers/openai/shim.ts
85021
85150
  var exports_shim = {};
85022
85151
  __export(exports_shim, {
@@ -85186,15 +85315,18 @@ function convertMessages(messages, system) {
85186
85315
  }
85187
85316
  }
85188
85317
  if (otherContent.length > 0) {
85189
- result.push({
85190
- role: "user",
85191
- content: convertContentBlocks(otherContent)
85192
- });
85318
+ const converted = convertContentBlocks(otherContent);
85319
+ if (converted !== "") {
85320
+ result.push({
85321
+ role: "user",
85322
+ content: converted
85323
+ });
85324
+ }
85193
85325
  }
85194
85326
  } else {
85195
85327
  result.push({
85196
85328
  role: "user",
85197
- content: convertContentBlocks(content)
85329
+ content: convertContentBlocks(content) || "."
85198
85330
  });
85199
85331
  }
85200
85332
  } else if (role === "assistant") {
@@ -85206,7 +85338,8 @@ function convertMessages(messages, system) {
85206
85338
  role: "assistant",
85207
85339
  content: (() => {
85208
85340
  const c5 = convertContentBlocks(textContent);
85209
- return typeof c5 === "string" ? c5 : Array.isArray(c5) ? c5.map((p) => p.text ?? "").join("") : "";
85341
+ const text = typeof c5 === "string" ? c5 : Array.isArray(c5) ? c5.map((p) => p.text ?? "").join("") : "";
85342
+ return text || null;
85210
85343
  })()
85211
85344
  };
85212
85345
  if (thinkingBlocks.length > 0) {
@@ -85229,52 +85362,63 @@ function convertMessages(messages, system) {
85229
85362
  }
85230
85363
  result.push(assistantMsg);
85231
85364
  } else {
85365
+ const c5 = convertContentBlocks(content);
85366
+ const text = typeof c5 === "string" ? c5 : Array.isArray(c5) ? c5.map((p) => p.text ?? "").join("") : "";
85232
85367
  result.push({
85233
85368
  role: "assistant",
85234
- content: (() => {
85235
- const c5 = convertContentBlocks(content);
85236
- return typeof c5 === "string" ? c5 : Array.isArray(c5) ? c5.map((p) => p.text ?? "").join("") : "";
85237
- })()
85369
+ content: text || null
85238
85370
  });
85239
85371
  }
85240
85372
  }
85241
85373
  }
85242
85374
  return result;
85243
85375
  }
85244
- function normalizeSchemaForOpenAI(schema, strict = true) {
85245
- const record2 = sanitizeSchemaForOpenAICompat(schema);
85376
+ function normalizeSchemaForOpenAI(schema, strict = true, topLevel = true, geminiTarget = false) {
85377
+ let record2 = sanitizeSchemaForOpenAICompat(schema);
85378
+ if (geminiTarget) {
85379
+ record2 = splitTypeArrayToAnyOf(record2);
85380
+ }
85246
85381
  if (record2.type === "object" && record2.properties) {
85247
85382
  const properties = record2.properties;
85248
85383
  const existingRequired = Array.isArray(record2.required) ? record2.required : [];
85249
85384
  const normalizedProps = {};
85250
85385
  for (const [key, value] of Object.entries(properties)) {
85251
- normalizedProps[key] = normalizeSchemaForOpenAI(value, strict);
85386
+ normalizedProps[key] = normalizeSchemaForOpenAI(value, strict, false, geminiTarget);
85252
85387
  }
85253
85388
  record2.properties = normalizedProps;
85254
85389
  if (strict) {
85255
85390
  const allKeys = Object.keys(normalizedProps);
85256
85391
  record2.required = Array.from(new Set([...existingRequired, ...allKeys]));
85257
85392
  record2.additionalProperties = false;
85393
+ if (topLevel) {
85394
+ const style = geminiTarget ? "nullable" : "union";
85395
+ for (const key of allKeys) {
85396
+ if (!existingRequired.includes(key)) {
85397
+ normalizedProps[key] = makeSchemaNullable(normalizedProps[key], style);
85398
+ }
85399
+ }
85400
+ }
85258
85401
  } else {
85259
85402
  record2.required = existingRequired.filter((k) => (k in normalizedProps));
85260
85403
  }
85261
85404
  }
85262
85405
  if ("items" in record2) {
85263
85406
  if (Array.isArray(record2.items)) {
85264
- record2.items = record2.items.map((item) => normalizeSchemaForOpenAI(item, strict));
85407
+ record2.items = record2.items.map((item) => normalizeSchemaForOpenAI(item, strict, false, geminiTarget));
85265
85408
  } else {
85266
- record2.items = normalizeSchemaForOpenAI(record2.items, strict);
85409
+ record2.items = normalizeSchemaForOpenAI(record2.items, strict, false, geminiTarget);
85267
85410
  }
85268
85411
  }
85269
85412
  for (const key of ["anyOf", "oneOf", "allOf"]) {
85270
85413
  if (key in record2 && Array.isArray(record2[key])) {
85271
- record2[key] = record2[key].map((item) => normalizeSchemaForOpenAI(item, strict));
85414
+ record2[key] = record2[key].map((item) => normalizeSchemaForOpenAI(item, strict, false, geminiTarget));
85272
85415
  }
85273
85416
  }
85274
85417
  return record2;
85275
85418
  }
85276
- function convertTools(tools) {
85419
+ function convertTools(tools, model = "") {
85277
85420
  const isGemini = isEnvTruthy(getQueryEnvVar("CLAUDE_CODE_USE_GEMINI"));
85421
+ const geminiTarget = isGeminiTarget(model);
85278
85422
  return tools.filter((t) => t.name !== "ToolSearchTool").map((t) => {
85279
85423
  const schema = { ...t.input_schema ?? { type: "object", properties: {} } };
85280
85424
  if (t.name === "Agent" && schema.properties) {
@@ -85292,7 +85436,7 @@ function convertTools(tools) {
85292
85436
  function: {
85293
85437
  name: t.name,
85294
85438
  description: t.description ?? "",
85295
- parameters: normalizeSchemaForOpenAI(schema, !isGemini)
85439
+ parameters: normalizeSchemaForOpenAI(schema, !isGemini, true, geminiTarget)
85296
85440
  }
85297
85441
  };
85298
85442
  });
@@ -85313,8 +85457,63 @@ function convertChunkUsage(usage) {
85313
85457
  function toOpenAIChatReasoningEffort(effort) {
85314
85458
  return effort === "xhigh" ? "high" : effort;
85315
85459
  }
85460
+ function getOpenAIChatProviderCapabilities(model) {
85461
+ return {
85462
+ supportsParallelToolCalls: openAICompatSupports("parallel-tool-calls", model)
85463
+ };
85464
+ }
85465
+ function collectAdjacentToolMessages(messages, startIndex) {
85466
+ const toolMessages = [];
85467
+ for (let i2 = startIndex;i2 < messages.length && messages[i2]?.role === "tool"; i2++) {
85468
+ toolMessages.push(messages[i2]);
85469
+ }
85470
+ return toolMessages;
85471
+ }
85472
+ function indexToolMessagesById(toolMessages) {
85473
+ const byId = new Map;
85474
+ for (const toolMessage of toolMessages) {
85475
+ if (typeof toolMessage.tool_call_id === "string") {
85476
+ byId.set(toolMessage.tool_call_id, toolMessage);
85477
+ }
85478
+ }
85479
+ return byId;
85480
+ }
85481
+ function splitParallelToolCallTurn(assistantMessage, toolCalls, toolMessagesById) {
85482
+ const serialized = [];
85483
+ toolCalls.forEach((toolCall, index) => {
85484
+ serialized.push({
85485
+ ...assistantMessage,
85486
+ tool_calls: [toolCall],
85487
+ content: index === 0 ? assistantMessage.content : null
85488
+ });
85489
+ const toolResponse = toolMessagesById.get(toolCall.id);
85490
+ if (toolResponse)
85491
+ serialized.push(toolResponse);
85492
+ });
85493
+ return serialized;
85494
+ }
85495
+ function serializeParallelToolCalls(messages, capabilities) {
85496
+ if (capabilities.supportsParallelToolCalls)
85497
+ return messages;
85498
+ const result = [];
85499
+ for (let i2 = 0;i2 < messages.length; i2++) {
85500
+ const message = messages[i2];
85501
+ const toolCalls = message.tool_calls;
85502
+ const isParallelToolTurn = message.role === "assistant" && (toolCalls?.length ?? 0) > 1;
85503
+ if (!isParallelToolTurn || !toolCalls) {
85504
+ result.push(message);
85505
+ continue;
85506
+ }
85507
+ const toolMessages = collectAdjacentToolMessages(messages, i2 + 1);
85508
+ const toolMessagesById = indexToolMessagesById(toolMessages);
85509
+ result.push(...splitParallelToolCallTurn(message, toolCalls, toolMessagesById));
85510
+ i2 += toolMessages.length;
85511
+ }
85512
+ return result;
85513
+ }
85316
85514
  function buildOpenAIRequestBody(params, ctx) {
85317
- const openaiMessages = convertMessages(params.messages, params.system);
85515
+ const capabilities = getOpenAIChatProviderCapabilities(ctx.resolvedModel);
85516
+ const openaiMessages = serializeParallelToolCalls(convertMessages(params.messages, params.system), capabilities);
85318
85517
  const body = {
85319
85518
  model: ctx.resolvedModel,
85320
85519
  messages: openaiMessages,
@@ -85342,9 +85541,12 @@ function buildOpenAIRequestBody(params, ctx) {
85342
85541
  body.reasoning_effort = toOpenAIChatReasoningEffort(ctx.reasoning.effort);
85343
85542
  }
85344
85543
  if (params.tools && params.tools.length > 0) {
85345
- const converted = convertTools(params.tools);
85544
+ const converted = convertTools(params.tools, ctx.resolvedModel);
85346
85545
  if (converted.length > 0) {
85347
85546
  body.tools = converted;
85547
+ if (!capabilities.supportsParallelToolCalls) {
85548
+ body.parallel_tool_calls = false;
85549
+ }
85348
85550
  if (params.tool_choice) {
85349
85551
  const tc = params.tool_choice;
85350
85552
  if (tc.type === "auto") {
@@ -85440,7 +85642,13 @@ async function* openaiStreamToAnthropic(response, model) {
85440
85642
  })}`);
85441
85643
  }
85442
85644
  }
85443
- if (delta.reasoning_content != null) {
85645
+ let reasoningText = delta.reasoning_content ?? delta.reasoning;
85646
+ if (reasoningText == null && Array.isArray(delta.reasoning_details)) {
85647
+ const parts = delta.reasoning_details.map((d) => d.content ?? d.summary ?? "").filter(Boolean);
85648
+ if (parts.length > 0)
85649
+ reasoningText = parts.join("");
85650
+ }
85651
+ if (reasoningText != null) {
85444
85652
  if (reasoningBlockIndex === null) {
85445
85653
  reasoningBlockIndex = contentBlockIndex;
85446
85654
  contentBlockIndex++;
@@ -85462,7 +85670,7 @@ async function* openaiStreamToAnthropic(response, model) {
85462
85670
  index: reasoningBlockIndex,
85463
85671
  delta: {
85464
85672
  type: "thinking_delta",
85465
- thinking: delta.reasoning_content
85673
+ thinking: reasoningText
85466
85674
  }
85467
85675
  };
85468
85676
  continue;
@@ -85825,6 +86033,22 @@ class OpenAIShimMessages {
85825
86033
  function convertOpenAIResponseToAnthropic(data, model) {
85826
86034
  const choice = data.choices?.[0];
85827
86035
  const content = [];
86036
+ const msg = choice?.message;
86037
+ let reasoningText = msg?.reasoning_content ?? msg?.reasoning;
86038
+ if (reasoningText == null && Array.isArray(msg?.reasoning_details)) {
86039
+ const parts = msg.reasoning_details.map((d) => d.content ?? d.summary ?? "").filter(Boolean);
86040
+ if (parts.length > 0)
86041
+ reasoningText = parts.join(`
86042
+ `);
86043
+ }
86044
+ if (typeof reasoningText === "string" && reasoningText) {
86045
+ content.push({
86046
+ type: "thinking",
86047
+ thinking: reasoningText,
86048
+ signature: "",
86049
+ extra_content: { provenance: "openai-chat" }
86050
+ });
86051
+ }
85828
86052
  const rawContent = choice?.message?.content;
85829
86053
  if (typeof rawContent === "string" && rawContent) {
85830
86054
  content.push({ type: "text", text: rawContent });
@@ -85928,6 +86152,7 @@ var init_shim2 = __esm(() => {
85928
86152
  init_config3();
85929
86153
  init_schemaSanitizer();
85930
86154
  init_providerProfile();
86155
+ init_capabilities2();
85931
86156
  OpenAIShimStream = class OpenAIShimStream {
85932
86157
  generator;
85933
86158
  controller = new AbortController;
@@ -86200,36 +86425,6 @@ var init_anthropic = __esm(() => {
86200
86425
  init_errors5();
86201
86426
  });
86202
86427
 
86203
- // src/providers/openai/capabilities.ts
86204
- function supportsReasoningEffort(model) {
86205
- return /^(o\d|gpt-5|gpt-4\.5)/i.test(model);
86206
- }
86207
- function getOpenAICompatMaxOutputTokens(model) {
86208
- const max = getOpenAIMaxOutputTokens(model);
86209
- if (max === undefined)
86210
- return null;
86211
- return { default: max, upperLimit: max };
86212
- }
86213
- function getOpenAICompatContextWindow(model) {
86214
- return getOpenAIContextWindow(model) ?? null;
86215
- }
86216
- function openAICompatSupports(feature, model) {
86217
- if (feature === "reasoning-effort")
86218
- return supportsReasoningEffort(model);
86219
- return FEATURES_OPENAI_COMPAT.includes(feature);
86220
- }
86221
- var FEATURES_OPENAI_COMPAT;
86222
- var init_capabilities2 = __esm(() => {
86223
- init_openaiContextWindows();
86224
- FEATURES_OPENAI_COMPAT = Object.freeze([
86225
- "streaming",
86226
- "tool-use",
86227
- "image-input",
86228
- "parallel-tool-calls",
86229
- "system-message-top-level"
86230
- ]);
86231
- });
86232
-
86233
86428
  // src/providers/openai/errors.ts
86234
86429
  function readErrorMessage(body) {
86235
86430
  if (!body || typeof body !== "object")
@@ -94171,7 +94366,7 @@ function printStartupScreen() {
94171
94366
  const sLen = ` ● ${sL} Ready — type /help to begin`.length;
94172
94367
  out.push(boxRow(sRow, W2, sLen));
94173
94368
  out.push(`${rgb(...BORDER)}╚${"═".repeat(W2 - 2)}╝${RESET}`);
94174
- out.push(` ${DIM}${rgb(...DIMCOL)}opencow ${RESET}${rgb(...ACCENT)}v${"0.4.2"}${RESET}`);
94369
+ out.push(` ${DIM}${rgb(...DIMCOL)}opencow ${RESET}${rgb(...ACCENT)}v${"0.4.4"}${RESET}`);
94175
94370
  out.push("");
94176
94371
  process.stdout.write(out.join(`
94177
94372
  `) + `
@@ -95326,10 +95521,10 @@ function getCLISyspromptPrefix(options) {
95326
95521
  return DEFAULT_PREFIX;
95327
95522
  }
95328
95523
  function isAttributionHeaderEnabled() {
95329
- if (isEnvDefinedFalsy(resolveEnvVar("ATTRIBUTION_HEADER"))) {
95330
- return false;
95524
+ if (isEnvTruthy(resolveEnvVar("ATTRIBUTION_HEADER"))) {
95525
+ return true;
95331
95526
  }
95332
- return getFeatureValue_CACHED_MAY_BE_STALE("tengu_attribution_header", true);
95527
+ return getFeatureValue_CACHED_MAY_BE_STALE("tengu_attribution_header", false);
95333
95528
  }
95334
95529
  function getAttributionHeader(fingerprint) {
95335
95530
  if (!isAttributionHeaderEnabled()) {
@@ -95340,7 +95535,7 @@ function getAttributionHeader(fingerprint) {
95340
95535
  const cch = "";
95341
95536
  const workload = getWorkload();
95342
95537
  const workloadPair = workload ? ` cc_workload=${workload};` : "";
95343
- const header = `x-anthropic-billing-header: cc_version=${version2}; cc_entrypoint=${entrypoint};${cch}${workloadPair}`;
95538
+ const header = `x-opencow-billing-header: cc_version=${version2}; cc_entrypoint=${entrypoint};${cch}${workloadPair}`;
95344
95539
  logForDebugging2(`attribution header ${header}`);
95345
95540
  return header;
95346
95541
  }
@@ -106266,7 +106461,7 @@ function getInitialAdvisorSetting() {
106266
106461
  return getInitialSettings().advisorModel;
106267
106462
  }
106268
106463
  function getAdvisorUsage(usage) {
106269
- const iterations = usage.iterations;
106464
+ const iterations = usage?.iterations;
106270
106465
  if (!iterations) {
106271
106466
  return [];
106272
106467
  }
@@ -106424,11 +106619,11 @@ function addToTotalModelUsage(cost, usage, model) {
106424
106619
  contextWindow: 0,
106425
106620
  maxOutputTokens: 0
106426
106621
  };
106427
- modelUsage.inputTokens += usage.input_tokens;
106428
- modelUsage.outputTokens += usage.output_tokens;
106429
- modelUsage.cacheReadInputTokens += usage.cache_read_input_tokens ?? 0;
106430
- modelUsage.cacheCreationInputTokens += usage.cache_creation_input_tokens ?? 0;
106431
- modelUsage.webSearchRequests += usage.server_tool_use?.web_search_requests ?? 0;
106622
+ modelUsage.inputTokens += usage?.input_tokens ?? 0;
106623
+ modelUsage.outputTokens += usage?.output_tokens ?? 0;
106624
+ modelUsage.cacheReadInputTokens += usage?.cache_read_input_tokens ?? 0;
106625
+ modelUsage.cacheCreationInputTokens += usage?.cache_creation_input_tokens ?? 0;
106626
+ modelUsage.webSearchRequests += usage?.server_tool_use?.web_search_requests ?? 0;
106432
106627
  modelUsage.costUSD += cost;
106433
106628
  modelUsage.contextWindow = getContextWindowForModel(model, getSdkBetas());
106434
106629
  modelUsage.maxOutputTokens = getModelMaxOutputTokens(model).default;
@@ -106437,15 +106632,18 @@ function addToTotalModelUsage(cost, usage, model) {
106437
106632
  function addToTotalSessionCost(cost, usage, model) {
106438
106633
  const modelUsage = addToTotalModelUsage(cost, usage, model);
106439
106634
  addToTotalCostState(cost, modelUsage, model);
106440
- const attrs = isFastModeEnabled() && usage.speed === "fast" ? { model, speed: "fast" } : { model };
106635
+ const attrs = isFastModeEnabled() && usage?.speed === "fast" ? { model, speed: "fast" } : { model };
106441
106636
  getCostCounter()?.add(cost, attrs);
106442
- getTokenCounter()?.add(usage.input_tokens, { ...attrs, type: "input" });
106443
- getTokenCounter()?.add(usage.output_tokens, { ...attrs, type: "output" });
106444
- getTokenCounter()?.add(usage.cache_read_input_tokens ?? 0, {
106637
+ getTokenCounter()?.add(usage?.input_tokens ?? 0, { ...attrs, type: "input" });
106638
+ getTokenCounter()?.add(usage?.output_tokens ?? 0, {
106639
+ ...attrs,
106640
+ type: "output"
106641
+ });
106642
+ getTokenCounter()?.add(usage?.cache_read_input_tokens ?? 0, {
106445
106643
  ...attrs,
106446
106644
  type: "cacheRead"
106447
106645
  });
106448
- getTokenCounter()?.add(usage.cache_creation_input_tokens ?? 0, {
106646
+ getTokenCounter()?.add(usage?.cache_creation_input_tokens ?? 0, {
106449
106647
  ...attrs,
106450
106648
  type: "cacheCreation"
106451
106649
  });
@@ -120565,7 +120763,7 @@ var init_FileReadTool = __esm(() => {
120565
120763
  },
120566
120764
  renderToolUseErrorMessage,
120567
120765
  async validateInput({ file_path, pages }, toolUseContext) {
120568
- if (pages !== undefined) {
120766
+ if (typeof pages === "string" && pages.trim() !== "") {
120569
120767
  const parsed = parsePDFPageRange(pages);
120570
120768
  if (!parsed) {
120571
120769
  return {
@@ -120614,7 +120812,8 @@ var init_FileReadTool = __esm(() => {
120614
120812
  }
120615
120813
  return { result: true };
120616
120814
  },
120617
- async call({ file_path, offset = 1, limit = undefined, pages }, context3, _canUseTool, parentMessage) {
120815
+ async call({ file_path, offset = 1, limit = undefined, pages: rawPages }, context3, _canUseTool, parentMessage) {
120816
+ const pages = typeof rawPages === "string" && rawPages.trim() !== "" ? rawPages : undefined;
120618
120817
  const { readFileState, fileReadingLimits } = context3;
120619
120818
  const defaults2 = getDefaultFileReadingLimits();
120620
120819
  const maxSizeBytes = fileReadingLimits?.maxSizeBytes ?? defaults2.maxSizeBytes;
@@ -239449,6 +239648,30 @@ var init_permissionLogging = __esm(() => {
239449
239648
  CODE_EDITING_TOOLS = ["Edit", "Write", "NotebookEdit"];
239450
239649
  });
239451
239650
 
239651
+ // src/lib/toolInputNullCoercion.ts
239652
+ function omitNullProps(input) {
239653
+ const out = {};
239654
+ for (const [key, value] of Object.entries(input)) {
239655
+ if (value !== null)
239656
+ out[key] = value;
239657
+ }
239658
+ return out;
239659
+ }
239660
+ function safeParseToolInputWithNullCoercion(schema, input) {
239661
+ const first = schema.safeParse(input);
239662
+ if (first.success)
239663
+ return first;
239664
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
239665
+ return first;
239666
+ }
239667
+ const record3 = input;
239668
+ const hasNull = Object.values(record3).some((value) => value === null);
239669
+ if (!hasNull)
239670
+ return first;
239671
+ const retry = schema.safeParse(omitNullProps(record3));
239672
+ return retry.success ? retry : first;
239673
+ }
239674
+
239452
239675
  // src/constants/tools.ts
239453
239676
  var ALL_AGENT_DISALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, ASYNC_AGENT_ALLOWED_TOOLS, IN_PROCESS_TEAMMATE_ALLOWED_TOOLS, COORDINATOR_MODE_ALLOWED_TOOLS;
239454
239677
  var init_tools = __esm(() => {
@@ -240552,7 +240775,7 @@ function streamedCheckPermissionsAndCallTool(tool, toolUseID, input, toolUseCont
240552
240775
  return stream4;
240553
240776
  }
240554
240777
  async function checkPermissionsAndCallTool(tool, toolUseID, input, toolUseContext, canUseTool, assistantMessage, messageId, requestId, mcpServerType, mcpServerBaseUrl, onToolProgress) {
240555
- const parsedInput = tool.inputSchema.safeParse(input);
240778
+ const parsedInput = safeParseToolInputWithNullCoercion(tool.inputSchema, input);
240556
240779
  if (!parsedInput.success) {
240557
240780
  let errorContent = formatZodValidationError(tool.name, parsedInput.error);
240558
240781
  const schemaHint = buildSchemaNotSentHint(tool, toolUseContext.messages, toolUseContext.options.tools);
@@ -243937,7 +244160,7 @@ function getAnthropicEnvMetadata() {
243937
244160
  function getBuildAgeMinutes() {
243938
244161
  if (false)
243939
244162
  ;
243940
- const buildTime = new Date("2026-05-19T14:04:55.374Z").getTime();
244163
+ const buildTime = new Date("2026-06-03T08:42:39.310Z").getTime();
243941
244164
  if (isNaN(buildTime))
243942
244165
  return;
243943
244166
  return Math.floor((Date.now() - buildTime) / 60000);
@@ -306164,7 +306387,7 @@ function splitSysPromptPrefix(systemPrompt, options2) {
306164
306387
  continue;
306165
306388
  if (prompt === SYSTEM_PROMPT_DYNAMIC_BOUNDARY)
306166
306389
  continue;
306167
- if (prompt.startsWith("x-anthropic-billing-header")) {
306390
+ if (prompt.startsWith("x-opencow-billing-header")) {
306168
306391
  attributionHeader2 = prompt;
306169
306392
  } else if (CLI_SYSPROMPT_PREFIXES.has(prompt)) {
306170
306393
  systemPromptPrefix2 = prompt;
@@ -306198,7 +306421,7 @@ function splitSysPromptPrefix(systemPrompt, options2) {
306198
306421
  const block2 = systemPrompt[i3];
306199
306422
  if (!block2 || block2 === SYSTEM_PROMPT_DYNAMIC_BOUNDARY)
306200
306423
  continue;
306201
- if (block2.startsWith("x-anthropic-billing-header")) {
306424
+ if (block2.startsWith("x-opencow-billing-header")) {
306202
306425
  attributionHeader2 = block2;
306203
306426
  } else if (CLI_SYSPROMPT_PREFIXES.has(block2)) {
306204
306427
  systemPromptPrefix2 = block2;
@@ -306241,7 +306464,7 @@ function splitSysPromptPrefix(systemPrompt, options2) {
306241
306464
  for (const block2 of systemPrompt) {
306242
306465
  if (!block2)
306243
306466
  continue;
306244
- if (block2.startsWith("x-anthropic-billing-header")) {
306467
+ if (block2.startsWith("x-opencow-billing-header")) {
306245
306468
  attributionHeader = block2;
306246
306469
  } else if (CLI_SYSPROMPT_PREFIXES.has(block2)) {
306247
306470
  systemPromptPrefix = block2;
@@ -479076,7 +479299,7 @@ function buildPrimarySection() {
479076
479299
  }, undefined, false, undefined, this);
479077
479300
  return [{
479078
479301
  label: "Version",
479079
- value: "0.4.2"
479302
+ value: "0.4.4"
479080
479303
  }, {
479081
479304
  label: "Session name",
479082
479305
  value: nameValue
@@ -535394,7 +535617,7 @@ var init_bridge_kick = __esm(() => {
535394
535617
  var call58 = async () => {
535395
535618
  return {
535396
535619
  type: "text",
535397
- value: `${"99.0.0"} (built ${"2026-05-19T14:04:55.374Z"})`
535620
+ value: `${"99.0.0"} (built ${"2026-06-03T08:42:39.310Z"})`
535398
535621
  };
535399
535622
  }, version2, version_default;
535400
535623
  var init_version = __esm(() => {
@@ -557504,7 +557727,7 @@ function WelcomeV2() {
557504
557727
  dimColor: true,
557505
557728
  children: [
557506
557729
  "v",
557507
- "0.4.2",
557730
+ "0.4.4",
557508
557731
  " "
557509
557732
  ]
557510
557733
  }, undefined, true, undefined, this)
@@ -557704,7 +557927,7 @@ function WelcomeV2() {
557704
557927
  dimColor: true,
557705
557928
  children: [
557706
557929
  "v",
557707
- "0.4.2",
557930
+ "0.4.4",
557708
557931
  " "
557709
557932
  ]
557710
557933
  }, undefined, true, undefined, this)
@@ -557930,7 +558153,7 @@ function AppleTerminalWelcomeV2(t0) {
557930
558153
  dimColor: true,
557931
558154
  children: [
557932
558155
  "v",
557933
- "0.4.2",
558156
+ "0.4.4",
557934
558157
  " "
557935
558158
  ]
557936
558159
  }, undefined, true, undefined, this);
@@ -558184,7 +558407,7 @@ function AppleTerminalWelcomeV2(t0) {
558184
558407
  dimColor: true,
558185
558408
  children: [
558186
558409
  "v",
558187
- "0.4.2",
558410
+ "0.4.4",
558188
558411
  " "
558189
558412
  ]
558190
558413
  }, undefined, true, undefined, this);
@@ -579030,7 +579253,7 @@ Usage: claude --remote "your task description"`, () => gracefulShutdown(1));
579030
579253
  pendingHookMessages
579031
579254
  }, renderAndRun);
579032
579255
  }
579033
- }).version("0.4.2 (OpenCow)", "-v, --version", "Output the version number");
579256
+ }).version("0.4.4 (OpenCow)", "-v, --version", "Output the version number");
579034
579257
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
579035
579258
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
579036
579259
  if (canUserConfigureAdvisor()) {
@@ -579676,7 +579899,7 @@ if (false) {}
579676
579899
  async function main2() {
579677
579900
  const args = process.argv.slice(2);
579678
579901
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
579679
- console.log(`${"0.4.2"} (OpenCow)`);
579902
+ console.log(`${"0.4.4"} (OpenCow)`);
579680
579903
  return;
579681
579904
  }
579682
579905
  if (args.includes("--provider")) {
@@ -579794,4 +580017,4 @@ async function main2() {
579794
580017
  }
579795
580018
  main2();
579796
580019
 
579797
- //# debugId=04CA1BD278A0566564756E2164756E21
580020
+ //# debugId=BECBE1E77E67BFDB64756E2164756E21