stable-harness 0.0.67 → 0.0.69
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/dist/src/adapter.js +1 -1
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/vfs-backend.d.ts +10 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/vfs-backend.js +1 -0
- package/node_modules/@stable-harness/adapter-deepagents/package.json +1 -0
- package/node_modules/@stable-harness/core/dist/quality/execution-review.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/completion.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/policy/tool-invocation.d.ts +1 -0
- package/node_modules/@stable-harness/core/dist/runtime/policy/tool-invocation.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/recovery/tool-call-policy.js +1 -1
- package/package.json +2 -1
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/vfs-backend.d.ts +10 -0
- package/packages/adapter-deepagents/dist/src/internal/vfs-backend.js +1 -0
- package/packages/adapter-deepagents/package.json +1 -0
- package/packages/core/dist/quality/execution-review.js +1 -1
- package/packages/core/dist/runtime/completion.js +1 -1
- package/packages/core/dist/runtime/policy/tool-invocation.d.ts +1 -0
- package/packages/core/dist/runtime/policy/tool-invocation.js +1 -1
- package/packages/core/dist/runtime/recovery/tool-call-policy.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as
|
|
1
|
+
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as c}from"./memory.js";import{buildDeepAgentRequest as l}from"./internal/messages.js";import{createRawToolCallParserMiddleware as d}from"./internal/raw-tool-call-parser.js";import{createBackendModel as m}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as u}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.js";import{cleanupDeepAgentsRuntimeSubstrate as f,resolveDeepAgentsRuntimeSubstrate as y}from"./internal/substrate/runtime.js";import{createDefaultDeepAgentsBackend as A}from"./internal/vfs-backend.js";export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"agent.handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,skills:t.agent.skills,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const r=e.createDeepAgent?void 0:await async function loadDeepAgentsModule(){try{return await async function importOptionalPackage(e){return import(e)}("deepagents")}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${function formatError(e){return e instanceof Error?e.message:String(e)}(e)}`)}}(),n=e.createDeepAgent??function readCreateDeepAgent(e){const t=e?.createDeepAgent;if("function"==typeof t)return t;throw new Error("DeepAgents package does not export createDeepAgent.")}(r),o={...readDeepAgentsConfig(e.config),...readDeepAgentsConfig(t.agent.config.deepagents)},a=y(t,o),c=resolveDeepAgentsSkills(t,t.agent),d=resolveDeepAgentsMemory(t,t.agent),m=void 0===o.backend?await A({workspaceRoot:t.workspace.root,skills:c,memory:d,config:o}):{cleanup:async()=>{}};try{const e=n(function buildDeepAgentParams(e,t,r,n,o={}){const a=o.skills??resolveDeepAgentsSkills(e,e.agent),p=o.memory??resolveDeepAgentsMemory(e,e.agent),c=t.permissions??s(e,e.agent),l=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:t.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:t.backend??o.backend??resolveDeepAgentsBackend(e,n,a),checkpointer:r.checkpointer,store:r.store,middleware:mergeMiddleware(e,e.agent,t.middleware,l),responseFormat:t.responseFormat,contextSchema:t.contextSchema,interruptOn:t.interruptOn,generalPurposeAgent:readBoolean(t.generalPurposeAgent),taskDescription:readString(t.taskDescription),permissions:c,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(0,e.agent,t),l),subagents:e.agent.subagents.map(t=>{const r=e.workspace.agents.get(t),n=readDeepAgentsConfig(r?.config.deepagents),o=n.permissions??s(e,r),a=scopedInput(e,r),p=requestScopedRepeatState(e,t);return pruneUndefined({name:t,description:r?.description??readString(r?.config.description)??r?.id,systemPrompt:buildSystemPrompt(e,r),model:n.model??(r?resolveAgentModel(e,r):void 0),middleware:mergeMiddleware(a,r,n.middleware,p),interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:o,responseFormat:n.responseFormat,tools:i(e,t,r?.tools??[],resolveAgentRepairModel(0,0,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:p,skills:a})}(t,o,a,r,{backend:m.backend,skills:c,memory:d})),u=l(t),f=function buildDeepAgentInvokeConfig(e,t){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit),configurable:{thread_id:t}})}(t.agent,a.threadId);if(!0===t.request.metadata?.openaiStream&&e.streamEvents){const r=await e.streamEvents(u,{version:"v3",...f});return await g(t,r,p)}const y=await e.invoke(u,f);return p(y)}finally{await m.cleanup(),await f(a)}}}}function buildSystemPrompt(e,t){const n=t?.systemPrompt??readString(t?.config.systemPrompt);return r({workspace:e.workspace,request:e.request,agent:t},n)}function resolveDeepAgentsMemory(e,t){const r=readDeepAgentsStringArray(t?.config,"memory");if(r)return r;const n=[...readAgentMemorySources(e.workspace.root,t),...c(e.workspace).map(e=>`/memories/${e.id}.md`)],o=[...new Set(n)];return o.length>0?o:void 0}function readAgentMemorySources(e,t){return(t?.memory??[]).flatMap(t=>"string"==typeof t&&t.trim()?[backendMemorySourcePath(e,t.trim())]:isRecord(t)&&"string"==typeof t.path&&t.path.trim()?[backendMemorySourcePath(e,t.path.trim())]:[])}function backendMemorySourcePath(e,r){if(r.startsWith("/"))return r;if(t.isAbsolute(r)){const n=t.relative(e,r);return n&&!n.startsWith("..")?`/${n.split(t.sep).join("/")}`:canonicalPath(r)}const n=r.split(t.sep).join("/");return n.startsWith("/")?n:`/${n}`}function resolveDeepAgentsSkills(e,r){const n=readDeepAgentsStringArray(r?.config,"skills");if(n)return n;const o=[...new Set((r?.skills??[]).map(t=>e.workspace.skills.get(t)?.path).filter(e=>"string"==typeof e&&e.trim().length>0).map(r=>function backendSkillSourcePath(e,r){const n=t.dirname(t.dirname(r)),o=t.relative(e,n);return!o||o.startsWith("..")||t.isAbsolute(o)?""===o?"/":canonicalPath(n):`/${o.split(t.sep).join("/")}`}(e.workspace.root,r)))];return o.length>0?o:void 0}function resolveDeepAgentsBackend(e,t,r){if(t?.FilesystemBackend&&r&&0!==r.length)return()=>new t.FilesystemBackend({rootDir:e.workspace.root})}function mergeMiddleware(e,t,r,s=a(e.workspace.runtime.toolGateway)){const i=Array.isArray(r)?r:[],p=scopedInput(e,t),c=new Set,l=readDeepAgentsConfig(t?.config.deepagents);return[o(p,{observedToolIds:c,repeatState:s,repairModel:resolveAgentRepairModel(0,0,l)}),n(p,{repeatState:s}),...u(e.workspace.runtime.retry),...i,d(p)]}function requestScopedRepeatState(e,t){const r=`deepagents.repeat.${t}`,n=e.requestState?.get(r);if(n)return n;const o=a(e.workspace.runtime.toolGateway);return e.requestState&&o&&e.requestState.set(r,o),o}function scopedInput(e,t){return t?{...e,agent:t}:e}function resolveAgentModel(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?m(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;return function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}(n)?n:void 0}function readDeepAgentsConfig(e){return isRecord(e)?e:{}}function readDeepAgentsStringArray(e,t){const r=isRecord(e)?e:{},n=readDeepAgentsConfig(r.deepagents),o="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of o){const t=readStringArray(n[e]);if(t)return t}return readStringArray(r[t])}function pruneUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readNumber(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function readBoolean(e){return"boolean"==typeof e?e:void 0}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function canonicalPath(t){try{return e.native(t)}catch{return t}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DefaultDeepAgentsBackend = {
|
|
2
|
+
backend?: unknown;
|
|
3
|
+
cleanup: () => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export declare function createDefaultDeepAgentsBackend(input: {
|
|
6
|
+
workspaceRoot: string;
|
|
7
|
+
skills: string[] | undefined;
|
|
8
|
+
memory: string[] | undefined;
|
|
9
|
+
config: Record<string, unknown>;
|
|
10
|
+
}): Promise<DefaultDeepAgentsBackend>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as t,readFile as e,stat as n}from"node:fs/promises";import o from"node:path";export async function createDefaultDeepAgentsBackend(t){const e=function readNodeVfsConfig(t){return readRecord(t.nodeVfs??t.nodeVFS)??{}}(t.config);if(!1===e.enabled)return{cleanup:async()=>{}};const n=await async function importNodeVfs(){return import("@langchain/node-vfs")}(),o=n.VfsSandbox?.create;if(!o)throw new Error("@langchain/node-vfs does not export VfsSandbox.create.");const a=await async function collectInitialFiles(t){const e={...t.configured};for(const n of t.sources){const o=backendPathToWorkspacePath(t.workspaceRoot,n);o&&await addPath(e,t.workspaceRoot,o)}return e}({workspaceRoot:t.workspaceRoot,sources:[...t.memory??[],...t.skills??[]],configured:readInitialFiles(e.initialFiles)}),r=await o({...Object.keys(a).length>0?{initialFiles:a}:{},..."string"==typeof e.mountPath?{mountPath:e.mountPath}:{},..."number"==typeof e.timeout?{timeout:e.timeout}:{}});return{backend:r,cleanup:async()=>{await(r.stop?.())}}}async function addPath(a,r,i){const s=await n(i).catch(()=>{});if(!s)return;if(s.isFile())return void(a[function workspaceBackendPath(t,e){return`/${o.relative(t,e).split(o.sep).join("/")}`}(r,i)]=await e(i));if(!s.isDirectory())return;const c=await t(i,{withFileTypes:!0});for(const t of c)"node_modules"!==t.name&&".git"!==t.name&&"dist"!==t.name&&await addPath(a,r,o.join(i,t.name))}function backendPathToWorkspacePath(t,e){if(!e.trim()||e.includes("\0"))return;const n=e.startsWith("/")?e.slice(1):e,a=o.resolve(t,n),r=o.relative(t,a);return!r||r.startsWith("..")||o.isAbsolute(r)?void 0:a}function readInitialFiles(t){const e=readRecord(t);return e?Object.fromEntries(Object.entries(e).filter(t=>"string"==typeof t[1]||t[1]instanceof Uint8Array)):{}}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlBlockers as e,
|
|
1
|
+
import{controlBlockers as e,controlGaps as n,successfulEvidenceOutputs as t,successfulEvidenceToolIds as r}from"./event-evidence.js";const s=/(?<![\w.])(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?[%kKmMbBtTxX]?(?!\w)/gu;export function reviewExecutionEvidence(e,n){if(!n.enabled||!n.executionReview.enabled)return{verdict:"pass",issues:[]};const t=[...blockerIssues(e,n),...controlGapIssues(e,n),...emptyFinalIssues(e,n),...toolEvidenceIssues(e,n),...ungroundedNumberIssues(e,n)];return 0===t.length?{verdict:"pass",issues:[]}:{verdict:t.some(e=>!e.recoverable)?"blocked":"continue_react",issues:t}}function ungroundedNumberIssues(e,n){if(!n.executionReview.rejectUngroundedNumbers||!e.output?.text.trim())return[];const r=numberSet(t(e.events).join("\n"));if(0===r.size)return[];const s=[...numberSet(e.output.text)].filter(e=>!function isSupportedNumber(e,n){if(n.has(e))return!0;const t=Number.parseFloat(e);if(!Number.isFinite(t))return!1;for(const e of n){const n=Number.parseFloat(e);if(Number.isFinite(n)&&Math.abs(n-t)<=roundingTolerance(t))return!0}return!1}(e,r));return 0===s.length?[]:[{code:"ungrounded_numeric_claim",message:`Final answer contains numeric claims not found in successful tool evidence: ${s.slice(0,12).join(", ")}`,recoverable:!1}]}function numberSet(e){const n=new Set;for(const t of e.matchAll(s)){const e=normalizeNumber(t[0]);e&&n.add(e)}return n}function normalizeNumber(e){const n=e.replace(/,/gu,"").replace(/^\+/u,"").replace(/[%kKmMbBtTxX]$/u,"").trim();if(n){if(/^\d+$/u.test(n)){const e=Number.parseInt(n,10);if(e>=1&&e<=20)return;return String(e)}return/^\d+\.\d+$/u.test(n)?n.replace(/0+$/u,"").replace(/\.$/u,""):void 0}}function roundingTolerance(e){return Math.abs(e)>=1e3?1:Math.abs(e)>=100?.1:Math.abs(e)>=10?.05:.005}function blockerIssues(n,t){return t.executionReview.stopOnBlocker?e(n.events).map(e=>({code:"control_blocker",message:`Execution produced a control blocker: ${e}`,recoverable:!1})):[]}function controlGapIssues(e,t){if(!t.executionReview.stopOnBlocker||!e.output?.text.trim())return[];const r=n(e.events).filter(n=>!function mentionsGap(e,n){const[t,r]=n.split(":"),s=e.toLowerCase();return s.includes(n.toLowerCase())||Boolean(t&&r&&s.includes(t.toLowerCase())&&s.includes(r.toLowerCase()))}(e.output?.text??"",n));return 0===r.length?[]:[{code:"unresolved_control_gap",message:`Final answer omitted unresolved runtime evidence gap(s): ${r.slice(0,8).join(", ")}`,recoverable:!0}]}function emptyFinalIssues(e,n){return!n.executionReview.rejectEmptyFinal||e.output?.text.trim()?[]:[{code:"empty_final_answer",message:"The final answer is empty.",recoverable:!0}]}function toolEvidenceIssues(e,n){return!n.executionReview.requireToolEvidence||r(e.events).length>0?[]:[{code:"missing_tool_evidence",message:"No successful tool or delegated-task evidence was observed.",recoverable:!0}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function completeRun(t){const e=t.store.getRun(t.requestId);if("cancelled"===e?.state)return response(t,"cancelled",e.artifacts);const
|
|
1
|
+
export function completeRun(t){const e=t.store.getRun(t.requestId);if("cancelled"===e?.state)return response(t,"cancelled",e.artifacts);!function assertDeliverableOutput(t){if(!t.text.trim())throw new Error("runtime_empty_output: Runtime request produced no user-facing output.")}(t.result);const r=(t.result.artifacts??[]).map(toPublicArtifact);e&&t.store.updateRun(t.requestId,{state:"completed",output:t.result.text,metadata:{...e.metadata,...t.result.metadata},artifacts:mergeArtifacts(e.artifacts,r),completedAt:(new Date).toISOString()});for(const e of t.result.artifacts??[])t.artifacts?.createArtifact({...e,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id});for(const e of r)t.emit({type:"runtime.artifact.created",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,artifact:e});return t.emit({type:"runtime.request.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,output:t.result.text}),response(t,"completed",t.store.getRun(t.requestId)?.artifacts)}export function failRun(t){const e=t.error instanceof Error?t.error.message:String(t.error);return t.store.getRun(t.requestId)&&t.store.updateRun(t.requestId,{state:"failed",error:e,completedAt:(new Date).toISOString()}),t.emit({type:"runtime.request.failed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,error:e}),{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:"failed",output:e}}function response(t,e,r){return{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:e,output:t.result.text,metadata:t.result.metadata,artifacts:r??t.result.artifacts}}function mergeArtifacts(t,e){const r=new Map;for(const s of[...t??[],...e??[]])r.set(s.id,s);return[...r.values()]}function toPublicArtifact(t){return{id:t.id,kind:t.kind,...t.uri?{uri:t.uri}:{},...t.metadata?{metadata:t.metadata}:{}}}
|
|
@@ -5,6 +5,7 @@ export type ToolRepeatState = {
|
|
|
5
5
|
latestSuccessfulOutputByTool: Map<string, string>;
|
|
6
6
|
successfulToolCounts: Map<string, number>;
|
|
7
7
|
toolCallCounts: Map<string, number>;
|
|
8
|
+
repeatLimitedTools: Set<string>;
|
|
8
9
|
maxDuplicateCallsPerTool?: number;
|
|
9
10
|
maxCallsPerTool?: number;
|
|
10
11
|
maxSuccessfulCallsPerTool?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const
|
|
1
|
+
export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,repeatLimitedTools:new Set,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const a=stableToolCallKey(e,t),s=o.successfulCalls.get(a);if(void 0!==s){const t=o.duplicateCallCounts.get(a)??0;if(o.duplicateCallCounts.set(a,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return o.repeatLimitedTools.add(e),{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,s);return{eventOutput:n,modelOutput:s}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;if(t.repeatLimitedTools.has(e))return!0;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e)
|
|
1
|
+
export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e))return o;const r=function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o)?o:function withDefaultToolCallRecovery(e){const o=readRecord(e.recovery),r=readRecord(o.toolCall);return{...e,recovery:{...o,toolCall:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(o);return function hasExplicitRepeatGuard(e){const o=readRecord(e.toolGateway);return"boolean"==typeof readRecord(o.repeatGuard).enabled}(r)?r:function withDefaultRepeatGuard(e){const o=readRecord(e.toolGateway),r=readRecord(o.repeatGuard);return{...e,toolGateway:{...o,repeatGuard:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(r)}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stable-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Stable application runtime and operator control plane for agent workspaces.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"@langchain/core": "^1.1.46",
|
|
80
80
|
"@langchain/langgraph": "^1.3.0",
|
|
81
81
|
"@langchain/langgraph-api": "^1.2.1",
|
|
82
|
+
"@langchain/node-vfs": "^0.1.4",
|
|
82
83
|
"@langchain/ollama": "^1.2.7",
|
|
83
84
|
"@langchain/openai": "^1.4.5",
|
|
84
85
|
"@stable-harness/adapter-deepagents": "0.0.1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as
|
|
1
|
+
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as c}from"./memory.js";import{buildDeepAgentRequest as l}from"./internal/messages.js";import{createRawToolCallParserMiddleware as d}from"./internal/raw-tool-call-parser.js";import{createBackendModel as m}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as u}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.js";import{cleanupDeepAgentsRuntimeSubstrate as f,resolveDeepAgentsRuntimeSubstrate as y}from"./internal/substrate/runtime.js";import{createDefaultDeepAgentsBackend as A}from"./internal/vfs-backend.js";export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"agent.handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,skills:t.agent.skills,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const r=e.createDeepAgent?void 0:await async function loadDeepAgentsModule(){try{return await async function importOptionalPackage(e){return import(e)}("deepagents")}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${function formatError(e){return e instanceof Error?e.message:String(e)}(e)}`)}}(),n=e.createDeepAgent??function readCreateDeepAgent(e){const t=e?.createDeepAgent;if("function"==typeof t)return t;throw new Error("DeepAgents package does not export createDeepAgent.")}(r),o={...readDeepAgentsConfig(e.config),...readDeepAgentsConfig(t.agent.config.deepagents)},a=y(t,o),c=resolveDeepAgentsSkills(t,t.agent),d=resolveDeepAgentsMemory(t,t.agent),m=void 0===o.backend?await A({workspaceRoot:t.workspace.root,skills:c,memory:d,config:o}):{cleanup:async()=>{}};try{const e=n(function buildDeepAgentParams(e,t,r,n,o={}){const a=o.skills??resolveDeepAgentsSkills(e,e.agent),p=o.memory??resolveDeepAgentsMemory(e,e.agent),c=t.permissions??s(e,e.agent),l=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:t.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:t.backend??o.backend??resolveDeepAgentsBackend(e,n,a),checkpointer:r.checkpointer,store:r.store,middleware:mergeMiddleware(e,e.agent,t.middleware,l),responseFormat:t.responseFormat,contextSchema:t.contextSchema,interruptOn:t.interruptOn,generalPurposeAgent:readBoolean(t.generalPurposeAgent),taskDescription:readString(t.taskDescription),permissions:c,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(0,e.agent,t),l),subagents:e.agent.subagents.map(t=>{const r=e.workspace.agents.get(t),n=readDeepAgentsConfig(r?.config.deepagents),o=n.permissions??s(e,r),a=scopedInput(e,r),p=requestScopedRepeatState(e,t);return pruneUndefined({name:t,description:r?.description??readString(r?.config.description)??r?.id,systemPrompt:buildSystemPrompt(e,r),model:n.model??(r?resolveAgentModel(e,r):void 0),middleware:mergeMiddleware(a,r,n.middleware,p),interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:o,responseFormat:n.responseFormat,tools:i(e,t,r?.tools??[],resolveAgentRepairModel(0,0,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:p,skills:a})}(t,o,a,r,{backend:m.backend,skills:c,memory:d})),u=l(t),f=function buildDeepAgentInvokeConfig(e,t){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit),configurable:{thread_id:t}})}(t.agent,a.threadId);if(!0===t.request.metadata?.openaiStream&&e.streamEvents){const r=await e.streamEvents(u,{version:"v3",...f});return await g(t,r,p)}const y=await e.invoke(u,f);return p(y)}finally{await m.cleanup(),await f(a)}}}}function buildSystemPrompt(e,t){const n=t?.systemPrompt??readString(t?.config.systemPrompt);return r({workspace:e.workspace,request:e.request,agent:t},n)}function resolveDeepAgentsMemory(e,t){const r=readDeepAgentsStringArray(t?.config,"memory");if(r)return r;const n=[...readAgentMemorySources(e.workspace.root,t),...c(e.workspace).map(e=>`/memories/${e.id}.md`)],o=[...new Set(n)];return o.length>0?o:void 0}function readAgentMemorySources(e,t){return(t?.memory??[]).flatMap(t=>"string"==typeof t&&t.trim()?[backendMemorySourcePath(e,t.trim())]:isRecord(t)&&"string"==typeof t.path&&t.path.trim()?[backendMemorySourcePath(e,t.path.trim())]:[])}function backendMemorySourcePath(e,r){if(r.startsWith("/"))return r;if(t.isAbsolute(r)){const n=t.relative(e,r);return n&&!n.startsWith("..")?`/${n.split(t.sep).join("/")}`:canonicalPath(r)}const n=r.split(t.sep).join("/");return n.startsWith("/")?n:`/${n}`}function resolveDeepAgentsSkills(e,r){const n=readDeepAgentsStringArray(r?.config,"skills");if(n)return n;const o=[...new Set((r?.skills??[]).map(t=>e.workspace.skills.get(t)?.path).filter(e=>"string"==typeof e&&e.trim().length>0).map(r=>function backendSkillSourcePath(e,r){const n=t.dirname(t.dirname(r)),o=t.relative(e,n);return!o||o.startsWith("..")||t.isAbsolute(o)?""===o?"/":canonicalPath(n):`/${o.split(t.sep).join("/")}`}(e.workspace.root,r)))];return o.length>0?o:void 0}function resolveDeepAgentsBackend(e,t,r){if(t?.FilesystemBackend&&r&&0!==r.length)return()=>new t.FilesystemBackend({rootDir:e.workspace.root})}function mergeMiddleware(e,t,r,s=a(e.workspace.runtime.toolGateway)){const i=Array.isArray(r)?r:[],p=scopedInput(e,t),c=new Set,l=readDeepAgentsConfig(t?.config.deepagents);return[o(p,{observedToolIds:c,repeatState:s,repairModel:resolveAgentRepairModel(0,0,l)}),n(p,{repeatState:s}),...u(e.workspace.runtime.retry),...i,d(p)]}function requestScopedRepeatState(e,t){const r=`deepagents.repeat.${t}`,n=e.requestState?.get(r);if(n)return n;const o=a(e.workspace.runtime.toolGateway);return e.requestState&&o&&e.requestState.set(r,o),o}function scopedInput(e,t){return t?{...e,agent:t}:e}function resolveAgentModel(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?m(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;return function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}(n)?n:void 0}function readDeepAgentsConfig(e){return isRecord(e)?e:{}}function readDeepAgentsStringArray(e,t){const r=isRecord(e)?e:{},n=readDeepAgentsConfig(r.deepagents),o="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of o){const t=readStringArray(n[e]);if(t)return t}return readStringArray(r[t])}function pruneUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readNumber(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function readBoolean(e){return"boolean"==typeof e?e:void 0}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function canonicalPath(t){try{return e.native(t)}catch{return t}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DefaultDeepAgentsBackend = {
|
|
2
|
+
backend?: unknown;
|
|
3
|
+
cleanup: () => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export declare function createDefaultDeepAgentsBackend(input: {
|
|
6
|
+
workspaceRoot: string;
|
|
7
|
+
skills: string[] | undefined;
|
|
8
|
+
memory: string[] | undefined;
|
|
9
|
+
config: Record<string, unknown>;
|
|
10
|
+
}): Promise<DefaultDeepAgentsBackend>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as t,readFile as e,stat as n}from"node:fs/promises";import o from"node:path";export async function createDefaultDeepAgentsBackend(t){const e=function readNodeVfsConfig(t){return readRecord(t.nodeVfs??t.nodeVFS)??{}}(t.config);if(!1===e.enabled)return{cleanup:async()=>{}};const n=await async function importNodeVfs(){return import("@langchain/node-vfs")}(),o=n.VfsSandbox?.create;if(!o)throw new Error("@langchain/node-vfs does not export VfsSandbox.create.");const a=await async function collectInitialFiles(t){const e={...t.configured};for(const n of t.sources){const o=backendPathToWorkspacePath(t.workspaceRoot,n);o&&await addPath(e,t.workspaceRoot,o)}return e}({workspaceRoot:t.workspaceRoot,sources:[...t.memory??[],...t.skills??[]],configured:readInitialFiles(e.initialFiles)}),r=await o({...Object.keys(a).length>0?{initialFiles:a}:{},..."string"==typeof e.mountPath?{mountPath:e.mountPath}:{},..."number"==typeof e.timeout?{timeout:e.timeout}:{}});return{backend:r,cleanup:async()=>{await(r.stop?.())}}}async function addPath(a,r,i){const s=await n(i).catch(()=>{});if(!s)return;if(s.isFile())return void(a[function workspaceBackendPath(t,e){return`/${o.relative(t,e).split(o.sep).join("/")}`}(r,i)]=await e(i));if(!s.isDirectory())return;const c=await t(i,{withFileTypes:!0});for(const t of c)"node_modules"!==t.name&&".git"!==t.name&&"dist"!==t.name&&await addPath(a,r,o.join(i,t.name))}function backendPathToWorkspacePath(t,e){if(!e.trim()||e.includes("\0"))return;const n=e.startsWith("/")?e.slice(1):e,a=o.resolve(t,n),r=o.relative(t,a);return!r||r.startsWith("..")||o.isAbsolute(r)?void 0:a}function readInitialFiles(t){const e=readRecord(t);return e?Object.fromEntries(Object.entries(e).filter(t=>"string"==typeof t[1]||t[1]instanceof Uint8Array)):{}}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{controlBlockers as e,
|
|
1
|
+
import{controlBlockers as e,controlGaps as n,successfulEvidenceOutputs as t,successfulEvidenceToolIds as r}from"./event-evidence.js";const s=/(?<![\w.])(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?[%kKmMbBtTxX]?(?!\w)/gu;export function reviewExecutionEvidence(e,n){if(!n.enabled||!n.executionReview.enabled)return{verdict:"pass",issues:[]};const t=[...blockerIssues(e,n),...controlGapIssues(e,n),...emptyFinalIssues(e,n),...toolEvidenceIssues(e,n),...ungroundedNumberIssues(e,n)];return 0===t.length?{verdict:"pass",issues:[]}:{verdict:t.some(e=>!e.recoverable)?"blocked":"continue_react",issues:t}}function ungroundedNumberIssues(e,n){if(!n.executionReview.rejectUngroundedNumbers||!e.output?.text.trim())return[];const r=numberSet(t(e.events).join("\n"));if(0===r.size)return[];const s=[...numberSet(e.output.text)].filter(e=>!function isSupportedNumber(e,n){if(n.has(e))return!0;const t=Number.parseFloat(e);if(!Number.isFinite(t))return!1;for(const e of n){const n=Number.parseFloat(e);if(Number.isFinite(n)&&Math.abs(n-t)<=roundingTolerance(t))return!0}return!1}(e,r));return 0===s.length?[]:[{code:"ungrounded_numeric_claim",message:`Final answer contains numeric claims not found in successful tool evidence: ${s.slice(0,12).join(", ")}`,recoverable:!1}]}function numberSet(e){const n=new Set;for(const t of e.matchAll(s)){const e=normalizeNumber(t[0]);e&&n.add(e)}return n}function normalizeNumber(e){const n=e.replace(/,/gu,"").replace(/^\+/u,"").replace(/[%kKmMbBtTxX]$/u,"").trim();if(n){if(/^\d+$/u.test(n)){const e=Number.parseInt(n,10);if(e>=1&&e<=20)return;return String(e)}return/^\d+\.\d+$/u.test(n)?n.replace(/0+$/u,"").replace(/\.$/u,""):void 0}}function roundingTolerance(e){return Math.abs(e)>=1e3?1:Math.abs(e)>=100?.1:Math.abs(e)>=10?.05:.005}function blockerIssues(n,t){return t.executionReview.stopOnBlocker?e(n.events).map(e=>({code:"control_blocker",message:`Execution produced a control blocker: ${e}`,recoverable:!1})):[]}function controlGapIssues(e,t){if(!t.executionReview.stopOnBlocker||!e.output?.text.trim())return[];const r=n(e.events).filter(n=>!function mentionsGap(e,n){const[t,r]=n.split(":"),s=e.toLowerCase();return s.includes(n.toLowerCase())||Boolean(t&&r&&s.includes(t.toLowerCase())&&s.includes(r.toLowerCase()))}(e.output?.text??"",n));return 0===r.length?[]:[{code:"unresolved_control_gap",message:`Final answer omitted unresolved runtime evidence gap(s): ${r.slice(0,8).join(", ")}`,recoverable:!0}]}function emptyFinalIssues(e,n){return!n.executionReview.rejectEmptyFinal||e.output?.text.trim()?[]:[{code:"empty_final_answer",message:"The final answer is empty.",recoverable:!0}]}function toolEvidenceIssues(e,n){return!n.executionReview.requireToolEvidence||r(e.events).length>0?[]:[{code:"missing_tool_evidence",message:"No successful tool or delegated-task evidence was observed.",recoverable:!0}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function completeRun(t){const e=t.store.getRun(t.requestId);if("cancelled"===e?.state)return response(t,"cancelled",e.artifacts);const
|
|
1
|
+
export function completeRun(t){const e=t.store.getRun(t.requestId);if("cancelled"===e?.state)return response(t,"cancelled",e.artifacts);!function assertDeliverableOutput(t){if(!t.text.trim())throw new Error("runtime_empty_output: Runtime request produced no user-facing output.")}(t.result);const r=(t.result.artifacts??[]).map(toPublicArtifact);e&&t.store.updateRun(t.requestId,{state:"completed",output:t.result.text,metadata:{...e.metadata,...t.result.metadata},artifacts:mergeArtifacts(e.artifacts,r),completedAt:(new Date).toISOString()});for(const e of t.result.artifacts??[])t.artifacts?.createArtifact({...e,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id});for(const e of r)t.emit({type:"runtime.artifact.created",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,artifact:e});return t.emit({type:"runtime.request.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,output:t.result.text}),response(t,"completed",t.store.getRun(t.requestId)?.artifacts)}export function failRun(t){const e=t.error instanceof Error?t.error.message:String(t.error);return t.store.getRun(t.requestId)&&t.store.updateRun(t.requestId,{state:"failed",error:e,completedAt:(new Date).toISOString()}),t.emit({type:"runtime.request.failed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,error:e}),{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:"failed",output:e}}function response(t,e,r){return{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,state:e,output:t.result.text,metadata:t.result.metadata,artifacts:r??t.result.artifacts}}function mergeArtifacts(t,e){const r=new Map;for(const s of[...t??[],...e??[]])r.set(s.id,s);return[...r.values()]}function toPublicArtifact(t){return{id:t.id,kind:t.kind,...t.uri?{uri:t.uri}:{},...t.metadata?{metadata:t.metadata}:{}}}
|
|
@@ -5,6 +5,7 @@ export type ToolRepeatState = {
|
|
|
5
5
|
latestSuccessfulOutputByTool: Map<string, string>;
|
|
6
6
|
successfulToolCounts: Map<string, number>;
|
|
7
7
|
toolCallCounts: Map<string, number>;
|
|
8
|
+
repeatLimitedTools: Set<string>;
|
|
8
9
|
maxDuplicateCallsPerTool?: number;
|
|
9
10
|
maxCallsPerTool?: number;
|
|
10
11
|
maxSuccessfulCallsPerTool?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const
|
|
1
|
+
export function createToolRepeatState(e){if(function repeatGuardEnabled(e){return!0===repeatGuardConfig(e).enabled}(e))return{successfulCalls:new Map,duplicateCallCounts:new Map,latestSuccessfulOutputByTool:new Map,successfulToolCounts:new Map,toolCallCounts:new Map,repeatLimitedTools:new Set,maxDuplicateCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxDuplicateCallsPerTool)??3,maxCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxCallsPerTool),maxSuccessfulCallsPerTool:readPositiveInteger(repeatGuardConfig(e).maxSuccessfulCallsPerTool),maxCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxCallsByTool),maxSuccessfulCallsByTool:readPositiveIntegerMap(repeatGuardConfig(e).maxSuccessfulCallsByTool),returnPreviousOutputOnRepeatLimit:!0===repeatGuardConfig(e).returnPreviousOutputOnRepeatLimit}}export function beforeToolInvoke(e,t,o){const n=o.toolCallCounts.get(e)??0;o.toolCallCounts.set(e,n+1);const r=o.maxCallsByTool.get(e)??o.maxCallsPerTool;if(void 0!==r&&n>=r){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const l=o.maxSuccessfulCallsByTool.get(e)??o.maxSuccessfulCallsPerTool;if(void 0!==l&&(o.successfulToolCounts.get(e)??0)>=l){const t=o.latestSuccessfulOutputByTool.get(e),n=repeatedToolCallLimitContent(e,t);return o.repeatLimitedTools.add(e),{eventOutput:n,modelOutput:repeatLimitModelOutput(n,t,o)}}const a=stableToolCallKey(e,t),s=o.successfulCalls.get(a);if(void 0!==s){const t=o.duplicateCallCounts.get(a)??0;if(o.duplicateCallCounts.set(a,t+1),void 0!==o.maxDuplicateCallsPerTool&&t>=o.maxDuplicateCallsPerTool){const t=repeatedToolCallLimitContent(e);return o.repeatLimitedTools.add(e),{eventOutput:t,modelOutput:t}}const n=function duplicateToolCallContent(e,t){return JSON.stringify({status:"duplicate_tool_call",toolId:e,instruction:"This agent already completed an equivalent tool call. Use the prior evidence instead of calling the tool again.",previousOutput:t})}(e,s);return{eventOutput:n,modelOutput:s}}}export function afterToolInvoke(e){return e.successful?(e.state.successfulCalls.set(stableToolCallKey(e.toolId,e.args),e.output),e.state.latestSuccessfulOutputByTool.set(e.toolId,e.output),e.state.successfulToolCounts.set(e.toolId,(e.state.successfulToolCounts.get(e.toolId)??0)+1),{}):{}}export function isToolRepeatLimitReached(e,t){if(!t)return!1;if(t.repeatLimitedTools.has(e))return!0;const o=t.maxCallsByTool.get(e)??t.maxCallsPerTool;if(void 0!==o&&(t.toolCallCounts.get(e)??0)>=o)return!0;const n=t.maxSuccessfulCallsByTool.get(e)??t.maxSuccessfulCallsPerTool;return void 0!==n&&(t.successfulToolCounts.get(e)??0)>=n}export function missingRequiredPlanContent(e){const t=readRecord(e.agent.config.executionContract);if(!0!==t.requiresPlan)return"";const o=readStringArray(t.planEvidenceTools);if(0===o.length||o.includes(e.toolId))return"";const n=new Set(e.events.flatMap(readEvidenceToolId));return o.some(e=>n.has(e))?"":["Status: plan_required",`Evidence tool: ${e.toolId}`,`Blocker: execution contract requires a planning checkpoint from one of: ${o.join(", ")} before evidence tools run.`,"Instruction: call the planning tool first, then retry this atomic evidence tool with repaired arguments."].join("\n")}export function missingToolDependencyContent(e){const t=readRecord(e.agent.config.executionContract),o=readStringArray(readRecord(t.toolDependencies)[e.toolId]);if(0===o.length)return"";const n=new Set(e.events.flatMap(readEvidenceToolId)),r=o.filter(e=>!n.has(e));return 0===r.length?"":["Status: dependency_required",`Evidence tool: ${e.toolId}`,`Blocker: this atomic evidence tool requires completed dependency evidence from: ${r.join(", ")}.`,"Instruction: complete the dependency tool first, evaluate it, then retry this atomic evidence tool."].join("\n")}export function toolInvocationEvents(e){const t=e.getEvents?.();return t??[]}function repeatGuardConfig(e){const t=readRecord(e);return readRecord(t.repeatGuard)}function readPositiveInteger(e){return"number"==typeof e&&Number.isInteger(e)&&e>0?e:void 0}function readPositiveIntegerMap(e){const t=readRecord(e);return new Map(Object.entries(t).map(([e,t])=>[e,readPositiveInteger(t)]).filter(e=>void 0!==e[1]))}function repeatLimitModelOutput(e,t,o){return o.returnPreviousOutputOnRepeatLimit&&void 0!==t&&0!==t.trim().length?t:e}function repeatedToolCallLimitContent(e,t){return JSON.stringify({status:"repeated_tool_call_limit",toolId:e,instruction:"This tool reached the configured repeat limit for this request. Do not call this tool or a substitute tool for the same evidence need again. Use previousOutput and the collected evidence to produce the final answer now, or report the remaining gap explicitly.",...void 0!==t?{previousOutput:t}:{}})}function stableToolCallKey(e,t){return`${e}:${stableJson(t)}`}function stableJson(e){return Array.isArray(e)?`[${e.map(stableJson).join(",")}]`:isRecord(e)?`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${stableJson(e[t])}`).join(",")}}`:JSON.stringify(e)}function readEvidenceToolId(e){return"runtime.tool.direct.completed"===e.type?[e.toolId]:"runtime.adapter.event"===e.type&&isRecord(e.event)&&function isToolResultEvent(e){return"deepagents.tool_execution.result"===e.eventType||"agent.tool.result"===e.phase}(e.event)&&"string"==typeof e.event.toolId&&function isSuccessfulEvidenceEvent(e){const t=function readString(e){return"string"==typeof e&&e.length>0?e:void 0}(e.controlStatus)??function readOutputStatus(e){if("string"!=typeof e)return;const t=function parseJsonRecord(e){try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:e.match(/^Status:\s*([A-Za-z0-9_-]+)/imu)?.[1]}(e.output);return!t||/^(?:completed|success|ok|recorded)$/iu.test(t)}(e.event)?[e.event.toolId]:[]}function readRecord(e){return isRecord(e)?e:{}}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e)
|
|
1
|
+
export function resolveToolCallRecoveryPolicy(e){const o=e.workspace.runtime;if(!function shouldDefaultToolCallRecovery(e){if(0===e.agent.tools.length)return!1;const o=e.agent.modelRef?e.workspace.models.get(e.agent.modelRef):void 0;return"openai-compatible"===o?.provider||"openai-compatible"===readString(o?.config?.toolCallingMode)||"structured"===readString(o?.config?.toolCallingMode)||function hasDirectBackendModel(e){const o=readRecord(e.config);return void 0!==readRecord(o.deepagents).model}(e.agent)}(e))return o;const r=function hasExplicitToolCallRecovery(e){const o=readRecord(e.recovery);return"boolean"==typeof readRecord(o.toolCall).enabled}(o)?o:function withDefaultToolCallRecovery(e){const o=readRecord(e.recovery),r=readRecord(o.toolCall);return{...e,recovery:{...o,toolCall:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(o);return function hasExplicitRepeatGuard(e){const o=readRecord(e.toolGateway);return"boolean"==typeof readRecord(o.repeatGuard).enabled}(r)?r:function withDefaultRepeatGuard(e){const o=readRecord(e.toolGateway),r=readRecord(o.repeatGuard);return{...e,toolGateway:{...o,repeatGuard:{...r,enabled:!0,defaultedForStructuredToolCalling:!0}}}}(r)}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}
|