stable-harness 0.0.24 → 0.0.25

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.
@@ -0,0 +1,15 @@
1
+ # Inventory Repair Coverage
2
+
3
+ Stable Harness may repair or block only typed runtime selections and observed upstream call boundaries that already cross the runtime policy layer. It must not repair free-form user intent, prompt wording, or downstream domain workflows.
4
+
5
+ | Boundary | Owner | Inventory Source | Runtime Action | Notes |
6
+ | --- | --- | --- | --- | --- |
7
+ | Explicit agent id | stable runtime policy | `workspace.agents` | Repair or block requested agent id before adapter dispatch | Applies only to typed `request.agentId`. |
8
+ | Explicit workflow route | stable runtime policy | `runtime.workflowRouting.routes` | Repair or block route id before workflow dispatch | Does not infer workflows from natural language. |
9
+ | Explicit workflow id | stable runtime policy | `workspace.workflows` | Repair or block workflow id before workflow adapter dispatch | Adapter still owns workflow execution. |
10
+ | Direct tool call | stable runtime policy | selected agent `tools` plus tool gateway registry | Repair or block tool id before gateway invoke | Tool arguments remain governed by gateway schema policy. |
11
+ | DeepAgents observed `task` call | stable runtime policy over upstream boundary | selected agent `subagents` and `builtinTools` policy | Repair or block the observed task target | DeepAgents still owns delegation semantics. |
12
+ | LangGraph skill resolver | protocol adapter | `workspace.skills` referenced by workflow nodes | Repair or block skill id during node resolution | LangGraph still owns graph execution. |
13
+ | `write_todos` normalization | upstream adapter compatibility | DeepAgents builtin schema shape | Shape/schema repair only | Not plan-quality evaluation or evidence synthesis. |
14
+
15
+ Diagnostics are emitted as `runtime.inventory.repair` events for native runtime boundaries and as adapter events with `phase: "inventory.repair"` for observed adapter boundaries. Trace projection uses the same `runtime.inventory.repair` label so operators can inspect the original selection, repaired selection, candidate inventory, owner, layer, and block reason when present.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stable-harness",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "description": "Stable application runtime and operator control plane for agent workspaces.",
6
6
  "license": "Apache-2.0",
