stable-harness 0.0.125 → 0.0.127
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/node_modules/@stable-harness/adapter-deepagents/package.json +2 -2
- package/node_modules/@stable-harness/adapter-langgraph/package.json +2 -2
- package/node_modules/@stable-harness/core/dist/quality/event-evidence.js +1 -1
- package/node_modules/@stable-harness/core/dist/recovery/control-omission.js +1 -1
- package/node_modules/@stable-harness/core/dist/recovery/execution-contract.d.ts +2 -1
- package/node_modules/@stable-harness/core/dist/recovery/execution-contract.js +1 -1
- package/node_modules/@stable-harness/core/dist/recovery/progress-intent.js +1 -1
- package/node_modules/@stable-harness/core/dist/recovery/raw-args.d.ts +2 -2
- package/node_modules/@stable-harness/core/dist/recovery/raw-args.js +1 -1
- package/node_modules/@stable-harness/core/dist/recovery/tool-call-structure.d.ts +3 -0
- package/node_modules/@stable-harness/core/dist/recovery/tool-call-structure.js +1 -0
- package/node_modules/@stable-harness/core/dist/recovery/tool-call.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/recovery/adapter-result.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime.js +1 -1
- package/node_modules/@stable-harness/core/package.json +3 -3
- package/node_modules/@stable-harness/governance/package.json +1 -1
- package/node_modules/@stable-harness/memory/package.json +1 -1
- package/node_modules/@stable-harness/protocols/package.json +2 -2
- package/node_modules/@stable-harness/tool-gateway/package.json +1 -1
- package/node_modules/@stable-harness/workspace-yaml/package.json +2 -2
- package/package.json +9 -9
- package/packages/adapter-deepagents/package.json +2 -2
- package/packages/adapter-langgraph/package.json +2 -2
- package/packages/cli/package.json +8 -8
- package/packages/core/dist/quality/event-evidence.js +1 -1
- package/packages/core/dist/recovery/control-omission.js +1 -1
- package/packages/core/dist/recovery/execution-contract.d.ts +2 -1
- package/packages/core/dist/recovery/execution-contract.js +1 -1
- package/packages/core/dist/recovery/progress-intent.js +1 -1
- package/packages/core/dist/recovery/raw-args.d.ts +2 -2
- package/packages/core/dist/recovery/raw-args.js +1 -1
- package/packages/core/dist/recovery/tool-call-structure.d.ts +3 -0
- package/packages/core/dist/recovery/tool-call-structure.js +1 -0
- package/packages/core/dist/recovery/tool-call.js +1 -1
- package/packages/core/dist/runtime/recovery/adapter-result.js +1 -1
- package/packages/core/dist/runtime.js +1 -1
- package/packages/core/package.json +3 -3
- package/packages/evaluation/package.json +2 -2
- package/packages/governance/package.json +1 -1
- package/packages/memory/package.json +1 -1
- package/packages/protocols/package.json +2 -2
- package/packages/tool-gateway/package.json +1 -1
- package/packages/workspace-yaml/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/adapter-deepagents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@langchain/node-vfs": "^0.1.4",
|
|
17
17
|
"@langchain/ollama": "^1.2.7",
|
|
18
18
|
"@langchain/openai": "^1.4.5",
|
|
19
|
-
"@stable-harness/core": "0.0.
|
|
19
|
+
"@stable-harness/core": "0.0.127",
|
|
20
20
|
"deepagents": "^1.10.1",
|
|
21
21
|
"langchain": "^1.4.0"
|
|
22
22
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/adapter-langgraph",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
"types": "dist/src/index.d.ts",
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"@langchain/langgraph": "^1.3.0",
|
|
15
|
-
"@stable-harness/core": "0.0.
|
|
15
|
+
"@stable-harness/core": "0.0.127"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function hasPlanningEvidence(t){return t.some(t=>{const e=readAdapterEvent(t);return!!e&&("plan"===e.traceType||String(e.traceLabel??"").startsWith("plan.")||"write_todos"===e.toolId&&String(e.phase??"").startsWith("agent.tool."))})}export function successfulEvidenceToolIds(t){const e=t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return[t.toolId];const e=readAdapterEvent(t);return isToolResultEvent(e)&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?[e.toolId]:[]});return[...new Set(e)]}export function successfulEvidenceOutputs(t){return successfulEvidenceItems(t).map(t=>t.output)}export function successfulEvidenceItems(t){return t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return stringifyEvidence(t.output).map(e=>({source:t.toolId,output:e}));const e=readAdapterEvent(t),
|
|
1
|
+
export function hasPlanningEvidence(t){return t.some(t=>{const e=readAdapterEvent(t);return!!e&&("plan"===e.traceType||String(e.traceLabel??"").startsWith("plan.")||"write_todos"===e.toolId&&String(e.phase??"").startsWith("agent.tool."))})}export function successfulEvidenceToolIds(t){const e=t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return[t.toolId];const e=readAdapterEvent(t);return isToolResultEvent(e)&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?[e.toolId]:[]});return[...new Set(e)]}export function successfulEvidenceOutputs(t){return successfulEvidenceItems(t).map(t=>t.output)}export function successfulEvidenceItems(t){return t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return stringifyEvidence(t.output).map(e=>({source:t.toolId,output:e}));const e=readAdapterEvent(t),n=readToolSource(e);return isToolResultEvent(e)&&n?!isSuccessfulEvidenceEvent(e)||function isPlanningTool(t){return"write_todos"===t||"read_todos"===t}(n)?[]:stringifyEvidence(e.evidenceOutput??e.output).filter(t=>function isUsableEvidenceOutput(t,e){return!("task"===t&&function looksLikeUnexecutedToolIntent(t){const e=t.trim();if(e.length>4e3)return!1;const n=function extractJsonSource(t){const e=t.trim();if(e.startsWith("{")&&e.endsWith("}")||e.startsWith("[")&&e.endsWith("]"))return e;if(!e.startsWith("```"))return;const n=e.indexOf("\n"),r=e.lastIndexOf("```");return n<0||r<=n?void 0:e.slice(n+1,r).trim()}(e);return n?function containsToolEnvelope(t){try{const e=JSON.parse(t);return Array.isArray(e)?e.some(isToolEnvelopeRecord):isToolEnvelopeRecord(e)}catch{return!1}}(n):function containsToolMarkup(t){const e=t.toLowerCase();return e.includes("<tool_call")||e.includes("</tool_call")||e.includes("<tool_code")||e.includes("</tool_code")}(e)||function containsBareToolFence(t){const e=t.trim(),n=e.indexOf("```");if(n<0||e.indexOf("```",n+3)!==e.lastIndexOf("```"))return!1;const r=e.indexOf("\n",n+3),o=e.lastIndexOf("```");return!(r<0||o<=r)&&function isIdentifierPath(t){return t.length>0&&[...t].every((t,e)=>{const n=t>="A"&&t<="Z"||t>="a"&&t<="z"||"_"===t;return 0===e?n:n||t>="0"&&t<="9"||"."===t||"-"===t})}(e.slice(r+1,o).trim())}(e)}(e))}(n,t)).map(t=>({source:n,output:t})):[]})}export function controlBlockers(t){const e=successfulEventIndexesBySource(t);return t.flatMap((t,n)=>{const r=readAdapterEvent(t),o=readControlStatus(r),s=readControlSource(r)??"tool";return o&&isBlockerStatus(o)?isResolvedByLaterCompletion(o)&&completedAfter(e,s,n)||isResolvedByLaterAnyCompletion(o)&&completedAfterAny(e,n)?[]:[`${s}:${o}`]:[]})}export function controlGaps(t){const e=new Set(successfulEvidenceItems(t).map(t=>t.source));return t.flatMap(t=>{const n=readAdapterEvent(t),r=readControlStatus(n),o=readControlSource(n)??"tool";return r&&isGapStatus(r)?e.has(o)&&isResolvedByLaterCompletion(r)?[]:[`${o}:${r}`]:[]})}export function omittedControlGaps(t,e){const n=successfulEventIndexesBySource(t),r=successfulEvidenceItems(t),o=function outputHasUnsupportedEvidenceClaims(t,e,n){const r=function evidenceCorpus(t,e){return[...e.map(t=>t.output),...t.flatMap(t=>"runtime.request.started"===t.type?[t.input??""]:[]),...t.flatMap(t=>"runtime.memory.recall.completed"===t.type?[t.context]:[])].join("\n")}(e,n).toLowerCase();return unsupportedTokens(t,r,/\b[A-Z][A-Z0-9]{1,12}-\d+\b/gu).length>0||unsupportedTokens(t,r,/\b[A-Za-z_$][A-Za-z0-9_$]*[A-Z][A-Za-z0-9_$]*\b/gu).filter(isCodeLikeIdentifier).length>=2}(e,t,r);return t.flatMap((t,s)=>{const u=readAdapterEvent(t),i=readControlStatus(u),a=readControlSource(u)??"tool";return i&&function isOmittedControlStatus(t){return isGapStatus(t)||isBlockerStatus(t)}(i)?isResolvedByLaterCompletion(i)&&completedAfter(n,a,s)||isResolvedByLaterAnyCompletion(i)&&completedAfterAny(n,s)||!o&&outputUsesPriorEvidence(e,a,r)?[]:[`${a}:${i}`]:[]})}function stringifyEvidence(t){return"string"==typeof t?t.trim()?[t]:[]:null==t?[]:[JSON.stringify(t)]}function isToolEnvelopeRecord(t){return!!isRecord(t)&&["tool","toolId","toolName","tool_name","name","type","subagent_type"].some(e=>"string"==typeof t[e])&&["args","arguments","parameters","params","kwargs","task"].some(e=>e in t)}function readAdapterEvent(t){if("runtime.adapter.event"===t.type&&isRecord(t.event))return t.event;const e=t;return isRecord(e)&&isToolResultEvent(e)?e:void 0}function isSuccessfulEvidenceEvent(t){const e=readEventStatus(t);return!e||/^(?:completed|success|ok|recorded)$/iu.test(e)}function isBlockerStatus(t){return/^(?:blocked|approval_required|schema_repair_failed|tool_argument_error|invalid_input|task_inventory_blocked)$/iu.test(t)}function isGapStatus(t){return/^(?:dependency_required|plan_required|repeated_tool_call_limit|duplicate_tool_call)$/iu.test(t)}function isResolvedByLaterCompletion(t){return isGapStatus(t)||isBlockerStatus(t)}function isResolvedByLaterAnyCompletion(t){return"task_inventory_blocked"===t}function successfulEventIndexesBySource(t){const e=new Map;return t.forEach((t,n)=>{const r=function successfulEventSource(t){if("runtime.tool.direct.completed"===t.type)return t.toolId;const e=readAdapterEvent(t),n=readToolSource(e);return isToolResultEvent(e)&&n&&isSuccessfulEvidenceEvent(e)?n:void 0}(t);r&&e.set(r,[...e.get(r)??[],n])}),e}function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase||"agent.tool.result"===t?.type||"deepagents.tool_execution.result"===t?.type}function completedAfter(t,e,n){return(t.get(e)??[]).some(t=>t>n)}function completedAfterAny(t,e){return[...t.values()].some(t=>t.some(t=>t>e))}export function outputUsesPriorEvidence(t,e,n){const r=t.toLowerCase();return n.filter(t=>t.source===e).some(t=>{const e=t.output.trim();return!!e&&(!!r.includes(e.slice(0,500).toLowerCase())||function matchingEvidenceTokens(t,e){const n=new Set(["status","completed","success","recorded"]);return[...new Set(e.toLowerCase().match(/[a-z0-9][a-z0-9_.-]{1,}/gu)??[])].filter(t=>!n.has(t)).filter(e=>t.includes(e)).length}(r,e)>=2)})}function unsupportedTokens(t,e,n){return[...new Set(t.match(n)??[])].filter(t=>!e.includes(t.toLowerCase()))}function isCodeLikeIdentifier(t){return!(t.length<8)&&(/(?:Service|Controller|Repository|Manager|Client|Resolver|Agent|Tool|Async)$/u.test(t)||/[a-z][A-Z]/u.test(t))}function readOutputStatus(t){if(isRecord(t)&&"string"==typeof t.status)return t.status;if("string"==typeof t){const e=parseJsonRecord(t);return"string"==typeof e?.status?e.status:t.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}}function parseJsonRecord(t){try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function readString(t){return"string"==typeof t&&t.trim()?t:void 0}function readEventStatus(t){return readString(t?.controlStatus)??readString(t?.status)??readOutputStatus(t?.output)}function readToolSource(t){return readString(t?.toolId)??readString(t?.toolName)??readString(t?.name)}function readControlStatus(t){const e=function readInventoryRepairControlStatus(t){if("inventory.repair"===t?.phase&&"blocked"===t.status)return"task"===readInventoryRepairSource(t)?"task_inventory_blocked":"blocked"}(t);if(e)return e;const n=readEventStatus(t);return n&&isControlStatus(n)?n:findNestedControlStatus(t)}function readControlSource(t){return readToolSource(t)??readInventoryRepairSource(t)??findNestedToolSource(t)}function isControlStatus(t){return isGapStatus(t)||isBlockerStatus(t)}function findNestedControlStatus(t,e=0){if(e>5||null==t)return;if("string"==typeof t)return function readNestedStringStatus(t,e){const n=parseJsonRecord(t);if(n)return findNestedControlStatus(n,e+1);const r=t.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1];return r&&isControlStatus(r)?r:function readControlToken(t){const e=t.match(/\b(?:blocked|approval_required|schema_repair_failed|tool_argument_error|invalid_input|task_inventory_blocked|dependency_required|plan_required|repeated_tool_call_limit|duplicate_tool_call)\b/iu)?.[0];return e&&isControlStatus(e)?e:void 0}(t)}(t,e);if(Array.isArray(t))return findFirstNested(t,t=>findNestedControlStatus(t,e+1));if(!isRecord(t))return;const n=readString(t.controlStatus)??readString(t.status);if(n&&isControlStatus(n))return n;const r=readOutputStatus(t.output);return r&&isControlStatus(r)?r:findFirstNested(Object.values(t),t=>findNestedControlStatus(t,e+1))}function findNestedToolSource(t,e=0){if(!(e>5||null==t)){if("string"==typeof t)return function readToolSourceFromText(t){const e=t.match(/["'](?:toolId|toolName|name)["']\s*:\s*["']([^"']+)["']/u)?.[1];return readString(e)}(t);if(Array.isArray(t))return findFirstNested(t,t=>findNestedToolSource(t,e+1));if(isRecord(t))return(readString(t.toolId)??readString(t.toolName)??readString(t.name))||findFirstNested(Object.values(t),t=>findNestedToolSource(t,e+1))}}function findFirstNested(t,e){for(const n of t){const t=e(n);if(void 0!==t)return t}}function readInventoryRepairSource(t){const e=isRecord(t?.diagnostic)?t.diagnostic:void 0;return readString(e?.layer)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlBlockers as e,omittedControlGaps as t}from"../quality/event-evidence.js";export function omittedControlRecoveryLines(o){const
|
|
1
|
+
import{controlBlockers as e,omittedControlGaps as t}from"../quality/event-evidence.js";export function omittedControlRecoveryLines(o){const r=e(o.events),n=t(o.events,o.output).filter(e=>!function mentionsGap(e,t){const[o,r]=t.split(":"),n=e.toLowerCase(),i=function statusPhrases(e){if(!e)return[];const t=e.toLowerCase().replaceAll("_"," ");return"task_inventory_blocked"===e?[t,"workspace inventory","not in the workspace inventory"]:"repeated_tool_call_limit"===e?[t,"repeat limit"]:[t]}(r);return n.includes(t.toLowerCase())||Boolean(r&&n.includes(r.toLowerCase()))||i.some(e=>n.includes(e))||Boolean(o&&r&&n.includes(o.toLowerCase())&&n.includes(r.toLowerCase()))}(o.output,e));if(0===n.length)return;const i=function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o||"task_inventory_blocked"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}(o.events,1e3);return["Stable runtime recovery: your previous final answer omitted unresolved runtime control gap(s) or blocker(s).",`Unresolved control gap(s): ${[...n,...r].slice(0,8).join(", ")}`,"Continue the same user request from the completed evidence.","If a declared available action is required to satisfy the request, continue with its structured tool call instead of delivering an incomplete final answer.",...o.availableToolIds?.length?[`Available configured tools: ${o.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If no declared action can safely continue, return a grounded blocker that explicitly preserves the unresolved runtime control state.",...i.length>0?["","Recent executed tool evidence:",...i]:[],"","Previous invalid final answer:",o.output]}export function assertNoDeclaredActionOmissionOutput(e){}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${JSON.stringify(e.args).slice(0,t)}`:"completed"}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { RuntimeEvent, RuntimeRequest } from "../types.js";
|
|
1
|
+
import type { RuntimeEvent, RuntimeRequest, WorkspaceAgent } from "../types.js";
|
|
2
2
|
export declare function buildExecutionContractRecoveryRequest(input: {
|
|
3
3
|
request: RuntimeRequest;
|
|
4
4
|
events: RuntimeEvent[];
|
|
5
|
+
agent: WorkspaceAgent;
|
|
5
6
|
policy: unknown;
|
|
6
7
|
}): RuntimeRequest | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{successfulEvidenceItems as e}from"../quality/event-evidence.js";export function buildExecutionContractRecoveryRequest(
|
|
1
|
+
import{successfulEvidenceItems as e}from"../quality/event-evidence.js";export function buildExecutionContractRecoveryRequest(t){if(!0!==function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}(t.policy).enabled)return;const n=function lastExecutionContractFailure(e){for(let t=e.length-1;t>=0;t-=1){const n=e[t];if("runtime.execution.contract.failed"===n?.type)return{reason:n.reason,missing:readStringArray(n.missingEvidenceTools)}}return{missing:[]}}(t.events);if(0===n.missing.length)return;if("missing_required_evidence_usage"===n.reason){const e=recentSuccessfulEvidence(t.events);return recoverRequest(t.request,["Stable runtime recovery: the execution contract was not satisfied.",`The final answer did not use required executed evidence from: ${n.missing.join(", ")}`,"Synthesize from those required source(s), or call them through normal structured tool calling if their evidence is unavailable.","Do not replace required evidence with unrelated intermediate evidence, progress text, or summaries from other tools.",...e.length>0?["","Prior successful tool evidence:",...e]:[]])}const r=recentSuccessfulEvidence(t.events),o=function recoveryToolTargets(t,n,r){const o=function readToolDependencies(e){return isRecord(e)?new Map(Object.entries(e).map(([e,t])=>[e,readStringArray(t)]).filter(e=>e[1].length>0)):new Map}(function readExecutionContract(e){return isRecord(e.config.executionContract)?e.config.executionContract:{}}(t).toolDependencies),i=new Set(e(r).map(e=>e.source)),s=new Set;for(const e of n)s.add(e),collectUnmetDependencies(e,o,i,s,new Set([e]));return[...s].filter(e=>t.tools.includes(e))}(t.agent,n.missing,t.events);return recoverRequest(t.request,["Stable runtime recovery: the execution contract was not satisfied.",`Required evidence tool(s) were missing: ${n.missing.join(", ")}`,`For this recovery turn, the allowed next tool call target(s) are: ${o.join(", ")}`,"Allowed targets include missing required evidence tools and any declared dependency tools that are still needed to build valid arguments.","Reuse exact values from prior successful tool evidence when building the required tool call. Do not invent replacement paths, IDs, handles, URLs, or parameters.","The next assistant action must be the backend's structured tool call for one allowed target, with no prose before it.","Do not call already completed intermediate tools unless they are listed above.","Do not produce a final answer until the required evidence tool call has executed and you have synthesized its result.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text in the final answer.",...r.length>0?["","Prior successful tool evidence:",...r]:[]],{stableHarnessRequiredEvidenceTools:o})}function recoverRequest(e,t,n={}){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call",...n}}}function collectUnmetDependencies(e,t,n,r,o){for(const i of t.get(e)??[])o.has(i)||(o.add(i),n.has(i)||r.add(i),collectUnmetDependencies(i,t,n,r,o))}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function recentSuccessfulEvidence(t){return e(t).slice(-5).map(e=>`- ${e.source}: ${function previewEvidence(e){const t=e.replace(/\s+/gu," ").trim();return t.length>1500?`${t.slice(0,1497)}...`:t}(e.output)}`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function containsProgressOnlyToolIntent(e
|
|
1
|
+
export function containsProgressOnlyToolIntent(t,e){const n=t.trim();return!!function looksLikeProgressOnlyCandidate(t){return t.length>0&&t.length<=1200&&!t.trimStart().startsWith("#")&&!t.includes("\n---\n")}(n)&&(e??[]).some(t=>function isToolInvocationBlock(t,e){const n=t.split("\n");return!(n[0]?.trim()!==e||n.length<3||n.length>9)&&n.slice(1).every(t=>function isIndentedKeyValueLine(t){if(!t.startsWith(" ")&&!t.startsWith("\t"))return!1;const e=t.indexOf(":");if(e<=0||e>80)return!1;const n=t.slice(0,e).trim();return n.length>0&&[...n].every(t=>function isIdentifierChar(t){return"_"===t||"-"===t||"."===t||t>="A"&&t<="Z"||t>="a"&&t<="z"||t>="0"&&t<="9"}(t))}(t))}(n,t))}export function progressOnlyToolIntentMessage(t){return`Adapter returned progress-only future tool intent as the final answer after recovery. The backend must execute the named tool or fail closed. Output preview: ${function previewOutput(t){const e=t.replace(/\s+/gu," ").trim();return e.length>300?`${e.slice(0,297)}...`:e}(t)}`}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RuntimeRequest, RuntimeToolGateway, WorkspaceAgent } from "../types.js";
|
|
2
2
|
import type { CompiledWorkspace } from "../workspace/types.js";
|
|
3
3
|
export type RawArgsRecoveryInput = {
|
|
4
4
|
request: RuntimeRequest;
|
|
@@ -6,7 +6,7 @@ export type RawArgsRecoveryInput = {
|
|
|
6
6
|
agent: WorkspaceAgent;
|
|
7
7
|
workspace: CompiledWorkspace;
|
|
8
8
|
toolGateway?: RuntimeToolGateway;
|
|
9
|
-
events?:
|
|
9
|
+
events?: unknown[];
|
|
10
10
|
candidateToolIds?: string[];
|
|
11
11
|
policy: unknown;
|
|
12
12
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{selectCallCandidateByArgsSchema as e}from"@easynet/better-call";export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=matchUniqueRawArgsTool(e);return t?function buildRawArgsRecoveryPrompt(e,t){return{...e,input:[e.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}(e.request,t):void 0}export function buildRawArgsToolEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer repeated a JSON argument object for a declared tool after a structured tool-call recovery request.",`Matched configured tool: ${e.match.toolId}`,"Stable runtime executed that matched declared tool through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool output:",e.toolOutput].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(matchUniqueRawArgsTool(e))}export function buildRawArgsToolSequenceEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer printed multiple JSON argument objects for declared tools after a recovery request.","Stable runtime matched and executed those declared tools through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool output:",e.toolOutput,""])].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function matchUniqueRawArgsTool(t){const
|
|
1
|
+
import{selectCallCandidateByArgsSchema as e}from"@easynet/better-call";export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=matchUniqueRawArgsTool(e);return t?function buildRawArgsRecoveryPrompt(e,t){return{...e,input:[e.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}(e.request,t):void 0}export function buildRawArgsToolEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer repeated a JSON argument object for a declared tool after a structured tool-call recovery request.",`Matched configured tool: ${e.match.toolId}`,"Stable runtime executed that matched declared tool through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool output:",e.toolOutput].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(matchUniqueRawArgsTool(e))}export function buildRawArgsToolSequenceEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer printed multiple JSON argument objects for declared tools after a recovery request.","Stable runtime matched and executed those declared tools through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool output:",e.toolOutput,""])].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function matchUniqueRawArgsTool(t){const o=parseStandaloneJsonValues(t.output,{allowArray:!1})[0];if(!o)return;const r=matchToolEnvelope(o,t);if(r)return r;const a=isRawArgsRecord(o)?o:void 0;if(!a)return;const n=e({args:a,candidates:buildCallCandidates(t)});return n.ok?{toolId:n.candidateId,args:n.args}:void 0}export function matchRawArgsToolSequence(t){if(!toolCallRecoveryEnabled(t.policy))return[];const o=parseStandaloneJsonValues(t.output,{allowArray:!0});if(o.length<2)return[];const r=buildCallCandidates(t),a=[];for(const n of o){const o=matchToolEnvelope(n,t);if(o){a.push(o);continue}if(!isRawArgsRecord(n))return[];const s=e({args:n,candidates:r});if(!s.ok)return[];a.push({toolId:s.candidateId,args:s.args})}return a}function buildCallCandidates(e){return candidateToolIds(e).map(t=>({id:t,schema:e.workspace.tools.get(t)?.schema??e.toolGateway?.get(t)?.schema}))}function candidateToolIds(e){const t=new Set(e.agent.tools),o=(e.candidateToolIds??[]).filter(e=>t.has(e));return o.length>0?o:e.agent.tools}function parseStandaloneJsonValues(e,t){const o=e.trim(),r=o.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),a=r??o;if(a.length>6e3)return[];if(!(t.allowArray||a.startsWith("{")&&a.endsWith("}")))return[];if(t.allowArray&&!(a.startsWith("{")&&a.endsWith("}")||a.startsWith("[")&&a.endsWith("]")))return[];try{const e=JSON.parse(a);return Array.isArray(e)&&t.allowArray?e:[e]}catch{return[]}}function matchToolEnvelope(e,t){if(!isRecord(e))return;const o=function readEnvelopeToolId(e){const t=["toolId","toolName","tool","tool_name","name"].map(t=>e[t]).filter(e=>"string"==typeof e&&e.length>0);return 1===new Set(t).size?t[0]:void 0}(e),r=function readEnvelopeArgs(e){for(const t of["args","arguments","parameters","params","kwargs"]){const o=e[t];if(isRecord(o))return o}}(e),a=candidateToolIds(t);return o&&r&&a.includes(o)?{toolId:o,args:r}:void 0}function isRawArgsRecord(e){return isRecord(e)&&!function isToolCallEnvelope(e){const t=["tool","tool_name","name","type","subagent_type"].some(t=>"string"==typeof e[t]),o=["args","arguments","parameters","kwargs"].some(t=>t in e);return t&&o}(e)&&!function isRuntimeControlObject(e){return"string"==typeof e.status||"string"==typeof e.error||"string"==typeof e.controlStatus}(e)}function toolCallRecoveryEnabled(e){return!!(isRecord(e)&&isRecord(e.recovery)&&isRecord(e.recovery.toolCall))&&!0===e.recovery.toolCall.enabled}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function hasStructuredToolEnvelope(t){const e=function extractJsonSource(t){const e=t.trim();if(e.startsWith("{")&&e.endsWith("}")||e.startsWith("[")&&e.endsWith("]"))return e;const n=function extractSingleFence(t){const e=t.indexOf("```");if(e<0||t.indexOf("```",e+3)!==t.lastIndexOf("```"))return;const n=t.indexOf("\n",e+3),r=t.lastIndexOf("```");return n<0||r<=n?void 0:t.slice(n+1,r).trim()}(e);return n&&(n.startsWith("{")&&n.endsWith("}")||n.startsWith("[")&&n.endsWith("]"))?n:void 0}(t);if(!e)return!1;try{const t=JSON.parse(e);return Array.isArray(t)?t.some(isToolEnvelopeRecord):isToolEnvelopeRecord(t)}catch{return!1}}export function hasXmlLikeToolMarkup(t){const e=t.trim().toLowerCase();return e.includes("<tool_call")||e.includes("</tool_call")||e.includes("<tool_code")||e.includes("</tool_code")||e.includes("<task")||e.includes("</task")}export function isFunctionStyleCall(t){const e=t.trim(),n=e.indexOf("(");return!(n<=0||!e.endsWith(")")||e.length>2500)&&function isIdentifierPath(t){return t.length>0&&[...t].every((t,e)=>{const n=t>="A"&&t<="Z"||t>="a"&&t<="z"||"_"===t;return 0===e?n:n||t>="0"&&t<="9"||"."===t||"-"===t})}(e.slice(0,n).trim())&&function balancedParens(t){let e,n=0;for(let r=0;r<t.length;r+=1){const o=t[r],s=t[r-1];if(e)o===e&&"\\"!==s&&(e=void 0);else if('"'===o||"'"===o)e=o;else if("("===o)n+=1;else if(")"===o&&(n-=1,n<0))return!1}return 0===n&&!e}(e.slice(n))}function isToolEnvelopeRecord(t){return!!isRecord(t)&&(isRecord(t.task)?"string"==typeof t.task.subagent_type||"string"==typeof t.task.task:["tool","toolId","toolName","tool_name","name","type","subagent_type"].some(e=>"string"==typeof t[e])&&["args","arguments","parameters","params","kwargs","task"].some(e=>e in t))}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlGaps as e}from"../quality/event-evidence.js";import{omittedControlRecoveryLines as t}from"./control-omission.js";import{containsProgressOnlyToolIntent as o,progressOnlyToolIntentMessage as n}from"./progress-intent.js";import{containsStructurallyIncompleteFinalOutput as r,structurallyIncompleteFinalMessage as s}from"./structural-output.js";import{containsRawToolResultText as a}from"./tool-result.js";export function toolCallRecoveryEnabled(e){return!0===readToolCallRecovery(e).enabled}export function isRecoverableAdapterError(e,t){const o=readToolCallRecovery(t);if(!0!==o.enabled)return!1;const n=e instanceof Error?e.message:String(e);return readRegexps(o.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content|repeat limit reached for tool/iu]).some(e=>e.test(n))}export function buildAdapterErrorRecoveryPrompt(e,t,o){const n=t instanceof Error?t.message:String(t),r=readToolCallRecovery(o).instruction;return recoverRequest(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${n}`,"string"==typeof r?r:"Continue the same user request using the backend's normal tool-calling mechanism, then return a final human-readable answer.","Do not print raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer."])}export function buildResultRecoveryRequest(e){const n=readToolCallRecovery(e.policy);if(!0!==n.enabled)return;if(containsRawToolCallText(e.output,n)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer printed raw tool-call markup instead of executing the tool.","Continue the same user request by calling the available upstream tool normally when more evidence is required.","If you call a tool, the next assistant action must be the backend's structured tool call itself, with no prose before it.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text such as saying you will call or wait for a tool.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(o(e.output,e.availableToolIds)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was progress-only text or a pseudo tool invocation block instead of a user-facing answer.","Continue the same user request by calling the named available tool through the backend's normal structured mechanism.","If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not narrate intended future tool calls or print tool invocation blocks as a final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(a(e.output,e.events)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer copied an executed tool result JSON as the user-facing answer.","Continue the same user request from the existing tool evidence.","If more evidence is required, use one remaining declared tool or subagent action through the backend's normal structured mechanism.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Otherwise synthesize a human-readable final answer from the executed tool evidence.","Do not return the raw tool result JSON as the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(containsToolExecutionErrorText(e.output,n)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer exposed a backend tool execution error instead of handling it.","Continue the same user request using the backend's normal structured tool-calling mechanism.","Do not retry the same invalid tool arguments. If the failed tool is not required to answer the user, synthesize the final answer from the available context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not print tool error stacks, schema validation diagnostics, raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(r(e.output)){const t=recentToolEvidence(e.events,6e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was structurally incomplete or truncated.","Retry synthesis from the existing executed evidence and return a complete user-facing answer.","Do not stop inside an unfinished Markdown fence, inline code span, emphasis marker, sentence, or list item.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous incomplete final answer:",e.output])}const s=t(e);if(s)return recoverRequest(e.request,s);const i="tool_call"===e.request.metadata?.stableHarnessRecovery?void 0:function lastConfiguredEventHint(e,t){const o=function readEventRecoveryHints(e){return(Array.isArray(e)?e:[]).flatMap(e=>isRecord(e)&&"string"==typeof e.instruction?[{..."string"==typeof e.toolId?{toolId:e.toolId}:{},..."string"==typeof e.phase?{phase:e.phase}:{},..."string"==typeof e.outputIncludes?{outputIncludes:e.outputIncludes}:{},..."string"==typeof e.outputMatches?{outputMatches:e.outputMatches}:{},instruction:e.instruction}]:[])}(t.eventRecoveryHints);if(0!==o.length)return e.flatMap(e=>function readMatchingHints(e,t){const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o?t.filter(e=>function eventMatchesHint(e,t){return(!t.toolId||e.toolId===t.toolId)&&(!t.phase||e.phase===t.phase)&&(t.outputIncludes?"string"==typeof e.output&&e.output.includes(t.outputIncludes):!t.outputMatches||"string"==typeof e.output&&new RegExp(t.outputMatches,"u").test(e.output))}(o,e)).map(e=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:e.instruction})):[]}(e,o)).at(-1)}(e.events,n);return i?recoverRequest(e.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",i.output,i.instruction]):void 0}export function assertNoRawToolCallOutput(e,t){if(containsRawToolCallOutput(e,t))throw new Error(`Adapter returned raw tool-call text as the final answer after recovery. The backend must execute tools instead of printing tool-call markup. Output preview: ${previewOutput(e)}`)}export function containsRawToolCallOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRawToolCallText(e,o)}export function containsRecoverableResultOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRecoverableResultFailureText(e,o)}export function assertNoRawToolResultOutput(e,t,o){if(!0===readToolCallRecovery(o).enabled&&a(e,t))throw new Error(`Adapter returned raw tool result JSON as the final answer after recovery. The backend must synthesize a user-facing answer. Output preview: ${previewOutput(e)}`)}export function assertNoToolExecutionErrorOutput(e,t){const o=readToolCallRecovery(t);if(!0===o.enabled&&containsToolExecutionErrorText(e,o))throw new Error(`Adapter returned a tool execution error as the final answer after recovery. Output preview: ${previewOutput(e)}`)}export function assertNoProgressOnlyToolIntentOutput(e,t,r){if(!0===readToolCallRecovery(r).enabled&&o(e,t))throw new Error(n(e))}export function assertNoStructurallyIncompleteFinalOutput(e,t){if(!0===readToolCallRecovery(t).enabled&&r(e))throw new Error(s(e))}export function rawToolCallFailureMessage(){return["The model attempted to call a tool but returned the tool call as text instead of executing it.","Please retry the request or use a model/backend configuration with reliable tool calling for this workspace."].join(" ")}export function buildEvidenceSynthesisOutput(t){const o=readToolCallRecovery(t.policy);if(!0!==o.enabled||!1===o.synthesizeFromEvidenceOnFailure||!containsRecoverableResultFailureText(t.output,o))return;const n=function latestDelegatedTaskReport(e){return e.flatMap(e=>{const t="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;if(!isToolResultEvent(t)||"task"!==t.toolId)return[];const o="string"==typeof t.output?t.output.trim():"";return function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(o)?[o]:[]}).at(-1)||void 0}(t.events);if(n)return n;const r=recentToolEvidence(t.events,6e3);if(0===r.length)return;const s=/\p{Script=Han}/u.test(t.request.input)?"zh":"en",a=e(t.events);return"zh"===s?function buildChineseEvidenceSynthesis(e,t,o){return["上游模型在已有工具证据后仍输出了伪工具调用;runtime 已拒绝该 raw 输出,并直接交付已执行工具返回的证据结果。","","已执行的工具证据:",...t,...o.length>0?["","未解决的证据缺口:",...o.map(e=>`- ${e}`)]:[],"",`被拒绝的最终输出预览:${previewRejectedOutput(e)}`].join("\n")}(t.output,r,a):function buildEnglishEvidenceSynthesis(e,t,o){return["The upstream model still returned pseudo tool-call text after tool evidence was available. The runtime rejected that raw output and is returning the executed tool evidence directly.","","Executed tool evidence:",...t,...o.length>0?["","Unresolved evidence gaps:",...o.map(e=>`- ${e}`)]:[],"",`Rejected final output preview: ${previewRejectedOutput(e)}`].join("\n")}(t.output,r,a)}function previewOutput(e){const t=e.replace(/\s+/gu," ").trim();return t.length>300?`${t.slice(0,297)}...`:t}function previewRejectedOutput(e){return previewOutput(e).replace(/[<>]/gu,"")}export function rawToolCallOutputPreview(e){return previewOutput(e)}function recoverRequest(e,t){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}function containsRawToolCallText(e,t){const o=readRegexps(t.rawOutputPatterns,[/\{\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:/iu,/\{\s*"tool_name"\s*:\s*"[^"]+"\s*,\s*"parameters"\s*:/iu,/\{\s*"type"\s*:\s*"[^"]+"\s*,\s*"args"\s*:/iu,/^\s*[A-Za-z_][\w.-]*\s*\([^)]{0,2000}\)\s*$/iu,/^\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|task)\s*$/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:[\s\S]{0,4000}"(?:arguments|parameters|task)"\s*:/iu,/```(?:json)?[\s\S]{0,2000}"query"\s*:[\s\S]{0,2000}"(?:max_results|count|freshness|market)"\s*:/iu]);return!![/<\s*(?:tool_call|task)\b[^>]*>/iu,/<\s*\/\s*(?:tool_call|task)\s*>/iu,/<\s*\/?\s*tool_code\b[^>]*>/iu,/<\s*[A-Za-z_][\w.-]*\s*\([^>]{0,2000}\)\s*>/iu,/<\s*\/?\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|_todos|task)\b[^>]*>/iu].some(t=>t.test(e))||function looksLikeStandaloneRecoveryCandidate(e){const t=e.trim();return t.length<=6e3||/^\s*(?:```|\{|\[|[A-Za-z_][\w.-]*\s*\()/u.test(t)}(e)&&(o.some(t=>t.test(e))||[/^[\s\S]{0,2400}\b(?:I need to|I will|I'll|I am going to|I'm going to)\s+(?:call|use|invoke|delegate)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I will|I'll|I am going to|I'm going to)\s+(?:investigate|gather|check)\b[\s\S]{0,1200}\b(?:evidence|cluster|system|results?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:waiting for|wait for)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:Would you like me to|Do you want me to|Should I|I can help with)\b[\s\S]{0,1200}\?[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bCould you please provide\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I don't|I do not) have enough information\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task|context)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bLet me\s+(?:call|use|invoke|delegate|check|run|verify|gather|inspect)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|results?|data|evidence|commands?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:Let me|I'll|I will|I am going to|I'm going to)\s+(?:start\s+by\s+)?(?:read(?:ing)?|access(?:ing)?|gather(?:ing)?|collect(?:ing)?|fetch(?:ing)?|check(?:ing)?|inspect(?:ing)?)\b[\s\S]{0,1200}\b(?:context|instructions?|workflow|pull request|PR|issue|data|evidence|details?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}(?:我需要|我要|我会|我将|让我|我来|接下来我(?:会|将)?)\s*(?:先)?(?:调用|使用|运行|执行|检查|读取|收集|调查|验证|查看)[\s\S]{0,1200}$/iu,/^[\s\S]{0,2400}(?:要不要|是否需要|需要我|你想让我)[\s\S]{0,1200}(?:继续|进一步|帮你|分析|检查)[\s\S]{0,1200}[??][\s\S]{0,400}$/iu].some(t=>t.test(e)))}function containsRecoverableResultFailureText(e,t){return containsRawToolCallText(e,t)||containsToolExecutionErrorText(e,t)}function containsToolExecutionErrorText(e,t){return readRegexps(t.toolFailureOutputPatterns,[/^Error invoking tool ['"][^'"]+['"] with kwargs /iu,/Received tool input did not match expected schema/iu,/ToolMessage.*status.*error/iu]).some(t=>t.test(e))}function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return isToolResultEvent(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${previewOutput(JSON.stringify(e.args))}`:"completed"}function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}function readRegexps(e,t){const o=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e&&e.length>0).map(e=>new RegExp(e,"iu"));return o.length>0?o:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
1
|
+
import{controlGaps as e}from"../quality/event-evidence.js";import{omittedControlRecoveryLines as t}from"./control-omission.js";import{containsProgressOnlyToolIntent as o,progressOnlyToolIntentMessage as r}from"./progress-intent.js";import{containsStructurallyIncompleteFinalOutput as n,structurallyIncompleteFinalMessage as a}from"./structural-output.js";import{hasStructuredToolEnvelope as l,hasXmlLikeToolMarkup as i,isFunctionStyleCall as s}from"./tool-call-structure.js";import{containsRawToolResultText as u}from"./tool-result.js";export function toolCallRecoveryEnabled(e){return!0===readToolCallRecovery(e).enabled}export function isRecoverableAdapterError(e,t){const o=readToolCallRecovery(t);if(!0!==o.enabled)return!1;const r=e instanceof Error?e.message:String(e);return readRegexps(o.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content|repeat limit reached for tool/iu]).some(e=>e.test(r))}export function buildAdapterErrorRecoveryPrompt(e,t,o){const r=t instanceof Error?t.message:String(t),n=readToolCallRecovery(o).instruction;return recoverRequest(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${r}`,"string"==typeof n?n:"Continue the same user request using the backend's normal tool-calling mechanism, then return a final human-readable answer.","Do not print raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer."])}export function buildResultRecoveryRequest(e){const r=readToolCallRecovery(e.policy);if(!0!==r.enabled)return;if(containsRawToolCallText(e.output)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer printed raw tool-call markup instead of executing the tool.","Continue the same user request by calling the available upstream tool normally when more evidence is required.","If you call a tool, the next assistant action must be the backend's structured tool call itself, with no prose before it.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text such as saying you will call or wait for a tool.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(o(e.output,e.availableToolIds)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was progress-only text or a pseudo tool invocation block instead of a user-facing answer.","Continue the same user request by calling the named available tool through the backend's normal structured mechanism.","If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not narrate intended future tool calls or print tool invocation blocks as a final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(u(e.output,e.events)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer copied an executed tool result JSON as the user-facing answer.","Continue the same user request from the existing tool evidence.","If more evidence is required, use one remaining declared tool or subagent action through the backend's normal structured mechanism.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Otherwise synthesize a human-readable final answer from the executed tool evidence.","Do not return the raw tool result JSON as the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(containsToolExecutionErrorText(e.output,r)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer exposed a backend tool execution error instead of handling it.","Continue the same user request using the backend's normal structured tool-calling mechanism.","Do not retry the same invalid tool arguments. If the failed tool is not required to answer the user, synthesize the final answer from the available context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not print tool error stacks, schema validation diagnostics, raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(n(e.output)){const t=recentToolEvidence(e.events,6e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was structurally incomplete or truncated.","Retry synthesis from the existing executed evidence and return a complete user-facing answer.","Do not stop inside an unfinished Markdown fence, inline code span, emphasis marker, sentence, or list item.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous incomplete final answer:",e.output])}const a=t(e);if(a)return recoverRequest(e.request,a);const l="tool_call"===e.request.metadata?.stableHarnessRecovery?void 0:function lastConfiguredEventHint(e,t){const o=function readEventRecoveryHints(e){return(Array.isArray(e)?e:[]).flatMap(e=>isRecord(e)&&"string"==typeof e.instruction?[{..."string"==typeof e.toolId?{toolId:e.toolId}:{},..."string"==typeof e.phase?{phase:e.phase}:{},instruction:e.instruction}]:[])}(t.eventRecoveryHints);if(0!==o.length)return e.flatMap(e=>function readMatchingHints(e,t){const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o?t.filter(e=>function eventMatchesHint(e,t){return!(t.toolId&&e.toolId!==t.toolId||t.phase&&e.phase!==t.phase)}(o,e)).map(e=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:e.instruction})):[]}(e,o)).at(-1)}(e.events,r);return l?recoverRequest(e.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",l.output,l.instruction]):void 0}export function assertNoRawToolCallOutput(e,t){if(containsRawToolCallOutput(e,t))throw new Error(`Adapter returned raw tool-call text as the final answer after recovery. The backend must execute tools instead of printing tool-call markup. Output preview: ${previewOutput(e)}`)}export function containsRawToolCallOutput(e,t){return!0===readToolCallRecovery(t).enabled&&containsRawToolCallText(e)}export function containsRecoverableResultOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRecoverableResultFailureText(e,o)}export function assertNoRawToolResultOutput(e,t,o){if(!0===readToolCallRecovery(o).enabled&&u(e,t))throw new Error(`Adapter returned raw tool result JSON as the final answer after recovery. The backend must synthesize a user-facing answer. Output preview: ${previewOutput(e)}`)}export function assertNoToolExecutionErrorOutput(e,t){const o=readToolCallRecovery(t);if(!0===o.enabled&&containsToolExecutionErrorText(e,o))throw new Error(`Adapter returned a tool execution error as the final answer after recovery. Output preview: ${previewOutput(e)}`)}export function assertNoProgressOnlyToolIntentOutput(e,t,n){if(!0===readToolCallRecovery(n).enabled&&o(e,t))throw new Error(r(e))}export function assertNoStructurallyIncompleteFinalOutput(e,t){if(!0===readToolCallRecovery(t).enabled&&n(e))throw new Error(a(e))}export function rawToolCallFailureMessage(){return["The model attempted to call a tool but returned the tool call as text instead of executing it.","Please retry the request or use a model/backend configuration with reliable tool calling for this workspace."].join(" ")}export function buildEvidenceSynthesisOutput(t){const o=readToolCallRecovery(t.policy);if(!0!==o.enabled||!1===o.synthesizeFromEvidenceOnFailure||!containsRecoverableResultFailureText(t.output,o))return;const r=function latestDelegatedTaskReport(e){return e.flatMap(e=>{const t="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;if(!isToolResultEvent(t)||"task"!==t.toolId)return[];const o="string"==typeof t.output?t.output.trim():"";return function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(o)?[o]:[]}).at(-1)||void 0}(t.events);if(r)return r;const n=recentToolEvidence(t.events,6e3);if(0===n.length)return;const a=/\p{Script=Han}/u.test(t.request.input)?"zh":"en",l=e(t.events);return"zh"===a?function buildChineseEvidenceSynthesis(e,t,o){return["上游模型在已有工具证据后仍输出了伪工具调用;runtime 已拒绝该 raw 输出,并直接交付已执行工具返回的证据结果。","","已执行的工具证据:",...t,...o.length>0?["","未解决的证据缺口:",...o.map(e=>`- ${e}`)]:[],"",`被拒绝的最终输出预览:${previewRejectedOutput(e)}`].join("\n")}(t.output,n,l):function buildEnglishEvidenceSynthesis(e,t,o){return["The upstream model still returned pseudo tool-call text after tool evidence was available. The runtime rejected that raw output and is returning the executed tool evidence directly.","","Executed tool evidence:",...t,...o.length>0?["","Unresolved evidence gaps:",...o.map(e=>`- ${e}`)]:[],"",`Rejected final output preview: ${previewRejectedOutput(e)}`].join("\n")}(t.output,n,l)}function previewOutput(e){const t=e.replace(/\s+/gu," ").trim();return t.length>300?`${t.slice(0,297)}...`:t}function previewRejectedOutput(e){return previewOutput(e).replace(/[<>]/gu,"")}export function rawToolCallOutputPreview(e){return previewOutput(e)}function recoverRequest(e,t){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}function containsRawToolCallText(e,t){return!function looksLikeCompletedMarkdownReport(e){const t=e.trimStart();return e.length>1200&&t.startsWith("#")}(e)&&!!(l(e)||i(e)||s(e))}function containsRecoverableResultFailureText(e,t){return containsRawToolCallText(e)||containsToolExecutionErrorText(e,t)}function containsToolExecutionErrorText(e,t){return readRegexps(t.toolFailureOutputPatterns,[/^Error invoking tool ['"][^'"]+['"] with kwargs /iu,/Received tool input did not match expected schema/iu,/ToolMessage.*status.*error/iu]).some(t=>t.test(e))}function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return isToolResultEvent(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${previewOutput(JSON.stringify(e.args))}`:"completed"}function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}function readRegexps(e,t){const o=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e&&e.length>0).map(e=>new RegExp(e,"iu"));return o.length>0?o:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{containsProgressOnlyToolIntent as t}from"../../recovery/progress-intent.js";import{buildRawArgsRecoveryRequest as o,buildRawArgsToolEvidenceRecoveryRequest as r,buildRawArgsToolSequenceEvidenceRecoveryRequest as a,hasUniqueRawArgsTool as s,matchRawArgsToolSequence as n,matchUniqueRawArgsTool as l}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as
|
|
1
|
+
import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{containsProgressOnlyToolIntent as t}from"../../recovery/progress-intent.js";import{buildRawArgsRecoveryRequest as o,buildRawArgsToolEvidenceRecoveryRequest as r,buildRawArgsToolSequenceEvidenceRecoveryRequest as a,hasUniqueRawArgsTool as s,matchRawArgsToolSequence as n,matchUniqueRawArgsTool as l}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as i,assertNoRawToolCallOutput as u,assertNoRawToolResultOutput as c,assertNoStructurallyIncompleteFinalOutput as d,assertNoToolExecutionErrorOutput as y,buildEvidenceSynthesisOutput as p,buildResultRecoveryRequest as v,containsRawToolCallOutput as g,rawToolCallFailureMessage as m,rawToolCallOutputPreview as f,toolCallRecoveryEnabled as w}from"../../recovery/tool-call.js";import{controlGaps as R}from"../../quality/event-evidence.js";export async function recoverAdapterResultOutput(t){let r=t.result,a=t.request;const n=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(t.recoveryPolicy),R=new Set,T=new Set;for(let e=0;;e+=1){const s=t.store.getRun(t.requestId)?.events??[],i=effectiveRecoveryToolIds(a,t.agent.tools);assertNoNonFocusedRecoveryIntent(r.text,t.recoveryPolicy,t.agent.tools,i);const u=await recoverRawArgsSequenceByToolGateway(t,a,r,T,e+1,i);if(u){a=u.request,r=u.result;continue}const c=l({output:r.text,agent:t.agent,workspace:t.workspace,toolGateway:t.toolGateway,events:s,candidateToolIds:i,policy:t.recoveryPolicy}),d=c?rawArgsToolKey(c):void 0;if(c&&d&&T.size>0&&!T.has(d)){const o=await recoverRawArgsByToolGateway(t,a,r,c,T,e+1);if(o){a=o.request,r=o.result;continue}}const y=d&&!R.has(d)?o({request:a,output:r.text,agent:t.agent,workspace:t.workspace,toolGateway:t.toolGateway,events:s,candidateToolIds:i,policy:t.recoveryPolicy}):void 0,p=e<n?v({request:a,output:r.text,events:s,availableToolIds:i,policy:t.recoveryPolicy}):void 0,g=y??p;if(!g)break;if(g===y&&R.add(d),a=g,emitRepair(t,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(r.text,i)),r=await t.runAdapter(g),emitRepair(t,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(r.text,i)),g===y){const o=await recoverRepeatedRawArgsByToolGateway(t,a,r,R,T,e+1);o&&(a=o.request,r=o.result)}}return function finalizeRecoveredOutput(t,o){if(!w(t.recoveryPolicy))return o;let r=!1;if(g(o.text,t.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(t.request.metadata)){const e=o.text;o={...o,text:m(),metadata:{...o.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,t.agent.tools))}const a=p({request:t.request,output:o.text,events:t.store.getRun(t.requestId)?.events??[],policy:t.recoveryPolicy});return a&&(r=!0,o={...o,text:a,metadata:{...o.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(t,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),r||(g(o.text,t.recoveryPolicy)&&emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(o.text,t.agent.tools)),u(o.text,t.recoveryPolicy),function assertNoRawArgsToolOutput(e,t){if(s({output:t,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:effectiveRecoveryToolIds(e.request,e.agent.tools),policy:e.recoveryPolicy}))throw new Error(`Adapter returned raw tool argument JSON as the final answer after recovery. The backend must execute the matching tool instead. Output preview: ${f(t)}`)}(t,o.text),i(o.text,t.agent.tools,t.recoveryPolicy),c(o.text,t.store.getRun(t.requestId)?.events??[],t.recoveryPolicy),y(o.text,t.recoveryPolicy),d(o.text,t.recoveryPolicy),e({output:o.text,events:t.store.getRun(t.requestId)?.events??[],availableToolIds:t.agent.tools})),o}(t,r)}async function recoverRawArgsSequenceByToolGateway(e,t,o,r,s,l){if(!e.runRecoveredToolCall)return;const i=n({output:o.text,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:l,policy:e.recoveryPolicy});if(i.length<2||i.some(e=>r.has(rawArgsToolKey(e))))return;emitRepair(e,"runtime.repair.started","result_output",s,"raw_args_tool_sequence_gateway_recovery",void 0,repairDiagnostics(o.text,l));const u=[];for(const t of i){r.add(rawArgsToolKey(t));const o=await e.runRecoveredToolCall(t.toolId,t.args);u.push({match:t,toolOutput:visibleRecoveredToolOutput(o)})}const c=a({request:t,evidences:u}),d=await e.runAdapter(c),y=d.text.trim()?d:{...d,text:buildEmptyRecoveredToolSequenceBlocker({evidences:u,events:e.store.getRun(e.requestId)?.events??[]}),metadata:{...d.metadata,toolCallRecovery:{blocked:!0,reason:"empty_output_after_recovered_tool_sequence"}}};return emitRepair(e,"runtime.repair.completed","result_output",s,"raw_args_tool_sequence_gateway_recovery","retried",repairDiagnostics(y.text,l)),{request:c,result:y}}async function recoverRepeatedRawArgsByToolGateway(e,t,o,r,a,s){const n=l({output:o.text,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:effectiveRecoveryToolIds(t,e.agent.tools),policy:e.recoveryPolicy});if(!n||!e.runRecoveredToolCall)return;const i=rawArgsToolKey(n);return r.has(i)&&!a.has(i)?recoverRawArgsByToolGateway(e,t,o,n,a,s):void 0}async function recoverRawArgsByToolGateway(e,t,o,a,s,n){if(!e.runRecoveredToolCall)return;const l=rawArgsToolKey(a);if(s.has(l))return;s.add(l),emitRepair(e,"runtime.repair.started","result_output",n,"raw_args_tool_gateway_recovery",void 0,repairDiagnostics(o.text,e.agent.tools));const i=visibleRecoveredToolOutput(await e.runRecoveredToolCall(a.toolId,a.args)),u=r({request:t,match:a,toolOutput:i}),c=await e.runAdapter(u),d=c.text.trim()?c:{...c,text:buildEmptyRecoveredToolBlocker({match:a,toolOutput:i,events:e.store.getRun(e.requestId)?.events??[]}),metadata:{...c.metadata,toolCallRecovery:{blocked:!0,reason:"empty_output_after_recovered_tool"}}};return emitRepair(e,"runtime.repair.completed","result_output",n,"raw_args_tool_gateway_recovery","retried",repairDiagnostics(d.text,e.agent.tools)),{request:u,result:d}}function assertNoNonFocusedRecoveryIntent(e,o,r,a){if(0===a.length||a.length===r.length)return;const s=new Set(a),n=visibleToolCandidates(e,r).filter(e=>!s.has(e)),l=g(e,o)||t(e,r)||function containsJsonToolEnvelope(e){const t=e.trim(),o=t.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),r=o??t;if(!r.startsWith("{")||!r.endsWith("}")||r.length>6e3)return!1;try{const e=JSON.parse(r);if(!function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(e))return!1;const t=["tool","tool_name","name","type","subagent_type"].some(t=>"string"==typeof e[t]),o=["args","arguments","parameters","kwargs"].some(t=>t in e);return t&&o}catch{return!1}}(e);if(n.length>0&&l)throw new Error(`Focused recovery output referenced non-focused tool(s): ${n.join(", ")}. The backend must call one of the focused gateway tools: ${a.join(", ")}.`)}function emitRepair(e,t,o,r,a,s,n){const l={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...n?{diagnostics:n}:{}};e.emit("runtime.repair.started"===t?{type:t,...l}:{type:t,...l,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:f(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])containsDelimitedToken(e,r)&&o.add(r);return[...o]}function containsDelimitedToken(e,t){if(!t)return!1;let o=e.indexOf(t);for(;o>=0;){const r=0===o?"":e[o-1],a=e[o+t.length]??"";if(!isTokenChar(r)&&!isTokenChar(a))return!0;o=e.indexOf(t,o+t.length)}return!1}function isTokenChar(e){return"_"===e||"-"===e||e>="A"&&e<="Z"||e>="a"&&e<="z"||e>="0"&&e<="9"}function effectiveRecoveryToolIds(e,t){const o=function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}(e.metadata?.stableHarnessRequiredEvidenceTools).filter(e=>t.includes(e));return o.length>0?o:t}function rawArgsToolKey(e){return`${e.toolId}:${JSON.stringify(e.args)}`}function visibleRecoveredToolOutput(e){return("string"==typeof e.text?e.text.trim():"")||"The recovered tool completed successfully but returned no user-visible output."}function buildEmptyRecoveredToolBlocker(e){const t=R(e.events);return["Stable runtime recovery executed the matched declared tool, but the backend returned no user-facing output after receiving the executed evidence.","",`Executed tool: ${e.match.toolId}`,"","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool evidence:",e.toolOutput,...t.length>0?["","Unresolved control gaps:",...t.map(e=>`- ${e}`)]:[]].join("\n")}function buildEmptyRecoveredToolSequenceBlocker(e){const t=R(e.events);return["Stable runtime recovery executed matched declared tools, but the backend returned no user-facing output after receiving the executed evidence.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool evidence:",e.toolOutput,""]),...t.length>0?["Unresolved control gaps:",...t.map(e=>`- ${e}`)]:[]].join("\n")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildExecutionContractRecoveryRequest as r}from"./recovery/execution-contract.js";import{buildAdapterErrorRecoveryPrompt as a,isRecoverableAdapterError as o}from"./recovery/tool-call.js";import{recoverQualityReview as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildExecutionContractRecoveryRequest as r}from"./recovery/execution-contract.js";import{buildAdapterErrorRecoveryPrompt as a,isRecoverableAdapterError as o}from"./recovery/tool-call.js";import{recoverQualityReview as n,resolveQualityPolicy as s}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as m}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as d}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeImprovementAdministration as w}from"./runtime/improvement/admin.js";import{createRuntimeEvidenceAdministration as g}from"./runtime/improvement/evidence-admin.js";import{createInMemoryRuntimeImprovementStore as y}from"./runtime/improvement/store.js";import{createRuntimeInspectionMethods as I}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as f,normalizeAdapterResult as q}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as v}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as R}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as k}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as A}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as b}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as j}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as x}from"./runtime/tool-failure.js";import{runWorkflowRequest as E}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const q=new Set,G=t.store??A(),S=t.improvements??y(),T=f([v(t),b({options:t.progressNarration,policy:t.workspace.runtime}),j({policy:t.workspace.runtime,store:G,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);G.appendEvent(r);for(const e of q)e(r)},emit=e=>{emitBase(e),T.emitSideEffects(e,emitBase)},h=l({gateway:d({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),M={...t,toolGateway:h},O=x(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),d=t.request.sessionId??e(),l=[],{agent:w,adapter:g}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,o=e.workspace.agents.get(a);if(!o)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:o,adapter:void 0};const n=e.adapters.find(e=>e.canRun(o));if(!n)throw new Error(`No runtime adapter can run backend ${o.backend} for agent ${o.id}`);return{agent:o,adapter:n}}(t.input,t.request,{requestId:p,sessionId:d,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,d,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:d,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await E({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:d,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await m({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:d,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,m=c.pluginMemories??[],d=R({workspace:e.input.workspace,agent:e.agent}),l=s(e.input.workspace.runtime,e.agent),w=new Map;let g;try{g=await runAdapterOnce(e,t,e.request,p,m,w,d)}catch(r){if(!o(r,d))throw r;e.emit(repairStarted(e,"adapter_error",1,errorMessage(r))),g=await runAdapterOnce(e,t,a(e.request,r,d),p,m,w,d),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(r)))}g=await i({...e,request:e.request,result:g,recoveryPolicy:d,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,m,w,d),runRecoveredToolCall:(t,r)=>runRecoveredToolCall(e,t,r)}),g=await n(createQualityRuntimeInput(e,p,m,w,d),e.request,g,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:g});try{assertRequestExecutionContract(e,g)}catch(a){const o=r({request:e.request,events:e.store.getRun(e.requestId)?.events??[],agent:e.agent,policy:d});if(!o)throw a;e.emit(repairStarted(e,"execution_contract",1,errorMessage(a))),g=await runAdapterOnce(e,t,o,p,m,w,d),g=await i({...e,request:o,result:g,recoveryPolicy:d,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,m,w,d),runRecoveredToolCall:(t,r)=>runRecoveredToolCall(e,t,r)}),g=await n(createQualityRuntimeInput(e,p,m,w,d),o,g,l),assertRequestExecutionContract(e,g),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(a)))}const y=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:g,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:g,response:y}),y}({...t,adapter:g,requestId:p,sessionId:d,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,error:e})}}({input:M,capabilities:T,store:G,emit:emit,request:t,toolFailureTracker:O}),subscribe:e=>(q.add(e),()=>q.delete(e)),...I({workspace:t.workspace,store:G,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:G,emit:emit}),...w({runtimeStore:G,store:S,emit:emit}),...g({runtimeStore:G,emit:emit}),...k({memory:t.memory}),cancel(e,t){const r=G.getRun(e);r&&"running"===r.state&&(G.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await T.stop(),q.clear()}}}function runRecoveredToolCall(e,t,r){return m({gateway:e.input.toolGateway,workspace:e.input.workspace,emit:e.emit,request:{...e.request,toolCall:{toolId:t,args:r}},requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,events:e.store.getRun(e.requestId)?.events??[]})}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,o){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:n=>runAdapterOnce(e,e.adapter,n,t,r,a,o),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e,r){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,output:r.text,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,o,n,s){return q(await t.run({workspace:{...e.input.workspace,runtime:s},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:o,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:n,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,o){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:o}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
".": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@stable-harness/governance": "0.0.
|
|
16
|
-
"@stable-harness/memory": "0.0.
|
|
15
|
+
"@stable-harness/governance": "0.0.127",
|
|
16
|
+
"@stable-harness/memory": "0.0.127"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/protocols",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -11,6 +11,6 @@
|
|
|
11
11
|
"main": "dist/src/index.js",
|
|
12
12
|
"types": "dist/src/index.d.ts",
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"@stable-harness/core": "0.0.
|
|
14
|
+
"@stable-harness/core": "0.0.127"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/workspace-yaml",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
".": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@stable-harness/core": "0.0.
|
|
15
|
+
"@stable-harness/core": "0.0.127"
|
|
16
16
|
}
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stable-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Stable application runtime and operator control plane for agent workspaces.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -82,14 +82,14 @@
|
|
|
82
82
|
"@langchain/node-vfs": "^0.1.4",
|
|
83
83
|
"@langchain/ollama": "^1.2.7",
|
|
84
84
|
"@langchain/openai": "^1.4.5",
|
|
85
|
-
"@stable-harness/adapter-deepagents": "0.0.
|
|
86
|
-
"@stable-harness/adapter-langgraph": "0.0.
|
|
87
|
-
"@stable-harness/core": "0.0.
|
|
88
|
-
"@stable-harness/governance": "0.0.
|
|
89
|
-
"@stable-harness/memory": "0.0.
|
|
90
|
-
"@stable-harness/protocols": "0.0.
|
|
91
|
-
"@stable-harness/tool-gateway": "0.0.
|
|
92
|
-
"@stable-harness/workspace-yaml": "0.0.
|
|
85
|
+
"@stable-harness/adapter-deepagents": "0.0.127",
|
|
86
|
+
"@stable-harness/adapter-langgraph": "0.0.127",
|
|
87
|
+
"@stable-harness/core": "0.0.127",
|
|
88
|
+
"@stable-harness/governance": "0.0.127",
|
|
89
|
+
"@stable-harness/memory": "0.0.127",
|
|
90
|
+
"@stable-harness/protocols": "0.0.127",
|
|
91
|
+
"@stable-harness/tool-gateway": "0.0.127",
|
|
92
|
+
"@stable-harness/workspace-yaml": "0.0.127",
|
|
93
93
|
"deepagents": "^1.10.1",
|
|
94
94
|
"langchain": "^1.4.0",
|
|
95
95
|
"yaml": "^2.8.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/adapter-deepagents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@langchain/node-vfs": "^0.1.4",
|
|
17
17
|
"@langchain/ollama": "^1.2.7",
|
|
18
18
|
"@langchain/openai": "^1.4.5",
|
|
19
|
-
"@stable-harness/core": "0.0.
|
|
19
|
+
"@stable-harness/core": "0.0.127",
|
|
20
20
|
"deepagents": "^1.10.1",
|
|
21
21
|
"langchain": "^1.4.0"
|
|
22
22
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/adapter-langgraph",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
"types": "dist/src/index.d.ts",
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"@langchain/langgraph": "^1.3.0",
|
|
15
|
-
"@stable-harness/core": "0.0.
|
|
15
|
+
"@stable-harness/core": "0.0.127"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"types": "dist/src/index.d.ts",
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@langchain/langgraph-api": "^1.2.1",
|
|
18
|
-
"@stable-harness/adapter-deepagents": "0.0.
|
|
19
|
-
"@stable-harness/adapter-langgraph": "0.0.
|
|
20
|
-
"@stable-harness/core": "0.0.
|
|
21
|
-
"@stable-harness/memory": "0.0.
|
|
22
|
-
"@stable-harness/protocols": "0.0.
|
|
23
|
-
"@stable-harness/tool-gateway": "0.0.
|
|
24
|
-
"@stable-harness/workspace-yaml": "0.0.
|
|
18
|
+
"@stable-harness/adapter-deepagents": "0.0.127",
|
|
19
|
+
"@stable-harness/adapter-langgraph": "0.0.127",
|
|
20
|
+
"@stable-harness/core": "0.0.127",
|
|
21
|
+
"@stable-harness/memory": "0.0.127",
|
|
22
|
+
"@stable-harness/protocols": "0.0.127",
|
|
23
|
+
"@stable-harness/tool-gateway": "0.0.127",
|
|
24
|
+
"@stable-harness/workspace-yaml": "0.0.127"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function hasPlanningEvidence(t){return t.some(t=>{const e=readAdapterEvent(t);return!!e&&("plan"===e.traceType||String(e.traceLabel??"").startsWith("plan.")||"write_todos"===e.toolId&&String(e.phase??"").startsWith("agent.tool."))})}export function successfulEvidenceToolIds(t){const e=t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return[t.toolId];const e=readAdapterEvent(t);return isToolResultEvent(e)&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?[e.toolId]:[]});return[...new Set(e)]}export function successfulEvidenceOutputs(t){return successfulEvidenceItems(t).map(t=>t.output)}export function successfulEvidenceItems(t){return t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return stringifyEvidence(t.output).map(e=>({source:t.toolId,output:e}));const e=readAdapterEvent(t),
|
|
1
|
+
export function hasPlanningEvidence(t){return t.some(t=>{const e=readAdapterEvent(t);return!!e&&("plan"===e.traceType||String(e.traceLabel??"").startsWith("plan.")||"write_todos"===e.toolId&&String(e.phase??"").startsWith("agent.tool."))})}export function successfulEvidenceToolIds(t){const e=t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return[t.toolId];const e=readAdapterEvent(t);return isToolResultEvent(e)&&"string"==typeof e.toolId&&isSuccessfulEvidenceEvent(e)?[e.toolId]:[]});return[...new Set(e)]}export function successfulEvidenceOutputs(t){return successfulEvidenceItems(t).map(t=>t.output)}export function successfulEvidenceItems(t){return t.flatMap(t=>{if("runtime.tool.direct.completed"===t.type)return stringifyEvidence(t.output).map(e=>({source:t.toolId,output:e}));const e=readAdapterEvent(t),n=readToolSource(e);return isToolResultEvent(e)&&n?!isSuccessfulEvidenceEvent(e)||function isPlanningTool(t){return"write_todos"===t||"read_todos"===t}(n)?[]:stringifyEvidence(e.evidenceOutput??e.output).filter(t=>function isUsableEvidenceOutput(t,e){return!("task"===t&&function looksLikeUnexecutedToolIntent(t){const e=t.trim();if(e.length>4e3)return!1;const n=function extractJsonSource(t){const e=t.trim();if(e.startsWith("{")&&e.endsWith("}")||e.startsWith("[")&&e.endsWith("]"))return e;if(!e.startsWith("```"))return;const n=e.indexOf("\n"),r=e.lastIndexOf("```");return n<0||r<=n?void 0:e.slice(n+1,r).trim()}(e);return n?function containsToolEnvelope(t){try{const e=JSON.parse(t);return Array.isArray(e)?e.some(isToolEnvelopeRecord):isToolEnvelopeRecord(e)}catch{return!1}}(n):function containsToolMarkup(t){const e=t.toLowerCase();return e.includes("<tool_call")||e.includes("</tool_call")||e.includes("<tool_code")||e.includes("</tool_code")}(e)||function containsBareToolFence(t){const e=t.trim(),n=e.indexOf("```");if(n<0||e.indexOf("```",n+3)!==e.lastIndexOf("```"))return!1;const r=e.indexOf("\n",n+3),o=e.lastIndexOf("```");return!(r<0||o<=r)&&function isIdentifierPath(t){return t.length>0&&[...t].every((t,e)=>{const n=t>="A"&&t<="Z"||t>="a"&&t<="z"||"_"===t;return 0===e?n:n||t>="0"&&t<="9"||"."===t||"-"===t})}(e.slice(r+1,o).trim())}(e)}(e))}(n,t)).map(t=>({source:n,output:t})):[]})}export function controlBlockers(t){const e=successfulEventIndexesBySource(t);return t.flatMap((t,n)=>{const r=readAdapterEvent(t),o=readControlStatus(r),s=readControlSource(r)??"tool";return o&&isBlockerStatus(o)?isResolvedByLaterCompletion(o)&&completedAfter(e,s,n)||isResolvedByLaterAnyCompletion(o)&&completedAfterAny(e,n)?[]:[`${s}:${o}`]:[]})}export function controlGaps(t){const e=new Set(successfulEvidenceItems(t).map(t=>t.source));return t.flatMap(t=>{const n=readAdapterEvent(t),r=readControlStatus(n),o=readControlSource(n)??"tool";return r&&isGapStatus(r)?e.has(o)&&isResolvedByLaterCompletion(r)?[]:[`${o}:${r}`]:[]})}export function omittedControlGaps(t,e){const n=successfulEventIndexesBySource(t),r=successfulEvidenceItems(t),o=function outputHasUnsupportedEvidenceClaims(t,e,n){const r=function evidenceCorpus(t,e){return[...e.map(t=>t.output),...t.flatMap(t=>"runtime.request.started"===t.type?[t.input??""]:[]),...t.flatMap(t=>"runtime.memory.recall.completed"===t.type?[t.context]:[])].join("\n")}(e,n).toLowerCase();return unsupportedTokens(t,r,/\b[A-Z][A-Z0-9]{1,12}-\d+\b/gu).length>0||unsupportedTokens(t,r,/\b[A-Za-z_$][A-Za-z0-9_$]*[A-Z][A-Za-z0-9_$]*\b/gu).filter(isCodeLikeIdentifier).length>=2}(e,t,r);return t.flatMap((t,s)=>{const u=readAdapterEvent(t),i=readControlStatus(u),a=readControlSource(u)??"tool";return i&&function isOmittedControlStatus(t){return isGapStatus(t)||isBlockerStatus(t)}(i)?isResolvedByLaterCompletion(i)&&completedAfter(n,a,s)||isResolvedByLaterAnyCompletion(i)&&completedAfterAny(n,s)||!o&&outputUsesPriorEvidence(e,a,r)?[]:[`${a}:${i}`]:[]})}function stringifyEvidence(t){return"string"==typeof t?t.trim()?[t]:[]:null==t?[]:[JSON.stringify(t)]}function isToolEnvelopeRecord(t){return!!isRecord(t)&&["tool","toolId","toolName","tool_name","name","type","subagent_type"].some(e=>"string"==typeof t[e])&&["args","arguments","parameters","params","kwargs","task"].some(e=>e in t)}function readAdapterEvent(t){if("runtime.adapter.event"===t.type&&isRecord(t.event))return t.event;const e=t;return isRecord(e)&&isToolResultEvent(e)?e:void 0}function isSuccessfulEvidenceEvent(t){const e=readEventStatus(t);return!e||/^(?:completed|success|ok|recorded)$/iu.test(e)}function isBlockerStatus(t){return/^(?:blocked|approval_required|schema_repair_failed|tool_argument_error|invalid_input|task_inventory_blocked)$/iu.test(t)}function isGapStatus(t){return/^(?:dependency_required|plan_required|repeated_tool_call_limit|duplicate_tool_call)$/iu.test(t)}function isResolvedByLaterCompletion(t){return isGapStatus(t)||isBlockerStatus(t)}function isResolvedByLaterAnyCompletion(t){return"task_inventory_blocked"===t}function successfulEventIndexesBySource(t){const e=new Map;return t.forEach((t,n)=>{const r=function successfulEventSource(t){if("runtime.tool.direct.completed"===t.type)return t.toolId;const e=readAdapterEvent(t),n=readToolSource(e);return isToolResultEvent(e)&&n&&isSuccessfulEvidenceEvent(e)?n:void 0}(t);r&&e.set(r,[...e.get(r)??[],n])}),e}function isToolResultEvent(t){return"deepagents.tool_execution.result"===t?.eventType||"agent.tool.result"===t?.phase||"agent.tool.result"===t?.type||"deepagents.tool_execution.result"===t?.type}function completedAfter(t,e,n){return(t.get(e)??[]).some(t=>t>n)}function completedAfterAny(t,e){return[...t.values()].some(t=>t.some(t=>t>e))}export function outputUsesPriorEvidence(t,e,n){const r=t.toLowerCase();return n.filter(t=>t.source===e).some(t=>{const e=t.output.trim();return!!e&&(!!r.includes(e.slice(0,500).toLowerCase())||function matchingEvidenceTokens(t,e){const n=new Set(["status","completed","success","recorded"]);return[...new Set(e.toLowerCase().match(/[a-z0-9][a-z0-9_.-]{1,}/gu)??[])].filter(t=>!n.has(t)).filter(e=>t.includes(e)).length}(r,e)>=2)})}function unsupportedTokens(t,e,n){return[...new Set(t.match(n)??[])].filter(t=>!e.includes(t.toLowerCase()))}function isCodeLikeIdentifier(t){return!(t.length<8)&&(/(?:Service|Controller|Repository|Manager|Client|Resolver|Agent|Tool|Async)$/u.test(t)||/[a-z][A-Z]/u.test(t))}function readOutputStatus(t){if(isRecord(t)&&"string"==typeof t.status)return t.status;if("string"==typeof t){const e=parseJsonRecord(t);return"string"==typeof e?.status?e.status:t.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}}function parseJsonRecord(t){try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function readString(t){return"string"==typeof t&&t.trim()?t:void 0}function readEventStatus(t){return readString(t?.controlStatus)??readString(t?.status)??readOutputStatus(t?.output)}function readToolSource(t){return readString(t?.toolId)??readString(t?.toolName)??readString(t?.name)}function readControlStatus(t){const e=function readInventoryRepairControlStatus(t){if("inventory.repair"===t?.phase&&"blocked"===t.status)return"task"===readInventoryRepairSource(t)?"task_inventory_blocked":"blocked"}(t);if(e)return e;const n=readEventStatus(t);return n&&isControlStatus(n)?n:findNestedControlStatus(t)}function readControlSource(t){return readToolSource(t)??readInventoryRepairSource(t)??findNestedToolSource(t)}function isControlStatus(t){return isGapStatus(t)||isBlockerStatus(t)}function findNestedControlStatus(t,e=0){if(e>5||null==t)return;if("string"==typeof t)return function readNestedStringStatus(t,e){const n=parseJsonRecord(t);if(n)return findNestedControlStatus(n,e+1);const r=t.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1];return r&&isControlStatus(r)?r:function readControlToken(t){const e=t.match(/\b(?:blocked|approval_required|schema_repair_failed|tool_argument_error|invalid_input|task_inventory_blocked|dependency_required|plan_required|repeated_tool_call_limit|duplicate_tool_call)\b/iu)?.[0];return e&&isControlStatus(e)?e:void 0}(t)}(t,e);if(Array.isArray(t))return findFirstNested(t,t=>findNestedControlStatus(t,e+1));if(!isRecord(t))return;const n=readString(t.controlStatus)??readString(t.status);if(n&&isControlStatus(n))return n;const r=readOutputStatus(t.output);return r&&isControlStatus(r)?r:findFirstNested(Object.values(t),t=>findNestedControlStatus(t,e+1))}function findNestedToolSource(t,e=0){if(!(e>5||null==t)){if("string"==typeof t)return function readToolSourceFromText(t){const e=t.match(/["'](?:toolId|toolName|name)["']\s*:\s*["']([^"']+)["']/u)?.[1];return readString(e)}(t);if(Array.isArray(t))return findFirstNested(t,t=>findNestedToolSource(t,e+1));if(isRecord(t))return(readString(t.toolId)??readString(t.toolName)??readString(t.name))||findFirstNested(Object.values(t),t=>findNestedToolSource(t,e+1))}}function findFirstNested(t,e){for(const n of t){const t=e(n);if(void 0!==t)return t}}function readInventoryRepairSource(t){const e=isRecord(t?.diagnostic)?t.diagnostic:void 0;return readString(e?.layer)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlBlockers as e,omittedControlGaps as t}from"../quality/event-evidence.js";export function omittedControlRecoveryLines(o){const
|
|
1
|
+
import{controlBlockers as e,omittedControlGaps as t}from"../quality/event-evidence.js";export function omittedControlRecoveryLines(o){const r=e(o.events),n=t(o.events,o.output).filter(e=>!function mentionsGap(e,t){const[o,r]=t.split(":"),n=e.toLowerCase(),i=function statusPhrases(e){if(!e)return[];const t=e.toLowerCase().replaceAll("_"," ");return"task_inventory_blocked"===e?[t,"workspace inventory","not in the workspace inventory"]:"repeated_tool_call_limit"===e?[t,"repeat limit"]:[t]}(r);return n.includes(t.toLowerCase())||Boolean(r&&n.includes(r.toLowerCase()))||i.some(e=>n.includes(e))||Boolean(o&&r&&n.includes(o.toLowerCase())&&n.includes(r.toLowerCase()))}(o.output,e));if(0===n.length)return;const i=function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o||"task_inventory_blocked"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}(o.events,1e3);return["Stable runtime recovery: your previous final answer omitted unresolved runtime control gap(s) or blocker(s).",`Unresolved control gap(s): ${[...n,...r].slice(0,8).join(", ")}`,"Continue the same user request from the completed evidence.","If a declared available action is required to satisfy the request, continue with its structured tool call instead of delivering an incomplete final answer.",...o.availableToolIds?.length?[`Available configured tools: ${o.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If no declared action can safely continue, return a grounded blocker that explicitly preserves the unresolved runtime control state.",...i.length>0?["","Recent executed tool evidence:",...i]:[],"","Previous invalid final answer:",o.output]}export function assertNoDeclaredActionOmissionOutput(e){}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${JSON.stringify(e.args).slice(0,t)}`:"completed"}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { RuntimeEvent, RuntimeRequest } from "../types.js";
|
|
1
|
+
import type { RuntimeEvent, RuntimeRequest, WorkspaceAgent } from "../types.js";
|
|
2
2
|
export declare function buildExecutionContractRecoveryRequest(input: {
|
|
3
3
|
request: RuntimeRequest;
|
|
4
4
|
events: RuntimeEvent[];
|
|
5
|
+
agent: WorkspaceAgent;
|
|
5
6
|
policy: unknown;
|
|
6
7
|
}): RuntimeRequest | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{successfulEvidenceItems as e}from"../quality/event-evidence.js";export function buildExecutionContractRecoveryRequest(
|
|
1
|
+
import{successfulEvidenceItems as e}from"../quality/event-evidence.js";export function buildExecutionContractRecoveryRequest(t){if(!0!==function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}(t.policy).enabled)return;const n=function lastExecutionContractFailure(e){for(let t=e.length-1;t>=0;t-=1){const n=e[t];if("runtime.execution.contract.failed"===n?.type)return{reason:n.reason,missing:readStringArray(n.missingEvidenceTools)}}return{missing:[]}}(t.events);if(0===n.missing.length)return;if("missing_required_evidence_usage"===n.reason){const e=recentSuccessfulEvidence(t.events);return recoverRequest(t.request,["Stable runtime recovery: the execution contract was not satisfied.",`The final answer did not use required executed evidence from: ${n.missing.join(", ")}`,"Synthesize from those required source(s), or call them through normal structured tool calling if their evidence is unavailable.","Do not replace required evidence with unrelated intermediate evidence, progress text, or summaries from other tools.",...e.length>0?["","Prior successful tool evidence:",...e]:[]])}const r=recentSuccessfulEvidence(t.events),o=function recoveryToolTargets(t,n,r){const o=function readToolDependencies(e){return isRecord(e)?new Map(Object.entries(e).map(([e,t])=>[e,readStringArray(t)]).filter(e=>e[1].length>0)):new Map}(function readExecutionContract(e){return isRecord(e.config.executionContract)?e.config.executionContract:{}}(t).toolDependencies),i=new Set(e(r).map(e=>e.source)),s=new Set;for(const e of n)s.add(e),collectUnmetDependencies(e,o,i,s,new Set([e]));return[...s].filter(e=>t.tools.includes(e))}(t.agent,n.missing,t.events);return recoverRequest(t.request,["Stable runtime recovery: the execution contract was not satisfied.",`Required evidence tool(s) were missing: ${n.missing.join(", ")}`,`For this recovery turn, the allowed next tool call target(s) are: ${o.join(", ")}`,"Allowed targets include missing required evidence tools and any declared dependency tools that are still needed to build valid arguments.","Reuse exact values from prior successful tool evidence when building the required tool call. Do not invent replacement paths, IDs, handles, URLs, or parameters.","The next assistant action must be the backend's structured tool call for one allowed target, with no prose before it.","Do not call already completed intermediate tools unless they are listed above.","Do not produce a final answer until the required evidence tool call has executed and you have synthesized its result.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text in the final answer.",...r.length>0?["","Prior successful tool evidence:",...r]:[]],{stableHarnessRequiredEvidenceTools:o})}function recoverRequest(e,t,n={}){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call",...n}}}function collectUnmetDependencies(e,t,n,r,o){for(const i of t.get(e)??[])o.has(i)||(o.add(i),n.has(i)||r.add(i),collectUnmetDependencies(i,t,n,r,o))}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function recentSuccessfulEvidence(t){return e(t).slice(-5).map(e=>`- ${e.source}: ${function previewEvidence(e){const t=e.replace(/\s+/gu," ").trim();return t.length>1500?`${t.slice(0,1497)}...`:t}(e.output)}`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function containsProgressOnlyToolIntent(e
|
|
1
|
+
export function containsProgressOnlyToolIntent(t,e){const n=t.trim();return!!function looksLikeProgressOnlyCandidate(t){return t.length>0&&t.length<=1200&&!t.trimStart().startsWith("#")&&!t.includes("\n---\n")}(n)&&(e??[]).some(t=>function isToolInvocationBlock(t,e){const n=t.split("\n");return!(n[0]?.trim()!==e||n.length<3||n.length>9)&&n.slice(1).every(t=>function isIndentedKeyValueLine(t){if(!t.startsWith(" ")&&!t.startsWith("\t"))return!1;const e=t.indexOf(":");if(e<=0||e>80)return!1;const n=t.slice(0,e).trim();return n.length>0&&[...n].every(t=>function isIdentifierChar(t){return"_"===t||"-"===t||"."===t||t>="A"&&t<="Z"||t>="a"&&t<="z"||t>="0"&&t<="9"}(t))}(t))}(n,t))}export function progressOnlyToolIntentMessage(t){return`Adapter returned progress-only future tool intent as the final answer after recovery. The backend must execute the named tool or fail closed. Output preview: ${function previewOutput(t){const e=t.replace(/\s+/gu," ").trim();return e.length>300?`${e.slice(0,297)}...`:e}(t)}`}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RuntimeRequest, RuntimeToolGateway, WorkspaceAgent } from "../types.js";
|
|
2
2
|
import type { CompiledWorkspace } from "../workspace/types.js";
|
|
3
3
|
export type RawArgsRecoveryInput = {
|
|
4
4
|
request: RuntimeRequest;
|
|
@@ -6,7 +6,7 @@ export type RawArgsRecoveryInput = {
|
|
|
6
6
|
agent: WorkspaceAgent;
|
|
7
7
|
workspace: CompiledWorkspace;
|
|
8
8
|
toolGateway?: RuntimeToolGateway;
|
|
9
|
-
events?:
|
|
9
|
+
events?: unknown[];
|
|
10
10
|
candidateToolIds?: string[];
|
|
11
11
|
policy: unknown;
|
|
12
12
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{selectCallCandidateByArgsSchema as e}from"@easynet/better-call";export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=matchUniqueRawArgsTool(e);return t?function buildRawArgsRecoveryPrompt(e,t){return{...e,input:[e.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}(e.request,t):void 0}export function buildRawArgsToolEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer repeated a JSON argument object for a declared tool after a structured tool-call recovery request.",`Matched configured tool: ${e.match.toolId}`,"Stable runtime executed that matched declared tool through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool output:",e.toolOutput].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(matchUniqueRawArgsTool(e))}export function buildRawArgsToolSequenceEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer printed multiple JSON argument objects for declared tools after a recovery request.","Stable runtime matched and executed those declared tools through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool output:",e.toolOutput,""])].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function matchUniqueRawArgsTool(t){const
|
|
1
|
+
import{selectCallCandidateByArgsSchema as e}from"@easynet/better-call";export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=matchUniqueRawArgsTool(e);return t?function buildRawArgsRecoveryPrompt(e,t){return{...e,input:[e.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}(e.request,t):void 0}export function buildRawArgsToolEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer repeated a JSON argument object for a declared tool after a structured tool-call recovery request.",`Matched configured tool: ${e.match.toolId}`,"Stable runtime executed that matched declared tool through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool output:",e.toolOutput].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(matchUniqueRawArgsTool(e))}export function buildRawArgsToolSequenceEvidenceRecoveryRequest(e){return{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer printed multiple JSON argument objects for declared tools after a recovery request.","Stable runtime matched and executed those declared tools through the governed tool gateway.","Continue the same user request from the executed evidence below.","If another declared tool is needed, call it through the backend's normal structured tool-calling mechanism.","Otherwise, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool output:",e.toolOutput,""])].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}}export function matchUniqueRawArgsTool(t){const o=parseStandaloneJsonValues(t.output,{allowArray:!1})[0];if(!o)return;const r=matchToolEnvelope(o,t);if(r)return r;const a=isRawArgsRecord(o)?o:void 0;if(!a)return;const n=e({args:a,candidates:buildCallCandidates(t)});return n.ok?{toolId:n.candidateId,args:n.args}:void 0}export function matchRawArgsToolSequence(t){if(!toolCallRecoveryEnabled(t.policy))return[];const o=parseStandaloneJsonValues(t.output,{allowArray:!0});if(o.length<2)return[];const r=buildCallCandidates(t),a=[];for(const n of o){const o=matchToolEnvelope(n,t);if(o){a.push(o);continue}if(!isRawArgsRecord(n))return[];const s=e({args:n,candidates:r});if(!s.ok)return[];a.push({toolId:s.candidateId,args:s.args})}return a}function buildCallCandidates(e){return candidateToolIds(e).map(t=>({id:t,schema:e.workspace.tools.get(t)?.schema??e.toolGateway?.get(t)?.schema}))}function candidateToolIds(e){const t=new Set(e.agent.tools),o=(e.candidateToolIds??[]).filter(e=>t.has(e));return o.length>0?o:e.agent.tools}function parseStandaloneJsonValues(e,t){const o=e.trim(),r=o.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),a=r??o;if(a.length>6e3)return[];if(!(t.allowArray||a.startsWith("{")&&a.endsWith("}")))return[];if(t.allowArray&&!(a.startsWith("{")&&a.endsWith("}")||a.startsWith("[")&&a.endsWith("]")))return[];try{const e=JSON.parse(a);return Array.isArray(e)&&t.allowArray?e:[e]}catch{return[]}}function matchToolEnvelope(e,t){if(!isRecord(e))return;const o=function readEnvelopeToolId(e){const t=["toolId","toolName","tool","tool_name","name"].map(t=>e[t]).filter(e=>"string"==typeof e&&e.length>0);return 1===new Set(t).size?t[0]:void 0}(e),r=function readEnvelopeArgs(e){for(const t of["args","arguments","parameters","params","kwargs"]){const o=e[t];if(isRecord(o))return o}}(e),a=candidateToolIds(t);return o&&r&&a.includes(o)?{toolId:o,args:r}:void 0}function isRawArgsRecord(e){return isRecord(e)&&!function isToolCallEnvelope(e){const t=["tool","tool_name","name","type","subagent_type"].some(t=>"string"==typeof e[t]),o=["args","arguments","parameters","kwargs"].some(t=>t in e);return t&&o}(e)&&!function isRuntimeControlObject(e){return"string"==typeof e.status||"string"==typeof e.error||"string"==typeof e.controlStatus}(e)}function toolCallRecoveryEnabled(e){return!!(isRecord(e)&&isRecord(e.recovery)&&isRecord(e.recovery.toolCall))&&!0===e.recovery.toolCall.enabled}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function hasStructuredToolEnvelope(t){const e=function extractJsonSource(t){const e=t.trim();if(e.startsWith("{")&&e.endsWith("}")||e.startsWith("[")&&e.endsWith("]"))return e;const n=function extractSingleFence(t){const e=t.indexOf("```");if(e<0||t.indexOf("```",e+3)!==t.lastIndexOf("```"))return;const n=t.indexOf("\n",e+3),r=t.lastIndexOf("```");return n<0||r<=n?void 0:t.slice(n+1,r).trim()}(e);return n&&(n.startsWith("{")&&n.endsWith("}")||n.startsWith("[")&&n.endsWith("]"))?n:void 0}(t);if(!e)return!1;try{const t=JSON.parse(e);return Array.isArray(t)?t.some(isToolEnvelopeRecord):isToolEnvelopeRecord(t)}catch{return!1}}export function hasXmlLikeToolMarkup(t){const e=t.trim().toLowerCase();return e.includes("<tool_call")||e.includes("</tool_call")||e.includes("<tool_code")||e.includes("</tool_code")||e.includes("<task")||e.includes("</task")}export function isFunctionStyleCall(t){const e=t.trim(),n=e.indexOf("(");return!(n<=0||!e.endsWith(")")||e.length>2500)&&function isIdentifierPath(t){return t.length>0&&[...t].every((t,e)=>{const n=t>="A"&&t<="Z"||t>="a"&&t<="z"||"_"===t;return 0===e?n:n||t>="0"&&t<="9"||"."===t||"-"===t})}(e.slice(0,n).trim())&&function balancedParens(t){let e,n=0;for(let r=0;r<t.length;r+=1){const o=t[r],s=t[r-1];if(e)o===e&&"\\"!==s&&(e=void 0);else if('"'===o||"'"===o)e=o;else if("("===o)n+=1;else if(")"===o&&(n-=1,n<0))return!1}return 0===n&&!e}(e.slice(n))}function isToolEnvelopeRecord(t){return!!isRecord(t)&&(isRecord(t.task)?"string"==typeof t.task.subagent_type||"string"==typeof t.task.task:["tool","toolId","toolName","tool_name","name","type","subagent_type"].some(e=>"string"==typeof t[e])&&["args","arguments","parameters","params","kwargs","task"].some(e=>e in t))}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlGaps as e}from"../quality/event-evidence.js";import{omittedControlRecoveryLines as t}from"./control-omission.js";import{containsProgressOnlyToolIntent as o,progressOnlyToolIntentMessage as n}from"./progress-intent.js";import{containsStructurallyIncompleteFinalOutput as r,structurallyIncompleteFinalMessage as s}from"./structural-output.js";import{containsRawToolResultText as a}from"./tool-result.js";export function toolCallRecoveryEnabled(e){return!0===readToolCallRecovery(e).enabled}export function isRecoverableAdapterError(e,t){const o=readToolCallRecovery(t);if(!0!==o.enabled)return!1;const n=e instanceof Error?e.message:String(e);return readRegexps(o.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content|repeat limit reached for tool/iu]).some(e=>e.test(n))}export function buildAdapterErrorRecoveryPrompt(e,t,o){const n=t instanceof Error?t.message:String(t),r=readToolCallRecovery(o).instruction;return recoverRequest(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${n}`,"string"==typeof r?r:"Continue the same user request using the backend's normal tool-calling mechanism, then return a final human-readable answer.","Do not print raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer."])}export function buildResultRecoveryRequest(e){const n=readToolCallRecovery(e.policy);if(!0!==n.enabled)return;if(containsRawToolCallText(e.output,n)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer printed raw tool-call markup instead of executing the tool.","Continue the same user request by calling the available upstream tool normally when more evidence is required.","If you call a tool, the next assistant action must be the backend's structured tool call itself, with no prose before it.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text such as saying you will call or wait for a tool.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(o(e.output,e.availableToolIds)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was progress-only text or a pseudo tool invocation block instead of a user-facing answer.","Continue the same user request by calling the named available tool through the backend's normal structured mechanism.","If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not narrate intended future tool calls or print tool invocation blocks as a final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(a(e.output,e.events)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer copied an executed tool result JSON as the user-facing answer.","Continue the same user request from the existing tool evidence.","If more evidence is required, use one remaining declared tool or subagent action through the backend's normal structured mechanism.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Otherwise synthesize a human-readable final answer from the executed tool evidence.","Do not return the raw tool result JSON as the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(containsToolExecutionErrorText(e.output,n)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer exposed a backend tool execution error instead of handling it.","Continue the same user request using the backend's normal structured tool-calling mechanism.","Do not retry the same invalid tool arguments. If the failed tool is not required to answer the user, synthesize the final answer from the available context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not print tool error stacks, schema validation diagnostics, raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(r(e.output)){const t=recentToolEvidence(e.events,6e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was structurally incomplete or truncated.","Retry synthesis from the existing executed evidence and return a complete user-facing answer.","Do not stop inside an unfinished Markdown fence, inline code span, emphasis marker, sentence, or list item.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous incomplete final answer:",e.output])}const s=t(e);if(s)return recoverRequest(e.request,s);const i="tool_call"===e.request.metadata?.stableHarnessRecovery?void 0:function lastConfiguredEventHint(e,t){const o=function readEventRecoveryHints(e){return(Array.isArray(e)?e:[]).flatMap(e=>isRecord(e)&&"string"==typeof e.instruction?[{..."string"==typeof e.toolId?{toolId:e.toolId}:{},..."string"==typeof e.phase?{phase:e.phase}:{},..."string"==typeof e.outputIncludes?{outputIncludes:e.outputIncludes}:{},..."string"==typeof e.outputMatches?{outputMatches:e.outputMatches}:{},instruction:e.instruction}]:[])}(t.eventRecoveryHints);if(0!==o.length)return e.flatMap(e=>function readMatchingHints(e,t){const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o?t.filter(e=>function eventMatchesHint(e,t){return(!t.toolId||e.toolId===t.toolId)&&(!t.phase||e.phase===t.phase)&&(t.outputIncludes?"string"==typeof e.output&&e.output.includes(t.outputIncludes):!t.outputMatches||"string"==typeof e.output&&new RegExp(t.outputMatches,"u").test(e.output))}(o,e)).map(e=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:e.instruction})):[]}(e,o)).at(-1)}(e.events,n);return i?recoverRequest(e.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",i.output,i.instruction]):void 0}export function assertNoRawToolCallOutput(e,t){if(containsRawToolCallOutput(e,t))throw new Error(`Adapter returned raw tool-call text as the final answer after recovery. The backend must execute tools instead of printing tool-call markup. Output preview: ${previewOutput(e)}`)}export function containsRawToolCallOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRawToolCallText(e,o)}export function containsRecoverableResultOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRecoverableResultFailureText(e,o)}export function assertNoRawToolResultOutput(e,t,o){if(!0===readToolCallRecovery(o).enabled&&a(e,t))throw new Error(`Adapter returned raw tool result JSON as the final answer after recovery. The backend must synthesize a user-facing answer. Output preview: ${previewOutput(e)}`)}export function assertNoToolExecutionErrorOutput(e,t){const o=readToolCallRecovery(t);if(!0===o.enabled&&containsToolExecutionErrorText(e,o))throw new Error(`Adapter returned a tool execution error as the final answer after recovery. Output preview: ${previewOutput(e)}`)}export function assertNoProgressOnlyToolIntentOutput(e,t,r){if(!0===readToolCallRecovery(r).enabled&&o(e,t))throw new Error(n(e))}export function assertNoStructurallyIncompleteFinalOutput(e,t){if(!0===readToolCallRecovery(t).enabled&&r(e))throw new Error(s(e))}export function rawToolCallFailureMessage(){return["The model attempted to call a tool but returned the tool call as text instead of executing it.","Please retry the request or use a model/backend configuration with reliable tool calling for this workspace."].join(" ")}export function buildEvidenceSynthesisOutput(t){const o=readToolCallRecovery(t.policy);if(!0!==o.enabled||!1===o.synthesizeFromEvidenceOnFailure||!containsRecoverableResultFailureText(t.output,o))return;const n=function latestDelegatedTaskReport(e){return e.flatMap(e=>{const t="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;if(!isToolResultEvent(t)||"task"!==t.toolId)return[];const o="string"==typeof t.output?t.output.trim():"";return function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(o)?[o]:[]}).at(-1)||void 0}(t.events);if(n)return n;const r=recentToolEvidence(t.events,6e3);if(0===r.length)return;const s=/\p{Script=Han}/u.test(t.request.input)?"zh":"en",a=e(t.events);return"zh"===s?function buildChineseEvidenceSynthesis(e,t,o){return["上游模型在已有工具证据后仍输出了伪工具调用;runtime 已拒绝该 raw 输出,并直接交付已执行工具返回的证据结果。","","已执行的工具证据:",...t,...o.length>0?["","未解决的证据缺口:",...o.map(e=>`- ${e}`)]:[],"",`被拒绝的最终输出预览:${previewRejectedOutput(e)}`].join("\n")}(t.output,r,a):function buildEnglishEvidenceSynthesis(e,t,o){return["The upstream model still returned pseudo tool-call text after tool evidence was available. The runtime rejected that raw output and is returning the executed tool evidence directly.","","Executed tool evidence:",...t,...o.length>0?["","Unresolved evidence gaps:",...o.map(e=>`- ${e}`)]:[],"",`Rejected final output preview: ${previewRejectedOutput(e)}`].join("\n")}(t.output,r,a)}function previewOutput(e){const t=e.replace(/\s+/gu," ").trim();return t.length>300?`${t.slice(0,297)}...`:t}function previewRejectedOutput(e){return previewOutput(e).replace(/[<>]/gu,"")}export function rawToolCallOutputPreview(e){return previewOutput(e)}function recoverRequest(e,t){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}function containsRawToolCallText(e,t){const o=readRegexps(t.rawOutputPatterns,[/\{\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:/iu,/\{\s*"tool_name"\s*:\s*"[^"]+"\s*,\s*"parameters"\s*:/iu,/\{\s*"type"\s*:\s*"[^"]+"\s*,\s*"args"\s*:/iu,/^\s*[A-Za-z_][\w.-]*\s*\([^)]{0,2000}\)\s*$/iu,/^\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|task)\s*$/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:/iu,/```(?:json)?[\s\S]{0,4000}"(?:tool_name|tool|name|subagent_type)"\s*:[\s\S]{0,4000}"(?:arguments|parameters|task)"\s*:/iu,/```(?:json)?[\s\S]{0,2000}"query"\s*:[\s\S]{0,2000}"(?:max_results|count|freshness|market)"\s*:/iu]);return!![/<\s*(?:tool_call|task)\b[^>]*>/iu,/<\s*\/\s*(?:tool_call|task)\s*>/iu,/<\s*\/?\s*tool_code\b[^>]*>/iu,/<\s*[A-Za-z_][\w.-]*\s*\([^>]{0,2000}\)\s*>/iu,/<\s*\/?\s*[A-Za-z_][\w.-]*(?:_command|_tool|_analysis|_investigate|_todos|task)\b[^>]*>/iu].some(t=>t.test(e))||function looksLikeStandaloneRecoveryCandidate(e){const t=e.trim();return t.length<=6e3||/^\s*(?:```|\{|\[|[A-Za-z_][\w.-]*\s*\()/u.test(t)}(e)&&(o.some(t=>t.test(e))||[/^[\s\S]{0,2400}\b(?:I need to|I will|I'll|I am going to|I'm going to)\s+(?:call|use|invoke|delegate)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I will|I'll|I am going to|I'm going to)\s+(?:investigate|gather|check)\b[\s\S]{0,1200}\b(?:evidence|cluster|system|results?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:waiting for|wait for)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:Would you like me to|Do you want me to|Should I|I can help with)\b[\s\S]{0,1200}\?[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bCould you please provide\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:I don't|I do not) have enough information\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|task|context)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\bLet me\s+(?:call|use|invoke|delegate|check|run|verify|gather|inspect)\b[\s\S]{0,1200}\b(?:tool|function|specialist|subagent|results?|data|evidence|commands?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}\b(?:Let me|I'll|I will|I am going to|I'm going to)\s+(?:start\s+by\s+)?(?:read(?:ing)?|access(?:ing)?|gather(?:ing)?|collect(?:ing)?|fetch(?:ing)?|check(?:ing)?|inspect(?:ing)?)\b[\s\S]{0,1200}\b(?:context|instructions?|workflow|pull request|PR|issue|data|evidence|details?)\b[\s\S]{0,400}$/iu,/^[\s\S]{0,2400}(?:我需要|我要|我会|我将|让我|我来|接下来我(?:会|将)?)\s*(?:先)?(?:调用|使用|运行|执行|检查|读取|收集|调查|验证|查看)[\s\S]{0,1200}$/iu,/^[\s\S]{0,2400}(?:要不要|是否需要|需要我|你想让我)[\s\S]{0,1200}(?:继续|进一步|帮你|分析|检查)[\s\S]{0,1200}[??][\s\S]{0,400}$/iu].some(t=>t.test(e)))}function containsRecoverableResultFailureText(e,t){return containsRawToolCallText(e,t)||containsToolExecutionErrorText(e,t)}function containsToolExecutionErrorText(e,t){return readRegexps(t.toolFailureOutputPatterns,[/^Error invoking tool ['"][^'"]+['"] with kwargs /iu,/Received tool input did not match expected schema/iu,/ToolMessage.*status.*error/iu]).some(t=>t.test(e))}function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return isToolResultEvent(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${previewOutput(JSON.stringify(e.args))}`:"completed"}function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}function readRegexps(e,t){const o=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e&&e.length>0).map(e=>new RegExp(e,"iu"));return o.length>0?o:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
1
|
+
import{controlGaps as e}from"../quality/event-evidence.js";import{omittedControlRecoveryLines as t}from"./control-omission.js";import{containsProgressOnlyToolIntent as o,progressOnlyToolIntentMessage as r}from"./progress-intent.js";import{containsStructurallyIncompleteFinalOutput as n,structurallyIncompleteFinalMessage as a}from"./structural-output.js";import{hasStructuredToolEnvelope as l,hasXmlLikeToolMarkup as i,isFunctionStyleCall as s}from"./tool-call-structure.js";import{containsRawToolResultText as u}from"./tool-result.js";export function toolCallRecoveryEnabled(e){return!0===readToolCallRecovery(e).enabled}export function isRecoverableAdapterError(e,t){const o=readToolCallRecovery(t);if(!0!==o.enabled)return!1;const r=e instanceof Error?e.message:String(e);return readRegexps(o.adapterErrorPatterns,[/XML syntax error|tool.?call.*syntax|malformed.*(?:XML|tool)|Non string tool message content|repeat limit reached for tool/iu]).some(e=>e.test(r))}export function buildAdapterErrorRecoveryPrompt(e,t,o){const r=t instanceof Error?t.message:String(t),n=readToolCallRecovery(o).instruction;return recoverRequest(e,["Stable runtime recovery: the backend failed while parsing a tool call.",`Parser error: ${r}`,"string"==typeof n?n:"Continue the same user request using the backend's normal tool-calling mechanism, then return a final human-readable answer.","Do not print raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer."])}export function buildResultRecoveryRequest(e){const r=readToolCallRecovery(e.policy);if(!0!==r.enabled)return;if(containsRawToolCallText(e.output)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer printed raw tool-call markup instead of executing the tool.","Continue the same user request by calling the available upstream tool normally when more evidence is required.","If you call a tool, the next assistant action must be the backend's structured tool call itself, with no prose before it.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.","Do not print XML, JSON, markdown fences, pseudo tool-call text, plans, or future-intent text such as saying you will call or wait for a tool.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(o(e.output,e.availableToolIds)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was progress-only text or a pseudo tool invocation block instead of a user-facing answer.","Continue the same user request by calling the named available tool through the backend's normal structured mechanism.","If the conversation context already contains enough evidence to answer, synthesize the final answer from that context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not narrate intended future tool calls or print tool invocation blocks as a final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(u(e.output,e.events)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer copied an executed tool result JSON as the user-facing answer.","Continue the same user request from the existing tool evidence.","If more evidence is required, use one remaining declared tool or subagent action through the backend's normal structured mechanism.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Otherwise synthesize a human-readable final answer from the executed tool evidence.","Do not return the raw tool result JSON as the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(containsToolExecutionErrorText(e.output,r)){const t=recentToolEvidence(e.events,1e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer exposed a backend tool execution error instead of handling it.","Continue the same user request using the backend's normal structured tool-calling mechanism.","Do not retry the same invalid tool arguments. If the failed tool is not required to answer the user, synthesize the final answer from the available context instead.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],"Do not print tool error stacks, schema validation diagnostics, raw tool-call markup, JSON tool-call envelopes, or pseudo tool-call text in the final answer.",...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous invalid final answer:",e.output])}if(n(e.output)){const t=recentToolEvidence(e.events,6e3);return recoverRequest(e.request,["Stable runtime recovery: your previous final answer was structurally incomplete or truncated.","Retry synthesis from the existing executed evidence and return a complete user-facing answer.","Do not stop inside an unfinished Markdown fence, inline code span, emphasis marker, sentence, or list item.",...e.availableToolIds?.length?[`Available configured tools: ${e.availableToolIds.join(", ")}`,"Do not invent, print, or call tools that are not in this list."]:[],...t.length>0?["","Recent executed tool evidence:",...t]:[],"","Previous incomplete final answer:",e.output])}const a=t(e);if(a)return recoverRequest(e.request,a);const l="tool_call"===e.request.metadata?.stableHarnessRecovery?void 0:function lastConfiguredEventHint(e,t){const o=function readEventRecoveryHints(e){return(Array.isArray(e)?e:[]).flatMap(e=>isRecord(e)&&"string"==typeof e.instruction?[{..."string"==typeof e.toolId?{toolId:e.toolId}:{},..."string"==typeof e.phase?{phase:e.phase}:{},instruction:e.instruction}]:[])}(t.eventRecoveryHints);if(0!==o.length)return e.flatMap(e=>function readMatchingHints(e,t){const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return o?t.filter(e=>function eventMatchesHint(e,t){return!(t.toolId&&e.toolId!==t.toolId||t.phase&&e.phase!==t.phase)}(o,e)).map(e=>({output:"string"==typeof o.output?o.output:"Adapter event matched configured recovery hint.",instruction:e.instruction})):[]}(e,o)).at(-1)}(e.events,r);return l?recoverRequest(e.request,["Stable runtime recovery: a previous adapter event matched a configured recovery hint.",l.output,l.instruction]):void 0}export function assertNoRawToolCallOutput(e,t){if(containsRawToolCallOutput(e,t))throw new Error(`Adapter returned raw tool-call text as the final answer after recovery. The backend must execute tools instead of printing tool-call markup. Output preview: ${previewOutput(e)}`)}export function containsRawToolCallOutput(e,t){return!0===readToolCallRecovery(t).enabled&&containsRawToolCallText(e)}export function containsRecoverableResultOutput(e,t){const o=readToolCallRecovery(t);return!0===o.enabled&&containsRecoverableResultFailureText(e,o)}export function assertNoRawToolResultOutput(e,t,o){if(!0===readToolCallRecovery(o).enabled&&u(e,t))throw new Error(`Adapter returned raw tool result JSON as the final answer after recovery. The backend must synthesize a user-facing answer. Output preview: ${previewOutput(e)}`)}export function assertNoToolExecutionErrorOutput(e,t){const o=readToolCallRecovery(t);if(!0===o.enabled&&containsToolExecutionErrorText(e,o))throw new Error(`Adapter returned a tool execution error as the final answer after recovery. Output preview: ${previewOutput(e)}`)}export function assertNoProgressOnlyToolIntentOutput(e,t,n){if(!0===readToolCallRecovery(n).enabled&&o(e,t))throw new Error(r(e))}export function assertNoStructurallyIncompleteFinalOutput(e,t){if(!0===readToolCallRecovery(t).enabled&&n(e))throw new Error(a(e))}export function rawToolCallFailureMessage(){return["The model attempted to call a tool but returned the tool call as text instead of executing it.","Please retry the request or use a model/backend configuration with reliable tool calling for this workspace."].join(" ")}export function buildEvidenceSynthesisOutput(t){const o=readToolCallRecovery(t.policy);if(!0!==o.enabled||!1===o.synthesizeFromEvidenceOnFailure||!containsRecoverableResultFailureText(t.output,o))return;const r=function latestDelegatedTaskReport(e){return e.flatMap(e=>{const t="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;if(!isToolResultEvent(t)||"task"!==t.toolId)return[];const o="string"==typeof t.output?t.output.trim():"";return function looksLikeFinalReport(e){const t=e.trim();return!(t.length<80)&&(/^#{1,3}\s+\S/mu.test(t)||/\n#{1,3}\s+\S/mu.test(t)||/\n-{3,}\n/u.test(t))}(o)?[o]:[]}).at(-1)||void 0}(t.events);if(r)return r;const n=recentToolEvidence(t.events,6e3);if(0===n.length)return;const a=/\p{Script=Han}/u.test(t.request.input)?"zh":"en",l=e(t.events);return"zh"===a?function buildChineseEvidenceSynthesis(e,t,o){return["上游模型在已有工具证据后仍输出了伪工具调用;runtime 已拒绝该 raw 输出,并直接交付已执行工具返回的证据结果。","","已执行的工具证据:",...t,...o.length>0?["","未解决的证据缺口:",...o.map(e=>`- ${e}`)]:[],"",`被拒绝的最终输出预览:${previewRejectedOutput(e)}`].join("\n")}(t.output,n,l):function buildEnglishEvidenceSynthesis(e,t,o){return["The upstream model still returned pseudo tool-call text after tool evidence was available. The runtime rejected that raw output and is returning the executed tool evidence directly.","","Executed tool evidence:",...t,...o.length>0?["","Unresolved evidence gaps:",...o.map(e=>`- ${e}`)]:[],"",`Rejected final output preview: ${previewRejectedOutput(e)}`].join("\n")}(t.output,n,l)}function previewOutput(e){const t=e.replace(/\s+/gu," ").trim();return t.length>300?`${t.slice(0,297)}...`:t}function previewRejectedOutput(e){return previewOutput(e).replace(/[<>]/gu,"")}export function rawToolCallOutputPreview(e){return previewOutput(e)}function recoverRequest(e,t){return{...e,input:[e.input,"",...t].join("\n"),metadata:{...e.metadata,stableHarnessRecovery:"tool_call"}}}function containsRawToolCallText(e,t){return!function looksLikeCompletedMarkdownReport(e){const t=e.trimStart();return e.length>1200&&t.startsWith("#")}(e)&&!!(l(e)||i(e)||s(e))}function containsRecoverableResultFailureText(e,t){return containsRawToolCallText(e)||containsToolExecutionErrorText(e,t)}function containsToolExecutionErrorText(e,t){return readRegexps(t.toolFailureOutputPatterns,[/^Error invoking tool ['"][^'"]+['"] with kwargs /iu,/Received tool input did not match expected schema/iu,/ToolMessage.*status.*error/iu]).some(t=>t.test(e))}function recentToolEvidence(e,t){return e.flatMap(e=>{const o="runtime.adapter.event"===e.type&&isRecord(e.event)?e.event:void 0;return isToolResultEvent(o)&&"string"==typeof o.toolId?function isControlToolOutput(e){if("string"!=typeof e||!e.trim().startsWith("{"))return!1;try{const t=JSON.parse(e),o=isRecord(t)?t.status:void 0;return"duplicate_tool_call"===o||"repeated_tool_call_limit"===o||"tool_argument_error"===o}catch{return!1}}(o.output)?[]:[`- ${o.toolId}: ${formatToolEvidence(o,t)}`]:[]}).slice(-5)}function isToolResultEvent(e){return"deepagents.tool_execution.result"===e?.eventType||"agent.tool.result"===e?.phase}function formatToolEvidence(e,t=1e3){return"string"==typeof e.output&&e.output.trim()?e.output.slice(0,t):"string"==typeof e.error&&e.error.trim()?`error: ${e.error.slice(0,t)}`:isRecord(e.args)?`completed with args: ${previewOutput(JSON.stringify(e.args))}`:"completed"}function readToolCallRecovery(e){if(!isRecord(e))return{};const t=isRecord(e.recovery)?e.recovery:{};return isRecord(t.toolCall)?t.toolCall:{}}function readRegexps(e,t){const o=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e&&e.length>0).map(e=>new RegExp(e,"iu"));return o.length>0?o:t}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{containsProgressOnlyToolIntent as t}from"../../recovery/progress-intent.js";import{buildRawArgsRecoveryRequest as o,buildRawArgsToolEvidenceRecoveryRequest as r,buildRawArgsToolSequenceEvidenceRecoveryRequest as a,hasUniqueRawArgsTool as s,matchRawArgsToolSequence as n,matchUniqueRawArgsTool as l}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as
|
|
1
|
+
import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{containsProgressOnlyToolIntent as t}from"../../recovery/progress-intent.js";import{buildRawArgsRecoveryRequest as o,buildRawArgsToolEvidenceRecoveryRequest as r,buildRawArgsToolSequenceEvidenceRecoveryRequest as a,hasUniqueRawArgsTool as s,matchRawArgsToolSequence as n,matchUniqueRawArgsTool as l}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as i,assertNoRawToolCallOutput as u,assertNoRawToolResultOutput as c,assertNoStructurallyIncompleteFinalOutput as d,assertNoToolExecutionErrorOutput as y,buildEvidenceSynthesisOutput as p,buildResultRecoveryRequest as v,containsRawToolCallOutput as g,rawToolCallFailureMessage as m,rawToolCallOutputPreview as f,toolCallRecoveryEnabled as w}from"../../recovery/tool-call.js";import{controlGaps as R}from"../../quality/event-evidence.js";export async function recoverAdapterResultOutput(t){let r=t.result,a=t.request;const n=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(t.recoveryPolicy),R=new Set,T=new Set;for(let e=0;;e+=1){const s=t.store.getRun(t.requestId)?.events??[],i=effectiveRecoveryToolIds(a,t.agent.tools);assertNoNonFocusedRecoveryIntent(r.text,t.recoveryPolicy,t.agent.tools,i);const u=await recoverRawArgsSequenceByToolGateway(t,a,r,T,e+1,i);if(u){a=u.request,r=u.result;continue}const c=l({output:r.text,agent:t.agent,workspace:t.workspace,toolGateway:t.toolGateway,events:s,candidateToolIds:i,policy:t.recoveryPolicy}),d=c?rawArgsToolKey(c):void 0;if(c&&d&&T.size>0&&!T.has(d)){const o=await recoverRawArgsByToolGateway(t,a,r,c,T,e+1);if(o){a=o.request,r=o.result;continue}}const y=d&&!R.has(d)?o({request:a,output:r.text,agent:t.agent,workspace:t.workspace,toolGateway:t.toolGateway,events:s,candidateToolIds:i,policy:t.recoveryPolicy}):void 0,p=e<n?v({request:a,output:r.text,events:s,availableToolIds:i,policy:t.recoveryPolicy}):void 0,g=y??p;if(!g)break;if(g===y&&R.add(d),a=g,emitRepair(t,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(r.text,i)),r=await t.runAdapter(g),emitRepair(t,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(r.text,i)),g===y){const o=await recoverRepeatedRawArgsByToolGateway(t,a,r,R,T,e+1);o&&(a=o.request,r=o.result)}}return function finalizeRecoveredOutput(t,o){if(!w(t.recoveryPolicy))return o;let r=!1;if(g(o.text,t.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(t.request.metadata)){const e=o.text;o={...o,text:m(),metadata:{...o.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,t.agent.tools))}const a=p({request:t.request,output:o.text,events:t.store.getRun(t.requestId)?.events??[],policy:t.recoveryPolicy});return a&&(r=!0,o={...o,text:a,metadata:{...o.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(t,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),r||(g(o.text,t.recoveryPolicy)&&emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(o.text,t.agent.tools)),u(o.text,t.recoveryPolicy),function assertNoRawArgsToolOutput(e,t){if(s({output:t,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:effectiveRecoveryToolIds(e.request,e.agent.tools),policy:e.recoveryPolicy}))throw new Error(`Adapter returned raw tool argument JSON as the final answer after recovery. The backend must execute the matching tool instead. Output preview: ${f(t)}`)}(t,o.text),i(o.text,t.agent.tools,t.recoveryPolicy),c(o.text,t.store.getRun(t.requestId)?.events??[],t.recoveryPolicy),y(o.text,t.recoveryPolicy),d(o.text,t.recoveryPolicy),e({output:o.text,events:t.store.getRun(t.requestId)?.events??[],availableToolIds:t.agent.tools})),o}(t,r)}async function recoverRawArgsSequenceByToolGateway(e,t,o,r,s,l){if(!e.runRecoveredToolCall)return;const i=n({output:o.text,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:l,policy:e.recoveryPolicy});if(i.length<2||i.some(e=>r.has(rawArgsToolKey(e))))return;emitRepair(e,"runtime.repair.started","result_output",s,"raw_args_tool_sequence_gateway_recovery",void 0,repairDiagnostics(o.text,l));const u=[];for(const t of i){r.add(rawArgsToolKey(t));const o=await e.runRecoveredToolCall(t.toolId,t.args);u.push({match:t,toolOutput:visibleRecoveredToolOutput(o)})}const c=a({request:t,evidences:u}),d=await e.runAdapter(c),y=d.text.trim()?d:{...d,text:buildEmptyRecoveredToolSequenceBlocker({evidences:u,events:e.store.getRun(e.requestId)?.events??[]}),metadata:{...d.metadata,toolCallRecovery:{blocked:!0,reason:"empty_output_after_recovered_tool_sequence"}}};return emitRepair(e,"runtime.repair.completed","result_output",s,"raw_args_tool_sequence_gateway_recovery","retried",repairDiagnostics(y.text,l)),{request:c,result:y}}async function recoverRepeatedRawArgsByToolGateway(e,t,o,r,a,s){const n=l({output:o.text,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,events:e.store.getRun(e.requestId)?.events??[],candidateToolIds:effectiveRecoveryToolIds(t,e.agent.tools),policy:e.recoveryPolicy});if(!n||!e.runRecoveredToolCall)return;const i=rawArgsToolKey(n);return r.has(i)&&!a.has(i)?recoverRawArgsByToolGateway(e,t,o,n,a,s):void 0}async function recoverRawArgsByToolGateway(e,t,o,a,s,n){if(!e.runRecoveredToolCall)return;const l=rawArgsToolKey(a);if(s.has(l))return;s.add(l),emitRepair(e,"runtime.repair.started","result_output",n,"raw_args_tool_gateway_recovery",void 0,repairDiagnostics(o.text,e.agent.tools));const i=visibleRecoveredToolOutput(await e.runRecoveredToolCall(a.toolId,a.args)),u=r({request:t,match:a,toolOutput:i}),c=await e.runAdapter(u),d=c.text.trim()?c:{...c,text:buildEmptyRecoveredToolBlocker({match:a,toolOutput:i,events:e.store.getRun(e.requestId)?.events??[]}),metadata:{...c.metadata,toolCallRecovery:{blocked:!0,reason:"empty_output_after_recovered_tool"}}};return emitRepair(e,"runtime.repair.completed","result_output",n,"raw_args_tool_gateway_recovery","retried",repairDiagnostics(d.text,e.agent.tools)),{request:u,result:d}}function assertNoNonFocusedRecoveryIntent(e,o,r,a){if(0===a.length||a.length===r.length)return;const s=new Set(a),n=visibleToolCandidates(e,r).filter(e=>!s.has(e)),l=g(e,o)||t(e,r)||function containsJsonToolEnvelope(e){const t=e.trim(),o=t.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),r=o??t;if(!r.startsWith("{")||!r.endsWith("}")||r.length>6e3)return!1;try{const e=JSON.parse(r);if(!function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(e))return!1;const t=["tool","tool_name","name","type","subagent_type"].some(t=>"string"==typeof e[t]),o=["args","arguments","parameters","kwargs"].some(t=>t in e);return t&&o}catch{return!1}}(e);if(n.length>0&&l)throw new Error(`Focused recovery output referenced non-focused tool(s): ${n.join(", ")}. The backend must call one of the focused gateway tools: ${a.join(", ")}.`)}function emitRepair(e,t,o,r,a,s,n){const l={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...n?{diagnostics:n}:{}};e.emit("runtime.repair.started"===t?{type:t,...l}:{type:t,...l,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:f(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])containsDelimitedToken(e,r)&&o.add(r);return[...o]}function containsDelimitedToken(e,t){if(!t)return!1;let o=e.indexOf(t);for(;o>=0;){const r=0===o?"":e[o-1],a=e[o+t.length]??"";if(!isTokenChar(r)&&!isTokenChar(a))return!0;o=e.indexOf(t,o+t.length)}return!1}function isTokenChar(e){return"_"===e||"-"===e||e>="A"&&e<="Z"||e>="a"&&e<="z"||e>="0"&&e<="9"}function effectiveRecoveryToolIds(e,t){const o=function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}(e.metadata?.stableHarnessRequiredEvidenceTools).filter(e=>t.includes(e));return o.length>0?o:t}function rawArgsToolKey(e){return`${e.toolId}:${JSON.stringify(e.args)}`}function visibleRecoveredToolOutput(e){return("string"==typeof e.text?e.text.trim():"")||"The recovered tool completed successfully but returned no user-visible output."}function buildEmptyRecoveredToolBlocker(e){const t=R(e.events);return["Stable runtime recovery executed the matched declared tool, but the backend returned no user-facing output after receiving the executed evidence.","",`Executed tool: ${e.match.toolId}`,"","Executed JSON arguments:",JSON.stringify(e.match.args),"","Executed tool evidence:",e.toolOutput,...t.length>0?["","Unresolved control gaps:",...t.map(e=>`- ${e}`)]:[]].join("\n")}function buildEmptyRecoveredToolSequenceBlocker(e){const t=R(e.events);return["Stable runtime recovery executed matched declared tools, but the backend returned no user-facing output after receiving the executed evidence.","",...e.evidences.flatMap((e,t)=>[`Executed tool ${t+1}: ${e.match.toolId}`,"Executed JSON arguments:",JSON.stringify(e.match.args),"Executed tool evidence:",e.toolOutput,""]),...t.length>0?["Unresolved control gaps:",...t.map(e=>`- ${e}`)]:[]].join("\n")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildExecutionContractRecoveryRequest as r}from"./recovery/execution-contract.js";import{buildAdapterErrorRecoveryPrompt as a,isRecoverableAdapterError as o}from"./recovery/tool-call.js";import{recoverQualityReview as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildExecutionContractRecoveryRequest as r}from"./recovery/execution-contract.js";import{buildAdapterErrorRecoveryPrompt as a,isRecoverableAdapterError as o}from"./recovery/tool-call.js";import{recoverQualityReview as n,resolveQualityPolicy as s}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as m}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as d}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeImprovementAdministration as w}from"./runtime/improvement/admin.js";import{createRuntimeEvidenceAdministration as g}from"./runtime/improvement/evidence-admin.js";import{createInMemoryRuntimeImprovementStore as y}from"./runtime/improvement/store.js";import{createRuntimeInspectionMethods as I}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as f,normalizeAdapterResult as q}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as v}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as R}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as k}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as A}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as b}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as j}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as x}from"./runtime/tool-failure.js";import{runWorkflowRequest as E}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const q=new Set,G=t.store??A(),S=t.improvements??y(),T=f([v(t),b({options:t.progressNarration,policy:t.workspace.runtime}),j({policy:t.workspace.runtime,store:G,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);G.appendEvent(r);for(const e of q)e(r)},emit=e=>{emitBase(e),T.emitSideEffects(e,emitBase)},h=l({gateway:d({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),M={...t,toolGateway:h},O=x(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),d=t.request.sessionId??e(),l=[],{agent:w,adapter:g}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,o=e.workspace.agents.get(a);if(!o)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:o,adapter:void 0};const n=e.adapters.find(e=>e.canRun(o));if(!n)throw new Error(`No runtime adapter can run backend ${o.backend} for agent ${o.id}`);return{agent:o,adapter:n}}(t.input,t.request,{requestId:p,sessionId:d,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,d,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:d,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await E({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:d,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await m({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:d,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,m=c.pluginMemories??[],d=R({workspace:e.input.workspace,agent:e.agent}),l=s(e.input.workspace.runtime,e.agent),w=new Map;let g;try{g=await runAdapterOnce(e,t,e.request,p,m,w,d)}catch(r){if(!o(r,d))throw r;e.emit(repairStarted(e,"adapter_error",1,errorMessage(r))),g=await runAdapterOnce(e,t,a(e.request,r,d),p,m,w,d),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(r)))}g=await i({...e,request:e.request,result:g,recoveryPolicy:d,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,m,w,d),runRecoveredToolCall:(t,r)=>runRecoveredToolCall(e,t,r)}),g=await n(createQualityRuntimeInput(e,p,m,w,d),e.request,g,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:g});try{assertRequestExecutionContract(e,g)}catch(a){const o=r({request:e.request,events:e.store.getRun(e.requestId)?.events??[],agent:e.agent,policy:d});if(!o)throw a;e.emit(repairStarted(e,"execution_contract",1,errorMessage(a))),g=await runAdapterOnce(e,t,o,p,m,w,d),g=await i({...e,request:o,result:g,recoveryPolicy:d,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,m,w,d),runRecoveredToolCall:(t,r)=>runRecoveredToolCall(e,t,r)}),g=await n(createQualityRuntimeInput(e,p,m,w,d),o,g,l),assertRequestExecutionContract(e,g),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(a)))}const y=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:g,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:g,response:y}),y}({...t,adapter:g,requestId:p,sessionId:d,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:d,agent:w,error:e})}}({input:M,capabilities:T,store:G,emit:emit,request:t,toolFailureTracker:O}),subscribe:e=>(q.add(e),()=>q.delete(e)),...I({workspace:t.workspace,store:G,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:G,emit:emit}),...w({runtimeStore:G,store:S,emit:emit}),...g({runtimeStore:G,emit:emit}),...k({memory:t.memory}),cancel(e,t){const r=G.getRun(e);r&&"running"===r.state&&(G.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await T.stop(),q.clear()}}}function runRecoveredToolCall(e,t,r){return m({gateway:e.input.toolGateway,workspace:e.input.workspace,emit:e.emit,request:{...e.request,toolCall:{toolId:t,args:r}},requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,events:e.store.getRun(e.requestId)?.events??[]})}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,o){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:n=>runAdapterOnce(e,e.adapter,n,t,r,a,o),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e,r){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,output:r.text,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,o,n,s){return q(await t.run({workspace:{...e.input.workspace,runtime:s},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:o,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:n,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,o){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:o}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
".": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@stable-harness/governance": "0.0.
|
|
16
|
-
"@stable-harness/memory": "0.0.
|
|
15
|
+
"@stable-harness/governance": "0.0.127",
|
|
16
|
+
"@stable-harness/memory": "0.0.127"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/evaluation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -11,6 +11,6 @@
|
|
|
11
11
|
"main": "dist/src/index.js",
|
|
12
12
|
"types": "dist/src/index.d.ts",
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"@stable-harness/core": "0.0.
|
|
14
|
+
"@stable-harness/core": "0.0.127"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/protocols",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -11,6 +11,6 @@
|
|
|
11
11
|
"main": "dist/src/index.js",
|
|
12
12
|
"types": "dist/src/index.d.ts",
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"@stable-harness/core": "0.0.
|
|
14
|
+
"@stable-harness/core": "0.0.127"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/workspace-yaml",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
".": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@stable-harness/core": "0.0.
|
|
15
|
+
"@stable-harness/core": "0.0.127"
|
|
16
16
|
}
|
|
17
17
|
}
|