stable-harness 0.0.46 → 0.0.47
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/builtin/task-inventory.d.ts +5 -1
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin/task-inventory.js +1 -1
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts +2 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -1
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js +1 -1
- package/node_modules/@stable-harness/core/dist/quality/llm-review.js +1 -1
- package/node_modules/@stable-harness/core/dist/quality/types.d.ts +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/tool-gateway.d.ts +1 -1
- package/package.json +2 -2
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/builtin/task-inventory.d.ts +5 -1
- package/packages/adapter-deepagents/dist/src/internal/builtin/task-inventory.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts +2 -0
- package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js +1 -1
- package/packages/core/dist/quality/llm-review.js +1 -1
- package/packages/core/dist/quality/types.d.ts +1 -1
- package/packages/core/dist/runtime/tool-gateway.d.ts +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 d}from"./memory.js";import{buildDeepAgentRequest as c}from"./internal/messages.js";import{createRawToolCallParserMiddleware as l}from"./internal/raw-tool-call-parser.js";import{createBackendModel as u}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as m}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.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,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=n(function buildDeepAgentParams(e,t,r){const n={...readDeepAgentsConfig(t),...readDeepAgentsConfig(e.agent.config.deepagents)},o=resolveDeepAgentsSkills(e,e.agent),a=n.permissions??s(e,e.agent),p=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:n.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:n.backend??resolveDeepAgentsBackend(e,r,o),checkpointer:n.checkpointer,store:n.store,middleware:mergeMiddleware(e,e.agent,n.middleware,p),responseFormat:n.responseFormat,contextSchema:n.contextSchema,interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:a,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(e,e.agent,n),p),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(a,r,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:resolveDeepAgentsMemory(e,e.agent),skills:o})}(t,e.config,r)),a=c(t),d=function buildDeepAgentInvokeConfig(e){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit)})}(t.agent);if(!0===t.request.metadata?.openaiStream&&o.streamEvents){const e=await o.streamEvents(a,{version:"v3",...d});return g(t,e,p)}const l=await o.invoke(a,d);return p(l)}}}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),...d(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),d=new Set,c=readDeepAgentsConfig(t?.config.deepagents);return[o(p,{observedToolIds:d,repeatState:s,repairModel:resolveAgentRepairModel(p,t,c)}),n(p,{repeatState:s}),...m(e.workspace.runtime.retry),...i,l(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?u(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;if(isRepairModel(n))return n;if(!t)return;const o=resolveAgentModel(e,t);return isRepairModel(o)?o: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)}function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}
|
|
@@ -6,7 +6,11 @@ export declare function repairTaskCall<T extends {
|
|
|
6
6
|
id?: string;
|
|
7
7
|
args?: unknown;
|
|
8
8
|
};
|
|
9
|
-
}>(input: AdapterRunInput, request: T
|
|
9
|
+
}>(input: AdapterRunInput, request: T, options?: {
|
|
10
|
+
repairModel?: {
|
|
11
|
+
invoke(input: unknown, options?: unknown): Promise<unknown> | unknown;
|
|
12
|
+
};
|
|
13
|
+
}): Promise<{
|
|
10
14
|
request: T;
|
|
11
15
|
blocked?: ToolMessage;
|
|
12
16
|
}>;
|
package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin/task-inventory.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{repairCallSelection as e}from"@easynet/better-call";import{ToolMessage as t}from"@langchain/core/messages";import{normalizeArgsRecord as
|
|
1
|
+
import{repairCallSelection as e}from"@easynet/better-call";import{ToolMessage as t}from"@langchain/core/messages";import{normalizeArgsRecord as r}from"../builtin-args.js";export async function repairTaskCall(n,a,s={}){const o=function allowedTaskTypes(e){const t=readConfigRecord(e.agent.config,"deepagents");if(!0===t?.generalPurposeAgent)return;const r=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1===r?[]:Array.isArray(r)?r.includes("task")?e.agent.subagents:[]:0===e.agent.subagents.length?[]:void 0}(n);if(void 0===o)return{request:a};const i=function normalizeTaskArgs(e){const t=r(e),n=function readNestedTaskRecord(e){return readJsonRecord(e.input)??readJsonRecord(e.task)??readJsonRecord(e.arguments)??readJsonRecord(e.parameters)}(t);if(!n)return t;const a={...t};for(const[e,t]of Object.entries(n))void 0===a[e]&&(a[e]=t);if(readJsonRecord(t.input)&&delete a.input,readJsonRecord(t.task)&&delete a.task,!hasCanonicalTaskTarget(a)&&!readString(a.description)){const e=readString(a.task)??readString(a.instruction);e&&(a.description=e)}return a}(a.toolCall?.args),d=function readTaskSubagentType(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)??readString(t.target)??readString(t.role)}(i),c=d;if(c&&o.includes(c)){const e=hasCanonicalTaskTarget(i)&&d===c?i:{...i,subagent_type:c};return{request:{...a,toolCall:{...a.toolCall,args:e}}}}const l=await e({userInput:n.request.input,call:{id:d??readString(i.role)??n.request.input,args:i},candidates:taskCallCandidates(n,o),mode:"repair",repairModel:s.repairModel});if(l.ok){emitInventoryRepair(n,"repaired",d,l.candidateId,o);const e={...i,...l.args,subagent_type:l.candidateId};return{request:{...a,toolCall:{...a.toolCall,args:e}}}}emitInventoryRepair(n,"blocked",d,void 0,o,l.reason);const g=d?`: ${d}`:"",u=o.length>0?o.join(", "):"none";return{request:a,blocked:new t({tool_call_id:a.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:[`Task delegation target is not in the workspace inventory${g}. Allowed task targets: ${u}.`,"Retry with an allowed target only when that target semantically owns the original user request.","Do not substitute another specialist just to continue the same evidence need; synthesize from already collected evidence when no allowed target is a semantic match."].join(" ")})}}function emitInventoryRepair(e,t,r,n,a,s){e.emit({type:"runtime.adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,event:{adapter:"deepagents",phase:"inventory.repair",status:t,diagnostic:{layer:"task",owner:"stable_runtime_policy",originalId:r,repairedId:n,candidateIds:a,reason:s}}})}function taskCallCandidates(e,t){return t.map(t=>({id:t,description:e.workspace.agents.get(t)?.description,schema:{type:"object",properties:{subagent_type:{type:"string"},subagentType:{type:"string"},target:{type:"string"},role:{type:"string"},description:{type:"string"},task:{type:"string"},instruction:{type:"string"},input:{type:"string"}},required:["description"],additionalProperties:!0}}))}function hasCanonicalTaskTarget(e){return Boolean(readString(e.subagent_type)??readString(e.subagentType))}function readJsonRecord(e){if(isRecord(e))return e;if("string"==typeof e&&e.trim())try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}function readConfigRecord(e,t){const r=isRecord(e)?e:{};return isRecord(r[t])?r[t]:void 0}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RuntimeAdapter } from "@stable-harness/core";
|
|
2
2
|
import { type ToolRepeatState } from "@stable-harness/core";
|
|
3
|
+
import type { RuntimeToolRepairModel } from "@stable-harness/core";
|
|
3
4
|
type AdapterRunInput = Parameters<RuntimeAdapter["run"]>[0];
|
|
4
5
|
export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput, options?: {
|
|
5
6
|
repeatState?: ToolRepeatState;
|
|
@@ -15,6 +16,7 @@ export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput
|
|
|
15
16
|
export declare function createObserverMiddleware(input: AdapterRunInput, options?: {
|
|
16
17
|
observedToolIds?: Set<string>;
|
|
17
18
|
repeatState?: ToolRepeatState;
|
|
19
|
+
repairModel?: RuntimeToolRepairModel;
|
|
18
20
|
}): {
|
|
19
21
|
name: string;
|
|
20
22
|
wrapToolCall(request: {
|
package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/builtin-tool-policy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ToolMessage as t}from"@langchain/core/messages";import{afterToolInvoke as e,beforeToolInvoke as o,createToolRepeatState as r}from"@stable-harness/core";import{filesystemBuiltinToolIds as
|
|
1
|
+
import{ToolMessage as t}from"@langchain/core/messages";import{afterToolInvoke as e,beforeToolInvoke as o,createToolRepeatState as r}from"@stable-harness/core";import{filesystemBuiltinToolIds as i,isFilesystemDisabled as n,isFilesystemTool as s,validateFilesystemBuiltinCall as a}from"./builtin/permissions.js";import{repairTaskCall as l}from"./builtin/task-inventory.js";import{repairBuiltinToolRequest as u}from"./builtin-call-repair.js";import{stringifyDeepAgentResult as c,toolControlProjection as d}from"./gateway-tools.js";import{isSuccessfulEvidenceOutput as p,observedToolEvidence as m,recordObservedToolEvidence as g}from"./gateway/tool-evidence.js";import{validateSkillFileBuiltinCall as f}from"./skill-file-policy.js";import{filterRepeatLimitedTools as v}from"./tool-repeat-visibility.js";import{traceProjectionForBuiltinTool as b}from"./trace-projection.js";const T=new Set(["write_todos","read_todos","task","execute",...i]);export function createBuiltinToolPolicyMiddleware(t,e={}){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(o,r){const i=Array.isArray(o.tools)?v(o.tools.filter(e=>!function hasHiddenBuiltins(t){return n(t)||!isTaskVisible(t)}(t)||isModelVisibleBuiltin(t,e.name)),e.repeatState):o.tools,s=function normalizeToolChoice(t,e,o){return"required"===e?o&&o.length>0?e:"auto":function isForcedHiddenTool(t,e){return"string"==typeof e?.function?.name&&!isModelVisibleBuiltin(t,e.function.name)}(t,e)?"auto":e}(t,o.toolChoice,i);return r({...o,tools:i,toolChoice:s})}}}export function createObserverMiddleware(i,n={}){const s=n.repeatState??r(i.workspace.runtime.toolGateway);return{name:"StableHarnessObserver",async wrapToolCall(r,d){const g=r.toolCall?.name;if(!g||!T.has(g))return d(r);const v=await u({toolId:g,request:r,workspaceRoot:i.workspace.root});emitToolEvent(i,g,"agent.tool.start",v.toolCall?.args);const b="task"===g?await l(i,v,{repairModel:n.repairModel}):{request:v},h=b.request,y=b.blocked;if(y)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:y.content}),y;const k=a(i,g,h);if(k)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:k.content}),k;const C=f(i,g,h);if(C)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:C.content}),C;try{const a=s?o(g,h.toolCall?.args,s):void 0;if(a)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:a.eventOutput}),builtinToolMessage(r,g,function modelOutputForRepeatedBuiltin(t,e){return"task"!==t?e:function readPreviousOutput(t){try{const e=JSON.parse(t);if(!isRecord(e)||"repeated_tool_call_limit"!==e.status||"string"!=typeof e.previousOutput)return;const o=e.previousOutput.trim();return o.length>0?o:void 0}catch{return}}(e)??e}(g,a.modelOutput));const l=await d(h),u=function observedToolOutput(t,e,o){return"write_todos"===t?JSON.stringify({status:"recorded",args:e.toolCall?.args}):c(o)}(g,h,l),m=s?e({toolId:g,args:h.toolCall?.args,output:u,successful:!(l instanceof t&&"error"===l.status)&&p(u),state:s}):{};return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:m.eventOutput??u}),n.observedToolIds?.add(g),void 0===m.modelOutput?l:builtinToolMessage(r,g,m.modelOutput)}catch(e){const o=function recoverableBuiltinToolError(e,o,r,i){const n=formatError(i);if("task"===o&&/repeat limit reached for tool/iu.test(n)){const o=function formatObservedEvidence(t){const e=m(t);if(0===e.length)return"";const o=e.map(t=>[`Agent: ${t.agentId}`,`Tool: ${t.toolId}`,t.output].join("\n")).join("\n\n---\n\n");return o.length>12e3?`${o.slice(0,12e3)}\n[truncated]`:o}(e);return new t({tool_call_id:r.toolCall?.id??"stable-harness-task-repeat-limit",name:"task",content:JSON.stringify({status:"delegated_task_repeat_limit",finalizationRequired:!0,instruction:"The delegated agent reached a configured tool repeat limit. Stop delegating this evidence need and do not send a synthesis task to another subagent for the same need. Finalize only from observedEvidence and other evidence that is already visible in this run. If the visible evidence is insufficient for a requested claim, report an explicit blocker or evidence gap instead of estimating, inventing, or using generic knowledge.",...o?{observedEvidence:o}:{},error:previewError(n)})})}if(/Received tool input did not match expected schema|Invalid input:/iu.test(n))return new t({tool_call_id:r.toolCall?.id??`stable-harness-${o}-argument-error`,name:o,status:"error",content:JSON.stringify({status:"tool_argument_error",toolId:o,instruction:"The upstream builtin tool rejected these arguments. Fix the tool arguments according to the tool schema, or choose a more appropriate available tool.",error:previewError(n)})})}(i,g,r,e);if(o)return emitToolEvent(i,g,"agent.tool.result",v.toolCall?.args,{output:o.content}),o;throw emitToolEvent(i,g,"agent.tool.result",v.toolCall?.args,{error:formatError(e)}),e}}}}function builtinToolMessage(e,o,r){return new t({tool_call_id:e.toolCall?.id??`stable-harness-${o}-repeat-guard`,name:o,content:r})}function emitToolEvent(t,e,o,r,i={}){"string"==typeof i.output&&g(t,t.agent.id,e,i.output),t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",eventGroup:"tool_execution",eventType:"agent.tool.start"===o?"deepagents.tool_execution.start":"deepagents.tool_execution.result",phase:o,toolId:e,..."agent.tool.start"===o?{args:r}:{},...i,..."string"==typeof i.output?d(i.output):{},...b(e,o,r)}})}function isTaskVisible(t){const e=function readConfigRecord(t,e){const o=isRecord(t)?t:{};return isRecord(o[e])?o[e]:void 0}(t.agent.config,"builtinTools")?.modelExposed;return!1!==e&&(!Array.isArray(e)||e.includes("task"))}function isModelVisibleBuiltin(t,e){return(!n(t)||!s(e))&&("task"!==e||isTaskVisible(t))}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function formatError(t){return t instanceof Error?t.message:String(t)}function previewError(t){const e=t.replace(/\s+/gu," ").trim();return e.length>800?`${e.slice(0,797)}...`:e}
|
package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/raw-tool-call-parser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AIMessage as e}from"@langchain/core/messages";export function createRawToolCallParserMiddleware(t){return{name:"StableHarnessRawToolCallParser",async wrapModelCall(n,
|
|
1
|
+
import{AIMessage as e}from"@langchain/core/messages";export function createRawToolCallParserMiddleware(t){return{name:"StableHarnessRawToolCallParser",async wrapModelCall(n,o){const r=await o(n);if(!function rawToolCallParsingEnabled(e){const t=isRecord(e.workspace.runtime.recovery)?e.workspace.runtime.recovery:{};return!0===(isRecord(t.toolCall)?t.toolCall:{}).enabled}(t))return r;const a=function parseRawToolCallResponse(t,n){if(0===n.size||!function isModelResponse(e){return isRecord(e)}(t)||function hasToolCalls(e){return Array.isArray(e.tool_calls)&&e.tool_calls.length>0}(t))return;const o=function readContentText(e){return"string"==typeof e?e.trim()?e:void 0:Array.isArray(e)&&e.map(e=>isRecord(e)&&"string"==typeof e.text?e.text:"").join("\n").trim()||void 0}(t.content);if(!o)return;const r=function readRawToolCalls(e,t){const n=readXmlToolCalls(e,t);if(n.length>0)return n;const o=function stripToolMarkup(e){return e.replace(/^\s*```(?:json)?/iu,"").replace(/```\s*$/iu,"").replace(/^\s*<\s*tool_call[^>]*>\s*/iu,"").replace(/\s*<\s*\/\s*tool_call\s*>\s*$/iu,"").trim()}(e),r=readXmlToolCalls(o,t);if(r.length>0)return r;const a=function readFunctionToolCalls(e,t){const n=[];for(const o of t){const t=new RegExp(`(?:^|\\s)${escapeRegexp(o)}\\s*\\(([^)]*)\\)`,"giu");for(const r of e.matchAll(t)){const e=readFunctionArgs(r[1]??"");e&&Object.keys(e).length>0&&n.push({id:`stable-harness-${o}-${Date.now().toString(36)}`,name:o,args:e})}}return n}(o,t);return a.length>0?a:function parseJsonObjects(e){const t=[];let n=e.indexOf("{");for(;n>=0;){const o=readBalancedJsonObject(e,n);if(o){try{const e=JSON.parse(o);isRecord(e)&&t.push(e)}catch{}n=e.indexOf("{",n+o.length)}else n=e.indexOf("{",n+1)}return t}(o).flatMap(e=>function readJsonToolCall(e,t){const n=function readNestedToolCall(e,t){const n=Object.entries(e);if(1!==n.length)return;const[o,r]=n[0];return t.has(o)&&isRecord(r)?{id:`stable-harness-${o}-${Date.now().toString(36)}`,name:o,args:r}:void 0}(e,t);if(n)return n;const o=readString(e.name)??readString(e.tool_name)??readString(e.tool)??readString(e.type),r=t.has(o??"")?o:singleToolName(t),a=function readArgs(e){return isRecord(e.arguments)?e.arguments:isRecord(e.parameters)?e.parameters:isRecord(e.args)?e.args:"args"in e&&void 0!==e.args?{args:e.args}:void 0}(e)??function readInlineArgs(e){const t=Object.fromEntries(Object.entries(e).filter(([e])=>!["name","tool_name","tool","type"].includes(e)));return Object.keys(t).length>0?t:void 0}(e);return r&&t.has(r)&&a?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:a}:void 0}(e,t)??[])}(o,n);return 0!==r.length?new e({content:"",id:"string"==typeof t.id?t.id:void 0,name:"string"==typeof t.name?t.name:void 0,additional_kwargs:isRecord(t.additional_kwargs)?t.additional_kwargs:{},response_metadata:isRecord(t.response_metadata)?t.response_metadata:{},tool_calls:r.map(e=>({id:e.id,name:e.name,args:e.args,type:"tool_call"}))}):void 0}(r,function visibleToolNames(e){return new Set((e.tools??[]).map(e=>e.name).filter(e=>"string"==typeof e&&e.length>0))}(n));return a??r}}}function readXmlToolCalls(e,t){const n=[],o=/<\s*(tool_call|tool_code)\b[^>]*>(?:[\s\S]*?<\s*\/\s*\1\s*>)?/giu;for(const r of e.matchAll(o)){const e=readXmlToolCall(r[0],t);e&&n.push(e)}return n}function readXmlToolCall(e,t){const n=function readToolCallAttributes(e){const t=/<\s*(?:tool_call|tool_code)\b([^>]*)>/iu.exec(e);if(!t)return;const n=[...t[1].matchAll(/([a-zA-Z_][\w.-]*)\s*=\s*"([^"]*)"/gu)];return n.length>0?Object.fromEntries(n.map(e=>[e[1],e[2]])):void 0}(e),o=readString(n?.name)??readString(n?.tool_name)??readString(n?.tool)??readXmlTag(e,"tool_name")??readXmlTag(e,"name")??readXmlTag(e,"tool")??function readBareXmlToolName(e,t){const n=readBareXmlToolBody(e),o=n?.trim();return o&&t.has(o)?o:void 0}(e,t),r=t.has(o??"")?o:singleToolName(t);if(!r&&!o&&t.has("task")){const t=readBareXmlToolBody(e);if(t)return{id:`stable-harness-task-${Date.now().toString(36)}`,name:"task",args:{input:t}}}if(!r||!t.has(r))return;const a=readXmlTag(e,"tool_args")??readXmlTag(e,"args")??readXmlTag(e,"arguments"),s=a?function readXmlArgs(e){const t=[...e.matchAll(/<\s*([a-zA-Z_][\w.-]*)\s*>([\s\S]*?)<\s*\/\s*\1\s*>/gu)];if(0===t.length){const t=e.trim();return t?{input:t}:void 0}return Object.fromEntries(t.map(e=>[e[1],e[2].trim()]))}(a):function readAttributeArgs(e){if(!e)return;const t=Object.fromEntries(Object.entries(e).filter(([e])=>!["name","tool_name","tool","type"].includes(e)));return Object.keys(t).length>0?t:void 0}(n);return!s&&o?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:{}}:s&&0!==Object.keys(s).length?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:s}:void 0}function readXmlTag(e,t){const n=new RegExp(`<\\s*${t}\\s*>([\\s\\S]*?)<\\s*\\/\\s*${t}\\s*>`,"iu").exec(e);return n?.[1]?.trim()||void 0}function readBareXmlToolBody(e){return function readXmlElementBody(e,t){const n=function readOpeningTag(e,t){for(const n of t){const t=e.indexOf(`<${n}`);if(t<0)continue;const o=e.indexOf(">",t+n.length+1);if(o>=0)return{end:o+1}}}(e,t);if(!n)return;const o=function findClosingTag(e,t,n){let o;for(const r of t){const t=[`</${r}>`,`</ ${r}>`];for(const r of t){const t=e.indexOf(r,n);t>=0&&(void 0===o||t<o)&&(o=t)}}return o}(e,t,n.end);return void 0===o?void 0:e.slice(n.end,o)}(e,["tool_call","tool_code"])?.trim()||void 0}function readFunctionArgs(e){const t=[...e.matchAll(/([a-zA-Z_][\w.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^,\s]+))/gu)];return t.length>0?Object.fromEntries(t.map(e=>[e[1],e[2]??e[3]??e[4]??""])):void 0}function readBalancedJsonObject(e,t){let n=0,o=!1,r=!1;for(let a=t;a<e.length;a+=1){const s=e[a];if(o)r="\\"===s&&!r,'"'!==s||r||(o=!1),"\\"!==s&&(r=!1);else if('"'===s&&(o=!0),"{"===s&&(n+=1),"}"===s&&(n-=1),0===n)return e.slice(t,a+1)}}function singleToolName(e){return 1===e.size?[...e][0]:void 0}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export async function reviewWithLlm(e){if(!e.model||"llm"!==e.policy.reviewer?.mode)return;const t="planning"===e.phase?e.policy.reviewer.planningPrompt??function defaultPlanningPrompt(){return["You are Stable Harness planning quality review.","Review only generic agent-work quality: goal coverage, executable steps, and declared inventory fit.",'Do not invent a domain workflow. Return only JSON: {"verdict":"pass|revise_plan|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}():e.policy.reviewer.executionPrompt??function defaultExecutionPrompt(){return["You are Stable Harness execution evidence review.","Review only whether execution evidence supports the final answer and whether unresolved blockers or gaps remain.",'Do not answer the user request. Return only JSON: {"verdict":"pass|continue_react|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}();return function parseReviewResult(e){const t=function readResponseText(e){if("string"==typeof e)return e;if(!isRecord(e))return;if("string"==typeof e.content)return e.content;const t=isRecord(e.message)?e.message:void 0;return"string"==typeof t?.content?t.content:void 0}(e),
|
|
1
|
+
export async function reviewWithLlm(e){if(!e.model||"llm"!==e.policy.reviewer?.mode)return;const t="planning"===e.phase?e.policy.reviewer.planningPrompt??function defaultPlanningPrompt(){return["You are Stable Harness planning quality review.","Review only generic agent-work quality: goal coverage, executable steps, and declared inventory fit.",'Do not invent a domain workflow. Return only JSON: {"verdict":"pass|revise_plan|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}():e.policy.reviewer.executionPrompt??function defaultExecutionPrompt(){return["You are Stable Harness execution evidence review.","Review only whether execution evidence supports the final answer and whether unresolved blockers or gaps remain.",'Do not answer the user request. Return only JSON: {"verdict":"pass|continue_react|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}();return function parseReviewResult(e){const t=function readResponseText(e){if("string"==typeof e)return e;if(!isRecord(e))return;if("string"==typeof e.content)return e.content;const t=isRecord(e.message)?e.message:void 0;return"string"==typeof t?.content?t.content:void 0}(e),r="string"==typeof t?function parseJsonRecord(e){const t=e.trim().replace(/^```(?:json)?\s*/iu,"").replace(/\s*```$/u,"");try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}(t):isRecord(e)?e:void 0,n=function readVerdict(e){return"pass"===e||"revise_plan"===e||"continue_react"===e||"blocked"===e?e:void 0}(r?.verdict);if(r&&n)return{verdict:n,issues:readIssues(r.issues)}}(await e.model.invoke([{role:"system",content:t},{role:"user",content:JSON.stringify(buildReviewContext(e.review),null,2)}],function structuredJsonOptions(e){return{response_format:{type:"json_schema",json_schema:{name:`stable_harness_${e}_quality_review`,strict:!0,schema:{type:"object",properties:{verdict:{type:"string",enum:"planning"===e?["pass","revise_plan","blocked"]:["pass","continue_react","blocked"]},issues:{type:"array",items:{type:"object",properties:{code:{type:"string"},message:{type:"string"},recoverable:{type:"boolean"}},required:["code","message","recoverable"],additionalProperties:!1}}},required:["verdict","issues"],additionalProperties:!1}}}}}(e.phase)))}function buildReviewContext(e){return{userRequest:e.request.input,agent:{id:e.agent.id,tools:e.agent.tools,skills:e.agent.skills??[],subagents:e.agent.subagents},finalOutput:e.output?.text,events:e.events.slice(-30).map(projectEvent)}}function projectEvent(e){return"runtime.adapter.event"===e.type?{type:e.type,event:e.event}:{...e}}function readIssues(e){return Array.isArray(e)?e.flatMap(e=>isRecord(e)&&"string"==typeof e.code&&"string"==typeof e.message?[{code:e.code,message:e.message,recoverable:!1!==e.recoverable}]:[]):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -33,7 +33,7 @@ export type RuntimeToolGatewayTool = {
|
|
|
33
33
|
schema?: unknown;
|
|
34
34
|
};
|
|
35
35
|
export type RuntimeToolRepairModel = {
|
|
36
|
-
invoke(input: unknown): Promise<unknown> | unknown;
|
|
36
|
+
invoke(input: unknown, options?: unknown): Promise<unknown> | unknown;
|
|
37
37
|
};
|
|
38
38
|
export type RuntimeToolGateway = {
|
|
39
39
|
get(toolId: string): RuntimeToolGatewayTool | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stable-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Stable application runtime and operator control plane for agent workspaces.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"packages/*"
|
|
79
79
|
],
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@easynet/better-call": "^0.1.
|
|
81
|
+
"@easynet/better-call": "^0.1.63",
|
|
82
82
|
"@langchain/core": "^1.1.46",
|
|
83
83
|
"@langchain/langgraph": "^1.3.0",
|
|
84
84
|
"@langchain/langgraph-api": "^1.2.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 d}from"./memory.js";import{buildDeepAgentRequest as c}from"./internal/messages.js";import{createRawToolCallParserMiddleware as l}from"./internal/raw-tool-call-parser.js";import{createBackendModel as u}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as m}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.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,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=n(function buildDeepAgentParams(e,t,r){const n={...readDeepAgentsConfig(t),...readDeepAgentsConfig(e.agent.config.deepagents)},o=resolveDeepAgentsSkills(e,e.agent),a=n.permissions??s(e,e.agent),p=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:n.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:n.backend??resolveDeepAgentsBackend(e,r,o),checkpointer:n.checkpointer,store:n.store,middleware:mergeMiddleware(e,e.agent,n.middleware,p),responseFormat:n.responseFormat,contextSchema:n.contextSchema,interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:a,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(e,e.agent,n),p),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(a,r,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:resolveDeepAgentsMemory(e,e.agent),skills:o})}(t,e.config,r)),a=c(t),d=function buildDeepAgentInvokeConfig(e){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit)})}(t.agent);if(!0===t.request.metadata?.openaiStream&&o.streamEvents){const e=await o.streamEvents(a,{version:"v3",...d});return g(t,e,p)}const l=await o.invoke(a,d);return p(l)}}}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),...d(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),d=new Set,c=readDeepAgentsConfig(t?.config.deepagents);return[o(p,{observedToolIds:d,repeatState:s,repairModel:resolveAgentRepairModel(p,t,c)}),n(p,{repeatState:s}),...m(e.workspace.runtime.retry),...i,l(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?u(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;if(isRepairModel(n))return n;if(!t)return;const o=resolveAgentModel(e,t);return isRepairModel(o)?o: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)}function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}
|
|
@@ -6,7 +6,11 @@ export declare function repairTaskCall<T extends {
|
|
|
6
6
|
id?: string;
|
|
7
7
|
args?: unknown;
|
|
8
8
|
};
|
|
9
|
-
}>(input: AdapterRunInput, request: T
|
|
9
|
+
}>(input: AdapterRunInput, request: T, options?: {
|
|
10
|
+
repairModel?: {
|
|
11
|
+
invoke(input: unknown, options?: unknown): Promise<unknown> | unknown;
|
|
12
|
+
};
|
|
13
|
+
}): Promise<{
|
|
10
14
|
request: T;
|
|
11
15
|
blocked?: ToolMessage;
|
|
12
16
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{repairCallSelection as e}from"@easynet/better-call";import{ToolMessage as t}from"@langchain/core/messages";import{normalizeArgsRecord as
|
|
1
|
+
import{repairCallSelection as e}from"@easynet/better-call";import{ToolMessage as t}from"@langchain/core/messages";import{normalizeArgsRecord as r}from"../builtin-args.js";export async function repairTaskCall(n,a,s={}){const o=function allowedTaskTypes(e){const t=readConfigRecord(e.agent.config,"deepagents");if(!0===t?.generalPurposeAgent)return;const r=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1===r?[]:Array.isArray(r)?r.includes("task")?e.agent.subagents:[]:0===e.agent.subagents.length?[]:void 0}(n);if(void 0===o)return{request:a};const i=function normalizeTaskArgs(e){const t=r(e),n=function readNestedTaskRecord(e){return readJsonRecord(e.input)??readJsonRecord(e.task)??readJsonRecord(e.arguments)??readJsonRecord(e.parameters)}(t);if(!n)return t;const a={...t};for(const[e,t]of Object.entries(n))void 0===a[e]&&(a[e]=t);if(readJsonRecord(t.input)&&delete a.input,readJsonRecord(t.task)&&delete a.task,!hasCanonicalTaskTarget(a)&&!readString(a.description)){const e=readString(a.task)??readString(a.instruction);e&&(a.description=e)}return a}(a.toolCall?.args),d=function readTaskSubagentType(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)??readString(t.target)??readString(t.role)}(i),c=d;if(c&&o.includes(c)){const e=hasCanonicalTaskTarget(i)&&d===c?i:{...i,subagent_type:c};return{request:{...a,toolCall:{...a.toolCall,args:e}}}}const l=await e({userInput:n.request.input,call:{id:d??readString(i.role)??n.request.input,args:i},candidates:taskCallCandidates(n,o),mode:"repair",repairModel:s.repairModel});if(l.ok){emitInventoryRepair(n,"repaired",d,l.candidateId,o);const e={...i,...l.args,subagent_type:l.candidateId};return{request:{...a,toolCall:{...a.toolCall,args:e}}}}emitInventoryRepair(n,"blocked",d,void 0,o,l.reason);const g=d?`: ${d}`:"",u=o.length>0?o.join(", "):"none";return{request:a,blocked:new t({tool_call_id:a.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:[`Task delegation target is not in the workspace inventory${g}. Allowed task targets: ${u}.`,"Retry with an allowed target only when that target semantically owns the original user request.","Do not substitute another specialist just to continue the same evidence need; synthesize from already collected evidence when no allowed target is a semantic match."].join(" ")})}}function emitInventoryRepair(e,t,r,n,a,s){e.emit({type:"runtime.adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,event:{adapter:"deepagents",phase:"inventory.repair",status:t,diagnostic:{layer:"task",owner:"stable_runtime_policy",originalId:r,repairedId:n,candidateIds:a,reason:s}}})}function taskCallCandidates(e,t){return t.map(t=>({id:t,description:e.workspace.agents.get(t)?.description,schema:{type:"object",properties:{subagent_type:{type:"string"},subagentType:{type:"string"},target:{type:"string"},role:{type:"string"},description:{type:"string"},task:{type:"string"},instruction:{type:"string"},input:{type:"string"}},required:["description"],additionalProperties:!0}}))}function hasCanonicalTaskTarget(e){return Boolean(readString(e.subagent_type)??readString(e.subagentType))}function readJsonRecord(e){if(isRecord(e))return e;if("string"==typeof e&&e.trim())try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}function readConfigRecord(e,t){const r=isRecord(e)?e:{};return isRecord(r[t])?r[t]:void 0}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RuntimeAdapter } from "@stable-harness/core";
|
|
2
2
|
import { type ToolRepeatState } from "@stable-harness/core";
|
|
3
|
+
import type { RuntimeToolRepairModel } from "@stable-harness/core";
|
|
3
4
|
type AdapterRunInput = Parameters<RuntimeAdapter["run"]>[0];
|
|
4
5
|
export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput, options?: {
|
|
5
6
|
repeatState?: ToolRepeatState;
|
|
@@ -15,6 +16,7 @@ export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput
|
|
|
15
16
|
export declare function createObserverMiddleware(input: AdapterRunInput, options?: {
|
|
16
17
|
observedToolIds?: Set<string>;
|
|
17
18
|
repeatState?: ToolRepeatState;
|
|
19
|
+
repairModel?: RuntimeToolRepairModel;
|
|
18
20
|
}): {
|
|
19
21
|
name: string;
|
|
20
22
|
wrapToolCall(request: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ToolMessage as t}from"@langchain/core/messages";import{afterToolInvoke as e,beforeToolInvoke as o,createToolRepeatState as r}from"@stable-harness/core";import{filesystemBuiltinToolIds as
|
|
1
|
+
import{ToolMessage as t}from"@langchain/core/messages";import{afterToolInvoke as e,beforeToolInvoke as o,createToolRepeatState as r}from"@stable-harness/core";import{filesystemBuiltinToolIds as i,isFilesystemDisabled as n,isFilesystemTool as s,validateFilesystemBuiltinCall as a}from"./builtin/permissions.js";import{repairTaskCall as l}from"./builtin/task-inventory.js";import{repairBuiltinToolRequest as u}from"./builtin-call-repair.js";import{stringifyDeepAgentResult as c,toolControlProjection as d}from"./gateway-tools.js";import{isSuccessfulEvidenceOutput as p,observedToolEvidence as m,recordObservedToolEvidence as g}from"./gateway/tool-evidence.js";import{validateSkillFileBuiltinCall as f}from"./skill-file-policy.js";import{filterRepeatLimitedTools as v}from"./tool-repeat-visibility.js";import{traceProjectionForBuiltinTool as b}from"./trace-projection.js";const T=new Set(["write_todos","read_todos","task","execute",...i]);export function createBuiltinToolPolicyMiddleware(t,e={}){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(o,r){const i=Array.isArray(o.tools)?v(o.tools.filter(e=>!function hasHiddenBuiltins(t){return n(t)||!isTaskVisible(t)}(t)||isModelVisibleBuiltin(t,e.name)),e.repeatState):o.tools,s=function normalizeToolChoice(t,e,o){return"required"===e?o&&o.length>0?e:"auto":function isForcedHiddenTool(t,e){return"string"==typeof e?.function?.name&&!isModelVisibleBuiltin(t,e.function.name)}(t,e)?"auto":e}(t,o.toolChoice,i);return r({...o,tools:i,toolChoice:s})}}}export function createObserverMiddleware(i,n={}){const s=n.repeatState??r(i.workspace.runtime.toolGateway);return{name:"StableHarnessObserver",async wrapToolCall(r,d){const g=r.toolCall?.name;if(!g||!T.has(g))return d(r);const v=await u({toolId:g,request:r,workspaceRoot:i.workspace.root});emitToolEvent(i,g,"agent.tool.start",v.toolCall?.args);const b="task"===g?await l(i,v,{repairModel:n.repairModel}):{request:v},h=b.request,y=b.blocked;if(y)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:y.content}),y;const k=a(i,g,h);if(k)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:k.content}),k;const C=f(i,g,h);if(C)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:C.content}),C;try{const a=s?o(g,h.toolCall?.args,s):void 0;if(a)return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:a.eventOutput}),builtinToolMessage(r,g,function modelOutputForRepeatedBuiltin(t,e){return"task"!==t?e:function readPreviousOutput(t){try{const e=JSON.parse(t);if(!isRecord(e)||"repeated_tool_call_limit"!==e.status||"string"!=typeof e.previousOutput)return;const o=e.previousOutput.trim();return o.length>0?o:void 0}catch{return}}(e)??e}(g,a.modelOutput));const l=await d(h),u=function observedToolOutput(t,e,o){return"write_todos"===t?JSON.stringify({status:"recorded",args:e.toolCall?.args}):c(o)}(g,h,l),m=s?e({toolId:g,args:h.toolCall?.args,output:u,successful:!(l instanceof t&&"error"===l.status)&&p(u),state:s}):{};return emitToolEvent(i,g,"agent.tool.result",h.toolCall?.args,{output:m.eventOutput??u}),n.observedToolIds?.add(g),void 0===m.modelOutput?l:builtinToolMessage(r,g,m.modelOutput)}catch(e){const o=function recoverableBuiltinToolError(e,o,r,i){const n=formatError(i);if("task"===o&&/repeat limit reached for tool/iu.test(n)){const o=function formatObservedEvidence(t){const e=m(t);if(0===e.length)return"";const o=e.map(t=>[`Agent: ${t.agentId}`,`Tool: ${t.toolId}`,t.output].join("\n")).join("\n\n---\n\n");return o.length>12e3?`${o.slice(0,12e3)}\n[truncated]`:o}(e);return new t({tool_call_id:r.toolCall?.id??"stable-harness-task-repeat-limit",name:"task",content:JSON.stringify({status:"delegated_task_repeat_limit",finalizationRequired:!0,instruction:"The delegated agent reached a configured tool repeat limit. Stop delegating this evidence need and do not send a synthesis task to another subagent for the same need. Finalize only from observedEvidence and other evidence that is already visible in this run. If the visible evidence is insufficient for a requested claim, report an explicit blocker or evidence gap instead of estimating, inventing, or using generic knowledge.",...o?{observedEvidence:o}:{},error:previewError(n)})})}if(/Received tool input did not match expected schema|Invalid input:/iu.test(n))return new t({tool_call_id:r.toolCall?.id??`stable-harness-${o}-argument-error`,name:o,status:"error",content:JSON.stringify({status:"tool_argument_error",toolId:o,instruction:"The upstream builtin tool rejected these arguments. Fix the tool arguments according to the tool schema, or choose a more appropriate available tool.",error:previewError(n)})})}(i,g,r,e);if(o)return emitToolEvent(i,g,"agent.tool.result",v.toolCall?.args,{output:o.content}),o;throw emitToolEvent(i,g,"agent.tool.result",v.toolCall?.args,{error:formatError(e)}),e}}}}function builtinToolMessage(e,o,r){return new t({tool_call_id:e.toolCall?.id??`stable-harness-${o}-repeat-guard`,name:o,content:r})}function emitToolEvent(t,e,o,r,i={}){"string"==typeof i.output&&g(t,t.agent.id,e,i.output),t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",eventGroup:"tool_execution",eventType:"agent.tool.start"===o?"deepagents.tool_execution.start":"deepagents.tool_execution.result",phase:o,toolId:e,..."agent.tool.start"===o?{args:r}:{},...i,..."string"==typeof i.output?d(i.output):{},...b(e,o,r)}})}function isTaskVisible(t){const e=function readConfigRecord(t,e){const o=isRecord(t)?t:{};return isRecord(o[e])?o[e]:void 0}(t.agent.config,"builtinTools")?.modelExposed;return!1!==e&&(!Array.isArray(e)||e.includes("task"))}function isModelVisibleBuiltin(t,e){return(!n(t)||!s(e))&&("task"!==e||isTaskVisible(t))}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function formatError(t){return t instanceof Error?t.message:String(t)}function previewError(t){const e=t.replace(/\s+/gu," ").trim();return e.length>800?`${e.slice(0,797)}...`:e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AIMessage as e}from"@langchain/core/messages";export function createRawToolCallParserMiddleware(t){return{name:"StableHarnessRawToolCallParser",async wrapModelCall(n,
|
|
1
|
+
import{AIMessage as e}from"@langchain/core/messages";export function createRawToolCallParserMiddleware(t){return{name:"StableHarnessRawToolCallParser",async wrapModelCall(n,o){const r=await o(n);if(!function rawToolCallParsingEnabled(e){const t=isRecord(e.workspace.runtime.recovery)?e.workspace.runtime.recovery:{};return!0===(isRecord(t.toolCall)?t.toolCall:{}).enabled}(t))return r;const a=function parseRawToolCallResponse(t,n){if(0===n.size||!function isModelResponse(e){return isRecord(e)}(t)||function hasToolCalls(e){return Array.isArray(e.tool_calls)&&e.tool_calls.length>0}(t))return;const o=function readContentText(e){return"string"==typeof e?e.trim()?e:void 0:Array.isArray(e)&&e.map(e=>isRecord(e)&&"string"==typeof e.text?e.text:"").join("\n").trim()||void 0}(t.content);if(!o)return;const r=function readRawToolCalls(e,t){const n=readXmlToolCalls(e,t);if(n.length>0)return n;const o=function stripToolMarkup(e){return e.replace(/^\s*```(?:json)?/iu,"").replace(/```\s*$/iu,"").replace(/^\s*<\s*tool_call[^>]*>\s*/iu,"").replace(/\s*<\s*\/\s*tool_call\s*>\s*$/iu,"").trim()}(e),r=readXmlToolCalls(o,t);if(r.length>0)return r;const a=function readFunctionToolCalls(e,t){const n=[];for(const o of t){const t=new RegExp(`(?:^|\\s)${escapeRegexp(o)}\\s*\\(([^)]*)\\)`,"giu");for(const r of e.matchAll(t)){const e=readFunctionArgs(r[1]??"");e&&Object.keys(e).length>0&&n.push({id:`stable-harness-${o}-${Date.now().toString(36)}`,name:o,args:e})}}return n}(o,t);return a.length>0?a:function parseJsonObjects(e){const t=[];let n=e.indexOf("{");for(;n>=0;){const o=readBalancedJsonObject(e,n);if(o){try{const e=JSON.parse(o);isRecord(e)&&t.push(e)}catch{}n=e.indexOf("{",n+o.length)}else n=e.indexOf("{",n+1)}return t}(o).flatMap(e=>function readJsonToolCall(e,t){const n=function readNestedToolCall(e,t){const n=Object.entries(e);if(1!==n.length)return;const[o,r]=n[0];return t.has(o)&&isRecord(r)?{id:`stable-harness-${o}-${Date.now().toString(36)}`,name:o,args:r}:void 0}(e,t);if(n)return n;const o=readString(e.name)??readString(e.tool_name)??readString(e.tool)??readString(e.type),r=t.has(o??"")?o:singleToolName(t),a=function readArgs(e){return isRecord(e.arguments)?e.arguments:isRecord(e.parameters)?e.parameters:isRecord(e.args)?e.args:"args"in e&&void 0!==e.args?{args:e.args}:void 0}(e)??function readInlineArgs(e){const t=Object.fromEntries(Object.entries(e).filter(([e])=>!["name","tool_name","tool","type"].includes(e)));return Object.keys(t).length>0?t:void 0}(e);return r&&t.has(r)&&a?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:a}:void 0}(e,t)??[])}(o,n);return 0!==r.length?new e({content:"",id:"string"==typeof t.id?t.id:void 0,name:"string"==typeof t.name?t.name:void 0,additional_kwargs:isRecord(t.additional_kwargs)?t.additional_kwargs:{},response_metadata:isRecord(t.response_metadata)?t.response_metadata:{},tool_calls:r.map(e=>({id:e.id,name:e.name,args:e.args,type:"tool_call"}))}):void 0}(r,function visibleToolNames(e){return new Set((e.tools??[]).map(e=>e.name).filter(e=>"string"==typeof e&&e.length>0))}(n));return a??r}}}function readXmlToolCalls(e,t){const n=[],o=/<\s*(tool_call|tool_code)\b[^>]*>(?:[\s\S]*?<\s*\/\s*\1\s*>)?/giu;for(const r of e.matchAll(o)){const e=readXmlToolCall(r[0],t);e&&n.push(e)}return n}function readXmlToolCall(e,t){const n=function readToolCallAttributes(e){const t=/<\s*(?:tool_call|tool_code)\b([^>]*)>/iu.exec(e);if(!t)return;const n=[...t[1].matchAll(/([a-zA-Z_][\w.-]*)\s*=\s*"([^"]*)"/gu)];return n.length>0?Object.fromEntries(n.map(e=>[e[1],e[2]])):void 0}(e),o=readString(n?.name)??readString(n?.tool_name)??readString(n?.tool)??readXmlTag(e,"tool_name")??readXmlTag(e,"name")??readXmlTag(e,"tool")??function readBareXmlToolName(e,t){const n=readBareXmlToolBody(e),o=n?.trim();return o&&t.has(o)?o:void 0}(e,t),r=t.has(o??"")?o:singleToolName(t);if(!r&&!o&&t.has("task")){const t=readBareXmlToolBody(e);if(t)return{id:`stable-harness-task-${Date.now().toString(36)}`,name:"task",args:{input:t}}}if(!r||!t.has(r))return;const a=readXmlTag(e,"tool_args")??readXmlTag(e,"args")??readXmlTag(e,"arguments"),s=a?function readXmlArgs(e){const t=[...e.matchAll(/<\s*([a-zA-Z_][\w.-]*)\s*>([\s\S]*?)<\s*\/\s*\1\s*>/gu)];if(0===t.length){const t=e.trim();return t?{input:t}:void 0}return Object.fromEntries(t.map(e=>[e[1],e[2].trim()]))}(a):function readAttributeArgs(e){if(!e)return;const t=Object.fromEntries(Object.entries(e).filter(([e])=>!["name","tool_name","tool","type"].includes(e)));return Object.keys(t).length>0?t:void 0}(n);return!s&&o?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:{}}:s&&0!==Object.keys(s).length?{id:`stable-harness-${r}-${Date.now().toString(36)}`,name:r,args:s}:void 0}function readXmlTag(e,t){const n=new RegExp(`<\\s*${t}\\s*>([\\s\\S]*?)<\\s*\\/\\s*${t}\\s*>`,"iu").exec(e);return n?.[1]?.trim()||void 0}function readBareXmlToolBody(e){return function readXmlElementBody(e,t){const n=function readOpeningTag(e,t){for(const n of t){const t=e.indexOf(`<${n}`);if(t<0)continue;const o=e.indexOf(">",t+n.length+1);if(o>=0)return{end:o+1}}}(e,t);if(!n)return;const o=function findClosingTag(e,t,n){let o;for(const r of t){const t=[`</${r}>`,`</ ${r}>`];for(const r of t){const t=e.indexOf(r,n);t>=0&&(void 0===o||t<o)&&(o=t)}}return o}(e,t,n.end);return void 0===o?void 0:e.slice(n.end,o)}(e,["tool_call","tool_code"])?.trim()||void 0}function readFunctionArgs(e){const t=[...e.matchAll(/([a-zA-Z_][\w.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^,\s]+))/gu)];return t.length>0?Object.fromEntries(t.map(e=>[e[1],e[2]??e[3]??e[4]??""])):void 0}function readBalancedJsonObject(e,t){let n=0,o=!1,r=!1;for(let a=t;a<e.length;a+=1){const s=e[a];if(o)r="\\"===s&&!r,'"'!==s||r||(o=!1),"\\"!==s&&(r=!1);else if('"'===s&&(o=!0),"{"===s&&(n+=1),"}"===s&&(n-=1),0===n)return e.slice(t,a+1)}}function singleToolName(e){return 1===e.size?[...e][0]:void 0}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export async function reviewWithLlm(e){if(!e.model||"llm"!==e.policy.reviewer?.mode)return;const t="planning"===e.phase?e.policy.reviewer.planningPrompt??function defaultPlanningPrompt(){return["You are Stable Harness planning quality review.","Review only generic agent-work quality: goal coverage, executable steps, and declared inventory fit.",'Do not invent a domain workflow. Return only JSON: {"verdict":"pass|revise_plan|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}():e.policy.reviewer.executionPrompt??function defaultExecutionPrompt(){return["You are Stable Harness execution evidence review.","Review only whether execution evidence supports the final answer and whether unresolved blockers or gaps remain.",'Do not answer the user request. Return only JSON: {"verdict":"pass|continue_react|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}();return function parseReviewResult(e){const t=function readResponseText(e){if("string"==typeof e)return e;if(!isRecord(e))return;if("string"==typeof e.content)return e.content;const t=isRecord(e.message)?e.message:void 0;return"string"==typeof t?.content?t.content:void 0}(e),
|
|
1
|
+
export async function reviewWithLlm(e){if(!e.model||"llm"!==e.policy.reviewer?.mode)return;const t="planning"===e.phase?e.policy.reviewer.planningPrompt??function defaultPlanningPrompt(){return["You are Stable Harness planning quality review.","Review only generic agent-work quality: goal coverage, executable steps, and declared inventory fit.",'Do not invent a domain workflow. Return only JSON: {"verdict":"pass|revise_plan|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}():e.policy.reviewer.executionPrompt??function defaultExecutionPrompt(){return["You are Stable Harness execution evidence review.","Review only whether execution evidence supports the final answer and whether unresolved blockers or gaps remain.",'Do not answer the user request. Return only JSON: {"verdict":"pass|continue_react|blocked","issues":[{"code":"...","message":"...","recoverable":true}]}'].join("\n")}();return function parseReviewResult(e){const t=function readResponseText(e){if("string"==typeof e)return e;if(!isRecord(e))return;if("string"==typeof e.content)return e.content;const t=isRecord(e.message)?e.message:void 0;return"string"==typeof t?.content?t.content:void 0}(e),r="string"==typeof t?function parseJsonRecord(e){const t=e.trim().replace(/^```(?:json)?\s*/iu,"").replace(/\s*```$/u,"");try{const e=JSON.parse(t);return isRecord(e)?e:void 0}catch{return}}(t):isRecord(e)?e:void 0,n=function readVerdict(e){return"pass"===e||"revise_plan"===e||"continue_react"===e||"blocked"===e?e:void 0}(r?.verdict);if(r&&n)return{verdict:n,issues:readIssues(r.issues)}}(await e.model.invoke([{role:"system",content:t},{role:"user",content:JSON.stringify(buildReviewContext(e.review),null,2)}],function structuredJsonOptions(e){return{response_format:{type:"json_schema",json_schema:{name:`stable_harness_${e}_quality_review`,strict:!0,schema:{type:"object",properties:{verdict:{type:"string",enum:"planning"===e?["pass","revise_plan","blocked"]:["pass","continue_react","blocked"]},issues:{type:"array",items:{type:"object",properties:{code:{type:"string"},message:{type:"string"},recoverable:{type:"boolean"}},required:["code","message","recoverable"],additionalProperties:!1}}},required:["verdict","issues"],additionalProperties:!1}}}}}(e.phase)))}function buildReviewContext(e){return{userRequest:e.request.input,agent:{id:e.agent.id,tools:e.agent.tools,skills:e.agent.skills??[],subagents:e.agent.subagents},finalOutput:e.output?.text,events:e.events.slice(-30).map(projectEvent)}}function projectEvent(e){return"runtime.adapter.event"===e.type?{type:e.type,event:e.event}:{...e}}function readIssues(e){return Array.isArray(e)?e.flatMap(e=>isRecord(e)&&"string"==typeof e.code&&"string"==typeof e.message?[{code:e.code,message:e.message,recoverable:!1!==e.recoverable}]:[]):[]}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -33,7 +33,7 @@ export type RuntimeToolGatewayTool = {
|
|
|
33
33
|
schema?: unknown;
|
|
34
34
|
};
|
|
35
35
|
export type RuntimeToolRepairModel = {
|
|
36
|
-
invoke(input: unknown): Promise<unknown> | unknown;
|
|
36
|
+
invoke(input: unknown, options?: unknown): Promise<unknown> | unknown;
|
|
37
37
|
};
|
|
38
38
|
export type RuntimeToolGateway = {
|
|
39
39
|
get(toolId: string): RuntimeToolGatewayTool | undefined;
|