@corbat-tech/coco 2.28.1 → 2.28.3

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/index.js CHANGED
@@ -44959,6 +44959,11 @@ var DEFAULT_SEARCH_TIMEOUT_MS = 15e3;
44959
44959
  var MAX_QUERY_LENGTH = 500;
44960
44960
  var MIN_REQUEST_INTERVAL_MS = 1e3;
44961
44961
  var lastRequestTime = 0;
44962
+ function isEngineConfigured(engine) {
44963
+ if (engine === "duckduckgo") return true;
44964
+ if (engine === "brave") return !!process.env.BRAVE_SEARCH_API_KEY;
44965
+ return !!process.env.SERPAPI_KEY;
44966
+ }
44962
44967
  function sanitizeQuery(query) {
44963
44968
  const cleaned = query.replace(/[\x00-\x1F\x7F]/g, " ").trim();
44964
44969
  return cleaned.slice(0, MAX_QUERY_LENGTH);
@@ -45160,7 +45165,9 @@ Examples:
45160
45165
  await enforceRateLimit();
45161
45166
  try {
45162
45167
  let results;
45163
- switch (engine) {
45168
+ const requestedEngine = engine;
45169
+ const effectiveEngine = isEngineConfigured(requestedEngine) ? requestedEngine : "duckduckgo";
45170
+ switch (effectiveEngine) {
45164
45171
  case "brave":
45165
45172
  results = await searchBrave(sanitizedQuery, maxResults, DEFAULT_SEARCH_TIMEOUT_MS);
45166
45173
  break;
@@ -45175,7 +45182,7 @@ Examples:
45175
45182
  return {
45176
45183
  results,
45177
45184
  totalResults: results.length,
45178
- engine: engine ?? "duckduckgo",
45185
+ engine: effectiveEngine,
45179
45186
  duration: performance.now() - startTime
45180
45187
  };
45181
45188
  } catch (error) {
@@ -53346,28 +53353,80 @@ ${tail}`;
53346
53353
  }
53347
53354
  function shouldRecoverNoToolTurn(stopReason, content) {
53348
53355
  const trimmed = content.trim();
53356
+ if (trimmed.length === 0) {
53357
+ return {
53358
+ recover: true,
53359
+ reason: "The previous response produced no usable output. Continue the task immediately or explain the blocker in one concise sentence.",
53360
+ category: "empty"
53361
+ };
53362
+ }
53349
53363
  if (stopReason === "tool_use") {
53350
53364
  return {
53351
53365
  recover: true,
53352
- reason: "The previous response indicated tool use, but no tool calls were received. Re-emit the tool call(s) now."
53366
+ reason: "The previous response indicated tool use, but no tool calls were received. Re-emit the tool call(s) now.",
53367
+ category: "tool_use"
53353
53368
  };
53354
53369
  }
53355
53370
  if (stopReason === "max_tokens" && trimmed.length === 0) {
53356
53371
  return {
53357
53372
  recover: true,
53358
- reason: "The previous response was cut off before producing any usable output. Continue immediately."
53373
+ reason: "The previous response was cut off before producing any usable output. Continue immediately.",
53374
+ category: "empty"
53359
53375
  };
53360
53376
  }
53361
- const planningOnly = trimmed.length > 0 && trimmed.length < 320 && /^(voy a|ahora voy|i('| )?ll|i will|let me|starting|preparing|activating|continuo|contin[uú]o|de acuerdo[, ]+voy)\b/i.test(
53377
+ const planningOnly = trimmed.length > 0 && trimmed.length < 320 && /^(voy a|ahora voy|voy a revisar|voy a comprobar|voy a mirar|déjame|dejame|a continuación|i('| )?ll|i will|let me|starting|preparing|activating|checking|reviewing|looking into|working on|continuo|contin[uú]o|de acuerdo[, ]+voy)\b/i.test(
53362
53378
  trimmed
53363
53379
  );
53364
53380
  if (planningOnly) {
53365
53381
  return {
53366
53382
  recover: true,
53367
- reason: "Do not only describe the next step. Execute it now with concrete tool calls."
53383
+ reason: "Do not only describe the next step. Execute it now with concrete tool calls.",
53384
+ category: "planning_only"
53368
53385
  };
53369
53386
  }
53370
- return { recover: false, reason: "" };
53387
+ return { recover: false, reason: "", category: "none" };
53388
+ }
53389
+ async function requestNoToolFallbackExplanation(priorContent, reason) {
53390
+ let explanation = "";
53391
+ let explanationThinkingEnded = false;
53392
+ options.onThinkingStart?.();
53393
+ try {
53394
+ const finalMessages = [
53395
+ ...getConversationContext(session, toolRegistry),
53396
+ {
53397
+ role: "assistant",
53398
+ content: priorContent || "[No output returned in previous step.]"
53399
+ },
53400
+ {
53401
+ role: "user",
53402
+ content: `[System: ${reason} Do not call tools. Either explain the exact blocker and ask the user for the smallest missing input, or, if the task is already complete, summarize it briefly. Do not return an empty response.]`
53403
+ }
53404
+ ];
53405
+ for await (const chunk of provider.streamWithTools(finalMessages, {
53406
+ tools: [],
53407
+ maxTokens: session.config.provider.maxTokens,
53408
+ signal: options.signal
53409
+ })) {
53410
+ if (options.signal?.aborted) break;
53411
+ if (chunk.type === "text" && chunk.text) {
53412
+ if (!explanationThinkingEnded) {
53413
+ options.onThinkingEnd?.();
53414
+ explanationThinkingEnded = true;
53415
+ }
53416
+ explanation += chunk.text;
53417
+ options.onStream?.(chunk);
53418
+ }
53419
+ if (chunk.type === "done") break;
53420
+ }
53421
+ } catch {
53422
+ } finally {
53423
+ if (!explanationThinkingEnded) options.onThinkingEnd?.();
53424
+ }
53425
+ const trimmed = explanation.trim();
53426
+ if (trimmed.length > 0) {
53427
+ return explanation;
53428
+ }
53429
+ return "I could not continue because the model stopped returning actionable output. Please retry, switch provider/model, or tell me the exact next step you want me to take.";
53371
53430
  }
53372
53431
  function shouldAutoExtendIterationBudget(latestExecuted, latestToolResults, isInErrorLoop) {
53373
53432
  if (isInErrorLoop) return false;
@@ -53537,6 +53596,15 @@ ${tail}`;
53537
53596
  });
53538
53597
  continue;
53539
53598
  }
53599
+ if (noToolRecovery.recover) {
53600
+ noToolRecoveryAttempts = 0;
53601
+ finalContent += await requestNoToolFallbackExplanation(
53602
+ responseContent,
53603
+ noToolRecovery.reason
53604
+ );
53605
+ addMessage(session, { role: "assistant", content: finalContent });
53606
+ break;
53607
+ }
53540
53608
  noToolRecoveryAttempts = 0;
53541
53609
  addMessage(session, { role: "assistant", content: responseContent });
53542
53610
  break;