stable-harness 0.0.53 → 0.0.55
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/README.md +0 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/docs/0.1.0-stable-runtime-development-roadmap.zh.md +14 -14
- package/docs/guides/integration-guide.md +12 -0
- package/docs/protocols/http-runtime.md +10 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/adapter.js +1 -1
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/checkpoint.d.ts +10 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/checkpoint.js +1 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/runtime.d.ts +11 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/runtime.js +1 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/store.d.ts +10 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/internal/substrate/store.js +1 -0
- package/node_modules/@stable-harness/core/dist/runtime/admin/administration.d.ts +9 -0
- package/node_modules/@stable-harness/core/dist/runtime/admin/administration.js +1 -0
- package/node_modules/@stable-harness/core/dist/runtime/admin/memory.d.ts +10 -0
- package/node_modules/@stable-harness/core/dist/runtime/admin/memory.js +1 -0
- package/node_modules/@stable-harness/core/dist/runtime/events.d.ts +11 -0
- package/node_modules/@stable-harness/core/dist/runtime/persistence/stores.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/types.d.ts +6 -0
- package/node_modules/@stable-harness/core/dist/runtime.js +1 -1
- package/node_modules/@stable-harness/core/dist/types.d.ts +13 -4
- package/node_modules/@stable-harness/core/dist/workspace/types.d.ts +1 -0
- package/node_modules/@stable-harness/memory/dist/src/index.d.ts +1 -1
- package/node_modules/@stable-harness/memory/dist/src/index.js +1 -1
- package/node_modules/@stable-harness/memory/dist/src/persistence.js +1 -1
- package/node_modules/@stable-harness/memory/dist/src/store.d.ts +3 -0
- package/node_modules/@stable-harness/memory/dist/src/store.js +1 -1
- package/node_modules/@stable-harness/memory/dist/src/types.d.ts +1 -1
- package/node_modules/@stable-harness/protocols/dist/src/http-server.js +1 -1
- package/node_modules/@stable-harness/protocols/dist/src/in-process-client.js +1 -1
- package/node_modules/@stable-harness/tool-gateway/dist/src/argument-guard.js +1 -1
- package/node_modules/@stable-harness/tool-gateway/dist/src/schema-validation.js +1 -1
- package/node_modules/@stable-harness/workspace-yaml/dist/documents.d.ts +7 -1
- package/node_modules/@stable-harness/workspace-yaml/dist/documents.js +1 -1
- package/node_modules/@stable-harness/workspace-yaml/dist/loader.js +1 -1
- package/package.json +4 -7
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
- package/packages/adapter-deepagents/dist/src/internal/substrate/checkpoint.d.ts +10 -0
- package/packages/adapter-deepagents/dist/src/internal/substrate/checkpoint.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/substrate/runtime.d.ts +11 -0
- package/packages/adapter-deepagents/dist/src/internal/substrate/runtime.js +1 -0
- package/packages/adapter-deepagents/dist/src/internal/substrate/store.d.ts +10 -0
- package/packages/adapter-deepagents/dist/src/internal/substrate/store.js +1 -0
- package/packages/cli/dist/src/server.js +1 -1
- package/packages/core/dist/runtime/admin/administration.d.ts +9 -0
- package/packages/core/dist/runtime/admin/administration.js +1 -0
- package/packages/core/dist/runtime/admin/memory.d.ts +10 -0
- package/packages/core/dist/runtime/admin/memory.js +1 -0
- package/packages/core/dist/runtime/events.d.ts +11 -0
- package/packages/core/dist/runtime/persistence/stores.js +1 -1
- package/packages/core/dist/runtime/types.d.ts +6 -0
- package/packages/core/dist/runtime.js +1 -1
- package/packages/core/dist/types.d.ts +13 -4
- package/packages/core/dist/workspace/types.d.ts +1 -0
- package/packages/memory/dist/src/index.d.ts +1 -1
- package/packages/memory/dist/src/index.js +1 -1
- package/packages/memory/dist/src/persistence.js +1 -1
- package/packages/memory/dist/src/store.d.ts +3 -0
- package/packages/memory/dist/src/store.js +1 -1
- package/packages/memory/dist/src/types.d.ts +1 -1
- package/packages/protocols/dist/src/http-server.js +1 -1
- package/packages/protocols/dist/src/in-process-client.js +1 -1
- package/packages/tool-gateway/dist/src/argument-guard.js +1 -1
- package/packages/tool-gateway/dist/src/schema-validation.js +1 -1
- package/packages/workspace-yaml/dist/documents.d.ts +7 -1
- package/packages/workspace-yaml/dist/documents.js +1 -1
- package/packages/workspace-yaml/dist/loader.js +1 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -2
- package/dist/compat/agent-harness.d.ts +0 -24
- package/dist/compat/agent-harness.js +0 -1
- package/dist/runtime/compat/agent-harness-compat-runner.d.ts +0 -2
- package/dist/runtime/compat/agent-harness-compat-runner.js +0 -1
- package/dist/runtime/compat/json.d.ts +0 -4
- package/dist/runtime/compat/json.js +0 -1
- package/dist/runtime/compat/presentation.d.ts +0 -1
- package/dist/runtime/compat/presentation.js +0 -1
- package/dist/runtime/compat/prompts.d.ts +0 -29
- package/dist/runtime/compat/prompts.js +0 -1
- package/dist/runtime/compat/tool-registry.d.ts +0 -3
- package/dist/runtime/compat/tool-registry.js +0 -1
- package/dist/runtime/compat/types.d.ts +0 -38
- package/dist/runtime/compat/types.js +0 -1
- package/docs/compatibility-matrix.md +0 -150
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createServer as
|
|
1
|
+
import{createServer as e}from"node:http";import{compileWorkflowPlan as t,projectRuntimeTrace as r,projectRuntimeTraceSpans as o,renderWorkflowMermaid as n}from"@stable-harness/core";export function createHttpServer(s){return e((e,a)=>{!async function handleHttpRequest(e,s,a){try{await async function routeHttpRequest(e,s,a){if("GET"===s.method&&"/health"===s.url)return void sendJson(a,200,{ok:!0});if("GET"===s.method&&"/inspect"===s.url)return void sendJson(a,200,e.inspect());if("GET"===s.method&&"/requests"===s.url)return void sendJson(a,200,e.listRequests());if(await async function handleAdministrationRoutes(e){const{runtime:t,request:r,response:o}=e;if("GET"===r.method&&"/sessions"===r.url)return sendJson(o,200,t.listSessions()),!0;const n=function readSessionDeleteId(e){const t=(e??"").match(/^\/sessions\/([^/]+)$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(r.url);if("DELETE"===r.method&&n)return sendJson(o,200,t.deleteSession(n)),!0;const s=function readRequestDeleteId(e){const t=(e??"").match(/^\/requests\/([^/]+)$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(r.url);if("DELETE"===r.method&&s)return sendJson(o,200,t.deleteRequest(s)),!0;if("GET"===r.method&&r.url?.startsWith("/memories"))return sendJson(o,200,await t.listMemories(function readMemoryList(e){const t=new URL(e??"/memories","http://stable-harness.local"),r=t.searchParams.getAll("status").filter(e=>"active"===e||"stale"===e||"conflicted"===e||"archived"===e||"pending_review"===e);return{...t.searchParams.get("namespace")?{namespace:t.searchParams.get("namespace")}:{},...r.length>0?{statuses:r}:{}}}(r.url))),!0;if("POST"===r.method&&"/memories"===r.url){const e=await readJson(r);return sendJson(o,200,await t.memorize(e)),!0}if("POST"===r.method&&"/memories/recall"===r.url){const e=await readJson(r);return sendJson(o,200,await t.recallMemories(e)),!0}const a=function readMemoryArchiveId(e){const t=(e??"").match(/^\/memories\/([^/]+)\/archive$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(r.url);if("POST"===r.method&&a){const e=await readJson(r);return sendJson(o,200,await t.archiveMemory(a,"string"==typeof e.reason?e.reason:void 0)),!0}const d=function readMemoryUpdateId(e){const t=(e??"").match(/^\/memories\/([^/]+)$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(r.url);return!("PATCH"!==r.method||!d||(sendJson(o,200,await t.updateMemory({id:d,...await readJson(r)})),0))}({runtime:e,request:s,response:a}))return;const d=function readArtifactList(e){if(!e?.startsWith("/artifacts"))return;const t=new URL(e,"http://stable-harness.local");return"/artifacts"===t.pathname?{...t.searchParams.get("requestId")?{requestId:t.searchParams.get("requestId")}:{},...t.searchParams.get("sessionId")?{sessionId:t.searchParams.get("sessionId")}:{},...t.searchParams.get("agentId")?{agentId:t.searchParams.get("agentId")}:{}}:void 0}(s.url);if("GET"===s.method&&d)return void sendJson(a,200,e.listArtifacts(d));const i=function readArtifactContentId(e){const t=(e??"").match(/^\/artifacts\/([^/]+)\/content$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&i){const t=e.getArtifact(i),r=e.readArtifact(i);return void sendJson(a,t&&void 0!==r?200:404,t&&void 0!==r?{artifact:t,content:r}:{error:"artifact_content_not_found"})}const u=function readArtifactId(e){const t=(e??"").match(/^\/artifacts\/([^/]+)$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&u){const t=e.getArtifact(u);return void sendJson(a,t?200:404,t??{error:"artifact_not_found"})}const c=function readApprovalList(e){if(!e?.startsWith("/approvals"))return;const t=new URL(e,"http://stable-harness.local");if("/approvals"!==t.pathname)return;const r=t.searchParams.get("status");return{status:"pending"===r||"approved"===r||"rejected"===r?r:void 0}}(s.url);if("GET"===s.method&&c)return void sendJson(a,200,await e.listApprovals(c.status));const f=function readApprovalDecision(e){const t=(e??"").match(/^\/approvals\/([^/]+)\/(approve|reject)$/u);if(t?.[1]&&t[2])return{id:decodeURIComponent(t[1]),status:"approve"===t[2]?"approved":"rejected"}}(s.url);if("POST"===s.method&&f){const t=await e.resolveApproval(f.id,f.status);return void sendJson(a,t?200:404,t??{error:"approval_not_found"})}if("GET"===s.method&&"/workflows"===s.url)return void sendJson(a,200,e.inspect().workflows);const m=function readWorkflowMermaidId(e){const t=(e??"").match(/^\/workflows\/([^/]+)\/mermaid$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&m){const t=e.getWorkflow(m);return void sendJson(a,t?200:404,t?{mermaid:n(t)}:{error:"workflow_not_found"})}const l=function readWorkflowPlanId(e){const t=(e??"").match(/^\/workflows\/([^/]+)\/plan$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&l){const r=e.getWorkflow(l);return void sendJson(a,r?200:404,r?t(r):{error:"workflow_not_found"})}const p=function readRequestInspectionId(e){const t=(e??"").match(/^\/requests\/([^/]+)$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&p){const t=e.inspectRequest(p);return void sendJson(a,t?200:404,t??{error:"request_not_found"})}const h=function readTraceRequestId(e){const t=(e??"").match(/^\/runs\/([^/]+)\/trace$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&h){const t=e.getRun(h);return void sendJson(a,t?200:404,t?r(t):{error:"run_not_found"})}const v=function readSpanRequestId(e){const t=(e??"").match(/^\/runs\/([^/]+)\/spans$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&v){const t=e.getRun(v);return void sendJson(a,t?200:404,t?o(t):{error:"run_not_found"})}const I=function readReplayRequestId(e){const t=(e??"").match(/^\/requests\/([^/]+)\/replay$/u);return t?.[1]?decodeURIComponent(t[1]):void 0}(s.url);if("GET"===s.method&&I){const t=e.exportReplayBundle(I);return void sendJson(a,t?200:404,t??{error:"run_not_found"})}if("POST"===s.method&&"/requests"===s.url){const t=await readJson(s);return void sendJson(a,200,await e.request(function readRuntimeRequest(e){const t=function readToolCall(e){if("object"!=typeof e||null===e)return;const t=e;return"string"==typeof t.toolId?{toolId:t.toolId,args:t.args}:void 0}(e.toolCall),r=function readWorkflow(e){const t=readRecord(e);if(t)return{..."string"==typeof t.workflowId?{workflowId:t.workflowId}:{},..."string"==typeof t.routeId?{routeId:t.routeId}:{},...void 0!==t.input?{input:t.input}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{}}}(e.workflow),o=function readMemory(e){const t=readRecord(e);if(t)return{..."string"==typeof t.namespace?{namespace:t.namespace}:{},...!1===t.recall||readRecord(t.recall)?{recall:t.recall}:{},...Array.isArray(t.candidates)?{candidates:t.candidates}:{}}}(e.memory),n=readRecord(e.metadata);return{input:"string"==typeof e.input?e.input:"",..."string"==typeof e.agentId?{agentId:e.agentId}:{},..."string"==typeof e.sessionId?{sessionId:e.sessionId}:{},..."string"==typeof e.requestId?{requestId:e.requestId}:{},..."string"==typeof e.parentRunId?{parentRunId:e.parentRunId}:{},...t?{toolCall:t}:{},...r?{workflow:r}:{},...o?{memory:o}:{},...n?{metadata:n}:{}}}(t)))}sendJson(a,404,{error:"not_found"})}(e,s,a)}catch(e){sendJson(a,500,{error:e instanceof Error?e.message:String(e)})}}(s,e,a)})}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}function sendJson(e,t,r){e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(r))}async function readJson(e){const t=[];for await(const r of e)t.push(Buffer.isBuffer(r)?r:Buffer.from(r));return 0===t.length?{}:JSON.parse(Buffer.concat(t).toString("utf8"))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function createInProcessClient(e){return{request:t=>e.request(t),subscribe:t=>e.subscribe(t),inspect:()=>e.inspect(),getRuntimePolicy:()=>e.getRuntimePolicy(),getWorkflow:t=>e.getWorkflow(t),getRun:t=>e.getRun(t),listArtifacts:t=>e.listArtifacts(t),getArtifact:t=>e.getArtifact(t),readArtifact:t=>e.readArtifact(t),exportReplayBundle:t=>e.exportReplayBundle(t),listRequests:t=>e.listRequests(t),listSessions:()=>e.listSessions(),inspectRequest:t=>e.inspectRequest(t),listApprovals:t=>e.listApprovals(t),getApproval:t=>e.getApproval(t),resolveApproval:(t,s)=>e.resolveApproval(t,s),cancel:(t,s)=>e.cancel(t,s),stop:()=>e.stop()}}
|
|
1
|
+
export function createInProcessClient(e){return{request:t=>e.request(t),subscribe:t=>e.subscribe(t),inspect:()=>e.inspect(),getRuntimePolicy:()=>e.getRuntimePolicy(),getWorkflow:t=>e.getWorkflow(t),getRun:t=>e.getRun(t),listArtifacts:t=>e.listArtifacts(t),getArtifact:t=>e.getArtifact(t),readArtifact:t=>e.readArtifact(t),exportReplayBundle:t=>e.exportReplayBundle(t),listRequests:t=>e.listRequests(t),listSessions:()=>e.listSessions(),inspectRequest:t=>e.inspectRequest(t),memorize:t=>e.memorize(t),recallMemories:t=>e.recallMemories(t),listMemories:t=>e.listMemories(t),updateMemory:t=>e.updateMemory(t),archiveMemory:(t,s)=>e.archiveMemory(t,s),listApprovals:t=>e.listApprovals(t),getApproval:t=>e.getApproval(t),resolveApproval:(t,s)=>e.resolveApproval(t,s),cancel:(t,s)=>e.cancel(t,s),deleteRequest:t=>e.deleteRequest(t),deleteSession:t=>e.deleteSession(t),stop:()=>e.stop()}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BetterToolValidationError as o,betterTools as t,defaultRepair as e,reliableToolCalls as a}from"@easynet/better-call";import{isRecord as r,validateWithZodSchema as
|
|
1
|
+
import{BetterToolValidationError as o,betterTools as t,defaultRepair as e,reliableToolCalls as a}from"@easynet/better-call";import{isRecord as r,validateWithZodSchema as l}from"./schema-validation.js";export class ToolArgumentValidationError extends Error{toolId;issues;constructor(o,t){super(`Tool argument validation failed for ${o}: ${t.map(o=>`${o.path} ${o.message}`).join("; ")}`),this.toolId=o,this.issues=t,this.name="ToolArgumentValidationError"}}export function createDefaultArgumentGuard(t={}){return{async validate(e){const a=e.tool.validateArgs?await e.tool.validateArgs({args:e.args,context:e.context}):{action:"allow",args:e.args};if("reject"===a.action)return a;const r=await async function validateWithBetterCall(t,e,a){const r=l(t.schema,e);if(void 0===t.schema)return r??{action:"allow",args:e};const i=await async function invokeBetterCallValidation(t,e,a){try{return{action:"allow",args:await createBetterCallValidationTool(t,a).invoke(e)}}catch(t){if(t instanceof o)return{action:"reject",reason:"BetterCall validation failed",issues:t.issues.map(toToolArgumentIssue)};throw t}}(t,"allow"===r?.action?r.args:e,a);return r?"allow"===r.action?i:"reject"===i.action?r:l(t.schema,i.args)||i:i}(e.tool,a.args,t.betterCall);return"reject"===r.action?r:"repair"===a.action?{...a,args:r.args}:r}}}export function assertToolArguments(o,t,e,a){return Promise.resolve(a.validate({tool:o,args:t,context:e})).then(t=>{if("reject"===t.action)throw new ToolArgumentValidationError(o.id,t.issues);return t.args})}export function prepareBetterCallTools(o,e){const a=t(o.map(toBetterCallTool),toBetterToolsOptions(e));return o.map((o,t)=>({...o,validationTool:a[t]}))}export async function repairBetterCallToolSelection(o){const t=function resolveRepair(o){return o?.repair??(o?.repairModel?e(o.repairModel):void 0)}(o.options);if(!t||0===o.tools.length)return;const l=await a({userInput:JSON.stringify({tool:o.toolId,args:o.args}),tools:o.tools.map(toToolDefinition),calls:[{tool:o.toolId,args:(i=o.args,r(i)?i:{input:i})}],repair:t,repairPolicy:o.options?.repairPolicy??{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0,allowModelRepair:!0},mode:o.options?.mode??"repair"});var i;const n=l.ok?l.calls.find(t=>o.tools.some(o=>o.id===t.tool)):void 0;return n?{toolId:n.tool,args:n.args}:void 0}function createBetterCallValidationTool(o,e){return o.validationTool??t([toBetterCallTool(o)],toBetterToolsOptions(e))[0]}function toBetterCallTool(o){return{name:o.id,description:o.description,schema:o.schema,invoke:o=>o}}function toToolDefinition(o){return{name:o.id,description:o.description,schema:o.schema}}function toToolArgumentIssue(o){return{path:o.path.replace(/^\$\.calls\[\d+\]\.args/u,"$"),message:o.message,expected:void 0===o.expected?void 0:String(o.expected),actual:o.actual}}function toBetterToolsOptions(o){const t=Boolean(o?.repair||o?.repairModel);return{mode:o?.mode??(t?"repair":"guard"),repair:o?.repair,repairModel:o?.repairModel,repairPolicy:o?.repairPolicy??(t?{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0,allowModelRepair:!0}:{allowCoercion:!1,allowClamp:!1,allowArrayStringSplit:!1,allowModelRepair:!1})}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeArgsBySchema as e}from"@easynet/better-call";export function validateWithZodSchema(
|
|
1
|
+
import{normalizeArgsBySchema as e}from"@easynet/better-call";export function validateWithZodSchema(t,r){return isZodLike(t)?toZodGuardResult(t.safeParse(r??{})):function isZodShape(e){return isRecord(e)&&Object.values(e).length>0&&Object.values(e).every(isZodLike)}(t)?function validateWithZodShape(t,r){const s=function normalizeZodShapeArgs(t,r){const s=isRecord(r)?r:{};return e(t,s,{allowCoercion:!0,allowClamp:!0,allowArrayStringSplit:!0}).args}(t,r),a={},o=[];for(const[e,r]of Object.entries(t)){const t=r.safeParse(s[e]);t.success?void 0!==t.data&&(a[e]=t.data):o.push(...t.error.issues.map(t=>({...t,path:[e,...t.path]})))}return o.length>0?toZodGuardResult({success:!1,error:{issues:o}}):{action:"allow",args:a}}(t,r):function isJsonObjectSchema(e){return isRecord(e)&&"object"===e.type}(t)?function validateWithJsonObjectSchema(e,t){const r=isRecord(t)?t:{},s=[];for(const t of e.required??[])t in r||s.push({path:`$.${t}`,message:"Required property is missing",expected:"required"});for(const[t,a]of Object.entries(e.properties??{}))t in r&&void 0!==a.type&&jsonType(r[t])!==a.type&&s.push({path:`$.${t}`,message:`Expected ${a.type}`,expected:a.type,actual:r[t]});return s.length>0?{action:"reject",reason:"JSON schema validation failed",issues:s}:{action:"allow",args:r}}(t,r):void 0}export function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function toZodGuardResult(e){return e.success?{action:"allow",args:e.data}:{action:"reject",reason:"Zod schema validation failed",issues:e.error.issues.map(e=>{return{path:(t=e.path,t.length>0?`$.${t.map(String).join(".")}`:"$"),message:e.message,expected:"schema"};var t})}}function isZodLike(e){return isRecord(e)&&"function"==typeof e.safeParse}function jsonType(e){return Array.isArray(e)?"array":null===e?"null":typeof e}
|
|
@@ -8,8 +8,14 @@ export type RawDocument = {
|
|
|
8
8
|
};
|
|
9
9
|
spec?: unknown;
|
|
10
10
|
};
|
|
11
|
+
export type WorkspaceToolSet = {
|
|
12
|
+
id: string;
|
|
13
|
+
tools: string[];
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
15
|
+
};
|
|
11
16
|
export declare function compileRuntime(document: RawDocument): WorkspaceRuntimePolicy;
|
|
12
|
-
export declare function compileAgent(document: RawDocument, sourcePath: string): WorkspaceAgent;
|
|
17
|
+
export declare function compileAgent(document: RawDocument, sourcePath: string, toolSets?: Map<string, WorkspaceToolSet>): WorkspaceAgent;
|
|
18
|
+
export declare function compileToolSets(document: RawDocument): WorkspaceToolSet[];
|
|
13
19
|
export declare function compileModel(document: RawDocument): WorkspaceModel;
|
|
14
20
|
export declare function compileModelSpec(spec: Record<string, unknown>, fallback?: string): WorkspaceModel;
|
|
15
21
|
export declare function compileTool(document: RawDocument, sourcePath?: string): WorkspaceTool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.tracing&&r.tracing?{tracing:r.tracing}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
|
1
|
+
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.tracing&&r.tracing?{tracing:r.tracing}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:assertStringArray(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r,t=new Map){const o=assertRecord(e.spec,"Agent.spec"),n=readName(e),i=readOptionalString(o.backend);if(!i)throw new Error(`Agent ${n} requires spec.backend`);const a="object"==typeof o.config&&o.config?o.config:{},s="string"==typeof o.systemPrompt?o.systemPrompt:"string"==typeof a.systemPrompt?a.systemPrompt:void 0,p=function readAgentToolBindings(e,r=new Map){return Array.isArray(e)?e.flatMap(e=>function readAgentToolBinding(e,r){return"string"==typeof e&&e.trim()?[toolBinding(e.trim(),void 0,r)]:"object"!=typeof e||null===e||Array.isArray(e)?[]:Object.entries(e).filter(([e])=>e.trim().length>0).map(([e,t])=>toolBinding(e.trim(),function readToolRefMetadata(e){if("object"==typeof e&&null!==e&&!Array.isArray(e))return e}(t),r))}(e,r)):[]}(o.tools,t);return{id:n,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:i,...p.some(e=>"toolset"===e.kind||e.metadata)?{metadata:{toolBindings:p}}:{},..."string"==typeof o.modelRef&&o.modelRef.trim()?{modelRef:(c=o.modelRef,c.replace(/^[^/]+\//u,""))}:{},...void 0!==s?{systemPrompt:s}:{},tools:(d=p.flatMap(e=>e.tools),[...new Set(d)]),skills:toStringArray(o.skills),memory:Array.isArray(o.memory)?o.memory:[],subagents:toStringArray(o.subagents),...void 0!==o.edges?{edges:readAgentEdges(o.edges,n)}:{},config:a};var d,c}export function compileToolSets(e){return Array.isArray(e.spec)?e.spec.map(e=>compileToolSetSpec(assertRecord(e,"ToolSets.spec[]"))):[compileToolSetSpec(assertRecord(e.spec,"ToolSets.spec"),readName(e,""))]}function compileToolSetSpec(e,r){const t=readOptionalString(e.name)??r;if(!t)throw new Error("ToolSets.spec[] requires name");const o=assertStringArray(e.tools,`ToolSet ${t}.tools`),n={...e};return delete n.name,delete n.tools,{id:t,tools:o,...Object.keys(n).length>0?{metadata:n}:{}}}function toolBinding(e,r,t){const o=t.get(e);return o?{ref:e,kind:"toolset",tools:o.tools,...r?{metadata:r}:{}}:{ref:e,kind:"tool",tools:[e],...r?{metadata:r}:{}}}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile as o}from"node:fs/promises";import e from"node:path";import{parseAllDocuments as
|
|
1
|
+
import{readFile as o}from"node:fs/promises";import e from"node:path";import{parseAllDocuments as t}from"yaml";import{discoverModuleTools as s,discoverSkills as n,listYamlFiles as r}from"./discovery.js";import{compileAgent as l,compileMemory as a,compileModel as i,compileModelSpec as c,compileRuntime as f,compileTool as u,compileToolSets as m}from"./documents.js";import{compileWorkflow as d,validateWorkflows as w}from"./workflows.js";import{compileEvaluation as p,validateEvaluations as k}from"./evaluations.js";import{assertWorkspaceBoundaryDiagnostics as g,scanWorkspaceBoundaries as v}from"./boundary-scan.js";import{assertWorkspaceToolQualityDiagnostics as h,scanWorkspaceToolQuality as y}from"@stable-harness/core";export async function loadWorkspaceFromYaml(l){const a=e.join(l,"config"),i=await r(a),c=[],f=new Map,u=new Map,m=new Map,d=new Map,p=new Map,M=new Map,W=new Map,A=new Map,S=[];for(const e of i){const s=await o(e,"utf8"),n=t(s).map(o=>o.toJSON()).filter(o=>null!==o);S.push(...n.map(o=>({document:o,file:e})))}for(const{document:o}of S)collectToolSetDocument(o,A);for(const{document:o,file:e}of S)collectWorkspaceDocument(o,e,{runtimeDocs:c,agents:f,models:u,tools:m,memories:p,workflows:M,evaluations:W,toolSets:A});for(const o of await s(l))m.has(o.id)||m.set(o.id,o);for(const o of await n(l))d.set(o.id,o);const T=c.at(-1)??{defaultAgentId:"orchestra"};w({workflows:M,agents:f,tools:m,skills:d}),k({evaluations:W,agents:f,tools:m,workflows:M}),function validateAgentTools(o,e){for(const t of o.values()){const o=t.tools.filter(o=>!e.has(o));if(o.length>0)throw new Error(`Agent ${t.id} references unknown tools ${o.join(", ")}`)}}(f,m),function validateAgentRouting(o,e){for(const t of o.routes??[])if(!e.has(t.agentId))throw new Error(`Runtime routing route ${t.id} references unknown agent ${t.agentId}`)}(T,f),function validateWorkflowRouting(o,e){const t=o.workflowRouting;if(t){if(t.defaultWorkflowId&&!e.has(t.defaultWorkflowId))throw new Error(`Runtime workflowRouting.defaultWorkflowId references unknown workflow ${t.defaultWorkflowId}`);for(const o of t.routes??[])if(!e.has(o.workflowId))throw new Error(`Runtime workflowRouting route ${o.id} references unknown workflow ${o.workflowId}`)}}(T,M);const R={root:l,runtime:T,agents:f,models:u,tools:m,skills:d,memories:p,workflows:M,evaluations:W},D=v(R);g(D);const I=y(R,T.workspaceValidation?.toolQuality);return h(I),{...R,...[...D??[],...I].length>0?{diagnostics:[...D,...I]}:{}}}function collectWorkspaceDocument(o,e,t){if("string"==typeof o.kind)switch(o.kind){case"Runtime":return void t.runtimeDocs.push(f(o));case"Agent":return collectOne(t.agents,l(o,e,t.toolSets));case"Model":return collectOne(t.models,i(o));case"Models":return function collectModelSpecs(o,e){if(Array.isArray(o.spec))for(const t of o.spec)if("object"==typeof t&&null!==t&&!Array.isArray(t)){const o=c(t);e.set(o.id,o)}}(o,t.models);case"Tool":return collectOne(t.tools,u(o,e));case"Memory":return collectOne(t.memories,a(o));case"Workflow":return collectOne(t.workflows,d(o,e));case"Evaluation":return collectOne(t.evaluations,p(o,e));default:return}}function collectToolSetDocument(o,e){if("ToolSets"===o.kind||"ToolSet"===o.kind)for(const t of m(o))e.set(t.id,t)}function collectOne(o,e){o.set(e.id,e)}
|
package/dist/cli.d.ts
DELETED
package/dist/cli.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{createDeepAgentsAdapter as t}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as o,projectEvent as e,projectRuntimeTrace as a}from"@stable-harness/core";import{createModuleToolGateway as r}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as s}from"@stable-harness/workspace-yaml";import{createAgentHarness as n,request as i,stop as c}from"./compat/agent-harness.js";import{formatCompatDelta as l}from"./runtime/compat/presentation.js";const p=function parseArgs(t){let o,e,a,r=process.cwd(),s=!1,n=!1,i=!1,c=!1,l=!1,p=Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5);const g=[];for(let m=0;m<t.length;m+=1)"-h"===t[m]||"--help"===t[m]?l=!0:"-w"===t[m]||"--workspace"===t[m]?r=t[++m]??r:"--agent"===t[m]?o=t[++m]:"--tool"===t[m]?e=t[++m]:"--tool-args-json"===t[m]?a=parseJsonArg(t[++m]??"{}"):"--trace"===t[m]?s=!0:"--trace-json"===t[m]?n=!0:"--progress"===t[m]?i=!0:"--native"===t[m]?c=!0:"--timeout-ms"===t[m]?p=Number(t[++m]??p):g.push(t[m]);return{workspaceRoot:r,agentId:o,toolId:e,toolArgs:a,trace:s,traceJson:n,progress:i,native:c,help:l,timeoutMs:p,prompt:g.join(" ")||"hello"}}(process.argv.slice(2));function formatNativeCompatEvent(t){return"runtime.tool.direct.started"===t.type?[`agent:${t.agentId} Running tool ${t.toolId}`]:[]}function parseJsonArg(t){try{return JSON.parse(t)}catch(t){throw new Error(`Invalid --tool-args-json value: ${t instanceof Error?t.message:String(t)}`)}}p.help?console.log(function legacyHelpText(){return["Usage:"," botbotgo -w <workspace> [--agent <id>] [prompt]"," botbotgo --native -w <workspace> [--agent <id>] [prompt]"," botbotgo --native -w <workspace> --tool <id> --tool-args-json <json>","","Options:"," -w, --workspace <path> Workspace root."," --agent <id> Select an agent."," --native Use the native stable runtime path."," --tool <id> Invoke an explicit registered tool on the native path."," --tool-args-json <json> Tool arguments for --tool."," --trace Print trace lines."," --trace-json Print trace JSON."," --progress Print native progress narration."," --timeout-ms <ms> Request timeout."," -h, --help Show this help."].join("\n")}()):p.toolId||p.native?await async function runNative(n){const i=setTimeout(()=>{process.stderr.write(`botbotgo native request timed out after ${n.timeoutMs}ms\n`),process.exit(124)},n.timeoutMs);try{const i=await s(n.workspaceRoot),c=await r({tools:i.tools.values()}),l=o({workspace:i,toolGateway:c,adapters:[t()],progressNarration:n.progress?{enabled:!0,style:"cli"}:void 0});n.trace?l.subscribe(t=>{const o=e(t);o&&console.log(`trace:${o.agentId}:${o.label}${function formatTraceDetail(t){return"string"==typeof t?.toolId?`:${t.toolId}`:""}(o.detail)}`);for(const o of formatNativeCompatEvent(t))console.log(o)}):l.subscribe(t=>{for(const o of formatNativeCompatEvent(t))console.log(o)}),n.progress&&l.subscribe(t=>{"runtime.progress.narration"===t.type&&console.log(`progress:${t.agentId}:${t.message}`)});const p=await l.request({agentId:n.agentId,input:n.prompt,toolCall:n.toolId?{toolId:n.toolId,args:n.toolArgs}:void 0});!function printNativeTrace(t,o,e){if(!e.trace&&!e.traceJson)return;const r=t.getRun(o),s=r?a(r):[];e.traceJson&&console.log(JSON.stringify({trace:s}))}(l,p.requestId,n),console.log(p.output),process.exitCode="completed"===p.state?0:1}finally{clearTimeout(i)}}(p):await async function runCompat(t){const o=await n(t.workspaceRoot);try{const e=await i(o,{agentId:t.agentId,input:t.prompt,dataListener(t){for(const o of l(t))console.log(o)}});console.log(e.output),process.exitCode="completed"===e.state?0:1}finally{await c(o)}}(p);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RuntimeRequestInput } from "../runtime/compat/types.js";
|
|
2
|
-
import type { CompiledWorkspace } from "../runtime/workspace/types.js";
|
|
3
|
-
export { loadWorkspace } from "../workspace/compile.js";
|
|
4
|
-
export declare function createAgentHarness(workspaceRoot: string): Promise<{
|
|
5
|
-
workspace: CompiledWorkspace;
|
|
6
|
-
request(input: RuntimeRequestInput): Promise<import("../runtime/compat/types.js").RuntimeResult>;
|
|
7
|
-
streamEvents(input: RuntimeRequestInput): AsyncGenerator<Record<string, unknown> | undefined, void, unknown>;
|
|
8
|
-
cancel(requestId: string): void;
|
|
9
|
-
stop(): Promise<void>;
|
|
10
|
-
}>;
|
|
11
|
-
export declare function request(runtime: StableCompatRuntime, input: RuntimeRequestInput): Promise<import("../runtime/compat/types.js").RuntimeResult>;
|
|
12
|
-
export declare function cancelRequest(runtime: StableCompatRuntime, input: {
|
|
13
|
-
requestId: string;
|
|
14
|
-
reason?: string;
|
|
15
|
-
}): Promise<void>;
|
|
16
|
-
export declare function stop(runtime: StableCompatRuntime): Promise<void>;
|
|
17
|
-
type StableCompatRuntime = ReturnType<typeof createRuntime>;
|
|
18
|
-
declare function createRuntime(workspace: CompiledWorkspace): {
|
|
19
|
-
workspace: CompiledWorkspace;
|
|
20
|
-
request(input: RuntimeRequestInput): Promise<import("../runtime/compat/types.js").RuntimeResult>;
|
|
21
|
-
streamEvents(input: RuntimeRequestInput): AsyncGenerator<Record<string, unknown> | undefined, void, unknown>;
|
|
22
|
-
cancel(requestId: string): void;
|
|
23
|
-
stop(): Promise<void>;
|
|
24
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{runAgentHarnessCompatAgent as t}from"../runtime/compat/agent-harness-compat-runner.js";import{loadWorkspace as n}from"../workspace/compile.js";export{loadWorkspace}from"../workspace/compile.js";export async function createAgentHarness(t){return function createRuntime(t){const n=new Set;return{workspace:t,async request(o){const r=e();return runRequest(t,o,r,n)},async*streamEvents(o){const r=e();yield{type:"event",event:{eventType:"request.created",requestId:r}};const s=function createAsyncQueue(){const e=[],t=[];let n=!1;return{push(n){const o=t.shift();o?o({value:n,done:!1}):e.push(n)},close(){for(n=!0;t.length;)t.shift()({value:void 0,done:!0})},[Symbol.asyncIterator]:()=>({next:async()=>{const o=e.shift();return o?{value:o,done:!1}:n?{value:void 0,done:!0}:new Promise(e=>t.push(e))}})}}(),a=runRequest(t,o,r,n,e=>{"agent.tool.start"===e.type?s.push({type:"event",event:{payload:{event:"on_tool_start",run_type:"tool",name:e.toolName}}}):s.push({requestId:r,...e,type:"tool-result"})}).finally(()=>s.close());for await(const e of s)yield e;await a},cancel(e){n.add(e)},async stop(){n.clear()}}}(await n(t))}export async function request(e,t){return e.request(t)}export async function cancelRequest(e,t){t.reason,e.cancel(t.requestId)}export async function stop(e){await e.stop()}async function runRequest(e,n,o,r,s){const a=n.agentId??"orchestra",c=e.agents.get(a);if(!c)throw new Error(`Unknown agent: ${a}`);return t({workspace:e,agent:c,request:{...n,dataListener:s??n.dataListener},requestId:o,cancelled:r})}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{generateWithModel as e}from"../model/ollama.js";import{containsRawToolCallText as t,parseToolCall as n}from"./json.js";import{buildAgentPrompt as o,buildFinalAnswerPrompt as r,buildRoutingPrompt as a,buildRoutingRepairPrompt as s,buildToolSelectionPrompt as i}from"./prompts.js";import{loadAgentTools as u}from"./tool-registry.js";export async function runAgentHarnessCompatAgent(t){const r=await async function resolveAgents(t){if(0===t.agent.subagentRefs.length)return[t.agent];const n=resolveModel(t.workspace,t.agent),o=t.request.input??"",r=await e(n,a(t.workspace,t.agent,o)),i=await async function repairRouting(t,n,o,r){let a=r,i=parseRouting(a);for(let r=0;r<3&&!hasEnoughRouting(t,o,i);r+=1)a=await e(n,s({workspace:t.workspace,agent:t.agent,userInput:o,previousResponse:a,issue:routingIssue(t,o,i)})),i=parseRouting(a);return hasEnoughRouting(t,o,i)?i:function readConfiguredRoutingTree(e,t){if(requiredRoutingCount(e,t)<=1)return[];const n=String(e.deepAgentConfig.systemPrompt??"").split(/\r?\n/u).map(e=>e.trim());for(const o of n){if(!/delegation tree|路由|委托/u.test(o)||!/must|必须|include|包含/u.test(o))continue;const n=e.subagentRefs.filter(e=>{return new RegExp(`\\b${t=e,t.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}\\b`,"u").test(o);var t});if(n.length>=requiredRoutingCount(e,t))return n}return[]}(t.agent,o)}(t,n,o,r);return i.map(e=>t.workspace.agents.get(e)).filter(e=>Boolean(e))}(t),i=r[0]??t.agent,l=[];!function emitRoutingEvents(e,t,n,o){if(t.length>1&&e.request.dataListener?.({type:"delegation.plan",requestId:e.requestId,agentId:e.agent.id,agentIds:t.map(e=>e.id)}),n.id===e.agent.id)return;const r={agentId:e.agent.id,toolName:"task",output:n.id};o.push(r),e.request.dataListener?.({type:"agent.tool.result",requestId:e.requestId,...r}),e.request.dataListener?.({type:"delegation.start",requestId:e.requestId,agentId:n.id})}(t,r,i,l);const c=resolveModel(t.workspace,i),d=await u(t.workspace,i.toolRefs),g=[],f=new Set;if(i.toolRefs.length>0){const e=await forceToolSelection(t,i,d,g);e&&d.has(e.name)&&(recordToolResult(t,l,g,await invokeToolWithStart(t,i,d.get(e.name),e.arguments)),f.add(toolKey(e.name,e.arguments)),await ensureEvidenceAfterPlanning(t,i,d,f,l,g))}for(let r=0;r<4;r+=1){if(t.cancelled.has(t.requestId))return completed(t.requestId,g.join("\n\n"),l,i.id);const r=o({workspace:t.workspace,agent:i,model:c,userInput:t.request.input??"",tools:d,observations:g}),a=await e(c,r),s=n(a);if(!s&&hasEvidence(l)){const e=isUsableFinalAnswer(a)?a:await synthesizeFinalAnswer(t,i,g);return completed(t.requestId,e,l,i.id)}if(s&&shouldSynthesizeRepeatedToolIntent(s,f,g)){const e=await synthesizeFinalAnswer(t,i,g);return completed(t.requestId,e,l,i.id)}const u=s??await forceToolSelection(t,i,d,g);if(!u||!d.has(u.name)){if(hasEvidence(l)){const e=await synthesizeFinalAnswer(t,i,g);return completed(t.requestId,e,l,i.id)}const e=await forceToolSelection(t,i,availableNextTools(d,f),g);if(e&&d.has(e.name)){recordToolResult(t,l,g,await invokeToolWithStart(t,i,d.get(e.name),e.arguments)),f.add(toolKey(e.name,e.arguments));continue}return completed(t.requestId,a,l,i.id)}const p=toolKey(u.name,u.arguments);if(f.has(p)){const e=await forceToolSelection(t,i,availableNextTools(d,f),g);if(e&&d.has(e.name)){recordToolResult(t,l,g,await invokeToolWithStart(t,i,d.get(e.name),e.arguments)),f.add(toolKey(e.name,e.arguments));continue}return completed(t.requestId,g.join("\n\n"),l,i.id)}recordToolResult(t,l,g,await invokeToolWithStart(t,i,d.get(u.name),u.arguments)),f.add(p),await ensureEvidenceAfterPlanning(t,i,d,f,l,g)}const p=hasEvidence(l)?await synthesizeFinalAnswer(t,i,g):g.join("\n\n");return completed(t.requestId,p,l,i.id)}async function forceToolSelection(t,o,r,a){if(t.cancelled.has(t.requestId)||0===r.size)return;const s=resolveModel(t.workspace,o),u=await e(s,i({agent:o,userInput:t.request.input??"",tools:r,observations:a}));return n(u)}function hasEnoughRouting(e,t,n){return n.filter(t=>e.workspace.agents.has(t)).length>=requiredRoutingCount(e.agent,t)}function requiredRoutingCount(e,t){const n=t.split(/\r?\n/u).filter(e=>/^\s*\d+[.)、]/u.test(e)).length;return Math.max(1,Math.min(e.subagentRefs.length,n||1))}function routingIssue(e,t,n){const o=requiredRoutingCount(e.agent,t);return 0===n.length?"No valid available subagent id was returned.":`Only ${n.length} valid subagent ids were returned; at least ${o} are required for this multi-part request.`}function resolveModel(e,t){const n=t.modelRef??"default",o=e.models.get(n)??e.models.get("default");if(!o)throw new Error(`No model configured for agent ${t.id}`);return o}async function invokeToolWithStart(e,t,n,o){return e.request.dataListener?.({type:"agent.tool.start",requestId:e.requestId,agentId:t.id,toolName:n.name}),await new Promise(e=>setImmediate(e)),e.cancelled.has(e.requestId)?{agentId:t.id,toolName:n.name,output:"cancelled before tool invocation",isError:!0}:async function invokeTool(e,t,n,o){const r=process.cwd();try{process.chdir(e.workspace.workspaceRoot);const r=await n.invoke(o);return{agentId:t.id,toolName:n.name,output:stringifyOutput(r)}}catch(e){return{agentId:t.id,toolName:n.name,output:stringifyOutput(e),isError:!0}}finally{process.chdir(r)}}(e,t,n,o)}function recordToolResult(e,t,n,o){t.push(o),e.request.dataListener?.({type:"agent.tool.result",requestId:e.requestId,...o}),n.push(`Tool ${o.toolName} returned:\n${o.output}`)}function isPlanningTool(e){return"task"===e}function hasEvidence(e){return e.some(e=>!e.isError&&!isPlanningTool(e.toolName))}async function ensureEvidenceAfterPlanning(e,t,n,o,r,a){if(hasEvidence(r))return;const s=await forceToolSelection(e,t,availableNextTools(n,o),a);s&&n.has(s.name)&&(recordToolResult(e,r,a,await invokeToolWithStart(e,t,n.get(s.name),s.arguments)),o.add(toolKey(s.name,s.arguments)))}async function synthesizeFinalAnswer(t,n,o){if(0===o.length)return"";const a=resolveModel(t.workspace,n);try{const s=await e(a,r({agent:n,userInput:t.request.input??"",observations:o}));return isUsableFinalAnswer(s)?s:o.join("\n\n")}catch{return o.join("\n\n")}}function isUsableFinalAnswer(e){return e.trim().length>0&&!t(e)}function shouldSynthesizeRepeatedToolIntent(e,t,n){if(!hasExecutedTool(e.name,t))return!1;const o=[...t].filter(t=>t.startsWith(`${e.name}:`)).length<2&&!t.has(toolKey(e.name,e.arguments))&&function latestEvidenceNeedsRetry(e){const t=e.at(-1)??"";return/Quality evaluation:\s*status:\s*(?:failed|weak)|nextAction:\s*make one corrected research call/iu.test(t)}(n);return!o}function availableNextTools(e,t){return new Map([...e].filter(([e])=>!isPlanningTool(e)&&!hasExecutedTool(e,t)))}function hasExecutedTool(e,t){return[...t].some(t=>t.startsWith(`${e}:`))}function parseRouting(e){try{const t=function parseJsonObject(e){try{return JSON.parse(e)}catch{const t=e.indexOf("{"),n=e.lastIndexOf("}");if(t>=0&&n>t)return JSON.parse(e.slice(t,n+1));throw new Error("No JSON object found")}}(e),n=function readRoutingIds(e){for(const t of["agentIds","routing","agents","delegations","plan"]){const n=e[t],o=Array.isArray(n)?n.filter(e=>"string"==typeof e):[];if(o.length>0)return[...new Set(o)]}return[]}(t);if(n.length>0)return n;const o=function readRoutingId(e){for(const t of["agentId","agent","owner","route"]){const n=e[t];if("string"==typeof n&&n.trim().length>0)return n}}(t);return o?[o]:[]}catch{return[]}}function completed(e,t,n,o){return{requestId:e,state:"completed",output:t,metadata:{executedToolResults:n,routedAgentId:o}}}function stringifyOutput(e){return e instanceof Error?e.stack??e.message:"string"==typeof e?e:JSON.stringify(e)}function toolKey(e,t){return`${e}:${JSON.stringify(t)}`}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function parseToolCall(t){return function parseToolCalls(t){if("string"!=typeof t)return[];const n=[];for(const e of function jsonCandidates(t){return[t.trim(),extractJsonObject(t)].filter(t=>Boolean(t))}(t)){const t=normalizeToolCall(safeParse(e));t&&n.push(t)}for(const e of function objectCandidates(t){return t.match(/\{[^{}]*"name"\s*:\s*"[^"]+"[\s\S]*?\}\s*\}/gu)??[]}(t)){const t=normalizeToolCall(safeParse(e));t&&n.push(t)}return function uniqueToolCalls(t){const n=new Set;return t.filter(t=>{const e=`${t.name}:${JSON.stringify(t.arguments)}`;return!n.has(e)&&(n.add(e),!0)})}(n)}(t)[0]}export function containsRawToolCallText(t){return void 0!==parseToolCall(t)||[/<\s*\/?\s*(?:tool_call|tool_code|task)\b[^>]*>/iu,/\{\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:/iu,/\{\s*"tool_name"\s*:\s*"[^"]+"\s*,\s*"parameters"\s*:/iu,/```(?:json)?[\s\S]{0,4000}"(?:name|tool|tool_name)"\s*:[\s\S]{0,4000}"(?:arguments|parameters|args)"\s*:/iu].some(n=>n.test(t))}export function extractJsonObject(t){const n=t.indexOf("{"),e=t.lastIndexOf("}");return n>=0&&e>n?t.slice(n,e+1):void 0}function safeParse(t){try{return JSON.parse(t)}catch{const n=function repairTrailingJson(t){const n=t.trim();if(!n.startsWith("{"))return;let e=0,r=0,o=!1,s=!1;for(const t of n)o?(s="\\"===t&&!s,'"'!==t||s||(o=!1),"\\"!==t&&(s=!1)):('"'===t&&(o=!0),"{"===t&&(e+=1),"}"===t&&(e-=1),"["===t&&(r+=1),"]"===t&&(r-=1));return o||e<0||r<0||e+r>3?void 0:`${n}${"]".repeat(r)}${"}".repeat(e)}`}(t);if(!n)return;try{return JSON.parse(n)}catch{return}}}function normalizeToolCall(t){if("object"!=typeof t||null===t)return;const n=t;if("string"!=typeof n.name)return;const e="object"==typeof n.arguments&&null!==n.arguments?n.arguments:{};return{name:n.name,arguments:e}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function formatCompatDelta(delta: Record<string, unknown>): string[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{readPlanTodos as t}from"@stable-harness/core";export function formatCompatDelta(e){return"delegation.start"===e.type?[`agent:${e.agentId} Starting delegated execution.`]:"delegation.plan"===e.type?[`Planned delegation tree: ${readAgentIds(e).join(" -> ")}`]:"agent.tool.start"===e.type?[`agent:${e.agentId} Running tool ${n=e.toolName,"write_todos"===n?"Call Write Todos.":String(n)}`]:"agent.tool.result"===e.type?function formatToolResult(e){if("task"===e.toolName)return[`agent:${e.agentId} Delegating to ${e.output}.`];if("write_todos"===e.toolName){const n=t(e.output);return n.length>0?function formatTodoBurnDown(t,e){const n=e.filter(t=>"completed"===t.status).length,o=e.filter(t=>"in_progress"===t.status).length,r=e.filter(t=>"pending"===t.status).length,a=[`agent:${t} TODO Burn Down | ${n}/${e.length} done | ${o} active | ${r} pending`];for(const t of e)a.push(` [${todoMarker(t.status)}] ${t.content}`);for(const n of e.filter(t=>"completed"===t.status||"failed"===t.status))a.push(`agent:${t} TODO ${n.status}: ${n.content}`);return a}(String(e.agentId),n):[]}return[]}(e):[];var n}function readAgentIds(t){return Array.isArray(t.agentIds)?t.agentIds.map(String):[]}function todoMarker(t){return"completed"===t?"x":"in_progress"===t?"~":"failed"===t?"!":" "}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { CompiledAgent, CompiledModel, CompiledWorkspace } from "../workspace/types.js";
|
|
2
|
-
import type { LoadedTool } from "./types.js";
|
|
3
|
-
export declare function buildAgentPrompt(input: {
|
|
4
|
-
workspace: CompiledWorkspace;
|
|
5
|
-
agent: CompiledAgent;
|
|
6
|
-
model: CompiledModel;
|
|
7
|
-
userInput: string;
|
|
8
|
-
tools: Map<string, LoadedTool>;
|
|
9
|
-
observations: string[];
|
|
10
|
-
}): string;
|
|
11
|
-
export declare function buildRoutingPrompt(workspace: CompiledWorkspace, agent: CompiledAgent, userInput: string): string;
|
|
12
|
-
export declare function buildRoutingRepairPrompt(input: {
|
|
13
|
-
workspace: CompiledWorkspace;
|
|
14
|
-
agent: CompiledAgent;
|
|
15
|
-
userInput: string;
|
|
16
|
-
previousResponse: string;
|
|
17
|
-
issue?: string;
|
|
18
|
-
}): string;
|
|
19
|
-
export declare function buildToolSelectionPrompt(input: {
|
|
20
|
-
agent: CompiledAgent;
|
|
21
|
-
userInput: string;
|
|
22
|
-
tools: Map<string, LoadedTool>;
|
|
23
|
-
observations?: string[];
|
|
24
|
-
}): string;
|
|
25
|
-
export declare function buildFinalAnswerPrompt(input: {
|
|
26
|
-
agent: CompiledAgent;
|
|
27
|
-
userInput: string;
|
|
28
|
-
observations: string[];
|
|
29
|
-
}): string;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function buildAgentPrompt(e){const o=[...e.tools.values()].map(e=>({name:e.name,description:e.description??""}));return[e.agent.deepAgentConfig.systemPrompt??"","","You are running inside stable-harness.",toolPolicyExcerpt(e.agent,e.tools),'If a tool is needed, return exactly one JSON object: {"name":"tool_name","arguments":{...}}.',"Before returning a final answer, re-read the tool policy excerpts and run any required follow-up evidence tool for this request.","If enough evidence is available, return the final answer only.","Available tools:",JSON.stringify(o,null,2),e.observations.length?`Tool observations:\n${e.observations.join("\n\n")}`:"",`User request:\n${e.userInput}`].filter(Boolean).join("\n")}export function buildRoutingPrompt(e,o,t){const n=o.subagentRefs.map(o=>e.agents.get(o)).filter(e=>Boolean(e)).map(e=>({id:e.id,description:e.description}));return["Choose the best subagent plan for this request.",routingPolicyExcerpt(o,n.map(e=>e.id)),o.deepAgentConfig.systemPrompt??"","Routing policy excerpts are authoritative workspace config.","This is a routing-only step. Tools are unavailable here.","Do not return write_todos, read_todos, task, markdown, or prose.","If a routing policy says a request must include one or more available subagents, include those subagents.",'If one owner is enough, return exactly JSON: {"agentId":"one_id","reason":"short reason"}.','If the request contains multiple specialist-owned tasks, return exactly JSON: {"agentIds":["first_id","second_id"],"reason":"short reason"}.',"For numbered or multi-part requests, check every item and include an owner for each distinct specialist-owned task.","Do not omit later tasks after selecting earlier owners.","Return only ids from Available subagents.","Available subagents:",JSON.stringify(n,null,2),`User request:\n${t}`].filter(Boolean).join("\n")}export function buildRoutingRepairPrompt(e){const o=e.agent.subagentRefs.map(o=>e.workspace.agents.get(o)).filter(e=>Boolean(e)).map(e=>({id:e.id,description:e.description}));return[e.issue??"Your previous routing response did not contain a valid complete routing plan.",routingPolicyExcerpt(e.agent,o.map(e=>e.id)),"This is a routing-only repair. Tools are unavailable here.","Do not return write_todos, read_todos, task, markdown, or prose.","Return JSON only.",'For one owner: {"agentId":"one_id","reason":"short reason"}.','For multiple owners: {"agentIds":["first_id","second_id"],"reason":"short reason"}.',"Use only ids from Available subagents.","Available subagents:",JSON.stringify(o,null,2),`Previous response:\n${e.previousResponse}`,`User request:\n${e.userInput}`].filter(Boolean).join("\n")}export function buildToolSelectionPrompt(e){const o=[...e.tools.values()].map(e=>({name:e.name,description:e.description??""}));return[`Agent: ${e.agent.id}`,e.agent.description?`Responsibility: ${e.agent.description}`:"",toolPolicyExcerpt(e.agent,e.tools),"Choose the single best evidence tool from the available tools.",'Return exactly one JSON object: {"name":"tool_name","arguments":{...}}.',"Infer arguments from the user request, tool description, and tool policy excerpts.","If the user explicitly names an available tool, choose that exact tool.","Do not use empty arguments when the tool policy or user request provides a concrete schema, URL, path, question, ticker, or command.","Prefer the most specific evidence tool for the requested artifact or operation before choosing a general search tool.","Available tools:",JSON.stringify(o,null,2),e.observations?.length?`Tool observations already gathered:\n${e.observations.join("\n\n")}`:"",`User request:\n${e.userInput}`].filter(Boolean).join("\n")}export function buildFinalAnswerPrompt(e){return[e.agent.deepAgentConfig.systemPrompt??"","","You are running inside stable-harness.","Tools are unavailable in this final-answer step.","Use only the tool observations below as evidence.","Return the final user-facing answer now.","Do not return JSON tool calls, markdown code fences, XML tool markup, pseudo tool calls, or future-intent text.","If the evidence is incomplete, answer with the supported findings and state the concrete gaps.","Match the user's request language unless the user explicitly requested another language.",`Tool observations:\n${e.observations.join("\n\n")}`,`User request:\n${e.userInput}`].filter(Boolean).join("\n")}function toolPolicyExcerpt(e,o){const t=String(e.deepAgentConfig.systemPrompt??""),n=[...o.keys()].filter(e=>"write_todos"!==e&&"read_todos"!==e),r=t.split(/\r?\n/u).map(e=>e.trim()).filter(e=>n.some(o=>e.includes(o))).slice(0,12);return r.length>0?`Tool policy excerpts:\n${r.join("\n")}`:""}function routingPolicyExcerpt(e,o){const t=String(e.deepAgentConfig.systemPrompt??"").split(/\r?\n/u).map(e=>e.trim()).filter(e=>function isRoutingPolicyLine(e,o){const t=e.toLowerCase();return o.some(o=>e.includes(o))&&/\b(route|routing|delegate|delegation|owner|specialist|include|tree|task)\b/u.test(t)}(e,o)),n=t.map(e=>({line:e,score:routingPolicyScore(e,o)})).sort((e,o)=>o.score-e.score).map(e=>e.line).slice(0,16);return n.length>0?`Routing policy excerpts:\n${n.join("\n")}`:""}function routingPolicyScore(e,o){const t=e.toLowerCase();return 10*o.filter(o=>e.includes(o)).length+(t.match(/\b(must|include|order|tree|requires|required|exactly|only)\b/gu)??[]).length}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createModuleToolGateway as o}from"@stable-harness/tool-gateway";export async function loadAgentTools(t,e){const s=new Map,a=await o({tools:[...t.tools.values()].filter(o=>e.includes(o.id))});for(const o of e){const e=a.get(o);e&&s.set(o,{name:o,description:e.description,schema:e.schema,invoke:e=>a.invoke({toolId:o,args:e,context:{workspaceRoot:t.workspaceRoot,requestId:"compat-tool-registry",sessionId:"compat",agentId:"compat"}}).then(o=>o.output)})}return s}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { CompiledAgent, CompiledWorkspace } from "../workspace/types.js";
|
|
2
|
-
export type RuntimeRequestInput = {
|
|
3
|
-
agentId?: string;
|
|
4
|
-
input?: string;
|
|
5
|
-
dataListener?: (delta: Record<string, unknown>) => void;
|
|
6
|
-
};
|
|
7
|
-
export type RuntimeResult = {
|
|
8
|
-
requestId: string;
|
|
9
|
-
state: "completed" | "failed" | "cancelled" | "blocked";
|
|
10
|
-
output: string;
|
|
11
|
-
metadata: {
|
|
12
|
-
executedToolResults: ExecutedToolResult[];
|
|
13
|
-
routedAgentId?: string;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
export type ExecutedToolResult = {
|
|
17
|
-
agentId: string;
|
|
18
|
-
toolName: string;
|
|
19
|
-
output: string;
|
|
20
|
-
isError?: boolean;
|
|
21
|
-
};
|
|
22
|
-
export type ToolCall = {
|
|
23
|
-
name: string;
|
|
24
|
-
arguments: Record<string, unknown>;
|
|
25
|
-
};
|
|
26
|
-
export type LoadedTool = {
|
|
27
|
-
name: string;
|
|
28
|
-
description?: string;
|
|
29
|
-
schema?: unknown;
|
|
30
|
-
invoke(args: unknown): Promise<unknown>;
|
|
31
|
-
};
|
|
32
|
-
export type AgentExecutionInput = {
|
|
33
|
-
workspace: CompiledWorkspace;
|
|
34
|
-
agent: CompiledAgent;
|
|
35
|
-
request: RuntimeRequestInput;
|
|
36
|
-
requestId: string;
|
|
37
|
-
cancelled: Set<string>;
|
|
38
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{};
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# Stable Harness Compatibility Matrix
|
|
2
|
-
|
|
3
|
-
This document tracks compatibility work against `agent-harness` while preserving the clean runtime boundary.
|
|
4
|
-
|
|
5
|
-
`stable-harness` should not replicate `agent-harness` as a project. It should only keep the compatibility surface needed for downstream workspaces while rebuilding runtime-owned capabilities as small, typed, pluggable modules.
|
|
6
|
-
|
|
7
|
-
## Classification
|
|
8
|
-
|
|
9
|
-
Every compatibility item must use one of these decisions:
|
|
10
|
-
|
|
11
|
-
- `passthrough`: the upstream backend already owns the capability
|
|
12
|
-
- `runtime wrapper`: `stable-harness` adds lifecycle, events, governance, persistence, or protocol access around upstream execution
|
|
13
|
-
- `plugin capability`: runtime-owned but optional and replaceable
|
|
14
|
-
- `downstream workspace`: application-specific behavior owned by EasyNet, Flev, or another workspace
|
|
15
|
-
- `do not build`: duplicates upstream execution semantics or hardcodes downstream behavior
|
|
16
|
-
|
|
17
|
-
## Current EasyNet Gate
|
|
18
|
-
|
|
19
|
-
EasyNet currently uses this local compatibility path:
|
|
20
|
-
|
|
21
|
-
```text
|
|
22
|
-
stable-harness -> file:../stable-harness
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The passing gate proves that `stable-harness` can run the current EasyNet E2E suite. It does not prove full `agent-harness` parity.
|
|
26
|
-
|
|
27
|
-
The current migration implementation lives under `runtime/compat`. New runtime capabilities should not extend that folder by default; they should move into typed packages or pluggable runtime modules.
|
|
28
|
-
|
|
29
|
-
The root package now exposes only native stable runtime entrypoints. The `agent-harness` API remains available only from `./compat/agent-harness.js` for explicit compatibility imports.
|
|
30
|
-
|
|
31
|
-
Verified gates:
|
|
32
|
-
|
|
33
|
-
- `npm test` in EasyNet
|
|
34
|
-
- `npm run test:botbotgo:full` in EasyNet
|
|
35
|
-
- `npm run test:stable-native-cli` in EasyNet
|
|
36
|
-
- stable-harness package tests for explicit compat import support through `./compat/agent-harness.js`
|
|
37
|
-
- CLI compatibility through EasyNet's package-local `node_modules/.bin/botbotgo`
|
|
38
|
-
- native typed tool execution through EasyNet's package-local `node_modules/.bin/botbotgo --tool`
|
|
39
|
-
- native CLI coverage through EasyNet's package-local `node_modules/.bin/stable-harness`
|
|
40
|
-
|
|
41
|
-
## Compatibility Rows
|
|
42
|
-
|
|
43
|
-
| Capability | Current owner | Decision | Current status | Next action |
|
|
44
|
-
| --- | --- | --- | --- | --- |
|
|
45
|
-
| Public compat API: `createAgentHarness`, `request`, `stop` | `compat/agent-harness` | runtime wrapper | Minimal EasyNet-compatible facade exists only on the explicit compat subpath | Keep as a thin migration facade; move implementation behind core runtime contracts |
|
|
46
|
-
| `botbotgo` CLI entrypoint | stable CLI facade | runtime wrapper | Natural-language requests stay on the compatibility runner; typed `--tool` requests now use native stable runtime/tool gateway | Continue moving typed surfaces first; switch natural-language requests only after upstream DeepAgents delegation/tool-calling satisfies the real matrix |
|
|
47
|
-
| Workspace YAML loading | stable runtime | plugin capability | Loads EasyNet agent/model/tool/skill/memory config; EasyNet config now uses `apiVersion: stable-harness.dev/v1` | Move package-local loader into `@stable-harness/workspace-yaml` as the single implementation |
|
|
48
|
-
| DeepAgents execution semantics | DeepAgents | passthrough | Native adapter can call upstream `createDeepAgent`; EasyNet direct tests use native runtime/tool calls, while natural-language `botbotgo` compatibility still uses the compatibility runner | Move downstream natural-language CLI flows from compat runner to native adapter when upstream tool calling is stable |
|
|
49
|
-
| Subagent delegation semantics | DeepAgents | passthrough | Current runner asks model for a routed agent list and emits stable events; direct user-text route shortcuts were removed from compat | Keep event projection; move actual delegation to upstream DeepAgents task/subagent primitives |
|
|
50
|
-
| Delegation plan events | stable runtime | runtime wrapper | Compat emits `delegation.plan` and `delegation.start`; native trace now projects observed upstream DeepAgents `task` tool calls as `delegation.start` and `delegation.completed` entries without selecting agents locally | Keep as normalized observability only; do not synthesize task calls or route from text |
|
|
51
|
-
| Explicit tool execution | stable runtime tool gateway | runtime wrapper | Native `RuntimeRequest.toolCall` invokes only the selected agent's declared tools through `toolGateway`; EasyNet tool matrix, contract tests, and native CLI E2E no longer use compat `toolName`/`args`; the compat direct-invoke request fields were removed | Keep direct tool execution native-only and continue migrating remaining natural-language compat paths separately |
|
|
52
|
-
| Upstream tool calling | upstream backend | passthrough | DeepAgents receives tool gateway tools, but the current remote Ollama path is not yet stable enough to replace compat tool selection | Keep as upstream passthrough; do not add prompt or keyword repair in the adapter |
|
|
53
|
-
| Tool start/result events | stable runtime | runtime wrapper | Native runtime emits `runtime.tool.direct.started` and `runtime.tool.direct.completed`; DeepAgents adapter emits upstream tool events under `runtime.adapter.event`; `projectRuntimeTrace` exposes a normalized trace view consumed by native CLI `--trace` and `--trace-json`; native CLI now streams `--trace` rows as events happen, so long/timeout runs expose progress before finalization; EasyNet asserts native `subscribe` tool events without compat `dataListener` | Continue moving downstream CLI trace checks from compat dataListener to native trace output |
|
|
54
|
-
| Tool argument generation | upstream backend | passthrough | Compatibility runner uses constrained model prompts; user-input JSON tool-call pre-execution was removed from compat | Remove from default DeepAgents adapter; keep only optional tool gateway repair/validation if configured |
|
|
55
|
-
| Required evidence tools | stable runtime policy | plugin capability | Native runtime validates `executionContract.requiredEvidenceTools` from emitted tool events and fails incomplete runs; compat repair for missing required evidence was removed | Keep as validation policy only; do not synthesize or repair tool calls from this contract |
|
|
56
|
-
| Required planning checkpoint | stable runtime policy | plugin capability | Native runtime validates `executionContract.requiresPlan` by observing `write_todos` tool events and fails incomplete runs | Keep as validation policy only; TODO execution remains upstream/back-end owned |
|
|
57
|
-
| TODO trace projection | stable runtime event/view | runtime wrapper | Native `projectRuntimeTrace` projects observed upstream `write_todos` tool completions as `plan.updated`; `readPlanTodos` normalizes structured TODO payloads for presentation; stable no longer provides local `write_todos` or `read_todos` tools | Keep as presentation/event projection only; do not parse TODO text to create tool calls |
|
|
58
|
-
| Built-in `write_todos` and `read_todos` | DeepAgents | passthrough/runtime wrapper | DeepAgents owns its built-in `write_todos`; stable observes upstream `write_todos`/`task` tool calls through middleware without injecting same-name tools; the stable tool gateway planning-tool implementation was removed | Keep observing upstream built-ins; do not synthesize planning or delegation calls |
|
|
59
|
-
| Model provider path | upstream backend adapter | passthrough | Minimal Ollama prompted JSON path supports EasyNet | Move provider handling into backend adapter config; avoid stable-owned model execution semantics |
|
|
60
|
-
| Result compression/final response | runtime optional layer | plugin capability | Not formalized; current runner returns model/fallback text | Design as optional output policy with typed config |
|
|
61
|
-
| Approvals/HITL | stable governance | plugin capability | Not implemented in compatibility runner | Build as independent governance capability |
|
|
62
|
-
| Sandbox policy | stable governance | plugin capability | Not implemented in compatibility runner | Build as independent sandbox policy capability |
|
|
63
|
-
| Run persistence/recovery | stable runtime | plugin capability | Not implemented in compatibility runner | Build as independent run store and recovery capability |
|
|
64
|
-
| Memory lifecycle | stable runtime | plugin capability | Not implemented beyond config load | Build memory lifecycle outside backend execution semantics |
|
|
65
|
-
| Replay/artifacts/traces | stable runtime | plugin capability | Runtime records events per run and exposes `projectRuntimeTrace`; native CLI can print stable trace rows or JSON trace; HTTP exposes `/runs/{requestId}/trace` | Add protocol streaming/export over the same event model |
|
|
66
|
-
| EasyNet specialist prompts and tool ownership | EasyNet workspace | downstream workspace | Owned by EasyNet YAML and resources | Keep out of generic runtime |
|
|
67
|
-
| Finance, Kubernetes, QA, release, secretary rules | EasyNet workspace | downstream workspace | Encoded in EasyNet agents, tools, and skills | Do not move into `stable-harness` runtime |
|
|
68
|
-
| Natural-language keyword routing | none | do not build | Forbidden | Use typed config, metadata, runtime state, or upstream primitives only |
|
|
69
|
-
| TODO text to tool-call inference | none | do not build | Forbidden | Use upstream tool calls or typed runtime policy only |
|
|
70
|
-
|
|
71
|
-
## Current Technical Debt
|
|
72
|
-
|
|
73
|
-
The EasyNet compatibility runner is intentionally temporary. It contains behavior that must be split before `stable-harness` becomes a clean production runtime:
|
|
74
|
-
|
|
75
|
-
- `runtime/compat` should remain a migration-only layer and must not become the default stable runtime core
|
|
76
|
-
- routing prompt and parser should become either upstream DeepAgents delegation passthrough or an optional typed router capability
|
|
77
|
-
- natural-language compat tool selection should be replaced by upstream DeepAgents tool calling; direct `toolName`/`args` invocation moved to native `RuntimeRequest.toolCall`, and execution contracts moved to native validation
|
|
78
|
-
- local TODO built-ins were removed; native planning evidence must come from observed upstream DeepAgents `write_todos`
|
|
79
|
-
- prompted JSON tool choice should not be the stable default when upstream tool calling exists
|
|
80
|
-
- compatibility CLI output should be replaced by native trace projection where the behavior is present in runtime events
|
|
81
|
-
|
|
82
|
-
Current migration evidence:
|
|
83
|
-
|
|
84
|
-
- `stable-harness` native CLI can run an EasyNet specialist through the real remote Ollama model for non-tool synthesis.
|
|
85
|
-
- `stable-harness` native runtime can load EasyNet workspace tools through `createModuleToolGateway`.
|
|
86
|
-
- `stable-harness` native runtime and native CLI can execute an explicit EasyNet `git_command` request through `RuntimeRequest.toolCall` and `createModuleToolGateway`, without using `runtime/compat`.
|
|
87
|
-
- EasyNet's package-local `botbotgo --tool` now executes typed tool calls through native stable runtime/tool gateway and emits native trace rows; natural-language `botbotgo` requests remain on compat.
|
|
88
|
-
- EasyNet's model/context matrix can run in native diagnostic mode with `EASYNET_E2E_NATIVE=1`; this drives `botbotgo --native --trace` while preserving the default compat matrix.
|
|
89
|
-
- EasyNet now has `npm run test:stable-native-diagnostics`, a non-compat-readiness gate that requires native natural-language runs to emit stable trace before they are allowed to fail on known upstream orchestration gaps.
|
|
90
|
-
- `stable-harness` native CLI `--trace` and `--trace-json` project `runtime.tool.direct.started` and `runtime.tool.direct.completed` from runtime events; EasyNet native CLI E2E asserts this trace without compat.
|
|
91
|
-
- `stable-harness` native trace projects observed `write_todos` completions as `plan.updated`; `readPlanTodos` reads structured TODO payloads for presentation, and does not synthesize TODO calls or parse TODO text.
|
|
92
|
-
- DeepAgents adapter now installs a `StableHarnessObserver` middleware that observes upstream built-in `write_todos` and `task` tool calls and emits stable `runtime.adapter.event` records without registering or replacing those tools.
|
|
93
|
-
- The same observer now records upstream DeepAgents filesystem built-ins (`ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`) so native traces expose policy-denied filesystem attempts without replaying or replacing upstream tools.
|
|
94
|
-
- Native `projectRuntimeTrace` now projects observed upstream DeepAgents `task` calls as stable delegation trace entries, preserving the upstream `subagent_type` as detail when present.
|
|
95
|
-
- Native DeepAgents adapter treats `config.builtinTools.modelExposed` as an explicit governance switch: `false` hides upstream `task`, `["task"]` restricts task targets to workspace-declared subagents, and omitted config preserves upstream DeepAgents task behavior including `general-purpose`.
|
|
96
|
-
- EasyNet native contract tests now assert that invalid upstream task targets such as `research-analyst` are blocked by the stable adapter policy and are not locally remapped to an EasyNet specialist.
|
|
97
|
-
- EasyNet native contract tests also assert that specialists with `modelExposed: false` block upstream `task` completely.
|
|
98
|
-
- Native DeepAgents adapter maps stable `config.builtinTools.filesystem: false` to upstream DeepAgents filesystem permissions that deny `read` and `write` on `/**`, unless the workspace explicitly provides `config.deepagents.permissions`.
|
|
99
|
-
- Native CLI `--trace` streams runtime trace rows before completion, making native adapter hangs/timeouts observable.
|
|
100
|
-
- Compatibility CLI output formatting is centralized in `formatCompatDelta`, which consumes the shared structured TODO reader instead of parsing TODO payloads in the CLI entrypoint.
|
|
101
|
-
- EasyNet native contract tests assert `runtime.tool.direct.started` and `runtime.tool.direct.completed` through stable runtime `subscribe`, without compat `dataListener`.
|
|
102
|
-
- Native workspace loader now discovers `resources/skills/*/SKILL.md` as stable skill inventory and reads each agent's `skills` and `memory` refs without executing them.
|
|
103
|
-
- Native workspace loader reads agent metadata descriptions, and the DeepAgents adapter passes those descriptions through for upstream subagent definitions.
|
|
104
|
-
- EasyNet skill metadata contract now consumes native `workspace.skills` inventory instead of the legacy `runtime/skills/skill-metadata.js` helper.
|
|
105
|
-
- Native workspace loader records agent source paths and discovers module tool ids from `export const <toolId> = tool(...)`, so tool inventory no longer depends on filename-only compatibility behavior.
|
|
106
|
-
- EasyNet contract and real integration tests no longer import the legacy `workspace/compile.js`; they use native `loadWorkspaceFromYaml` for model, agent, tool, skill, memory, source, and response-format inventory.
|
|
107
|
-
- EasyNet specialist response formats are explicit in workspace YAML instead of relying on the legacy compiler's default response-format completion.
|
|
108
|
-
- EasyNet tests and scripts no longer import `compat/agent-harness.js`; remaining EasyNet compatibility coverage goes through the package-local `botbotgo` CLI while native coverage uses `stable-harness` runtime/CLI entrypoints.
|
|
109
|
-
- `stable-harness` native runtime validates EasyNet release `requiredEvidenceTools` and reports missing evidence without compat repair prompts.
|
|
110
|
-
- `stable-harness` native runtime validates EasyNet specialist `requiresPlan` and reports missing `write_todos` checkpoints without synthesizing TODO calls.
|
|
111
|
-
- EasyNet's real specialist tool matrix now executes through native stable `toolCall`; compat request `toolName`/`args` no longer exists as a migration path.
|
|
112
|
-
- EasyNet real and full matrix scripts now resolve `botbotgo` from the workspace package bin instead of a checkout-internal `stable-harness/dist/cli.js` path.
|
|
113
|
-
- EasyNet workspace YAML now declares `apiVersion: stable-harness.dev/v1`; the old `agent-harness/v1alpha1` name is no longer the application config identity.
|
|
114
|
-
- Compatibility runner no longer exposes local `write_todos` or `read_todos`; visible planning evidence in native paths must come from observed upstream DeepAgents built-ins, not stable-owned duplicate tools.
|
|
115
|
-
- DeepAgents 1.9.1 rejects custom tools named `write_todos` because planning is a built-in upstream tool; the native adapter intentionally does not inject stable planning tools over upstream built-ins.
|
|
116
|
-
- Native EasyNet research still is not a full replacement for compat: real runs can fail before synthesis when the upstream model selects the built-in `task` tool with an invalid agent type such as `research-analyst`, and repeated checks also hit remote model `502 Bad Gateway` or 120s timeouts; this must be solved by upstream delegation/tool behavior, endpoint stability, or typed workspace configuration, not by runtime keyword routing.
|
|
117
|
-
- A native diagnostic matrix sample against EasyNet `research-stock` now observes stable trace rows and classifies upstream filesystem access as `native_filesystem_denied` when EasyNet disables filesystem built-ins; the current DeepAgents API still exposes filesystem middleware by default, so this remains an upstream/workspace configuration blocker rather than a stable runtime routing feature.
|
|
118
|
-
- The native diagnostic gate now separates stable readiness from compat-style business assertions: `passed` means native trace/readiness when `EASYNET_E2E_REQUIRE_NATIVE_TRACE=1`, while `businessPassed` keeps the old full-matrix success signal for natural-language migration work. Filesystem-denied native blockers must include a concrete upstream builtin trace such as `agent.tool.start:grep`.
|
|
119
|
-
- Compatibility runner no longer pre-executes JSON tool calls parsed directly from user input; explicit execution belongs to native typed `RuntimeRequest.toolCall`.
|
|
120
|
-
- Compatibility runner no longer routes directly from user text patterns such as explicit `delegate/route/委托 <agentId>`; routing now goes through the compat model-routing prompt until upstream DeepAgents delegation replaces it.
|
|
121
|
-
- Native upstream DeepAgents tool-calling with the current remote Ollama path is not yet a replacement for the compatibility runner; a direct `git_command` request hung until terminated. Keep compat tool-selection behavior until upstream tool-calling is stable or an explicit typed tool-execution policy replaces it.
|
|
122
|
-
|
|
123
|
-
## Acceptance Rule
|
|
124
|
-
|
|
125
|
-
A compatibility feature is acceptable only when all of these are true:
|
|
126
|
-
|
|
127
|
-
- it does not duplicate a current DeepAgents execution primitive in the default path
|
|
128
|
-
- it can be disabled, replaced, or moved behind typed config
|
|
129
|
-
- it has focused tests that assert runtime contracts rather than downstream business cases
|
|
130
|
-
- it keeps downstream product logic in the workspace
|
|
131
|
-
- it improves migration without expanding the public runtime API unnecessarily
|
|
132
|
-
|
|
133
|
-
## Next Cleanup Sequence
|
|
134
|
-
|
|
135
|
-
1. Replace the compatibility runner's default DeepAgents path with upstream `createDeepAgent`.
|
|
136
|
-
2. Replace natural-language compat tool selection with upstream DeepAgents tool calling once the remote Ollama tool-call path is stable.
|
|
137
|
-
3. Move remaining CLI trace checks from compat `dataListener` to native `projectRuntimeTrace` where native runtime events exist.
|
|
138
|
-
4. Keep only the explicit `./compat/agent-harness.js` facade until downstream workspaces can use the native stable runtime API directly.
|
|
139
|
-
5. Add tests for each runtime capability boundary before broadening beyond EasyNet.
|
|
140
|
-
|
|
141
|
-
## Retirement Gates
|
|
142
|
-
|
|
143
|
-
Compatibility can shrink only when the replacement is expressed as one of the stable native boundaries below:
|
|
144
|
-
|
|
145
|
-
- upstream passthrough through a backend adapter, with no local replay of execution semantics
|
|
146
|
-
- a typed runtime capability that can be enabled, disabled, replaced, and tested independently
|
|
147
|
-
- a protocol or operator projection over existing runtime events, traces, artifacts, approvals, or run state
|
|
148
|
-
- downstream workspace config, prompt, tool, or test changes for application-owned behavior
|
|
149
|
-
|
|
150
|
-
New work must not import `runtime/compat` or `compat/agent-harness` from native packages. Static architecture tests enforce this and also guard core source from backend imports and downstream domain vocabulary.
|