@@ -1 +1 @@
1
- import{realpathSync as e}from"node:fs";import{repairCallSelection as t}from"@botbotgo/better-call";import{ToolMessage as o}from"@langchain/core/messages";import{normalizeArgsRecord as n}from"./builtin-args.js";import{repairBuiltinToolRequest as r}from"./builtin-call-repair.js";import{afterToolInvoke as i,beforeToolInvoke as a,createToolRepeatState as s,stringifyDeepAgentResult as l,toolControlProjection as u}from"./gateway-tools.js";import{observedToolEvidence as c,recordObservedToolEvidence as d}from"./gateway/tool-evidence.js";import{validateSkillFileBuiltinCall as g}from"./skill-file-policy.js";import{filterRepeatLimitedTools as p}from"./tool-repeat-visibility.js";import{traceProjectionForBuiltinTool as f}from"./trace-projection.js";const m=new Set(["ls","read_file","write_file","edit_file","glob","grep"]),h=new Set(["write_todos","read_todos","task","execute",...m]);export function createBuiltinToolPolicyMiddleware(e,t={}){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(o,n){const r=Array.isArray(o.tools)?p(o.tools.filter(t=>!function hasHiddenBuiltins(e){return isFilesystemDisabled(e)||!isTaskVisible(e)}(e)||isModelVisibleBuiltin(e,t.name)),t.repeatState):o.tools,i=function normalizeToolChoice(e,t,o){return"required"===t?o&&o.length>0?t:"auto":function isForcedHiddenTool(e,t){return"string"==typeof t?.function?.name&&!isModelVisibleBuiltin(e,t.function.name)}(e,t)?"auto":t}(e,o.toolChoice,r);return n({...o,tools:r,toolChoice:i})}}}export function validateFilesystemBuiltinCall(e,t,n){if(isFilesystemDisabled(e)&&m.has(t))return new o({tool_call_id:n.toolCall?.id??`stable-harness-${t}-policy`,name:t,content:`Filesystem builtin tool '${t}' is disabled for this agent. Do not retry filesystem tools; use the agent's registered workspace tools and already collected evidence instead.`})}export function createObserverMiddleware(e,u={}){const d=u.repeatState??s(e.workspace.runtime.toolGateway);return{name:"StableHarnessObserver",async wrapToolCall(s,p){const f=s.toolCall?.name;if(!f||!h.has(f))return p(s);const m=await r({toolId:f,request:s,workspaceRoot:e.workspace.root});emitToolEvent(e,f,"agent.tool.start",m.toolCall?.args);const y="task"===f?await async function repairTaskCall(e,r){const i=function allowedTaskTypes(e){const t=readConfigRecord(e.agent.config,"deepagents");if(!0===t?.generalPurposeAgent)return;const o=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1===o?[]:Array.isArray(o)?o.includes("task")?e.agent.subagents:[]:0===e.agent.subagents.length?[]:void 0}(e);if(void 0===i)return{request:r};const a=n(r.toolCall?.args),s=function readTaskSubagentType(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)}(a);if(s&&i.includes(s))return{request:r};const l=await t({call:{id:s,args:a},candidates:taskCallCandidates(e,i),mode:"repair"});if(l.ok){const e={...a,...l.args,subagent_type:l.candidateId};return{request:{...r,toolCall:{...r.toolCall,args:e}}}}const u=s?`: ${s}`:"",c=i.length>0?i.join(", "):"none";return{request:r,blocked:new o({tool_call_id:r.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:[`Task delegation target is not in the workspace inventory${u}. Allowed task targets: ${c}.`,"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(" ")})}}(e,m):{request:m},b=y.request,v=y.blocked;if(v)return emitToolEvent(e,f,"agent.tool.result",b.toolCall?.args,{output:v.content}),v;const w=validateFilesystemBuiltinCall(e,f,b);if(w)return emitToolEvent(e,f,"agent.tool.result",b.toolCall?.args,{output:w.content}),w;const k=g(e,f,b);if(k)return emitToolEvent(e,f,"agent.tool.result",b.toolCall?.args,{output:k.content}),k;try{const t=d?a(f,b.toolCall?.args,d):void 0;if(t)return emitToolEvent(e,f,"agent.tool.result",b.toolCall?.args,{output:t.eventOutput}),builtinToolMessage(s,f,t.modelOutput);const o=await p(b),n=function observedToolOutput(e,t,o){return"write_todos"===e?JSON.stringify({status:"recorded",args:t.toolCall?.args}):l(o)}(f,b,o),r=d?i(f,b.toolCall?.args,n,o,d):{};return emitToolEvent(e,f,"agent.tool.result",b.toolCall?.args,{output:r.eventOutput??n}),u.observedToolIds?.add(f),void 0===r.modelOutput?o:builtinToolMessage(s,f,r.modelOutput)}catch(t){const n=function recoverableBuiltinToolError(e,t,n,r){const i=formatError(r);if("task"===t&&/repeat limit reached for tool/iu.test(i)){const t=function formatObservedEvidence(e){const t=c(e);if(0===t.length)return"";const o=t.map(e=>[`Agent: ${e.agentId}`,`Tool: ${e.toolId}`,e.output].join("\n")).join("\n\n---\n\n");return o.length>12e3?`${o.slice(0,12e3)}\n[truncated]`:o}(e);return new o({tool_call_id:n.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.",...t?{observedEvidence:t}:{},error:previewError(i)})})}if(/Received tool input did not match expected schema|Invalid input:/iu.test(i))return new o({tool_call_id:n.toolCall?.id??`stable-harness-${t}-argument-error`,name:t,status:"error",content:JSON.stringify({status:"tool_argument_error",toolId:t,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(i)})})}(e,f,s,t);if(n)return emitToolEvent(e,f,"agent.tool.result",m.toolCall?.args,{output:n.content}),n;throw emitToolEvent(e,f,"agent.tool.result",m.toolCall?.args,{error:formatError(t)}),t}}}}function builtinToolMessage(e,t,n){return new o({tool_call_id:e.toolCall?.id??`stable-harness-${t}-repeat-guard`,name:t,content:n})}export function resolveFilesystemPermissions(e,t){const o=readConfigRecord(t?.config,"builtinTools"),n=[];if(n.push(...function skillReadPermissions(e,t){const o=[...new Set((t?.skills??[]).flatMap(t=>function skillReadPaths(e,t){return t?[...new Set([t,canonicalPath(t),backendSkillPath(e,t)])].flatMap(e=>function skillReadPathCandidates(e){const t=e.replace(/\/+$/u,""),o=t.endsWith("/SKILL.md")?t.slice(0,-9):t,n=function parentPath(e){const t=e.lastIndexOf("/");return t>0?e.slice(0,t):void 0}(o);return[t,o,`${o}/**`,...n?[n,`${n}/**`]:[]]}(e)):[]}(e.workspace.root,e.workspace.skills.get(t)?.path)).filter(e=>e.startsWith("/")))];return o.length>0?[{operations:["read"],paths:o,mode:"allow"}]:[]}(e,t)),!1!==o?.filesystem){if(deepagentsMemoryWritable(e))return n.length>0?n:void 0}else n.push({operations:["read"],paths:["/memories/**"],mode:"allow"}),n.push({operations:["read","write"],paths:["/**"],mode:"deny"});return deepagentsMemoryWritable(e)||n.push({operations:["write"],paths:["/memories/**"],mode:"deny"}),n.length>0?n:void 0}function emitToolEvent(e,t,o,n,r={}){"string"==typeof r.output&&d(e,e.agent.id,t,r.output),e.emit({type:"runtime.adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,event:{adapter:"deepagents",phase:o,toolId:t,..."agent.tool.start"===o?{args:n}:{},...r,..."string"==typeof r.output?u(r.output):{},...f(t,o,n)}})}function backendSkillPath(e,t){const o=function pathRelative(e,t){const o=e.split("/").filter(Boolean),n=t.split("/").filter(Boolean);if(!(n.length<o.length)){for(let e=0;e<o.length;e+=1)if(o[e]!==n[e])return;return n.slice(o.length).join("/")}}(e,t);return void 0===o?t:`/${o.split("/").filter(Boolean).join("/")}`}function canonicalPath(t){try{return e.native(t)}catch{return t}}function deepagentsMemoryWritable(e){const t=readConfigRecord(e.workspace.runtime.memory,"deepagentsMem");return!1!==t?.write}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"},description:{type:"string"}},required:["description"],additionalProperties:!0}}))}function isFilesystemDisabled(e){const t=readConfigRecord(e.agent.config,"builtinTools");return!1===t?.filesystem}function isTaskVisible(e){const t=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1!==t&&(!Array.isArray(t)||t.includes("task"))}function isModelVisibleBuiltin(e,t){return(!isFilesystemDisabled(e)||!function isFilesystemTool(e){return"string"==typeof e&&m.has(e)}(t))&&("task"!==t||isTaskVisible(e))}function readConfigRecord(e,t){const o=isRecord(e)?e:{};return isRecord(o[t])?o[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)}function formatError(e){return e instanceof Error?e.message:String(e)}function previewError(e){const t=e.replace(/\s+/gu," ").trim();return t.length>800?`${t.slice(0,797)}...`:t}
1
+ import{realpathSync as e}from"node:fs";import{repairCallSelection as t}from"@botbotgo/better-call";import{ToolMessage as o}from"@langchain/core/messages";import{normalizeArgsRecord as n}from"./builtin-args.js";import{repairBuiltinToolRequest as r}from"./builtin-call-repair.js";import{afterToolInvoke as i,beforeToolInvoke as a,createToolRepeatState as s,stringifyDeepAgentResult as l,toolControlProjection as d}from"./gateway-tools.js";import{observedToolEvidence as u,recordObservedToolEvidence as c}from"./gateway/tool-evidence.js";import{validateSkillFileBuiltinCall as p}from"./skill-file-policy.js";import{filterRepeatLimitedTools as g}from"./tool-repeat-visibility.js";import{traceProjectionForBuiltinTool as f}from"./trace-projection.js";const m=new Set(["ls","read_file","write_file","edit_file","glob","grep"]),h=new Set(["write_todos","read_todos","task","execute",...m]);export function createBuiltinToolPolicyMiddleware(e,t={}){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(o,n){const r=Array.isArray(o.tools)?g(o.tools.filter(t=>!function hasHiddenBuiltins(e){return isFilesystemDisabled(e)||!isTaskVisible(e)}(e)||isModelVisibleBuiltin(e,t.name)),t.repeatState):o.tools,i=function normalizeToolChoice(e,t,o){return"required"===t?o&&o.length>0?t:"auto":function isForcedHiddenTool(e,t){return"string"==typeof t?.function?.name&&!isModelVisibleBuiltin(e,t.function.name)}(e,t)?"auto":t}(e,o.toolChoice,r);return n({...o,tools:r,toolChoice:i})}}}export function validateFilesystemBuiltinCall(e,t,n){if(isFilesystemDisabled(e)&&m.has(t))return new o({tool_call_id:n.toolCall?.id??`stable-harness-${t}-policy`,name:t,content:`Filesystem builtin tool '${t}' is disabled for this agent. Do not retry filesystem tools; use the agent's registered workspace tools and already collected evidence instead.`})}export function createObserverMiddleware(e,d={}){const c=d.repeatState??s(e.workspace.runtime.toolGateway);return{name:"StableHarnessObserver",async wrapToolCall(s,g){const f=s.toolCall?.name;if(!f||!h.has(f))return g(s);const m=await r({toolId:f,request:s,workspaceRoot:e.workspace.root});emitToolEvent(e,f,"agent.tool.start",m.toolCall?.args);const y="task"===f?await async function repairTaskCall(e,r){const i=function allowedTaskTypes(e){const t=readConfigRecord(e.agent.config,"deepagents");if(!0===t?.generalPurposeAgent)return;const o=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1===o?[]:Array.isArray(o)?o.includes("task")?e.agent.subagents:[]:0===e.agent.subagents.length?[]:void 0}(e);if(void 0===i)return{request:r};const a=n(r.toolCall?.args),s=function readTaskSubagentType(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)}(a);if(s&&i.includes(s))return{request:r};const l=await t({call:{id:s,args:a},candidates:taskCallCandidates(e,i),mode:"repair"});if(l.ok){emitInventoryRepair(e,"repaired",s,l.candidateId,i);const t={...a,...l.args,subagent_type:l.candidateId};return{request:{...r,toolCall:{...r.toolCall,args:t}}}}emitInventoryRepair(e,"blocked",s,void 0,i,l.reason);const d=s?`: ${s}`:"",u=i.length>0?i.join(", "):"none";return{request:r,blocked:new o({tool_call_id:r.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:[`Task delegation target is not in the workspace inventory${d}. 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(" ")})}}(e,m):{request:m},v=y.request,b=y.blocked;if(b)return emitToolEvent(e,f,"agent.tool.result",v.toolCall?.args,{output:b.content}),b;const k=validateFilesystemBuiltinCall(e,f,v);if(k)return emitToolEvent(e,f,"agent.tool.result",v.toolCall?.args,{output:k.content}),k;const w=p(e,f,v);if(w)return emitToolEvent(e,f,"agent.tool.result",v.toolCall?.args,{output:w.content}),w;try{const t=c?a(f,v.toolCall?.args,c):void 0;if(t)return emitToolEvent(e,f,"agent.tool.result",v.toolCall?.args,{output:t.eventOutput}),builtinToolMessage(s,f,t.modelOutput);const o=await g(v),n=function observedToolOutput(e,t,o){return"write_todos"===e?JSON.stringify({status:"recorded",args:t.toolCall?.args}):l(o)}(f,v,o),r=c?i(f,v.toolCall?.args,n,o,c):{};return emitToolEvent(e,f,"agent.tool.result",v.toolCall?.args,{output:r.eventOutput??n}),d.observedToolIds?.add(f),void 0===r.modelOutput?o:builtinToolMessage(s,f,r.modelOutput)}catch(t){const n=function recoverableBuiltinToolError(e,t,n,r){const i=formatError(r);if("task"===t&&/repeat limit reached for tool/iu.test(i)){const t=function formatObservedEvidence(e){const t=u(e);if(0===t.length)return"";const o=t.map(e=>[`Agent: ${e.agentId}`,`Tool: ${e.toolId}`,e.output].join("\n")).join("\n\n---\n\n");return o.length>12e3?`${o.slice(0,12e3)}\n[truncated]`:o}(e);return new o({tool_call_id:n.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.",...t?{observedEvidence:t}:{},error:previewError(i)})})}if(/Received tool input did not match expected schema|Invalid input:/iu.test(i))return new o({tool_call_id:n.toolCall?.id??`stable-harness-${t}-argument-error`,name:t,status:"error",content:JSON.stringify({status:"tool_argument_error",toolId:t,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(i)})})}(e,f,s,t);if(n)return emitToolEvent(e,f,"agent.tool.result",m.toolCall?.args,{output:n.content}),n;throw emitToolEvent(e,f,"agent.tool.result",m.toolCall?.args,{error:formatError(t)}),t}}}}function builtinToolMessage(e,t,n){return new o({tool_call_id:e.toolCall?.id??`stable-harness-${t}-repeat-guard`,name:t,content:n})}export function resolveFilesystemPermissions(e,t){const o=readConfigRecord(t?.config,"builtinTools"),n=[];if(n.push(...function skillReadPermissions(e,t){const o=[...new Set((t?.skills??[]).flatMap(t=>function skillReadPaths(e,t){return t?[...new Set([t,canonicalPath(t),backendSkillPath(e,t)])].flatMap(e=>function skillReadPathCandidates(e){const t=e.replace(/\/+$/u,""),o=t.endsWith("/SKILL.md")?t.slice(0,-9):t,n=function parentPath(e){const t=e.lastIndexOf("/");return t>0?e.slice(0,t):void 0}(o);return[t,o,`${o}/**`,...n?[n,`${n}/**`]:[]]}(e)):[]}(e.workspace.root,e.workspace.skills.get(t)?.path)).filter(e=>e.startsWith("/")))];return o.length>0?[{operations:["read"],paths:o,mode:"allow"}]:[]}(e,t)),!1!==o?.filesystem){if(deepagentsMemoryWritable(e))return n.length>0?n:void 0}else n.push({operations:["read"],paths:["/memories/**"],mode:"allow"}),n.push({operations:["read","write"],paths:["/**"],mode:"deny"});return deepagentsMemoryWritable(e)||n.push({operations:["write"],paths:["/memories/**"],mode:"deny"}),n.length>0?n:void 0}function emitToolEvent(e,t,o,n,r={}){"string"==typeof r.output&&c(e,e.agent.id,t,r.output),e.emit({type:"runtime.adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,event:{adapter:"deepagents",phase:o,toolId:t,..."agent.tool.start"===o?{args:n}:{},...r,..."string"==typeof r.output?d(r.output):{},...f(t,o,n)}})}function backendSkillPath(e,t){const o=function pathRelative(e,t){const o=e.split("/").filter(Boolean),n=t.split("/").filter(Boolean);if(!(n.length<o.length)){for(let e=0;e<o.length;e+=1)if(o[e]!==n[e])return;return n.slice(o.length).join("/")}}(e,t);return void 0===o?t:`/${o.split("/").filter(Boolean).join("/")}`}function canonicalPath(t){try{return e.native(t)}catch{return t}}function deepagentsMemoryWritable(e){const t=readConfigRecord(e.workspace.runtime.memory,"deepagentsMem");return!1!==t?.write}function emitInventoryRepair(e,t,o,n,r,i){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:o,repairedId:n,candidateIds:r,reason:i}}})}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"},description:{type:"string"}},required:["description"],additionalProperties:!0}}))}function isFilesystemDisabled(e){const t=readConfigRecord(e.agent.config,"builtinTools");return!1===t?.filesystem}function isTaskVisible(e){const t=readConfigRecord(e.agent.config,"builtinTools")?.modelExposed;return!1!==t&&(!Array.isArray(t)||t.includes("task"))}function isModelVisibleBuiltin(e,t){return(!isFilesystemDisabled(e)||!function isFilesystemTool(e){return"string"==typeof e&&m.has(e)}(t))&&("task"!==t||isTaskVisible(e))}function readConfigRecord(e,t){const o=isRecord(e)?e:{};return isRecord(o[t])?o[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)}function formatError(e){return e instanceof Error?e.message:String(e)}function previewError(e){const t=e.replace(/\s+/gu," ").trim();return t.length>800?`${t.slice(0,797)}...`:t}
@@ -1 +1 @@
1
- import{readFile as e}from"node:fs/promises";import r from"node:path";import{repairRuntimeSelection as t}from"@stable-harness/core";export function createRegistrySkillResolverProvider(e={}){return{name:"registry-resolver",resolve:r=>async function resolveRegistrySkill(e,r){const o=await async function resolveWorkspaceSkill(e){const r=e.workspace.skills.get(e.id);if(r)return r;const o=await t({id:e.id,candidates:[...e.workspace.skills.values()].map(e=>({id:e.id,description:e.description}))});return o.ok?e.workspace.skills.get(o.id):void 0}(e);if(!o)throw new Error(`LangGraph skill resolver cannot find skill ${e.id}`);return{id:o.id,path:o.path,...o.description?{description:o.description}:{},allowedTools:o.allowedTools,...!1===r.includeContent?{}:{content:await readSkillContent(o,r.maxBytes)}}}(r,e)}}export function createDeepAgentsMiddlewareSkillProvider(e={}){return{name:"deepagents-middleware",async createMiddleware(r){const t=await async function loadDeepAgentsSkillsModule(e){return e.importDeepAgents?e.importDeepAgents():import("deepagents")}(e),o=t.createSkillsMiddleware;if("function"!=typeof o)throw new Error("deepagents does not export createSkillsMiddleware");return o({backend:e.backend??createDeepAgentsFilesystemBackend(t,r.workspace.root),sources:e.sources??deriveDeepAgentsSkillSources(r)})}}}export function resolveSkillProvider(e){if(!1!==e.skillProvider)return e.skillProvider??createRegistrySkillResolverProvider()}async function readSkillContent(r,t=1048576){const o=await e(r.path,"utf8");if(Buffer.byteLength(o,"utf8")>t)throw new Error(`Skill ${r.id} exceeds registry resolver size limit of ${t} bytes`);return o}function createDeepAgentsFilesystemBackend(e,r){if("function"!=typeof e.FilesystemBackend)throw new Error("deepagents does not export FilesystemBackend");return new e.FilesystemBackend({rootDir:r})}function deriveDeepAgentsSkillSources(e){const t=new Set([...(o=e.agent,o?.skills??[]),...skillIdsFromWorkflow(e)]);var o;const i=new Set;for(const o of t){const t=e.workspace.skills.get(o);t&&i.add(toPosixPath(r.relative(e.workspace.root,r.dirname(r.dirname(t.path)))))}return[...i].filter(e=>e&&!e.startsWith(".."))}function skillIdsFromWorkflow(e){return e.workflow.nodes.map(e=>e.use.match(/^skills\.([^./][^.]*)$/u)?.[1]).filter(e=>Boolean(e))}function toPosixPath(e){return e.split(r.sep).join("/")}
1
+ import{readFile as e}from"node:fs/promises";import r from"node:path";import{repairRuntimeSelection as t}from"@stable-harness/core";export function createRegistrySkillResolverProvider(e={}){return{name:"registry-resolver",resolve:r=>async function resolveRegistrySkill(e,r){const i=await async function resolveWorkspaceSkill(e){const r=e.workspace.skills.get(e.id);if(r)return r;const i=await t({id:e.id,candidates:[...e.workspace.skills.values()].map(e=>({id:e.id,description:e.description}))});return e.emit({phase:"inventory.repair",status:i.ok?"repaired":"blocked",diagnostic:{layer:"skill",owner:"protocol_adapter",originalId:i.diagnostics?.originalId??e.id,repairedId:i.ok?i.id:i.diagnostics?.repairedId,candidateIds:[...e.workspace.skills.keys()],...i.ok?{}:{reason:i.reason},matchSource:i.diagnostics?.matchSource,confidence:i.diagnostics?.confidence}}),i.ok?e.workspace.skills.get(i.id):void 0}(e);if(!i)throw new Error(`LangGraph skill resolver cannot find skill ${e.id}`);return{id:i.id,path:i.path,...i.description?{description:i.description}:{},allowedTools:i.allowedTools,...!1===r.includeContent?{}:{content:await readSkillContent(i,r.maxBytes)}}}(r,e)}}export function createDeepAgentsMiddlewareSkillProvider(e={}){return{name:"deepagents-middleware",async createMiddleware(r){const t=await async function loadDeepAgentsSkillsModule(e){return e.importDeepAgents?e.importDeepAgents():import("deepagents")}(e),i=t.createSkillsMiddleware;if("function"!=typeof i)throw new Error("deepagents does not export createSkillsMiddleware");return i({backend:e.backend??createDeepAgentsFilesystemBackend(t,r.workspace.root),sources:e.sources??deriveDeepAgentsSkillSources(r)})}}}export function resolveSkillProvider(e){if(!1!==e.skillProvider)return e.skillProvider??createRegistrySkillResolverProvider()}async function readSkillContent(r,t=1048576){const i=await e(r.path,"utf8");if(Buffer.byteLength(i,"utf8")>t)throw new Error(`Skill ${r.id} exceeds registry resolver size limit of ${t} bytes`);return i}function createDeepAgentsFilesystemBackend(e,r){if("function"!=typeof e.FilesystemBackend)throw new Error("deepagents does not export FilesystemBackend");return new e.FilesystemBackend({rootDir:r})}function deriveDeepAgentsSkillSources(e){const t=new Set([...(i=e.agent,i?.skills??[]),...skillIdsFromWorkflow(e)]);var i;const o=new Set;for(const i of t){const t=e.workspace.skills.get(i);t&&o.add(toPosixPath(r.relative(e.workspace.root,r.dirname(r.dirname(t.path)))))}return[...o].filter(e=>e&&!e.startsWith(".."))}function skillIdsFromWorkflow(e){return e.workflow.nodes.map(e=>e.use.match(/^skills\.([^./][^.]*)$/u)?.[1]).filter(e=>Boolean(e))}function toPosixPath(e){return e.split(r.sep).join("/")}
@@ -1 +1 @@
1
- export async function runDirectToolCall(t){const o=t.request.toolCall;if(!o)throw new Error("Direct tool call request is missing");if(!t.gateway)throw new Error("Runtime tool gateway is not configured");const e=await async function resolveDirectToolCall(t){if(t.agent.tools.includes(t.toolId)&&t.gateway.get(t.toolId))return{toolId:t.toolId,args:t.args};const o=await(t.gateway.repairToolCall?.({toolId:t.toolId,args:t.args,allowedToolIds:t.agent.tools,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,requestInput:t.request.input}}));if(o&&t.agent.tools.includes(o.toolId)&&t.gateway.get(o.toolId))return o;if(!t.agent.tools.includes(t.toolId))throw new Error(`Tool ${t.toolId} is not assigned to agent ${t.agent.id}`);throw new Error(`Tool is not registered: ${t.toolId}`)}({gateway:t.gateway,workspace:t.workspace,requestId:t.requestId,sessionId:t.sessionId,agent:t.agent,request:t.request,toolId:o.toolId,args:o.args});t.emit({type:"runtime.tool.direct.started",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,toolId:e.toolId});const s=await t.gateway.invoke({toolId:e.toolId,args:e.args,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,requestInput:t.request.input}});return t.emit({type:"runtime.tool.direct.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,toolId:s.toolId,output:s.output}),{text:(r=s.output,"string"==typeof r?r:JSON.stringify(r)),metadata:{toolCall:{toolId:s.toolId}}};var r}
1
+ export async function runDirectToolCall(t){const o=t.request.toolCall;if(!o)throw new Error("Direct tool call request is missing");if(!t.gateway)throw new Error("Runtime tool gateway is not configured");const e=await async function resolveDirectToolCall(t){if(t.agent.tools.includes(t.toolId)&&t.gateway.get(t.toolId))return{toolId:t.toolId,args:t.args};const o=await(t.gateway.repairToolCall?.({toolId:t.toolId,args:t.args,allowedToolIds:t.agent.tools,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,requestInput:t.request.input}}));if(o&&t.agent.tools.includes(o.toolId)&&t.gateway.get(o.toolId))return emitToolRepair(t,"repaired",o.toolId),o;if(!t.agent.tools.includes(t.toolId))throw emitToolRepair(t,"blocked",void 0,`Tool ${t.toolId} is not assigned to agent ${t.agent.id}`),new Error(`Tool ${t.toolId} is not assigned to agent ${t.agent.id}`);throw emitToolRepair(t,"blocked",void 0,`Tool is not registered: ${t.toolId}`),new Error(`Tool is not registered: ${t.toolId}`)}({gateway:t.gateway,workspace:t.workspace,requestId:t.requestId,sessionId:t.sessionId,agent:t.agent,emit:t.emit,request:t.request,toolId:o.toolId,args:o.args});t.emit({type:"runtime.tool.direct.started",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,toolId:e.toolId});const s=await t.gateway.invoke({toolId:e.toolId,args:e.args,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,requestInput:t.request.input}});return t.emit({type:"runtime.tool.direct.completed",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,toolId:s.toolId,output:s.output}),{text:(r=s.output,"string"==typeof r?r:JSON.stringify(r)),metadata:{toolCall:{toolId:s.toolId}}};var r}function emitToolRepair(t,o,e,s){t.emit({type:"runtime.inventory.repair",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,status:o,diagnostic:{layer:"tool",owner:"stable_runtime_policy",originalId:t.toolId,repairedId:e,candidateIds:t.agent.tools,reason:s}})}
@@ -1,6 +1,18 @@
1
1
  import type { MemoryCandidate, MemoryDecision, MemoryRecord } from "@stable-harness/memory";
2
2
  import type { ApprovalRequest } from "@stable-harness/governance";
3
3
  import type { RuntimeArtifact } from "../types.js";
4
+ export type RuntimeInventoryRepairLayer = "agent" | "workflow_route" | "workflow" | "tool" | "task" | "skill";
5
+ export type RuntimeInventoryRepairStatus = "repaired" | "blocked";
6
+ export type RuntimeInventoryRepairDiagnostic = {
7
+ layer: RuntimeInventoryRepairLayer;
8
+ owner: "stable_runtime_policy" | "protocol_adapter" | "upstream_backend" | "workspace_config";
9
+ originalId?: string;
10
+ repairedId?: string;
11
+ candidateIds: string[];
12
+ reason?: string;
13
+ matchSource?: string;
14
+ confidence?: number;
15
+ };
4
16
  export type RuntimeEvent = {
5
17
  type: "runtime.request.started";
6
18
  requestId: string;
@@ -38,6 +50,13 @@ export type RuntimeEvent = {
38
50
  agentId: string;
39
51
  reason: string;
40
52
  missingEvidenceTools?: string[];
53
+ } | {
54
+ type: "runtime.inventory.repair";
55
+ requestId: string;
56
+ sessionId: string;
57
+ agentId: string;
58
+ status: RuntimeInventoryRepairStatus;
59
+ diagnostic: RuntimeInventoryRepairDiagnostic;
41
60
  } | {
42
61
  type: "runtime.tool.direct.started";
43
62
  requestId: string;
@@ -1 +1 @@
1
- export function resolveProgressNarrator(e){if(!1===e.options)return;const t=readProgressPolicy(e.policy);return e.options?.enabled??t.enabled?e.options?.provider??function createTemplateProgressNarrator(){const e=new Map,t=new Map;return{name:"template",narrate(r,n){var o;"runtime.request.started"===r.type&&(e.set(r.requestId,{language:(o=r.input??"",/\p{Script=Han}/u.test(o)?"zh":void 0),input:r.input}),t.delete(r.requestId));const i=function templateMessage(e,t){const r="zh"===t?.language;return"runtime.request.started"===e.type?r?`我开始处理这个请求:${summarizeText(e.input)}`:`I'm starting on this request: ${summarizeText(e.input)}`:"runtime.request.completed"===e.type?r?"我已经完成执行链,正在交付最终结果。":"I've finished the execution chain and am returning the final result.":"runtime.request.failed"===e.type?r?"执行链失败了,我会保留具体错误方便定位。":"The execution chain failed; I'm keeping the concrete error visible for diagnosis.":"runtime.request.cancelled"===e.type?r?"这个请求已取消,后续执行会停止。":"The request was cancelled, so the remaining execution will stop.":"runtime.tool.direct.started"===e.type?r?`我正在运行 ${e.toolId}。`:`I'm running ${e.toolId}.`:"runtime.tool.direct.completed"===e.type?r?`${e.toolId} 已返回结果,我会继续使用这份证据。`:`${e.toolId} returned; I'll keep using that evidence.`:"runtime.workflow.started"===e.type?r?`我正在启动 workflow ${e.workflowId}。`:`I'm starting workflow ${e.workflowId}.`:"runtime.workflow.completed"===e.type?r?`workflow ${e.workflowId} 已完成。`:`Workflow ${e.workflowId} is complete.`:"runtime.specDriven.phase.started"===e.type?r?`我正在进入 spec-driven 阶段 ${e.phaseId}。`:`I'm starting spec-driven phase ${e.phaseId}.`:"runtime.specDriven.phase.blocked"===e.type?r?`spec-driven 阶段 ${e.phaseId} 被 gate 阻塞。`:`Spec-driven phase ${e.phaseId} is blocked by a gate.`:"runtime.specDriven.phase.completed"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已完成。`:`Spec-driven phase ${e.phaseId} is complete.`:"runtime.specDriven.phase.verified"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已验证。`:`Spec-driven phase ${e.phaseId} is verified.`:"runtime.artifact.created"===e.type?r?"我已经保存一份运行产物。":"I've saved a runtime artifact.":"runtime.execution.contract.failed"===e.type?r?"运行证据没有满足执行契约,我会进入恢复或失败路径。":"The run evidence did not satisfy the execution contract, so I'll recover or fail explicitly.":"runtime.skill.candidate.created"===e.type?r?`我发现一个可沉淀的 skill 候选:${e.name}。`:`I found a reusable skill candidate: ${e.name}.`:e.type.startsWith("runtime.memory.")?function memoryMessage(e,t){return"runtime.memory.lifecycle"===e.type?t?`我进入记忆阶段:${e.hook}。`:`I'm in the memory lifecycle phase: ${e.hook}.`:"runtime.memory.recall.completed"===e.type?t?`我召回了 ${e.recordIds.length} 条相关记忆。`:`I recalled ${e.recordIds.length} relevant memory records.`:"runtime.memory.candidate.submitted"===e.type?t?"我提交了一条候选记忆。":"I submitted a memory candidate.":"runtime.memory.approval.requested"===e.type?t?"我提交了记忆审批请求。":"I requested memory approval.":"runtime.memory.plugin.started"===e.type?t?`我正在运行记忆插件 ${e.provider}。`:`I'm running memory plugin ${e.provider}.`:"runtime.memory.plugin.completed"===e.type?t?`记忆插件 ${e.provider} 已完成。`:`Memory plugin ${e.provider} completed.`:"runtime.memory.plugin.failed"===e.type?t?`记忆插件 ${e.provider} 失败了;主任务会继续,不把它当成执行结果。`:`Memory plugin ${e.provider} failed; the main task will continue without treating it as the result.`:"runtime.memory.maintenance.started"===e.type?t?`我正在维护 ${e.target} 记忆。`:`I'm maintaining ${e.target} memory.`:"runtime.memory.maintenance.completed"===e.type?t?`${e.target} 记忆维护完成。`:`${e.target} memory maintenance completed.`:"runtime.memory.maintenance.failed"===e.type?t?`${e.target} 记忆维护失败。`:`${e.target} memory maintenance failed.`:void 0}(e,r):"runtime.adapter.event"===e.type?function adapterMessage(e,t){if(isRecord(e))return"agent.handoff"===e.phase?t?"我把请求交给上游 agent backend,让它负责规划和执行。":"I'm handing the request to the upstream agent backend for planning and execution.":"agent.tool.start"===e.phase&&"string"==typeof e.toolId?function toolStartMessage(e,t,r){if("task"===e){const e=function readTaskTarget(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)}(t),n=function readDescription(e){const t=isRecord(e)?e:{};return summarizeText(readString(t.description)??readString(t.task))}(t);if(e&&n)return r?`我正在请求 task 工具委派给 ${e}:${n}`:`I'm asking the task tool to delegate to ${e}: ${n}`;if(e)return r?`我正在请求 task 工具委派给 ${e}。`:`I'm asking the task tool to delegate to ${e}.`}return r?`我正在运行 ${e} 收集证据。`:`I'm running ${e} to gather evidence.`}(e.toolId,e.args,t):"agent.tool.result"===e.phase&&"string"==typeof e.toolId?function toolResultMessage(e,t,r,n,o){if(r)return o?`${e} 返回错误:${summarizeText(String(r))}`:`${e} returned an error: ${summarizeText(String(r))}`;const i="string"==typeof n?n:function readToolControlStatus(e){const t=function parseToolOutputRecord(e){if(isRecord(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:"string"==typeof t?.error?t.error:"string"==typeof e&&e.startsWith("Task delegation target is not in the workspace inventory")?"task_inventory_blocked":void 0}(t);if(i)return function toolControlMessage(e,t,r){return"duplicate_tool_call"===t?r?`${e} 重复调用已复用已有证据。`:`${e} repeated an equivalent call, so the existing evidence was reused.`:"repeated_tool_call_limit"===t?r?`${e} 出现重复调用循环,我会基于已有证据继续收敛。`:`${e} entered a repeated-call loop, so I'll continue from the evidence already collected.`:"tool_argument_error"===t||"tool_argument_validation_failed"===t?r?`${e} 参数被工具 schema 拒绝,我会让 agent 修正参数或改用合适工具。`:`${e} arguments were rejected by the tool schema; I'll have the agent repair them or choose a suitable tool.`:"task_inventory_blocked"===t?r?"task 委派目标不在当前 workspace inventory 中,已被运行时策略阻止。":"The task delegation target is not in the current workspace inventory and was blocked by runtime policy.":r?`${e} 返回运行时控制状态:${t}。`:`${e} returned runtime control status: ${t}.`}(e,i,o);if("task"===e)return o?"委派任务已返回结果,我会基于这些证据继续推进。":"The delegated task returned; I'll keep going with that evidence.";const a=function summarizeToolOutput(e){if("string"==typeof e)return summarizeText(e);if(isRecord(e)){if("string"==typeof e.status)return summarizeText(e.status);if("string"==typeof e.summary)return summarizeText(e.summary)}}(t);return o?`${e} 已返回${a?`:${a}`:",我会继续判断下一步。"}`:`${e} returned${a?`: ${a}`:"; I'll decide the next step from here."}`}(e.toolId,e.output,e.error,e.controlStatus,t):"agent.langgraph.invoke"===e.phase?t?"我正在调用 workflow backend。":"I'm invoking the workflow backend.":"agent.node.completed"===e.phase&&"string"==typeof e.nodeId?t?`节点 ${e.nodeId} 已完成。`:`Node ${e.nodeId} is complete.`:void 0}(e.event,r):void 0}(r,e.get(r.requestId));if(i&&i!==t.get(r.requestId))return t.set(r.requestId,i),"runtime.request.failed"!==r.type&&"runtime.request.cancelled"!==r.type||(e.delete(r.requestId),t.delete(r.requestId)),function pruneRequestState(e,t){for(;e.size>200;){const r=e.keys().next().value;if(!r)break;e.delete(r),t.delete(r)}}(e,t),{message:i,style:n.style,model:n.model}}}}():void 0}export function createProgressNarrationEvent(e){if(!e.narrator||"runtime.progress.narration"===e.source.type)return;const t=readProgressPolicy(e.policy),r=!1===e.options?void 0:e.options,n=e.narrator.narrate(e.source,{style:r?.style??t.style,model:r?.model??t.model});return function isPromiseLike(e){return isRecord(e)&&"function"==typeof e.then}(n)?n.then(t=>toNarrationEvent(e.source,e.narrator,t)):toNarrationEvent(e.source,e.narrator,n)}export function createProgressNarrationCapability(e){const t=resolveProgressNarrator(e);if(t)return{id:"runtime.progress.narration",onEvent(r,n){try{const o=createProgressNarrationEvent({source:r,narrator:t,options:e.options,policy:e.policy});!function isRuntimeEventPromise(e){return isRecord(e)&&"function"==typeof e.then}(o)?o&&n(o):o.then(e=>{e&&n(e)}).catch(()=>{})}catch{return}}}}function toNarrationEvent(e,t,r){if(r?.message.trim())return{type:"runtime.progress.narration",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,message:r.message,provider:t.name,sourceEventTypes:r.sourceEventTypes??[e.type],sourceEventIds:r.sourceEventIds,model:r.model,style:r.style}}function summarizeText(e){const t=e?.replace(/\s+/gu," ").trim();return t?t.length>120?`${t.slice(0,117)}...`:t:""}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readProgressPolicy(e){const t=isRecord(e?.progress)?e.progress:{},r=isRecord(t.narration)?t.narration:{};return{enabled:"boolean"==typeof r.enabled?r.enabled:void 0,style:"string"==typeof r.style?r.style:void 0,model:"string"==typeof r.model?r.model:void 0}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
1
+ export function resolveProgressNarrator(e){if(!1===e.options)return;const t=readProgressPolicy(e.policy);return e.options?.enabled??t.enabled?e.options?.provider??function createTemplateProgressNarrator(){const e=new Map,t=new Map;return{name:"template",narrate(r,n){var o;"runtime.request.started"===r.type&&(e.set(r.requestId,{language:(o=r.input??"",/\p{Script=Han}/u.test(o)?"zh":void 0),input:r.input}),t.delete(r.requestId));const i=function templateMessage(e,t){const r="zh"===t?.language;return"runtime.request.started"===e.type?r?`我开始处理这个请求:${summarizeText(e.input)}`:`I'm starting on this request: ${summarizeText(e.input)}`:"runtime.request.completed"===e.type?r?"我已经完成执行链,正在交付最终结果。":"I've finished the execution chain and am returning the final result.":"runtime.request.failed"===e.type?r?"执行链失败了,我会保留具体错误方便定位。":"The execution chain failed; I'm keeping the concrete error visible for diagnosis.":"runtime.request.cancelled"===e.type?r?"这个请求已取消,后续执行会停止。":"The request was cancelled, so the remaining execution will stop.":"runtime.tool.direct.started"===e.type?r?`我正在运行 ${e.toolId}。`:`I'm running ${e.toolId}.`:"runtime.tool.direct.completed"===e.type?r?`${e.toolId} 已返回结果,我会继续使用这份证据。`:`${e.toolId} returned; I'll keep using that evidence.`:"runtime.workflow.started"===e.type?r?`我正在启动 workflow ${e.workflowId}。`:`I'm starting workflow ${e.workflowId}.`:"runtime.workflow.completed"===e.type?r?`workflow ${e.workflowId} 已完成。`:`Workflow ${e.workflowId} is complete.`:"runtime.specDriven.phase.started"===e.type?r?`我正在进入 spec-driven 阶段 ${e.phaseId}。`:`I'm starting spec-driven phase ${e.phaseId}.`:"runtime.specDriven.phase.blocked"===e.type?r?`spec-driven 阶段 ${e.phaseId} 被 gate 阻塞。`:`Spec-driven phase ${e.phaseId} is blocked by a gate.`:"runtime.specDriven.phase.completed"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已完成。`:`Spec-driven phase ${e.phaseId} is complete.`:"runtime.specDriven.phase.verified"===e.type?r?`spec-driven 阶段 ${e.phaseId} 已验证。`:`Spec-driven phase ${e.phaseId} is verified.`:"runtime.artifact.created"===e.type?r?"我已经保存一份运行产物。":"I've saved a runtime artifact.":"runtime.execution.contract.failed"===e.type?r?"运行证据没有满足执行契约,我会进入恢复或失败路径。":"The run evidence did not satisfy the execution contract, so I'll recover or fail explicitly.":"runtime.inventory.repair"===e.type?inventoryRepairMessage(e.status,e.diagnostic.layer,r):"runtime.skill.candidate.created"===e.type?r?`我发现一个可沉淀的 skill 候选:${e.name}。`:`I found a reusable skill candidate: ${e.name}.`:e.type.startsWith("runtime.memory.")?function memoryMessage(e,t){return"runtime.memory.lifecycle"===e.type?t?`我进入记忆阶段:${e.hook}。`:`I'm in the memory lifecycle phase: ${e.hook}.`:"runtime.memory.recall.completed"===e.type?t?`我召回了 ${e.recordIds.length} 条相关记忆。`:`I recalled ${e.recordIds.length} relevant memory records.`:"runtime.memory.candidate.submitted"===e.type?t?"我提交了一条候选记忆。":"I submitted a memory candidate.":"runtime.memory.approval.requested"===e.type?t?"我提交了记忆审批请求。":"I requested memory approval.":"runtime.memory.plugin.started"===e.type?t?`我正在运行记忆插件 ${e.provider}。`:`I'm running memory plugin ${e.provider}.`:"runtime.memory.plugin.completed"===e.type?t?`记忆插件 ${e.provider} 已完成。`:`Memory plugin ${e.provider} completed.`:"runtime.memory.plugin.failed"===e.type?t?`记忆插件 ${e.provider} 失败了;主任务会继续,不把它当成执行结果。`:`Memory plugin ${e.provider} failed; the main task will continue without treating it as the result.`:"runtime.memory.maintenance.started"===e.type?t?`我正在维护 ${e.target} 记忆。`:`I'm maintaining ${e.target} memory.`:"runtime.memory.maintenance.completed"===e.type?t?`${e.target} 记忆维护完成。`:`${e.target} memory maintenance completed.`:"runtime.memory.maintenance.failed"===e.type?t?`${e.target} 记忆维护失败。`:`${e.target} memory maintenance failed.`:void 0}(e,r):"runtime.adapter.event"===e.type?function adapterMessage(e,t){if(isRecord(e)){if("agent.handoff"===e.phase)return t?"我把请求交给上游 agent backend,让它负责规划和执行。":"I'm handing the request to the upstream agent backend for planning and execution.";if("agent.tool.start"===e.phase&&"string"==typeof e.toolId)return function toolStartMessage(e,t,r){if("task"===e){const e=function readTaskTarget(e){const t=isRecord(e)?e:{};return readString(t.subagent_type)??readString(t.subagentType)}(t),n=function readDescription(e){const t=isRecord(e)?e:{};return summarizeText(readString(t.description)??readString(t.task))}(t);if(e&&n)return r?`我正在请求 task 工具委派给 ${e}:${n}`:`I'm asking the task tool to delegate to ${e}: ${n}`;if(e)return r?`我正在请求 task 工具委派给 ${e}。`:`I'm asking the task tool to delegate to ${e}.`}return r?`我正在运行 ${e} 收集证据。`:`I'm running ${e} to gather evidence.`}(e.toolId,e.args,t);if("agent.tool.result"===e.phase&&"string"==typeof e.toolId)return function toolResultMessage(e,t,r,n,o){if(r)return o?`${e} 返回错误:${summarizeText(String(r))}`:`${e} returned an error: ${summarizeText(String(r))}`;const i="string"==typeof n?n:function readToolControlStatus(e){const t=function parseToolOutputRecord(e){if(isRecord(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e);return"string"==typeof t?.status?t.status:"string"==typeof t?.error?t.error:"string"==typeof e&&e.startsWith("Task delegation target is not in the workspace inventory")?"task_inventory_blocked":void 0}(t);if(i)return function toolControlMessage(e,t,r){return"duplicate_tool_call"===t?r?`${e} 重复调用已复用已有证据。`:`${e} repeated an equivalent call, so the existing evidence was reused.`:"repeated_tool_call_limit"===t?r?`${e} 出现重复调用循环,我会基于已有证据继续收敛。`:`${e} entered a repeated-call loop, so I'll continue from the evidence already collected.`:"tool_argument_error"===t||"tool_argument_validation_failed"===t?r?`${e} 参数被工具 schema 拒绝,我会让 agent 修正参数或改用合适工具。`:`${e} arguments were rejected by the tool schema; I'll have the agent repair them or choose a suitable tool.`:"task_inventory_blocked"===t?r?"task 委派目标不在当前 workspace inventory 中,已被运行时策略阻止。":"The task delegation target is not in the current workspace inventory and was blocked by runtime policy.":r?`${e} 返回运行时控制状态:${t}。`:`${e} returned runtime control status: ${t}.`}(e,i,o);if("task"===e)return o?"委派任务已返回结果,我会基于这些证据继续推进。":"The delegated task returned; I'll keep going with that evidence.";const a=function summarizeToolOutput(e){if("string"==typeof e)return summarizeText(e);if(isRecord(e)){if("string"==typeof e.status)return summarizeText(e.status);if("string"==typeof e.summary)return summarizeText(e.summary)}}(t);return o?`${e} 已返回${a?`:${a}`:",我会继续判断下一步。"}`:`${e} returned${a?`: ${a}`:"; I'll decide the next step from here."}`}(e.toolId,e.output,e.error,e.controlStatus,t);if("agent.langgraph.invoke"===e.phase)return t?"我正在调用 workflow backend。":"I'm invoking the workflow backend.";if("agent.node.completed"===e.phase&&"string"==typeof e.nodeId)return t?`节点 ${e.nodeId} 已完成。`:`Node ${e.nodeId} is complete.`;if("inventory.repair"===e.phase&&"string"==typeof e.status){const r=isRecord(e.diagnostic)?e.diagnostic:{};return inventoryRepairMessage(e.status,readString(r.layer)??"selection",t)}}}(e.event,r):void 0}(r,e.get(r.requestId));if(i&&i!==t.get(r.requestId))return t.set(r.requestId,i),"runtime.request.failed"!==r.type&&"runtime.request.cancelled"!==r.type||(e.delete(r.requestId),t.delete(r.requestId)),function pruneRequestState(e,t){for(;e.size>200;){const r=e.keys().next().value;if(!r)break;e.delete(r),t.delete(r)}}(e,t),{message:i,style:n.style,model:n.model}}}}():void 0}export function createProgressNarrationEvent(e){if(!e.narrator||"runtime.progress.narration"===e.source.type)return;const t=readProgressPolicy(e.policy),r=!1===e.options?void 0:e.options,n=e.narrator.narrate(e.source,{style:r?.style??t.style,model:r?.model??t.model});return function isPromiseLike(e){return isRecord(e)&&"function"==typeof e.then}(n)?n.then(t=>toNarrationEvent(e.source,e.narrator,t)):toNarrationEvent(e.source,e.narrator,n)}export function createProgressNarrationCapability(e){const t=resolveProgressNarrator(e);if(t)return{id:"runtime.progress.narration",onEvent(r,n){try{const o=createProgressNarrationEvent({source:r,narrator:t,options:e.options,policy:e.policy});!function isRuntimeEventPromise(e){return isRecord(e)&&"function"==typeof e.then}(o)?o&&n(o):o.then(e=>{e&&n(e)}).catch(()=>{})}catch{return}}}}function toNarrationEvent(e,t,r){if(r?.message.trim())return{type:"runtime.progress.narration",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agentId,message:r.message,provider:t.name,sourceEventTypes:r.sourceEventTypes??[e.type],sourceEventIds:r.sourceEventIds,model:r.model,style:r.style}}function inventoryRepairMessage(e,t,r){return"repaired"===e?r?`${t} 选择已按 workspace inventory 修正。`:`${t} selection was repaired against the workspace inventory.`:r?`${t} 选择不在 workspace inventory 中,已被阻止。`:`${t} selection was blocked because it is outside the workspace inventory.`}function summarizeText(e){const t=e?.replace(/\s+/gu," ").trim();return t?t.length>120?`${t.slice(0,117)}...`:t:""}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readProgressPolicy(e){const t=isRecord(e?.progress)?e.progress:{},r=isRecord(t.narration)?t.narration:{};return{enabled:"boolean"==typeof r.enabled?r.enabled:void 0,style:"string"==typeof r.style?r.style:void 0,model:"string"==typeof r.model?r.model:void 0}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1,4 +1,5 @@
1
1
  import type { CallCandidate, CallSelectionDiagnostics } from "@botbotgo/better-call";
2
+ import type { RuntimeEvent, RuntimeInventoryRepairDiagnostic, RuntimeInventoryRepairLayer } from "./events.js";
2
3
  export type RuntimeSelectionRepairResult = {
3
4
  ok: true;
4
5
  id: string;
@@ -8,7 +9,16 @@ export type RuntimeSelectionRepairResult = {
8
9
  reason: string;
9
10
  diagnostics?: CallSelectionDiagnostics;
10
11
  };
12
+ export type RuntimeSelectionRepairTrace = {
13
+ layer: RuntimeInventoryRepairLayer;
14
+ owner: RuntimeInventoryRepairDiagnostic["owner"];
15
+ requestId: string;
16
+ sessionId: string;
17
+ agentId: string;
18
+ emit: (event: RuntimeEvent) => void;
19
+ };
11
20
  export declare function repairRuntimeSelection(input: {
12
21
  id: string;
13
22
  candidates: CallCandidate[];
23
+ trace?: RuntimeSelectionRepairTrace;
14
24
  }): Promise<RuntimeSelectionRepairResult>;
@@ -1 +1 @@
1
- import{repairCallSelection as a}from"@botbotgo/better-call";export async function repairRuntimeSelection(i){const t=await a({rawIntent:i.id,candidates:i.candidates,mode:"repair"});return t.ok?{ok:!0,id:t.candidateId,diagnostics:t.diagnostics}:{ok:!1,reason:t.reason,diagnostics:t.diagnostics}}
1
+ import{repairCallSelection as e}from"@botbotgo/better-call";export async function repairRuntimeSelection(i){const a=await e({rawIntent:i.id,candidates:i.candidates,mode:"repair"});return a.ok?(emitSelectionRepair(i,"repaired",a.candidateId,a.diagnostics),{ok:!0,id:a.candidateId,diagnostics:a.diagnostics}):(emitSelectionRepair(i,"blocked",void 0,a.diagnostics,a.reason),{ok:!1,reason:a.reason,diagnostics:a.diagnostics})}function emitSelectionRepair(e,i,a,t,n){const d=e.trace;d&&d.emit({type:"runtime.inventory.repair",requestId:d.requestId,sessionId:d.sessionId,agentId:d.agentId,status:i,diagnostic:{layer:d.layer,owner:d.owner,originalId:t?.originalId??e.id,repairedId:t?.repairedId??a,candidateIds:e.candidates.map(e=>e.id),reason:n,matchSource:t?.matchSource,confidence:t?.confidence}})}
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{projectRequestInspection as r,projectRequestSummary as s,projectSessionSummaries as o}from"./runtime/persistence/inspection.js";import{assertNoRawToolCallOutput as a,assertNoToolExecutionErrorOutput as n,buildAdapterErrorRecoveryPrompt as i,buildEvidenceSynthesisOutput as u,buildExecutionContractRecoveryRequest as c,buildResultRecoveryRequest as l,containsRawToolCallOutput as p,isRecoverableAdapterError as d,rawToolCallFailureMessage as m,toolCallRecoveryEnabled as w}from"./recovery/tool-call.js";import{recoverQualityReview as f,resolveQualityPolicy as y}from"./quality/index.js";import{completeRun as R,failRun as g}from"./runtime/completion.js";import{runDirectToolCall as I}from"./runtime/direct-tool-call.js";import{createRuntimeCapabilityRegistry as q,normalizeAdapterResult as k}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as v}from"./runtime/memory.js";import{createInMemoryRuntimeStore as b}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as A}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{runWorkflowRequest as x}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const a=new Set,n=t.store??b(),u=q([v(t),A({options:t.progressNarration,policy:t.workspace.runtime}),...t.capabilities??[]]),emitBase=e=>{n.appendEvent(e);for(const t of a)t(e)},emit=e=>{emitBase(e),u.emitSideEffects(e,emitBase)};return{request:async r=>async function runRuntimeRequest(t){const{agent:r,adapter:s}=await async function resolveExecution(e,t){const r=t.agentId?await async function resolveRequestedAgentId(e,t){if(e.agents.has(t))return t;const r=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description}))});return r.ok?r.id:t}(e.workspace,t.agentId):function resolveRoutedAgentId(e,t){for(const r of e.runtime.routes??[])if(routeMatches(r,t))return r.agentId;return e.runtime.defaultAgentId}(e.workspace,t.input),s=e.workspace.agents.get(r);if(!s)throw new Error(`Agent ${r} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:s,adapter:void 0};const o=e.adapters.find(e=>e.canRun(s));if(!o)throw new Error(`No runtime adapter can run backend ${s.backend} for agent ${s.id}`);return{agent:s,adapter:o}}(t.input,t.request),o=t.request.requestId??e(),a=t.request.sessionId??e();t.store.createRun(function createRunRecord(e,t,r,s){return{requestId:t,sessionId:r,agentId:s.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,o,a,r)),t.emit({type:"runtime.request.started",requestId:o,sessionId:a,agentId:r.id,input:t.request.input});try{if(t.request.workflow){const e=await x({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:o,sessionId:a,agentId:r.id,emit:t.emit});return R({store:t.store,emit:t.emit,requestId:o,sessionId:a,agent:r,result:e})}if(t.request.toolCall){const e=await I({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:o,sessionId:a,agent:r});return R({store:t.store,emit:t.emit,requestId:o,sessionId:a,agent:r,result:e})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,r=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),s=r.memory,o=r.pluginMemories??[],a=e.input.workspace.runtime,n=y(e.input.workspace.runtime,e.agent),u=new Map;let l;try{l=await runAdapterOnce(e,t,e.request,s,o,u)}catch(r){if(!d(r,a))throw r;l=await runAdapterOnce(e,t,i(e.request,r,a),s,o,u)}l=await recoverAdapterResultOutput(e,t,e.request,l,s,o,a,u),l=await f(createQualityRuntimeInput(e,s,o,u),e.request,l,n),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:l});try{assertRequestExecutionContract(e)}catch(r){const i=c({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:a});if(!i)throw r;l=await runAdapterOnce(e,t,i,s,o,u),l=await recoverAdapterResultOutput(e,t,i,l,s,o,a,u),l=await f(createQualityRuntimeInput(e,s,o,u),i,l,n),assertRequestExecutionContract(e)}const p=R({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:l});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:l,response:p}),p}({...t,adapter:s,requestId:o,sessionId:a,agent:r})}catch(e){return g({store:t.store,emit:t.emit,requestId:o,sessionId:a,agent:r,error:e})}}({input:t,capabilities:u,store:n,emit:emit,request:r}),subscribe:e=>(a.add(e),()=>a.delete(e)),inspect(){return{workspaceRoot:t.workspace.root,agents:[...t.workspace.agents.keys()].sort(),workflows:[...t.workspace.workflows.keys()].sort(),...t.workspace.runtime.specDrivenWorkflow?{specDrivenWorkflow:(e=t.workspace.runtime.specDrivenWorkflow,{enabled:e.enabled,artifactsDir:e.artifactsDir,...e.constitution?{constitution:e.constitution}:{},phases:e.phases.map(e=>e.id)})}:{},evaluations:[...t.workspace.evaluations?.keys()??[]].sort(),...t.workspace.runtime.workflowRouting?.defaultWorkflowId?{defaultWorkflowId:t.workspace.runtime.workflowRouting.defaultWorkflowId}:{},workflowRoutes:(t.workspace.runtime.workflowRouting?.routes??[]).map(e=>e.id).sort(),models:[...t.workspace.models.keys()].sort(),tools:[...t.workspace.tools.keys()].sort(),runs:n.listRuns()};var e},getRuntimePolicy:()=>t.workspace.runtime,getWorkflow:e=>t.workspace.workflows.get(e),getRun:e=>n.getRun(e),listRequests:e=>n.listRuns(e).map(s),listSessions:()=>o(n.listRuns()),inspectRequest(e){const s=n.getRun(e);return s?r(t.workspace,s):void 0},cancel(e,t){const r=n.getRun(e);r&&"running"===r.state&&(n.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await u.stop(),a.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,s),reviewModel:e.input.qualityReviewModel,memory:t,pluginMemories:r}}async function recoverAdapterResultOutput(e,t,r,s,o,i,c,d){let f=r;const y=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,r="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,s="object"!=typeof r||null===r||Array.isArray(r)?void 0:r.maxResultRecoveryAttempts;return"number"==typeof s&&Number.isInteger(s)&&s>0?s:3}(c);let R=0;for(let r=0;r<y;r+=1){const r=e.store.getRun(e.requestId)?.events??[],a=l({request:f,output:s.text,events:r.slice(R),availableToolIds:e.agent.tools,policy:c});if(!a)break;f=a,R=e.store.getRun(e.requestId)?.events.length??0,s=await runAdapterOnce(e,t,a,o,i,d)}if(w(c)){let t=!1;p(s.text,c)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(r.metadata)&&(s={...s,text:m(),metadata:{...s.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}});const o=u({request:r,output:s.text,events:e.store.getRun(e.requestId)?.events??[],policy:c});o&&(t=!0,s={...s,text:o,metadata:{...s.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}}),t||(a(s.text,c),n(s.text,c))}return s}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,s,o,a){return k(await t.run({workspace:e.input.workspace,agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:s,pluginMemories:o,toolGateway:e.input.toolGateway,requestState:a,emit:e.emit}))}function routeMatches(e,t){if(e.pattern)try{if(new RegExp(e.pattern,"iu").test(t))return!0}catch{return!1}const r=t.toLowerCase();return(e.keywords??[]).some(e=>r.includes(e.toLowerCase()))}
1
+ import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{projectRequestInspection as r,projectRequestSummary as s,projectSessionSummaries as o}from"./runtime/persistence/inspection.js";import{assertNoRawToolCallOutput as a,assertNoToolExecutionErrorOutput as n,buildAdapterErrorRecoveryPrompt as i,buildEvidenceSynthesisOutput as u,buildExecutionContractRecoveryRequest as c,buildResultRecoveryRequest as l,containsRawToolCallOutput as p,isRecoverableAdapterError as d,rawToolCallFailureMessage as m,toolCallRecoveryEnabled as w}from"./recovery/tool-call.js";import{recoverQualityReview as f,resolveQualityPolicy as y}from"./quality/index.js";import{completeRun as R,failRun as g}from"./runtime/completion.js";import{runDirectToolCall as I}from"./runtime/direct-tool-call.js";import{createRuntimeCapabilityRegistry as q,normalizeAdapterResult as k}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as v}from"./runtime/memory.js";import{createInMemoryRuntimeStore as b}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as A}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{runWorkflowRequest as x}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const a=new Set,n=t.store??b(),u=q([v(t),A({options:t.progressNarration,policy:t.workspace.runtime}),...t.capabilities??[]]),emitBase=e=>{n.appendEvent(e);for(const t of a)t(e)},emit=e=>{emitBase(e),u.emitSideEffects(e,emitBase)};return{request:async r=>async function runRuntimeRequest(t){const r=t.request.requestId??e(),s=t.request.sessionId??e(),o=[],{agent:a,adapter:n}=await async function resolveExecution(e,t,r){const s=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const s=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return s.ok?s.id:t}(e.workspace,t.agentId,r):function resolveRoutedAgentId(e,t){for(const r of e.runtime.routes??[])if(routeMatches(r,t))return r.agentId;return e.runtime.defaultAgentId}(e.workspace,t.input),o=e.workspace.agents.get(s);if(!o)throw new Error(`Agent ${s} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:o,adapter:void 0};const a=e.adapters.find(e=>e.canRun(o));if(!a)throw new Error(`No runtime adapter can run backend ${o.backend} for agent ${o.id}`);return{agent:o,adapter:a}}(t.input,t.request,{requestId:r,sessionId:s,emit:e=>o.push(e)});t.store.createRun(function createRunRecord(e,t,r,s){return{requestId:t,sessionId:r,agentId:s.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,r,s,a)),o.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:r,sessionId:s,agentId:a.id,input:t.request.input});try{if(t.request.workflow){const e=await x({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:r,sessionId:s,agentId:a.id,emit:t.emit});return R({store:t.store,emit:t.emit,requestId:r,sessionId:s,agent:a,result:e})}if(t.request.toolCall){const e=await I({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:r,sessionId:s,agent:a});return R({store:t.store,emit:t.emit,requestId:r,sessionId:s,agent:a,result:e})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,r=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),s=r.memory,o=r.pluginMemories??[],a=e.input.workspace.runtime,n=y(e.input.workspace.runtime,e.agent),u=new Map;let l;try{l=await runAdapterOnce(e,t,e.request,s,o,u)}catch(r){if(!d(r,a))throw r;l=await runAdapterOnce(e,t,i(e.request,r,a),s,o,u)}l=await recoverAdapterResultOutput(e,t,e.request,l,s,o,a,u),l=await f(createQualityRuntimeInput(e,s,o,u),e.request,l,n),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:l});try{assertRequestExecutionContract(e)}catch(r){const i=c({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:a});if(!i)throw r;l=await runAdapterOnce(e,t,i,s,o,u),l=await recoverAdapterResultOutput(e,t,i,l,s,o,a,u),l=await f(createQualityRuntimeInput(e,s,o,u),i,l,n),assertRequestExecutionContract(e)}const p=R({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:l});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:l,response:p}),p}({...t,adapter:n,requestId:r,sessionId:s,agent:a})}catch(e){return g({store:t.store,emit:t.emit,requestId:r,sessionId:s,agent:a,error:e})}}({input:t,capabilities:u,store:n,emit:emit,request:r}),subscribe:e=>(a.add(e),()=>a.delete(e)),inspect(){return{workspaceRoot:t.workspace.root,agents:[...t.workspace.agents.keys()].sort(),workflows:[...t.workspace.workflows.keys()].sort(),...t.workspace.runtime.specDrivenWorkflow?{specDrivenWorkflow:(e=t.workspace.runtime.specDrivenWorkflow,{enabled:e.enabled,artifactsDir:e.artifactsDir,...e.constitution?{constitution:e.constitution}:{},phases:e.phases.map(e=>e.id)})}:{},evaluations:[...t.workspace.evaluations?.keys()??[]].sort(),...t.workspace.runtime.workflowRouting?.defaultWorkflowId?{defaultWorkflowId:t.workspace.runtime.workflowRouting.defaultWorkflowId}:{},workflowRoutes:(t.workspace.runtime.workflowRouting?.routes??[]).map(e=>e.id).sort(),models:[...t.workspace.models.keys()].sort(),tools:[...t.workspace.tools.keys()].sort(),runs:n.listRuns()};var e},getRuntimePolicy:()=>t.workspace.runtime,getWorkflow:e=>t.workspace.workflows.get(e),getRun:e=>n.getRun(e),listRequests:e=>n.listRuns(e).map(s),listSessions:()=>o(n.listRuns()),inspectRequest(e){const s=n.getRun(e);return s?r(t.workspace,s):void 0},cancel(e,t){const r=n.getRun(e);r&&"running"===r.state&&(n.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await u.stop(),a.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,s),reviewModel:e.input.qualityReviewModel,memory:t,pluginMemories:r}}async function recoverAdapterResultOutput(e,t,r,s,o,i,c,d){let f=r;const y=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,r="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,s="object"!=typeof r||null===r||Array.isArray(r)?void 0:r.maxResultRecoveryAttempts;return"number"==typeof s&&Number.isInteger(s)&&s>0?s:3}(c);let R=0;for(let r=0;r<y;r+=1){const r=e.store.getRun(e.requestId)?.events??[],a=l({request:f,output:s.text,events:r.slice(R),availableToolIds:e.agent.tools,policy:c});if(!a)break;f=a,R=e.store.getRun(e.requestId)?.events.length??0,s=await runAdapterOnce(e,t,a,o,i,d)}if(w(c)){let t=!1;p(s.text,c)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(r.metadata)&&(s={...s,text:m(),metadata:{...s.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}});const o=u({request:r,output:s.text,events:e.store.getRun(e.requestId)?.events??[],policy:c});o&&(t=!0,s={...s,text:o,metadata:{...s.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}}),t||(a(s.text,c),n(s.text,c))}return s}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,s,o,a){return k(await t.run({workspace:e.input.workspace,agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:s,pluginMemories:o,toolGateway:e.input.toolGateway,requestState:a,emit:e.emit}))}function routeMatches(e,t){if(e.pattern)try{if(new RegExp(e.pattern,"iu").test(t))return!0}catch{return!1}const r=t.toLowerCase();return(e.keywords??[]).some(e=>r.includes(e.toLowerCase()))}
@@ -1 +1 @@
1
- export function projectRuntimeTrace(e){return e.events.map(projectEvent).filter(isTraceEntry)}export function projectEvent(e){return"runtime.request.started"===e.type||"runtime.request.completed"===e.type||"runtime.request.failed"===e.type?base(e,"request",e.type):"runtime.request.cancelled"===e.type?base(e,"request",e.type,{reason:e.reason}):"runtime.execution.contract.failed"===e.type?base(e,"request",e.type,{reason:e.reason,missingEvidenceTools:e.missingEvidenceTools}):"runtime.tool.direct.started"===e.type?base(e,"tool","runtime.tool.direct.started",{toolId:e.toolId}):"runtime.tool.direct.completed"===e.type?base(e,"tool","runtime.tool.direct.completed",{toolId:e.toolId}):"runtime.workflow.started"===e.type||"runtime.workflow.completed"===e.type?base(e,"workflow",e.type,{workflowId:e.workflowId,adapter:e.adapter}):function isSpecDrivenPhaseEvent(e){return e.type.startsWith("runtime.specDriven.phase.")}(e)?base(e,"spec",e.type,{phaseId:e.phaseId,..."workflowId"in e&&e.workflowId?{workflowId:e.workflowId}:{},..."reason"in e?{reason:e.reason}:{},..."artifact"in e&&e.artifact?{artifact:e.artifact}:{}}):"runtime.adapter.event"===e.type?function adapterTrace(e){const t=e.event;if(isRecord(t)&&"string"==typeof t.phase){const r=function semanticAdapterTrace(e,t){const r=function readTraceType(e){const t=readString(e);return"request"===t||"tool"===t||"workflow"===t||"spec"===t||"adapter"===t||"memory"===t||"artifact"===t||"progress"===t||"plan"===t||"delegation"===t?t:void 0}(t.traceType),o=readString(t.traceLabel);if(r&&o)return base(e,r,o,t)}(e,t);return r||base(e,"adapter",t.phase.startsWith("agent.")?t.phase:`adapter.${t.phase}`,t)}return base(e,"adapter","runtime.adapter.event",{event:t})}(e):"runtime.artifact.created"===e.type?base(e,"artifact","runtime.artifact.created",{artifact:e.artifact}):e.type.startsWith("runtime.memory.")?base(e,"memory",e.type):"runtime.progress.narration"===e.type?base(e,"progress",e.type,{message:e.message,provider:e.provider,sourceEventTypes:e.sourceEventTypes}):void 0}export function readPlanTodos(e){const t=function readPlanRecord(e){if(isRecord(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e),r=function readTodosArray(e){const t=isRecord(e?.args)?e.args:void 0;return Array.isArray(e?.todos)?e.todos:Array.isArray(t?.todos)?t.todos:[]}(t);return r.map(readTodo).filter(isPlanTodoItem)}function readTodo(e){if(isRecord(e)&&"string"==typeof e.content)return{content:e.content,status:"string"==typeof e.status?e.status:"pending"}}function isPlanTodoItem(e){return void 0!==e}function base(e,t,r,o){return{type:t,label:r,agentId:e.agentId,requestId:e.requestId,detail:o}}function isTraceEntry(e){return void 0!==e}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}
1
+ export function projectRuntimeTrace(e){return e.events.map(projectEvent).filter(isTraceEntry)}export function projectEvent(e){return"runtime.request.started"===e.type||"runtime.request.completed"===e.type||"runtime.request.failed"===e.type?base(e,"request",e.type):"runtime.request.cancelled"===e.type?base(e,"request",e.type,{reason:e.reason}):"runtime.execution.contract.failed"===e.type?base(e,"request",e.type,{reason:e.reason,missingEvidenceTools:e.missingEvidenceTools}):"runtime.inventory.repair"===e.type?base(e,"adapter","runtime.inventory.repair",{status:e.status,...e.diagnostic}):"runtime.tool.direct.started"===e.type?base(e,"tool","runtime.tool.direct.started",{toolId:e.toolId}):"runtime.tool.direct.completed"===e.type?base(e,"tool","runtime.tool.direct.completed",{toolId:e.toolId}):"runtime.workflow.started"===e.type||"runtime.workflow.completed"===e.type?base(e,"workflow",e.type,{workflowId:e.workflowId,adapter:e.adapter}):function isSpecDrivenPhaseEvent(e){return e.type.startsWith("runtime.specDriven.phase.")}(e)?base(e,"spec",e.type,{phaseId:e.phaseId,..."workflowId"in e&&e.workflowId?{workflowId:e.workflowId}:{},..."reason"in e?{reason:e.reason}:{},..."artifact"in e&&e.artifact?{artifact:e.artifact}:{}}):"runtime.adapter.event"===e.type?function adapterTrace(e){const t=e.event;if(isRecord(t)&&"string"==typeof t.phase){const r=function semanticAdapterTrace(e,t){if("inventory.repair"===t.phase)return base(e,"adapter","runtime.inventory.repair",{status:t.status,...isRecord(t.diagnostic)?t.diagnostic:{}});const r=function readTraceType(e){const t=readString(e);return"request"===t||"tool"===t||"workflow"===t||"spec"===t||"adapter"===t||"memory"===t||"artifact"===t||"progress"===t||"plan"===t||"delegation"===t?t:void 0}(t.traceType),o=readString(t.traceLabel);return r&&o?base(e,r,o,t):void 0}(e,t);return r||base(e,"adapter",t.phase.startsWith("agent.")?t.phase:`adapter.${t.phase}`,t)}return base(e,"adapter","runtime.adapter.event",{event:t})}(e):"runtime.artifact.created"===e.type?base(e,"artifact","runtime.artifact.created",{artifact:e.artifact}):e.type.startsWith("runtime.memory.")?base(e,"memory",e.type):"runtime.progress.narration"===e.type?base(e,"progress",e.type,{message:e.message,provider:e.provider,sourceEventTypes:e.sourceEventTypes}):void 0}export function readPlanTodos(e){const t=function readPlanRecord(e){if(isRecord(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);return isRecord(t)?t:void 0}catch{return}}(e),r=function readTodosArray(e){const t=isRecord(e?.args)?e.args:void 0;return Array.isArray(e?.todos)?e.todos:Array.isArray(t?.todos)?t.todos:[]}(t);return r.map(readTodo).filter(isPlanTodoItem)}function readTodo(e){if(isRecord(e)&&"string"==typeof e.content)return{content:e.content,status:"string"==typeof e.status?e.status:"pending"}}function isPlanTodoItem(e){return void 0!==e}function base(e,t,r,o){return{type:t,label:r,agentId:e.agentId,requestId:e.requestId,detail:o}}function isTraceEntry(e){return void 0!==e}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}
@@ -1 +1 @@
1
- import{repairRuntimeSelection as e}from"../runtime/selection-repair.js";export async function runWorkflowRequest(o){const r=await async function resolveWorkflow(o,r){const t=r.routeId?await async function resolveWorkflowRouteId(o,r){const t=o.runtime.workflowRouting?.routes??[];if(t.some(e=>e.id===r))return r;const n=await e({id:r,candidates:t.map(e=>({id:e.id,description:e.description,metadata:e.metadata}))});return n.ok?n.id:r}(o,r.routeId):void 0,n=t?o.runtime.workflowRouting?.routes?.find(e=>e.id===t):void 0;if(r.routeId&&!n)throw new Error(`Workflow route is not defined: ${r.routeId}`);const i=(r.workflowId?await async function resolveWorkflowId(o,r){if(o.workflows.has(r))return r;const t=await e({id:r,candidates:[...o.workflows.values()].map(e=>({id:e.id,description:e.description}))});return t.ok?t.id:r}(o,r.workflowId):void 0)??n?.workflowId??o.runtime.workflowRouting?.defaultWorkflowId;if(!i)throw new Error("Workflow request requires workflowId, routeId, or runtime.workflowRouting.defaultWorkflowId");const s=o.workflows.get(i);if(!s)throw new Error(`Workflow is not defined: ${i}`);return s}(o.workspace,o.request),t=function resolveWorkflowAdapter(e,o){const r=o?e.find(e=>e.name===o):e[0];if(!r)throw new Error("No workflow adapter is configured"+(o?` for ${o}`:""));return r}(o.adapters,r.adapter);o.emit({type:"runtime.workflow.started",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,adapter:t.name,workflowId:r.id});const n=await t.run({workspace:o.workspace,workflow:r,request:o.request,requestId:o.requestId,sessionId:o.sessionId,toolGateway:o.toolGateway,emit:e=>o.emit({type:"runtime.adapter.event",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,event:e})});return o.emit({type:"runtime.workflow.completed",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,adapter:t.name,workflowId:r.id}),"string"==typeof n?{text:n}:n}
1
+ import{repairRuntimeSelection as e}from"../runtime/selection-repair.js";export async function runWorkflowRequest(o){const r=await async function resolveWorkflow(o,r,t){const n=r.routeId?await async function resolveWorkflowRouteId(o,r,t){const n=o.runtime.workflowRouting?.routes??[];if(n.some(e=>e.id===r))return r;const i=await e({id:r,candidates:n.map(e=>({id:e.id,description:e.description,metadata:e.metadata})),trace:{...t,layer:"workflow_route",owner:"stable_runtime_policy"}});return i.ok?i.id:r}(o,r.routeId,t):void 0,i=n?o.runtime.workflowRouting?.routes?.find(e=>e.id===n):void 0;if(r.routeId&&!i)throw new Error(`Workflow route is not defined: ${r.routeId}`);const s=(r.workflowId?await async function resolveWorkflowId(o,r,t){if(o.workflows.has(r))return r;const n=await e({id:r,candidates:[...o.workflows.values()].map(e=>({id:e.id,description:e.description})),trace:{...t,layer:"workflow",owner:"stable_runtime_policy"}});return n.ok?n.id:r}(o,r.workflowId,t):void 0)??i?.workflowId??o.runtime.workflowRouting?.defaultWorkflowId;if(!s)throw new Error("Workflow request requires workflowId, routeId, or runtime.workflowRouting.defaultWorkflowId");const d=o.workflows.get(s);if(!d)throw new Error(`Workflow is not defined: ${s}`);return d}(o.workspace,o.request,o),t=function resolveWorkflowAdapter(e,o){const r=o?e.find(e=>e.name===o):e[0];if(!r)throw new Error("No workflow adapter is configured"+(o?` for ${o}`:""));return r}(o.adapters,r.adapter);o.emit({type:"runtime.workflow.started",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,adapter:t.name,workflowId:r.id});const n=await t.run({workspace:o.workspace,workflow:r,request:o.request,requestId:o.requestId,sessionId:o.sessionId,toolGateway:o.toolGateway,emit:e=>o.emit({type:"runtime.adapter.event",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,event:e})});return o.emit({type:"runtime.workflow.completed",requestId:o.requestId,sessionId:o.sessionId,agentId:o.agentId,adapter:t.name,workflowId:r.id}),"string"==typeof n?{text:n}:n}