@ouro.bot/cli 0.1.0-alpha.492 → 0.1.0-alpha.494

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/changelog.json CHANGED
@@ -1,6 +1,18 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.494",
6
+ "changes": [
7
+ "Bump default Azure Blob operation timeout from 20s to 60s. Slugger's HEY-corpus validation against the booking-aware ranking from #608 surfaced a real issue: ranking and metadata are clean, but body fetches for targeted retrieval (`mail_thread`-style 'open this specific message') were timing out on real-world mail bodies. HEY mail with HTML-heavy booking confirmations regularly exceed the 20s ceiling on cold reads from Azure Blob. 60s with 2 attempts gives 120s max wait, which matches Azure's actual cold-read SLA for few-MB blobs while still bounding total wait. Index reads still fit comfortably in this budget. Existing test fixture for the timeout error message updated."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.493",
12
+ "changes": [
13
+ "Position-aware orphan-tool-result detection in `repairToolCallSequences`. Slugger's session was STILL hitting MiniMax error 2013 even after the alpha.492 inline-reasoning strip landed because the orphan check was global (a tool result was kept if its tool_call_id appeared in ANY assistant message in the conversation, regardless of order). After session pruning, a synthetic tool-result for a long-pruned tool_call ended up at sequence 86 referencing `call_function_utqogadgqp5h_1` while the assistant message that defined that id lived at sequence 88 — AFTER the tool result. MiniMax requires tool results to follow their matching assistant. The fix walks the conversation in order, tracking tool_call_ids only as they're encountered in assistant messages; tool results referencing ids that haven't been defined yet are removed. Regression test reproduces the exact misordered shape and asserts the misplaced tool result is dropped while the correctly-ordered one survives. This is the third and final layer of the empty-reply chain (#611 stripped the operator surface, #612 stripped the persisted content + load-time repair, #493 fixes orphan-detection ordering)."
14
+ ]
15
+ },
4
16
  {
5
17
  "version": "0.1.0-alpha.492",
6
18
  "changes": [
@@ -361,27 +361,39 @@ const TOOL_SCAN_BOUNDARY_ROLES = new Set(["assistant", "user"]);
361
361
  // 1. If an assistant message has tool_calls but missing tool results, inject synthetic error results.
362
362
  // 2. If a tool result's tool_call_id doesn't match any tool_calls in a preceding assistant message, remove it.
363
363
  // This prevents 400 errors from the API after an aborted turn.
364
+ //
365
+ // Position-aware: a tool result is orphaned when its tool_call_id hasn't been
366
+ // defined by an assistant message AT THIS POSITION yet. MiniMax-M2.7 reuses
367
+ // canonical tool_call_ids across turns, so the global-set check that this
368
+ // function used previously kept misordered tool results that MiniMax then
369
+ // rejected with error 2013 ("tool result's tool id not found"). Walking
370
+ // in order matches what MiniMax actually enforces.
364
371
  function repairOrphanedToolCalls(messages) {
365
- // Pass 1: collect all valid tool_call IDs from assistant messages
366
- const validCallIds = new Set();
367
- for (const msg of messages) {
372
+ // Pass 1: walk in order, accumulate seen tool_call_ids per-position, and
373
+ // mark tool results for removal if their id hasn't been defined yet.
374
+ const seenCallIds = new Set();
375
+ const removeIndices = [];
376
+ for (let i = 0; i < messages.length; i++) {
377
+ const msg = messages[i];
368
378
  if (msg.role === "assistant") {
369
379
  const asst = msg;
370
380
  if (asst.tool_calls) {
371
381
  for (const tc of asst.tool_calls)
372
- validCallIds.add(tc.id);
382
+ seenCallIds.add(tc.id);
373
383
  }
384
+ continue;
374
385
  }
375
- }
376
- // Pass 2: remove orphaned tool results (tool_call_id not in any assistant's tool_calls)
377
- for (let i = messages.length - 1; i >= 0; i--) {
378
- if (messages[i].role === "tool") {
379
- const toolMsg = messages[i];
380
- if (!validCallIds.has(toolMsg.tool_call_id)) {
381
- messages.splice(i, 1);
386
+ if (msg.role === "tool") {
387
+ const toolMsg = msg;
388
+ if (!seenCallIds.has(toolMsg.tool_call_id)) {
389
+ removeIndices.push(i);
382
390
  }
383
391
  }
384
392
  }
393
+ // Splice from the end so earlier indices stay valid.
394
+ for (let i = removeIndices.length - 1; i >= 0; i--) {
395
+ messages.splice(removeIndices[i], 1);
396
+ }
385
397
  // Pass 3: inject synthetic results for tool_calls missing their tool results
386
398
  for (let i = 0; i < messages.length; i++) {
387
399
  const msg = messages[i];
@@ -336,18 +336,22 @@ function repairSessionMessages(messages) {
336
336
  }
337
337
  function repairToolCallSequences(messages, inlineReasoningStrippedCallIds = new Set()) {
338
338
  const normalized = messages.map(normalizeMessage);
339
- const validCallIds = new Set();
340
- for (const msg of normalized) {
341
- if (msg.role !== "assistant")
342
- continue;
343
- for (const toolCall of msg.toolCalls)
344
- validCallIds.add(toolCall.id);
345
- }
339
+ // Position-aware orphan detection. A tool result is orphaned if there is
340
+ // no preceding assistant message in the array whose tool_calls contain the
341
+ // matching id. (The previous logic checked all assistant messages
342
+ // globally, which kept tool results that appeared BEFORE their matching
343
+ // assistant invalid order — and triggered MiniMax error 2013 on replay.)
346
344
  let removed = 0;
345
+ const seenCallIds = new Set();
347
346
  const repaired = normalized.filter((msg) => {
347
+ if (msg.role === "assistant") {
348
+ for (const tc of msg.toolCalls)
349
+ seenCallIds.add(tc.id);
350
+ return true;
351
+ }
348
352
  if (msg.role !== "tool")
349
353
  return true;
350
- const keep = msg.toolCallId !== null && validCallIds.has(msg.toolCallId);
354
+ const keep = msg.toolCallId !== null && seenCallIds.has(msg.toolCallId);
351
355
  if (!keep)
352
356
  removed++;
353
357
  return keep;
@@ -9,7 +9,13 @@ const MESSAGE_INDEX_PREFIX = "message-index";
9
9
  const MESSAGE_INDEX_SORT_MAX_MS = 9_999_999_999_999;
10
10
  const MESSAGE_INDEX_SORT_WIDTH = 13;
11
11
  const MESSAGE_INDEX_NO_SOURCE = "~";
12
- const DEFAULT_BLOB_OPERATION_TIMEOUT_MS = 20_000;
12
+ // Bumped from 20s after Slugger's HEY-corpus validation revealed that
13
+ // real-world mail bodies (HTML-heavy booking confirmations, MBOX-imported
14
+ // large messages) regularly exceed the original 20s ceiling. 60s with 2
15
+ // attempts = 120s max wait, which is closer to what Azure Blob actually
16
+ // needs for cold reads of a few-MB message body. Index reads still fit
17
+ // comfortably in this budget.
18
+ const DEFAULT_BLOB_OPERATION_TIMEOUT_MS = 60_000;
13
19
  const DEFAULT_BLOB_DOWNLOAD_ATTEMPTS = 2;
14
20
  const DEFAULT_MESSAGE_FETCH_CONCURRENCY = 20;
15
21
  const DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY = 8;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.492",
3
+ "version": "0.1.0-alpha.494",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",