@lazyingart/agintiflow 0.20.69 → 0.20.70

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.69",
3
+ "version": "0.20.70",
4
4
  "type": "module",
5
5
  "description": "Low-cost, project-aware Web and CLI agents with DeepSeek/Venice/OpenAI routing, visible tool calls, durable sessions, scouts, AAPS, SCS, and guarded local execution.",
6
6
  "license": "Apache-2.0",
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { repairModelMessageHistory, runAgent } from "../src/agent-runner.js";
6
+ import { repairModelMessageHistory, runAgent, shouldShortCircuitToolBatch, skippedAfterBlockedToolResult } from "../src/agent-runner.js";
7
7
  import { resolveRuntimeConfig } from "../src/config.js";
8
8
  import { readCodebaseMap } from "../src/codebase-map.js";
9
9
  import { evaluateCommandPolicy } from "../src/command-policy.js";
@@ -119,6 +119,25 @@ try {
119
119
  interruptedDeepSeekState.messages.at(-1)?.content === "Continue with this new request: /review",
120
120
  "interrupted repair dropped the new user request"
121
121
  );
122
+ const blockedBatchResult = {
123
+ ok: false,
124
+ blocked: true,
125
+ toolName: "run_command",
126
+ category: "nested-aginti",
127
+ permissionAdvice: { category: "nested-aginti", suggestedCommand: "aginti doctor --json" },
128
+ };
129
+ assert(shouldShortCircuitToolBatch(blockedBatchResult), "permissionAdvice block did not trigger batch short-circuit");
130
+ const skippedBatchResult = skippedAfterBlockedToolResult(
131
+ {
132
+ id: "call-b",
133
+ type: "function",
134
+ function: { name: "run_command", arguments: "{\"command\":\"npx aginti capabilities --json\"}" },
135
+ },
136
+ blockedBatchResult
137
+ );
138
+ assert(skippedBatchResult.skipped, "skipped tool result did not mark skipped=true");
139
+ assert(skippedBatchResult.blocked, "skipped tool result did not remain blocked");
140
+ assert(skippedBatchResult.priorBlockedCategory === "nested-aginti", "skipped tool result did not preserve prior block category");
122
141
  const completeToolState = {
123
142
  messages: [
124
143
  { role: "system", content: "system" },
@@ -513,6 +532,7 @@ try {
513
532
  workspace,
514
533
  checks: [
515
534
  "deepseek_history_repair",
535
+ "blocked_tool_batch_short_circuit",
516
536
  "deepseek_pro_patch_route",
517
537
  "large_profile_pro_route",
518
538
  "auto_system_pro_route",
@@ -659,6 +659,35 @@ function sanitizeToolArgs(toolName, args) {
659
659
  return safeArgs;
660
660
  }
661
661
 
662
+ function safeParseToolArgs(toolCall) {
663
+ try {
664
+ return JSON.parse(toolCall?.function?.arguments || "{}");
665
+ } catch {
666
+ return {};
667
+ }
668
+ }
669
+
670
+ export function shouldShortCircuitToolBatch(toolResult) {
671
+ return Boolean(toolResult?.blocked && toolResult?.permissionAdvice);
672
+ }
673
+
674
+ export function skippedAfterBlockedToolResult(toolCall, blockedResult) {
675
+ const toolName = toolCall?.function?.name || "unknown";
676
+ const args = sanitizeToolArgs(toolName, safeParseToolArgs(toolCall));
677
+ return {
678
+ ok: false,
679
+ blocked: true,
680
+ skipped: true,
681
+ toolName,
682
+ args,
683
+ category: "blocked-batch",
684
+ reason:
685
+ "Skipped because an earlier tool call in the same assistant message returned permissionAdvice. The runtime stops the batch so the agent cannot retry variants before the user/model sees the blocker.",
686
+ priorBlockedTool: blockedResult?.toolName || "",
687
+ priorBlockedCategory: blockedResult?.category || "",
688
+ };
689
+ }
690
+
662
691
  function goalClearlyAllowsOverwrite(goal = "") {
663
692
  const text = String(goal || "").toLowerCase();
664
693
  return (
@@ -1723,7 +1752,8 @@ export async function runAgent(config) {
1723
1752
  }
1724
1753
 
1725
1754
  let continueForQueuedInput = false;
1726
- for (const toolCall of toolCalls) {
1755
+ for (let toolIndex = 0; toolIndex < toolCalls.length; toolIndex += 1) {
1756
+ const toolCall = toolCalls[toolIndex];
1727
1757
  throwIfAborted(config);
1728
1758
  const toolResult = await executeTool(browserState, toolCall, snapshot, config, store, observers, state);
1729
1759
  state.messages.push({
@@ -1797,6 +1827,24 @@ export async function runAgent(config) {
1797
1827
  });
1798
1828
  }
1799
1829
 
1830
+ if (shouldShortCircuitToolBatch(toolResult)) {
1831
+ for (const skippedToolCall of toolCalls.slice(toolIndex + 1)) {
1832
+ const skippedResult = skippedAfterBlockedToolResult(skippedToolCall, toolResult);
1833
+ state.messages.push({
1834
+ role: "tool",
1835
+ tool_call_id: skippedToolCall.id,
1836
+ content: JSON.stringify(skippedResult),
1837
+ });
1838
+ await store.appendEvent("tool.skipped", sanitizeToolResult(skippedResult));
1839
+ observers.event("tool.skipped", {
1840
+ toolName: skippedResult.toolName,
1841
+ reason: skippedResult.reason,
1842
+ priorBlockedTool: skippedResult.priorBlockedTool,
1843
+ });
1844
+ }
1845
+ break;
1846
+ }
1847
+
1800
1848
  if (config.provider === "mock" && toolResult.ok === false && !toolResult.blocked) {
1801
1849
  throw new Error(
1802
1850
  `Mock tool failed: ${toolResult.error || toolResult.reason || `${toolResult.toolName || "tool"} returned ok=false`}`