stable-harness 0.0.66 → 0.0.68

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.
@@ -1 +1 @@
1
- export function containsRawToolResultText(t,n){if(!function looksLikeJsonDocument(t){const n=t.trim();return n.startsWith("{")||n.startsWith("[")}(t))return!1;const e=canonicalJson(t);return!!e&&function recentToolResultOutputs(t){return t.flatMap(t=>{const n="runtime.adapter.event"===t.type&&isRecord(t.event)?t.event:void 0;return function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase}(n)&&"string"==typeof n.output?function isControlToolOutput(t){if("string"!=typeof t||!t.trim().startsWith("{"))return!1;try{const n=JSON.parse(t),e=isRecord(n)?n.status:void 0;return"duplicate_tool_call"===e||"repeated_tool_call_limit"===e||"tool_argument_error"===e}catch{return!1}}(n.output)?[]:[n.output]:[]}).slice(-5)}(n).some(t=>canonicalJson(t)===e)}function canonicalJson(t){try{return stableJsonStringify(JSON.parse(t))}catch{return}}function stableJsonStringify(t){return Array.isArray(t)?`[${t.map(stableJsonStringify).join(",")}]`:isRecord(t)?`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${stableJsonStringify(t[n])}`).join(",")}}`:JSON.stringify(t)}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
1
+ export function containsRawToolResultText(t,n){if(!function looksLikeJsonDocument(t){const n=t.trim();return n.startsWith("{")||n.startsWith("[")}(t))return!1;const e=canonicalJson(t);return!!e&&function recentToolResultOutputs(t){return t.flatMap(t=>{const n="runtime.adapter.event"===t.type&&isRecord(t.event)?t.event:void 0;if(!function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase}(n))return[];const e=function readToolResultOutput(t){return t.evidenceOutput??t.output}(n);return"string"!=typeof e||function isControlToolOutput(t){if("string"!=typeof t||!t.trim().startsWith("{"))return!1;try{const n=JSON.parse(t),e=isRecord(n)?n.status:void 0;return"duplicate_tool_call"===e||"repeated_tool_call_limit"===e||"tool_argument_error"===e}catch{return!1}}(e)?[]:[e]}).slice(-5)}(n).some(t=>canonicalJson(t)===e)}function canonicalJson(t){try{return stableJsonStringify(JSON.parse(t))}catch{return}}function stableJsonStringify(t){return Array.isArray(t)?`[${t.map(stableJsonStringify).join(",")}]`:isRecord(t)?`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${stableJsonStringify(t[n])}`).join(",")}}`:JSON.stringify(t)}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
@@ -5,6 +5,7 @@ export type ToolRepeatState = {
5
5
  latestSuccessfulOutputByTool: Map<string, string>;
6
6
  successfulToolCounts: Map<string, number>;
7
7
  toolCallCounts: Map<string, number>;
8
+ repeatLimitedTools: Set<string>;
8
9
  maxDuplicateCallsPerTool?: number;
9
10
  maxCallsPerTool?: number;
10
11
  maxSuccessfulCallsPerTool?: number;
@@ -1 +1 @@
1
- export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const s=stableToolCallKey(e,t),u=o.successfulCalls.get(s);if(void 0!==u){const t=o.duplicateCallCounts.get(s)??0;if(o.duplicateCallCounts.set(s,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,u);return{eventOutput:n,modelOutput:u}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
1
+ export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,repeatLimitedTools:new Set,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const a=stableToolCallKey(e,t),s=o.successfulCalls.get(a);if(void 0!==s){const t=o.duplicateCallCounts.get(a)??0;if(o.duplicateCallCounts.set(a,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return o.repeatLimitedTools.add(e),{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,s);return{eventOutput:n,modelOutput:s}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;if(t.repeatLimitedTools.has(e))return!0;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1 +1 @@
1
- export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e)||function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o))return o;const r=readRecord(o.recovery),t=readRecord(r.toolCall);return{...o,recovery:{...r,toolCall:{...t,enabled:!0,defaultedForStructuredToolCalling:!0}}}}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
1
+ export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e))return o;const r=function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o)?o:function withDefaultToolCallRecovery(e){const o=readRecord(e.recovery),r=readRecord(o.toolCall);return{...e,recovery:{...o,toolCall:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(o);return function hasExplicitRepeatGuard(e){const o=readRecord(e.toolGateway);return"boolean"==typeof readRecord(o.repeatGuard).enabled}(r)?r:function withDefaultRepeatGuard(e){const o=readRecord(e.toolGateway),r=readRecord(o.repeatGuard);return{...e,toolGateway:{...o,repeatGuard:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(r)}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stable-harness",
3
- "version": "0.0.66",
3
+ "version": "0.0.68",
4
4
  "type": "module",
5
5
  "description": "Stable application runtime and operator control plane for agent workspaces.",
6
6
  "license": "Apache-2.0",
@@ -1 +1 @@
1
- export function containsRawToolResultText(t,n){if(!function looksLikeJsonDocument(t){const n=t.trim();return n.startsWith("{")||n.startsWith("[")}(t))return!1;const e=canonicalJson(t);return!!e&&function recentToolResultOutputs(t){return t.flatMap(t=>{const n="runtime.adapter.event"===t.type&&isRecord(t.event)?t.event:void 0;return function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase}(n)&&"string"==typeof n.output?function isControlToolOutput(t){if("string"!=typeof t||!t.trim().startsWith("{"))return!1;try{const n=JSON.parse(t),e=isRecord(n)?n.status:void 0;return"duplicate_tool_call"===e||"repeated_tool_call_limit"===e||"tool_argument_error"===e}catch{return!1}}(n.output)?[]:[n.output]:[]}).slice(-5)}(n).some(t=>canonicalJson(t)===e)}function canonicalJson(t){try{return stableJsonStringify(JSON.parse(t))}catch{return}}function stableJsonStringify(t){return Array.isArray(t)?`[${t.map(stableJsonStringify).join(",")}]`:isRecord(t)?`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${stableJsonStringify(t[n])}`).join(",")}}`:JSON.stringify(t)}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
1
+ export function containsRawToolResultText(t,n){if(!function looksLikeJsonDocument(t){const n=t.trim();return n.startsWith("{")||n.startsWith("[")}(t))return!1;const e=canonicalJson(t);return!!e&&function recentToolResultOutputs(t){return t.flatMap(t=>{const n="runtime.adapter.event"===t.type&&isRecord(t.event)?t.event:void 0;if(!function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase}(n))return[];const e=function readToolResultOutput(t){return t.evidenceOutput??t.output}(n);return"string"!=typeof e||function isControlToolOutput(t){if("string"!=typeof t||!t.trim().startsWith("{"))return!1;try{const n=JSON.parse(t),e=isRecord(n)?n.status:void 0;return"duplicate_tool_call"===e||"repeated_tool_call_limit"===e||"tool_argument_error"===e}catch{return!1}}(e)?[]:[e]}).slice(-5)}(n).some(t=>canonicalJson(t)===e)}function canonicalJson(t){try{return stableJsonStringify(JSON.parse(t))}catch{return}}function stableJsonStringify(t){return Array.isArray(t)?`[${t.map(stableJsonStringify).join(",")}]`:isRecord(t)?`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${stableJsonStringify(t[n])}`).join(",")}}`:JSON.stringify(t)}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
@@ -5,6 +5,7 @@ export type ToolRepeatState = {
5
5
  latestSuccessfulOutputByTool: Map<string, string>;
6
6
  successfulToolCounts: Map<string, number>;
7
7
  toolCallCounts: Map<string, number>;
8
+ repeatLimitedTools: Set<string>;
8
9
  maxDuplicateCallsPerTool?: number;
9
10
  maxCallsPerTool?: number;
10
11
  maxSuccessfulCallsPerTool?: number;
@@ -1 +1 @@
1
- export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const s=stableToolCallKey(e,t),u=o.successfulCalls.get(s);if(void 0!==u){const t=o.duplicateCallCounts.get(s)??0;if(o.duplicateCallCounts.set(s,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,u);return{eventOutput:n,modelOutput:u}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
1
+ export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,repeatLimitedTools:new Set,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const a=stableToolCallKey(e,t),s=o.successfulCalls.get(a);if(void 0!==s){const t=o.duplicateCallCounts.get(a)??0;if(o.duplicateCallCounts.set(a,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return o.repeatLimitedTools.add(e),{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,s);return{eventOutput:n,modelOutput:s}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;if(t.repeatLimitedTools.has(e))return!0;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1 +1 @@
1
- export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e)||function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o))return o;const r=readRecord(o.recovery),t=readRecord(r.toolCall);return{...o,recovery:{...r,toolCall:{...t,enabled:!0,defaultedForStructuredToolCalling:!0}}}}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
1
+ export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e))return o;const r=function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o)?o:function withDefaultToolCallRecovery(e){const o=readRecord(e.recovery),r=readRecord(o.toolCall);return{...e,recovery:{...o,toolCall:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(o);return function hasExplicitRepeatGuard(e){const o=readRecord(e.toolGateway);return"boolean"==typeof readRecord(o.repeatGuard).enabled}(r)?r:function withDefaultRepeatGuard(e){const o=readRecord(e.toolGateway),r=readRecord(o.repeatGuard);return{...e,toolGateway:{...o,repeatGuard:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(r)}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}