loopengine 0.1.52 → 0.1.53

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.
@@ -13,6 +13,7 @@ import { BudgetTracker } from './budget.js';
13
13
  import { Compactor } from './compaction.js';
14
14
  import { ToolLane } from './toollane.js';
15
15
  import { Recovery } from './recovery.js';
16
+ import { collectKnownUrls, correctToolUseInput, recordKnownUrlsFromResult } from './known-urls.js';
16
17
  import { loadAgentModule } from './discover-agents.js';
17
18
  import { agentAsTool } from './agent-as-tool.js';
18
19
  import { loadGatewayToolsFromDir } from './gateway-tools.js';
@@ -458,6 +459,12 @@ async function runLoop(ctx, messages, newMessages, starterMessage) {
458
459
  messages.push(message);
459
460
  newMessages.push(message);
460
461
  }
462
+ // See known-urls.ts's own doc comment — seeded once from this
463
+ // session's full prior history (a resumed session's own tool results,
464
+ // not just this run's), then kept current live as this run's own new
465
+ // toollane:result events come in below. One map for the whole run, not
466
+ // re-derived every turn.
467
+ const knownUrlsByBase = collectKnownUrls(messages);
461
468
  const recovery = new Recovery({
462
469
  onPromptTooLong: async (currentMessages) => {
463
470
  // newMessages (this turn's own content — not durably stored
@@ -566,6 +573,12 @@ async function runLoop(ctx, messages, newMessages, starterMessage) {
566
573
  // changing toollane's own types.
567
574
  const approvedMetaById = new Map();
568
575
  for (const block of toolUseBlocks) {
576
+ // Before anything else looks at this block's own input at all
577
+ // (Skill's own args included) — see known-urls.ts's own doc
578
+ // comment: a URL the model just copied from an earlier tool
579
+ // result into this call's own arguments gets snapped back to the
580
+ // known-good one sharing its base, if they differ.
581
+ correctToolUseInput(block, knownUrlsByBase);
569
582
  // Skill invocation injects instructions into context; it isn't a
570
583
  // real tool call and doesn't need ActAuth gating or ToolLane
571
584
  // scheduling — but it's still a tool_use block the model emitted,
@@ -737,6 +750,11 @@ async function runLoop(ctx, messages, newMessages, starterMessage) {
737
750
  const summary = result.status === 'fulfilled' ? JSON.stringify(result.value) : `ERROR: ${result.error}`;
738
751
  const meta = approvedMetaById.get(result.id);
739
752
  log({ type: 'toollane:result', name: result.name, summary });
753
+ // A later tool call this same run (or a follow-up message in
754
+ // this same session) can reference a URL from this result —
755
+ // see known-urls.ts's own doc comment. Harmless no-op for a
756
+ // non-JSON/error summary.
757
+ recordKnownUrlsFromResult(summary, knownUrlsByBase);
740
758
  resultBlocks.push({
741
759
  type: 'tool_result',
742
760
  tool_use_id: result.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopengine",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
4
4
  "type": "module",
5
5
  "description": "Runtime for tool-using AI agents with a transparent ReAct loop.",
6
6
  "license": "MIT",