stable-harness 0.0.1
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 +32 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +2 -0
- package/dist/compat/agent-harness.d.ts +24 -0
- package/dist/compat/agent-harness.js +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1 -0
- package/dist/runtime/compat/agent-harness-compat-runner.d.ts +2 -0
- package/dist/runtime/compat/agent-harness-compat-runner.js +1 -0
- package/dist/runtime/compat/json.d.ts +3 -0
- package/dist/runtime/compat/json.js +1 -0
- package/dist/runtime/compat/presentation.d.ts +1 -0
- package/dist/runtime/compat/presentation.js +1 -0
- package/dist/runtime/compat/prompts.d.ts +24 -0
- package/dist/runtime/compat/prompts.js +1 -0
- package/dist/runtime/compat/tool-registry.d.ts +3 -0
- package/dist/runtime/compat/tool-registry.js +1 -0
- package/dist/runtime/compat/types.d.ts +38 -0
- package/dist/runtime/compat/types.js +1 -0
- package/dist/runtime/model/ollama.d.ts +2 -0
- package/dist/runtime/model/ollama.js +1 -0
- package/dist/runtime/skills/skill-metadata.d.ts +7 -0
- package/dist/runtime/skills/skill-metadata.js +1 -0
- package/dist/runtime/workspace/types.d.ts +38 -0
- package/dist/runtime/workspace/types.js +1 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.js +1 -0
- package/dist/workspace/compile.d.ts +2 -0
- package/dist/workspace/compile.js +1 -0
- package/package.json +94 -0
- package/packages/adapter-deepagents/dist/src/adapter.d.ts +8 -0
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -0
- package/packages/adapter-deepagents/dist/src/builtin-tool-policy.d.ts +18 -0
- package/packages/adapter-deepagents/dist/src/builtin-tool-policy.js +1 -0
- package/packages/adapter-deepagents/dist/src/index.d.ts +2 -0
- package/packages/adapter-deepagents/dist/src/index.js +1 -0
- package/packages/adapter-deepagents/dist/src/messages.d.ts +9 -0
- package/packages/adapter-deepagents/dist/src/messages.js +1 -0
- package/packages/adapter-deepagents/dist/src/retry-policy.d.ts +2 -0
- package/packages/adapter-deepagents/dist/src/retry-policy.js +1 -0
- package/packages/adapter-deepagents/dist/src/stream-events.d.ts +2 -0
- package/packages/adapter-deepagents/dist/src/stream-events.js +1 -0
- package/packages/adapter-deepagents/dist/src/types.d.ts +6 -0
- package/packages/adapter-deepagents/dist/src/types.js +1 -0
- package/packages/adapter-deepagents/package.json +26 -0
- package/packages/cli/dist/src/cli.d.ts +2 -0
- package/packages/cli/dist/src/cli.js +2 -0
- package/packages/cli/dist/src/index.d.ts +1 -0
- package/packages/cli/dist/src/index.js +1 -0
- package/packages/cli/package.json +22 -0
- package/packages/core/dist/artifacts.d.ts +8 -0
- package/packages/core/dist/artifacts.js +1 -0
- package/packages/core/dist/execution-contract.d.ts +8 -0
- package/packages/core/dist/execution-contract.js +1 -0
- package/packages/core/dist/index.d.ts +9 -0
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/inspection.d.ts +4 -0
- package/packages/core/dist/inspection.js +1 -0
- package/packages/core/dist/memory-plugins.d.ts +68 -0
- package/packages/core/dist/memory-plugins.js +1 -0
- package/packages/core/dist/queue.d.ts +2 -0
- package/packages/core/dist/queue.js +1 -0
- package/packages/core/dist/runtime.d.ts +12 -0
- package/packages/core/dist/runtime.js +1 -0
- package/packages/core/dist/stores.d.ts +3 -0
- package/packages/core/dist/stores.js +1 -0
- package/packages/core/dist/trace.d.ts +15 -0
- package/packages/core/dist/trace.js +1 -0
- package/packages/core/dist/types.d.ts +526 -0
- package/packages/core/dist/types.js +1 -0
- package/packages/core/package.json +17 -0
- package/packages/evaluation/dist/src/index.d.ts +2 -0
- package/packages/evaluation/dist/src/index.js +1 -0
- package/packages/evaluation/dist/src/trace.d.ts +16 -0
- package/packages/evaluation/dist/src/trace.js +1 -0
- package/packages/evaluation/dist/src/types.d.ts +11 -0
- package/packages/evaluation/dist/src/types.js +1 -0
- package/packages/evaluation/package.json +15 -0
- package/packages/governance/dist/src/approval-queue.d.ts +2 -0
- package/packages/governance/dist/src/approval-queue.js +1 -0
- package/packages/governance/dist/src/index.d.ts +4 -0
- package/packages/governance/dist/src/index.js +1 -0
- package/packages/governance/dist/src/policy-engine.d.ts +2 -0
- package/packages/governance/dist/src/policy-engine.js +1 -0
- package/packages/governance/dist/src/skill-candidates.d.ts +2 -0
- package/packages/governance/dist/src/skill-candidates.js +1 -0
- package/packages/governance/dist/src/types.d.ts +100 -0
- package/packages/governance/dist/src/types.js +1 -0
- package/packages/governance/package.json +12 -0
- package/packages/memory/dist/src/index.d.ts +9 -0
- package/packages/memory/dist/src/index.js +1 -0
- package/packages/memory/dist/src/langmem-service.d.ts +8 -0
- package/packages/memory/dist/src/langmem-service.js +1 -0
- package/packages/memory/dist/src/maintenance.d.ts +2 -0
- package/packages/memory/dist/src/maintenance.js +1 -0
- package/packages/memory/dist/src/persistence.d.ts +4 -0
- package/packages/memory/dist/src/persistence.js +1 -0
- package/packages/memory/dist/src/policy.d.ts +2 -0
- package/packages/memory/dist/src/policy.js +1 -0
- package/packages/memory/dist/src/provider.d.ts +50 -0
- package/packages/memory/dist/src/provider.js +1 -0
- package/packages/memory/dist/src/store.d.ts +5 -0
- package/packages/memory/dist/src/store.js +1 -0
- package/packages/memory/dist/src/types.d.ts +138 -0
- package/packages/memory/dist/src/types.js +1 -0
- package/packages/memory/package.json +12 -0
- package/packages/protocols/dist/src/http-server.d.ts +3 -0
- package/packages/protocols/dist/src/http-server.js +1 -0
- package/packages/protocols/dist/src/in-process-client.d.ts +2 -0
- package/packages/protocols/dist/src/in-process-client.js +1 -0
- package/packages/protocols/dist/src/index.d.ts +4 -0
- package/packages/protocols/dist/src/index.js +1 -0
- package/packages/protocols/dist/src/openai-compatible.d.ts +9 -0
- package/packages/protocols/dist/src/openai-compatible.js +1 -0
- package/packages/protocols/package.json +15 -0
- package/packages/tool-gateway/dist/src/argument-guard.d.ts +32 -0
- package/packages/tool-gateway/dist/src/argument-guard.js +1 -0
- package/packages/tool-gateway/dist/src/in-memory.d.ts +4 -0
- package/packages/tool-gateway/dist/src/in-memory.js +1 -0
- package/packages/tool-gateway/dist/src/index.d.ts +7 -0
- package/packages/tool-gateway/dist/src/index.js +1 -0
- package/packages/tool-gateway/dist/src/module-loader.d.ts +13 -0
- package/packages/tool-gateway/dist/src/module-loader.js +1 -0
- package/packages/tool-gateway/dist/src/types.d.ts +65 -0
- package/packages/tool-gateway/dist/src/types.js +1 -0
- package/packages/tool-gateway/package.json +15 -0
- package/packages/workspace-yaml/dist/index.d.ts +1 -0
- package/packages/workspace-yaml/dist/index.js +1 -0
- package/packages/workspace-yaml/dist/loader.d.ts +2 -0
- package/packages/workspace-yaml/dist/loader.js +1 -0
- package/packages/workspace-yaml/package.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# stable-harness
|
|
2
|
+
|
|
3
|
+
Stable runtime and operator control plane for agent applications.
|
|
4
|
+
|
|
5
|
+
`stable-harness` is not an agent execution framework. It loads a YAML-defined
|
|
6
|
+
workspace, maps that workspace onto an upstream agent framework, and owns the
|
|
7
|
+
production runtime surfaces around execution: requests, sessions, approvals,
|
|
8
|
+
events, artifacts, memory lifecycle, recovery, governance, and protocol access.
|
|
9
|
+
|
|
10
|
+
The first backend target is DeepAgents. The adapter contract is intentionally
|
|
11
|
+
thin: upstream frameworks own execution semantics; stable-harness owns runtime
|
|
12
|
+
assembly and lifecycle.
|
|
13
|
+
|
|
14
|
+
## First Run
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
npm run check:rules
|
|
20
|
+
npm run test
|
|
21
|
+
npm run example:minimal
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Product Boundary
|
|
25
|
+
|
|
26
|
+
See:
|
|
27
|
+
|
|
28
|
+
- [Product boundary](docs/product-boundary.md)
|
|
29
|
+
- [Compatibility matrix](docs/compatibility-matrix.md)
|
|
30
|
+
- [Implementation blueprint](docs/implementation-blueprint.md)
|
|
31
|
+
- [Engineering rules](docs/engineering-rules.md)
|
|
32
|
+
- [Adapter contract](docs/adapter-contract.md)
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
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 s}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as r}from"@stable-harness/workspace-yaml";import{createAgentHarness as n,request as c,stop as l}from"./compat/agent-harness.js";import{formatCompatDelta as i}from"./runtime/compat/presentation.js";const p=function(t){let o,e,a,s=process.cwd(),r=!1,n=!1,c=!1,l=Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5);const i=[];for(let p=0;p<t.length;p+=1)"-w"===t[p]||"--workspace"===t[p]?s=t[++p]??s:"--agent"===t[p]?o=t[++p]:"--tool"===t[p]?e=t[++p]:"--tool-args-json"===t[p]?a=m(t[++p]??"{}"):"--trace"===t[p]?r=!0:"--trace-json"===t[p]?n=!0:"--native"===t[p]?c=!0:"--timeout-ms"===t[p]?l=Number(t[++p]??l):i.push(t[p]);return{workspaceRoot:s,agentId:o,toolId:e,toolArgs:a,trace:r,traceJson:n,native:c,timeoutMs:l,prompt:i.join(" ")||"hello"}}(process.argv.slice(2));function u(t){return"tool.started"===t.type?[`agent:${t.agentId} Running tool ${t.toolId}`]:[]}function m(t){try{return JSON.parse(t)}catch(t){throw new Error(`Invalid --tool-args-json value: ${t instanceof Error?t.message:String(t)}`)}}p.toolId||p.native?await async function(n){const c=setTimeout(()=>{process.stderr.write(`botbotgo native request timed out after ${n.timeoutMs}ms\n`),process.exit(124)},n.timeoutMs);try{const c=await r(n.workspaceRoot),l=await s({tools:c.tools.values()}),i=o({workspace:c,toolGateway:l,adapters:[t()]});n.trace?i.subscribe(t=>{const o=e(t);var a;o&&console.log(`trace:${o.agentId}:${o.label}${a=o.detail,"string"==typeof a?.toolId?`:${a.toolId}`:""}`);for(const o of u(t))console.log(o)}):i.subscribe(t=>{for(const o of u(t))console.log(o)});const p=await i.request({agentId:n.agentId,input:n.prompt,toolCall:n.toolId?{toolId:n.toolId,args:n.toolArgs}:void 0});!function(t,o,e){if(!e.trace&&!e.traceJson)return;const s=t.getRun(o),r=s?a(s):[];e.traceJson&&console.log(JSON.stringify({trace:r}))}(i,p.requestId,n),console.log(p.output),process.exitCode="completed"===p.state?0:1}finally{clearTimeout(c)}}(p):await async function(t){const o=await n(t.workspaceRoot);try{const e=await c(o,{agentId:t.agentId,input:t.prompt,dataListener(t){for(const o of i(t))console.log(o)}});console.log(e.output),process.exitCode="completed"===e.state?0:1}finally{await l(o)}}(p);
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
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(t){const n=new Set;return{workspace:t,async request(r){const s=e();return o(t,r,s,n)},async*streamEvents(r){const s=e();yield{type:"event",event:{eventType:"request.created",requestId:s}};const a=function(){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))}})}}(),c=o(t,r,s,n,e=>{"tool.start"===e.type?a.push({type:"event",event:{payload:{event:"on_tool_start",run_type:"tool",name:e.toolName}}}):a.push({requestId:s,...e,type:"tool-result"})}).finally(()=>a.close());for await(const e of a)yield e;await c},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 o(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})}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RuntimeAdapter, RuntimeRequest, StableHarnessRuntime } from "@stable-harness/core";
|
|
2
|
+
export { createDeepAgentsAdapter } from "@stable-harness/adapter-deepagents";
|
|
3
|
+
export { createStableHarnessRuntime } from "@stable-harness/core";
|
|
4
|
+
export { createLangMemServiceProvider } from "@stable-harness/memory";
|
|
5
|
+
export type { CompiledWorkspace, RuntimeAdapter, RuntimeEvent, RuntimeRequest, RuntimeResponse, RuntimeRunRecord, StableHarnessRuntime, WorkspaceAgent, WorkspaceModel, WorkspaceRuntimePolicy, WorkspaceTool, } from "@stable-harness/core";
|
|
6
|
+
export { loadWorkspaceFromYaml } from "@stable-harness/workspace-yaml";
|
|
7
|
+
export { createInMemoryToolGateway, createModuleToolGateway } from "@stable-harness/tool-gateway";
|
|
8
|
+
export type { ModuleToolDescriptor, ToolGateway, ToolGatewayContext, ToolGatewayInvokeRequest, ToolGatewayInvokeResult, ToolGatewayTool, } from "@stable-harness/tool-gateway";
|
|
9
|
+
export declare function createStableRuntime(input: {
|
|
10
|
+
workspaceRoot: string;
|
|
11
|
+
adapters?: RuntimeAdapter[];
|
|
12
|
+
}): Promise<StableHarnessRuntime>;
|
|
13
|
+
export declare function requestStableRuntime(runtime: StableHarnessRuntime, request: RuntimeRequest): Promise<import("@stable-harness/core").RuntimeResponse>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createDeepAgentsAdapter as e}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as a}from"@stable-harness/core";import{loadWorkspaceFromYaml as r}from"@stable-harness/workspace-yaml";export{createDeepAgentsAdapter}from"@stable-harness/adapter-deepagents";export{createStableHarnessRuntime}from"@stable-harness/core";export{createLangMemServiceProvider}from"@stable-harness/memory";export{loadWorkspaceFromYaml}from"@stable-harness/workspace-yaml";export{createInMemoryToolGateway,createModuleToolGateway}from"@stable-harness/tool-gateway";export async function createStableRuntime(t){const s=await r(t.workspaceRoot);return a({workspace:s,adapters:t.adapters??[e()]})}export async function requestStableRuntime(e,a){return e.request(a)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{generateWithModel as t}from"../model/ollama.js";import{parseToolCall as e}from"./json.js";import{buildAgentPrompt as n,buildRoutingPrompt as r,buildRoutingRepairPrompt as a,buildToolSelectionPrompt as o}from"./prompts.js";import{loadAgentTools as s}from"./tool-registry.js";export async function runAgentHarnessCompatAgent(o){const m=await async function(e){if(0===e.agent.subagentRefs.length)return[e.agent];const n=l(e.workspace,e.agent),o=e.request.input??"",s=await t(n,r(e.workspace,e.agent,o)),u=await async function(e,n,r,o){let s=o,u=I(s);for(let o=0;o<3&&!i(e,r,u);o+=1)s=await t(n,a({workspace:e.workspace,agent:e.agent,userInput:r,previousResponse:s,issue:c(e,r,u)})),u=I(s);return i(e,r,u)?u:function(t,e){if(d(t,e)<=1)return[];const n=String(t.deepAgentConfig.systemPrompt??"").split(/\r?\n/u).map(t=>t.trim());for(const r of n){if(!/delegation tree|路由|委托/u.test(r)||!/must|必须|include|包含/u.test(r))continue;const n=t.subagentRefs.filter(t=>{return new RegExp(`\\b${e=t,e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}\\b`,"u").test(r);var e});if(n.length>=d(t,e))return n}return[]}(e.agent,r)}(e,n,o,s);return u.map(t=>e.workspace.agents.get(t)).filter(t=>Boolean(t))}(o),y=m[0]??o.agent,b=[];!function(t,e,n,r){if(e.length>1&&t.request.dataListener?.({type:"delegation.plan",requestId:t.requestId,agentId:t.agent.id,agentIds:e.map(t=>t.id)}),n.id===t.agent.id)return;const a={agentId:t.agent.id,toolName:"task",output:n.id};r.push(a),t.request.dataListener?.({type:"tool.result",requestId:t.requestId,...a}),t.request.dataListener?.({type:"delegation.start",requestId:t.requestId,agentId:n.id})}(o,m,y,b);const N=l(o.workspace,y),R=await s(o.workspace,y.toolRefs),$=[],j=new Set;if(y.toolRefs.length>0){const t=await u(o,y,R,$);t&&R.has(t.name)&&(f(o,b,$,await g(o,y,R.get(t.name),t.arguments)),j.add(k(t.name,t.arguments)),await w(o,y,R,j,b,$))}for(let r=0;r<4;r+=1){if(o.cancelled.has(o.requestId))return q(o.requestId,$.join("\n\n"),b,y.id);const r=n({workspace:o.workspace,agent:y,model:N,userInput:o.request.input??"",tools:R,observations:$}),a=await t(N,r),s=e(a);if(!s&&p(b))return q(o.requestId,a,b,y.id);const i=s??await u(o,y,R,$);if(!i||!R.has(i.name)){const t=await u(o,y,h(R,j),$);if(t&&R.has(t.name)){f(o,b,$,await g(o,y,R.get(t.name),t.arguments)),j.add(k(t.name,t.arguments));continue}return q(o.requestId,a,b,y.id)}const d=k(i.name,i.arguments);if(j.has(d)){const t=await u(o,y,h(R,j),$);if(t&&R.has(t.name)){f(o,b,$,await g(o,y,R.get(t.name),t.arguments)),j.add(k(t.name,t.arguments));continue}return q(o.requestId,$.join("\n\n"),b,y.id)}f(o,b,$,await g(o,y,R.get(i.name),i.arguments)),j.add(d),await w(o,y,R,j,b,$)}return q(o.requestId,$.join("\n\n"),b,y.id)}async function u(n,r,a,s){if(n.cancelled.has(n.requestId)||0===a.size)return;const u=l(n.workspace,r),i=await t(u,o({agent:r,userInput:n.request.input??"",tools:a,observations:s}));return e(i)}function i(t,e,n){return n.filter(e=>t.workspace.agents.has(e)).length>=d(t.agent,e)}function d(t,e){const n=e.split(/\r?\n/u).filter(t=>/^\s*\d+[.)、]/u.test(t)).length;return Math.max(1,Math.min(t.subagentRefs.length,n||1))}function c(t,e,n){const r=d(t.agent,e);return 0===n.length?"No valid available subagent id was returned.":`Only ${n.length} valid subagent ids were returned; at least ${r} are required for this multi-part request.`}function l(t,e){const n=e.modelRef??"default",r=t.models.get(n)??t.models.get("default");if(!r)throw new Error(`No model configured for agent ${e.id}`);return r}async function g(t,e,n,r){return t.request.dataListener?.({type:"tool.start",requestId:t.requestId,agentId:e.id,toolName:n.name}),await new Promise(t=>setImmediate(t)),t.cancelled.has(t.requestId)?{agentId:e.id,toolName:n.name,output:"cancelled before tool invocation",isError:!0}:async function(t,e,n,r){const a=process.cwd();try{process.chdir(t.workspace.workspaceRoot);const a=await n.invoke(r);return{agentId:e.id,toolName:n.name,output:y(a)}}catch(t){return{agentId:e.id,toolName:n.name,output:y(t),isError:!0}}finally{process.chdir(a)}}(t,e,n,r)}function f(t,e,n,r){e.push(r),t.request.dataListener?.({type:"tool.result",requestId:t.requestId,...r}),n.push(`Tool ${r.toolName} returned:\n${r.output}`)}function m(t){return"task"===t}function p(t){return t.some(t=>!t.isError&&!m(t.toolName))}async function w(t,e,n,r,a,o){if(p(a))return;const s=await u(t,e,h(n,r),o);s&&n.has(s.name)&&(f(t,a,o,await g(t,e,n.get(s.name),s.arguments)),r.add(k(s.name,s.arguments)))}function h(t,e){return new Map([...t].filter(([t])=>!m(t)&&!function(t,e){return[...e].some(e=>e.startsWith(`${t}:`))}(t,e)))}function I(t){try{const e=function(t){try{return JSON.parse(t)}catch{const e=t.indexOf("{"),n=t.lastIndexOf("}");if(e>=0&&n>e)return JSON.parse(t.slice(e,n+1));throw new Error("No JSON object found")}}(t),n=function(t){for(const e of["agentIds","routing","agents","delegations","plan"]){const n=t[e],r=Array.isArray(n)?n.filter(t=>"string"==typeof t):[];if(r.length>0)return[...new Set(r)]}return[]}(e);if(n.length>0)return n;const r=function(t){for(const e of["agentId","agent","owner","route"]){const n=t[e];if("string"==typeof n&&n.trim().length>0)return n}}(e);return r?[r]:[]}catch{return[]}}function q(t,e,n,r){return{requestId:t,state:"completed",output:e,metadata:{executedToolResults:n,routedAgentId:r}}}function y(t){return t instanceof Error?t.stack??t.message:"string"==typeof t?t:JSON.stringify(t)}function k(t,e){return`${t}:${JSON.stringify(e)}`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function parseToolCall(r){return function(r){if("string"!=typeof r)return[];const e=[];for(const o of function(t){return[t.trim(),extractJsonObject(t)].filter(t=>Boolean(t))}(r)){const r=n(t(o));r&&e.push(r)}for(const o of function(t){return t.match(/\{[^{}]*"name"\s*:\s*"[^"]+"[\s\S]*?\}\s*\}/gu)??[]}(r)){const r=n(t(o));r&&e.push(r)}return function(t){const n=new Set;return t.filter(t=>{const r=`${t.name}:${JSON.stringify(t.arguments)}`;return!n.has(r)&&(n.add(r),!0)})}(e)}(r)[0]}export function extractJsonObject(t){const n=t.indexOf("{"),r=t.lastIndexOf("}");return n>=0&&r>n?t.slice(n,r+1):void 0}function t(t){try{return JSON.parse(t)}catch{return}}function n(t){if("object"!=typeof t||null===t)return;const n=t;if("string"!=typeof n.name)return;const r="object"==typeof n.arguments&&null!==n.arguments?n.arguments:{};return{name:n.name,arguments:r}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatCompatDelta(delta: Record<string, unknown>): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readPlanTodos as t}from"@stable-harness/core";export function formatCompatDelta(o){return"delegation.start"===o.type?[`agent:${o.agentId} Starting delegated execution.`]:"delegation.plan"===o.type?[`Planned delegation tree: ${e(o).join(" -> ")}`]:"tool.start"===o.type?[`agent:${o.agentId} Running tool ${a=o.toolName,"write_todos"===a?"Call Write Todos.":String(a)}`]:"tool.result"===o.type?function(e){if("task"===e.toolName)return[`agent:${e.agentId} Delegating to ${e.output}.`];if("write_todos"===e.toolName){const o=t(e.output);return o.length>0?function(t,e){const o=e.filter(t=>"completed"===t.status).length,a=e.filter(t=>"in_progress"===t.status).length,r=e.filter(t=>"pending"===t.status).length,s=[`agent:${t} TODO Burn Down | ${o}/${e.length} done | ${a} active | ${r} pending`];for(const t of e)s.push(` [${n(t.status)}] ${t.content}`);for(const n of e.filter(t=>"completed"===t.status||"failed"===t.status))s.push(`agent:${t} TODO ${n.status}: ${n.content}`);return s}(String(e.agentId),o):[]}return[]}(o):[];var a}function e(t){return Array.isArray(t.agentIds)?t.agentIds.map(String):[]}function n(t){return"completed"===t?"x":"in_progress"===t?"~":"failed"===t?"!":" "}
|
|
@@ -0,0 +1,24 @@
|
|
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function buildAgentPrompt(o){const t=[...o.tools.values()].map(e=>({name:e.name,description:e.description??""}));return[o.agent.deepAgentConfig.systemPrompt??"","","You are running inside stable-harness.",e(o.agent,o.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(t,null,2),o.observations.length?`Tool observations:\n${o.observations.join("\n\n")}`:"",`User request:\n${o.userInput}`].filter(Boolean).join("\n")}export function buildRoutingPrompt(e,t,n){const r=t.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.",o(t,r.map(e=>e.id)),t.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(r,null,2),`User request:\n${n}`].filter(Boolean).join("\n")}export function buildRoutingRepairPrompt(e){const t=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.",o(e.agent,t.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(t,null,2),`Previous response:\n${e.previousResponse}`,`User request:\n${e.userInput}`].filter(Boolean).join("\n")}export function buildToolSelectionPrompt(o){const t=[...o.tools.values()].map(e=>({name:e.name,description:e.description??""}));return[`Agent: ${o.agent.id}`,o.agent.description?`Responsibility: ${o.agent.description}`:"",e(o.agent,o.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(t,null,2),o.observations?.length?`Tool observations already gathered:\n${o.observations.join("\n\n")}`:"",`User request:\n${o.userInput}`].filter(Boolean).join("\n")}function e(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 o(e,o){const n=String(e.deepAgentConfig.systemPrompt??"").split(/\r?\n/u).map(e=>e.trim()).filter(e=>function(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)),r=n.map(e=>({line:e,score:t(e,o)})).sort((e,o)=>o.score-e.score).map(e=>e.line).slice(0,16);return r.length>0?`Routing policy excerpts:\n${r.join("\n")}`:""}function t(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}
|
|
@@ -0,0 +1 @@
|
|
|
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}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export async function generateWithModel(n,i){if("ollama"!==n.provider&&"openai-compatible"!==n.provider)throw new Error(`Unsupported model provider: ${n.provider}`);const o=function(t){const e=t.trim()||"http://127.0.0.1:11434/";return e.endsWith("/")?e:`${e}/`}(String(n.init.baseUrl??n.init.baseURL??"")),a="ollama"===n.provider?`${o}api/generate`:`${o}v1/chat/completions`,s=Number(n.init.timeout??12e4),c=Number(n.init.retries??2)+1;let u;for(let o=1;o<=c;o+=1)try{return await t(n,a,i,s)}catch(t){if(u=t,o===c||!e(t))throw t;await r(500*o)}throw u instanceof Error?u:new Error(String(u))}async function t(t,e,r,o){const a=new AbortController,s=setTimeout(()=>a.abort(),o),c=await function(t,e,r,o){return fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify("ollama"===t.provider?n(t,r):i(t,r)),signal:o})}(t,e,r,a.signal).finally(()=>clearTimeout(s));if(!c.ok)throw new Error(`Model request failed with HTTP ${c.status}: ${await c.text()}`);const u=await c.json();return function(t,e){if("ollama"===t)return String(e.response??"");const r=(Array.isArray(e.choices)?e.choices:[])[0];return String(r?.message?.content??"")}(t.provider,u)}function e(t){if(t instanceof DOMException&&"AbortError"===t.name)return!1;const e=t instanceof Error?t.message:String(t);return/fetch failed|ECONNRESET|ETIMEDOUT|EAI_AGAIN|socket|network/i.test(e)}function r(t){return new Promise(e=>setTimeout(e,t))}function n(t,e){return{model:t.model,prompt:e,stream:!1,think:t.init.think??!1,options:{num_ctx:t.init.numCtx,num_predict:t.init.numPredict,temperature:t.init.temperature}}}function i(t,e){return{model:t.model,messages:[{role:"user",content:e}],temperature:t.init.temperature??0}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as r,statSync as t}from"node:fs";import*as o from"node:path";import{parse as e}from"yaml";export function validateSkillMetadata(i){const a=t(i).isDirectory()?o.join(i,"SKILL.md"):i,s=r(a,"utf8").match(/^---\n([\s\S]*?)\n---/u);if(!s)throw new Error(`${a} is missing YAML front matter`);const m=e(s[1]),l=n(m.name,"name",a),f=n(m.description,"description",a),d=(c=m["allowed-tools"],Array.isArray(c)?c.filter(r=>"string"==typeof r&&r.trim().length>0):[]);var c;if(0===d.length)throw new Error(`${o.basename(i)} must declare allowed-tools`);return{name:l,description:f,allowedTools:d,path:a}}function n(r,t,o){if("string"!=typeof r||!r.trim())throw new Error(`${o} front matter requires ${t}`);return r.trim()}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type CompiledModel = {
|
|
2
|
+
name: string;
|
|
3
|
+
provider: string;
|
|
4
|
+
model: string;
|
|
5
|
+
init: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
export type CompiledAgent = {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
sourcePath: string;
|
|
12
|
+
modelRef?: string;
|
|
13
|
+
toolRefs: string[];
|
|
14
|
+
skillPathRefs: string[];
|
|
15
|
+
subagentRefs: string[];
|
|
16
|
+
memorySources: string[];
|
|
17
|
+
deepAgentConfig: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
export type CompiledTool = {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
sourcePath?: string;
|
|
23
|
+
spec?: unknown;
|
|
24
|
+
};
|
|
25
|
+
export type CompiledSkill = {
|
|
26
|
+
name: string;
|
|
27
|
+
path: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
allowedTools: string[];
|
|
30
|
+
};
|
|
31
|
+
export type CompiledWorkspace = {
|
|
32
|
+
workspaceRoot: string;
|
|
33
|
+
models: Map<string, CompiledModel>;
|
|
34
|
+
agents: Map<string, CompiledAgent>;
|
|
35
|
+
tools: Map<string, CompiledTool>;
|
|
36
|
+
skills: Map<string, CompiledSkill>;
|
|
37
|
+
bindings: Map<string, Record<string, unknown>>;
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function tool(input: {
|
|
2
|
+
name?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
schema?: unknown;
|
|
5
|
+
func?: (args: unknown) => unknown | Promise<unknown>;
|
|
6
|
+
invoke?: (args: unknown) => unknown | Promise<unknown>;
|
|
7
|
+
}): {
|
|
8
|
+
name: string | undefined;
|
|
9
|
+
description: string | undefined;
|
|
10
|
+
schema: unknown;
|
|
11
|
+
invoke(args: unknown): Promise<unknown>;
|
|
12
|
+
};
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function tool(n){return{name:n.name,description:n.description,schema:n.schema,async invoke(o){if(n.invoke)return n.invoke(o);if(n.func)return n.func(o);throw new Error(`Tool ${n.name??"unknown"} has no function`)}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as e,readFile as t}from"node:fs/promises";import*as s from"node:path";import{parseAllDocuments as n}from"yaml";import{validateSkillMetadata as r}from"../runtime/skills/skill-metadata.js";export async function loadWorkspace(u){const y=s.resolve(u),g=await async function(e){const s=await o(e),r=[];for(const e of s){const s=await t(e,"utf8");for(const e of n(s)){const t=e.toJSON();t?.kind&&r.push({...t,metadata:t.metadata??{},spec:t.spec??{}})}}return r}(s.join(y,"config")),w=function(e){const t=new Map;for(const s of e){if("Models"===s.kind&&Array.isArray(s.spec))for(const e of s.spec){const s=i(e);t.set(String(s.name),s)}if("Model"===s.kind&&d(s.spec)){const e=i({name:s.metadata?.name,...s.spec});t.set(String(e.name),e)}}return t}(g),k=function(e,t){const n=new Map;for(const r of t.filter(e=>"Agent"===e.kind)){if(!d(r.spec))continue;const t=String(r.metadata?.name),o=d(r.spec.config)?r.spec.config:{},i=c(r.spec,o);n.set(t,{id:t,name:t,description:r.metadata?.description??"",sourcePath:s.join(e,"config","agents",`${t}.yaml`),modelRef:l(r.spec.modelRef),toolRefs:f(r.spec.tools),skillPathRefs:f(r.spec.skills).map(t=>s.join(e,"resources","skills",t)),subagentRefs:f(r.spec.subagents),memorySources:m(r.spec.memory),deepAgentConfig:{...o,responseFormat:p(o.responseFormat),systemPrompt:i}})}return n}(y,g),A=await async function(n,r){const o=new Map;for(const e of r.filter(e=>"Tool"===e.kind)){const t=e.metadata?.name;t&&o.set(t,{name:t,id:t,spec:e.spec})}return await async function(n,r){const o=await e(n,{withFileTypes:!0});for(const e of o){if(!e.isFile()||!e.name.endsWith(".mjs")||e.name.startsWith("_"))continue;const o=s.join(n,e.name),i=(await t(o,"utf8")).match(/export\s+const\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*tool/u),a=i?.[1]??s.basename(e.name,".mjs");r.set(a,{name:a,id:a,sourcePath:o})}}(s.join(n,"resources","tools"),o),o}(y,g),h=await async function(t){const n=new Map,o=s.join(t,"resources","skills");for(const t of await e(o,{withFileTypes:!0})){if(!t.isDirectory())continue;const e=s.join(o,t.name),i=r(e);n.set(i.name,{name:i.name,path:e,description:i.description,allowedTools:i.allowedTools})}return n}(y);return function(e,t){for(const n of e.values())n.skillPathRefs=n.skillPathRefs.map(e=>{const n=s.basename(e);return t.get(n)?.path??e})}(k,h),function(e,t){e.has("direct")||e.set("direct",{id:"direct",name:"direct",description:"Direct execution agent.",sourcePath:s.join(t,"config","runtime","workspace.yaml"),toolRefs:[],skillPathRefs:[],subagentRefs:[],memorySources:[],deepAgentConfig:{builtinTools:{filesystem:!1,modelExposed:!1}}})}(k,y),{workspaceRoot:y,models:w,agents:k,tools:A,skills:h,bindings:a(k)}}async function o(t){const n=await e(t,{withFileTypes:!0});return(await Promise.all(n.map(async e=>{const n=s.join(t,e.name);return e.isDirectory()?o(n):e.isFile()&&/\.ya?ml$/iu.test(e.name)?[n]:[]}))).flat().sort()}function i(e){const t=String(e.name),s={...e};return delete s.name,delete s.provider,delete s.model,{name:t,provider:String(u(e.provider)),model:String(u(e.model)),init:(n=s,Object.fromEntries(Object.entries(n).map(([e,t])=>[e,u(t)])))};var n}function a(e){const t=new Map;for(const[s,n]of e){const e=n.deepAgentConfig;t.set(s,{agentId:s,deepAgentParams:{responseFormat:e.responseFormat,systemPrompt:e.systemPrompt}})}return t}function c(e,t){return"string"==typeof e.systemPrompt?e.systemPrompt:"string"==typeof t.systemPrompt?t.systemPrompt:""}function p(e){const t={type:"object",properties:{status:{type:"string",enum:["completed","blocked","failed","refused"]},summary:{type:"array",items:{type:"string"}},findings:{type:"array",items:{type:"string"}},blockers:{type:"array",items:{type:"string"}},nextActions:{type:"array",items:{type:"string"}},report:{type:"string"}},required:["status","summary","findings","blockers","nextActions","report"]};if(!d(e))return t;const s=d(e.properties)?e.properties:{},n=Array.isArray(e.required)?e.required:[];return{...t,...e,properties:{...t.properties,...s},required:[...new Set([...t.required,...n].filter(e=>"string"==typeof e))]}}function m(e){return Array.isArray(e)?e.flatMap(e=>d(e)&&"string"==typeof e.path?[e.path]:[]):[]}function f(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function l(e){return"string"==typeof e?e.replace(/^[^/]+\//u,""):void 0}function u(e){if("string"!=typeof e)return e;const t=e.replace(/\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*?))?\}/gu,(e,t,s)=>process.env[t]??s??"");return/^(true|false)$/iu.test(t)?"true"===t.toLowerCase():/^-?\d+$/u.test(t)?Number(t):t}function d(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stable-harness",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Stable application runtime and operator control plane for agent workspaces.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"packageManager": "npm@10.9.2",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/botbotgo/stable-harness.git"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"registry": "https://registry.npmjs.org/"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=24 <25"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"README.md",
|
|
21
|
+
"dist/*.js",
|
|
22
|
+
"dist/*.d.ts",
|
|
23
|
+
"dist/compat/**/*.js",
|
|
24
|
+
"dist/compat/**/*.d.ts",
|
|
25
|
+
"dist/runtime/**/*.js",
|
|
26
|
+
"dist/runtime/**/*.d.ts",
|
|
27
|
+
"dist/workspace/**/*.js",
|
|
28
|
+
"dist/workspace/**/*.d.ts",
|
|
29
|
+
"packages/*/dist/**/*.js",
|
|
30
|
+
"packages/*/dist/**/*.d.ts",
|
|
31
|
+
"packages/*/package.json"
|
|
32
|
+
],
|
|
33
|
+
"bin": {
|
|
34
|
+
"botbotgo": "dist/cli.js",
|
|
35
|
+
"stable-harness": "packages/cli/dist/src/cli.js"
|
|
36
|
+
},
|
|
37
|
+
"exports": {
|
|
38
|
+
".": "./dist/index.js",
|
|
39
|
+
"./compat/agent-harness.js": "./dist/compat/agent-harness.js",
|
|
40
|
+
"./tools": "./dist/tools.js",
|
|
41
|
+
"./workspace/compile.js": "./dist/workspace/compile.js",
|
|
42
|
+
"./runtime/skills/skill-metadata.js": "./dist/runtime/skills/skill-metadata.js",
|
|
43
|
+
"./governance": "./packages/governance/dist/src/index.js",
|
|
44
|
+
"./memory": "./packages/memory/dist/src/index.js",
|
|
45
|
+
"./protocols": "./packages/protocols/dist/src/index.js",
|
|
46
|
+
"./tool-gateway": "./packages/tool-gateway/dist/src/index.js"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc -b && npm run build:chmod",
|
|
50
|
+
"build:chmod": "chmod +x dist/cli.js packages/cli/dist/src/cli.js",
|
|
51
|
+
"check": "tsc -b --pretty false",
|
|
52
|
+
"check:rules": "node scripts/check-project-rules.mjs",
|
|
53
|
+
"compare:tool-calling": "node scripts/compare-granite-tool-calling.mjs",
|
|
54
|
+
"compare:granite-tools": "node scripts/compare-granite-tool-calling.mjs",
|
|
55
|
+
"benchmark:bfcl-tool-guard": "node scripts/benchmark-bfcl-tool-guard.mjs",
|
|
56
|
+
"benchmark:retry-policy": "node scripts/benchmark-retry-policy.mjs",
|
|
57
|
+
"benchmark:tool-guard": "node scripts/benchmark-tool-argument-guard.mjs",
|
|
58
|
+
"benchmark:tool-guard:matrix": "node scripts/benchmark-tool-argument-guard-matrix.mjs",
|
|
59
|
+
"test:langmem:sqlite:e2e": "node scripts/run-langmem-sqlite-e2e.mjs",
|
|
60
|
+
"validate:workspace": "node scripts/validate-workspace.mjs",
|
|
61
|
+
"test": "node --test dist/test/*.test.js dist/test/memory/*.test.js dist/test/retry/*.test.js dist/test/workspace/*.test.js",
|
|
62
|
+
"test:langmem:maintenance:e2e": "node scripts/run-langmem-maintenance-e2e.mjs",
|
|
63
|
+
"test:skill-mining:e2e": "node scripts/run-skill-candidate-mining-e2e.mjs",
|
|
64
|
+
"prepack": "npm run release:minify",
|
|
65
|
+
"release:minify": "find dist packages -type f -name '*.js' \\( -path 'dist/*' -o -path '*/dist/*' \\) -exec sh -c 'for f do ./node_modules/.bin/terser \"$f\" --compress passes=2 --mangle --module --toplevel --comments false --output \"$f\"; done' sh {} +",
|
|
66
|
+
"release:pack": "npm pack --dry-run",
|
|
67
|
+
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/",
|
|
68
|
+
"example:minimal": "node dist/examples/minimal-deepagents/run.js"
|
|
69
|
+
},
|
|
70
|
+
"workspaces": [
|
|
71
|
+
"packages/*"
|
|
72
|
+
],
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@botbotgo/better-call": "^0.1.1",
|
|
75
|
+
"@langchain/core": "^1.1.43",
|
|
76
|
+
"@langchain/ollama": "^1.2.7",
|
|
77
|
+
"@stable-harness/adapter-deepagents": "file:packages/adapter-deepagents",
|
|
78
|
+
"@stable-harness/core": "file:packages/core",
|
|
79
|
+
"@stable-harness/governance": "file:packages/governance",
|
|
80
|
+
"@stable-harness/memory": "file:packages/memory",
|
|
81
|
+
"@stable-harness/protocols": "file:packages/protocols",
|
|
82
|
+
"@stable-harness/tool-gateway": "file:packages/tool-gateway",
|
|
83
|
+
"@stable-harness/workspace-yaml": "file:packages/workspace-yaml",
|
|
84
|
+
"deepagents": "^1.9.1",
|
|
85
|
+
"langchain": "^1.3.1",
|
|
86
|
+
"yaml": "^2.8.2",
|
|
87
|
+
"zod": "^4.1.13"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^24.10.1",
|
|
91
|
+
"terser": "^5.47.1",
|
|
92
|
+
"typescript": "^5.9.3"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RuntimeAdapter } from "@stable-harness/core";
|
|
2
|
+
import type { DeepAgentFactory, DeepAgentsAdapterRunner } from "./types.js";
|
|
3
|
+
type DeepAgentsAdapterOptions = {
|
|
4
|
+
runner?: DeepAgentsAdapterRunner;
|
|
5
|
+
createDeepAgent?: DeepAgentFactory;
|
|
6
|
+
};
|
|
7
|
+
export declare function createDeepAgentsAdapter(options?: DeepAgentsAdapterOptions): RuntimeAdapter;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ToolMessage as e}from"@langchain/core/messages";import{tool as t}from"@langchain/core/tools";import{ChatOllama as n}from"@langchain/ollama";import{resolveDeepAgentsNativeMemories as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as s,validateFilesystemBuiltinCall as o}from"./builtin-tool-policy.js";import{buildDeepAgentRequest as a}from"./messages.js";import{createDeepAgentsRetryMiddleware as i}from"./retry-policy.js";import{streamDeepAgentResult as d}from"./stream-events.js";const u=new Set(["write_todos","task","ls","read_file","write_file","edit_file","glob","grep"]);export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const n=(e.createDeepAgent??await async function(){try{const e=(await async function(){return new Function("specifier","return import(specifier)")("deepagents")}()).createDeepAgent;if("function"==typeof e)return e}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${D(e)}`)}throw new Error("DeepAgents package does not export createDeepAgent.")}())(function(e){const t=w(e.agent.config.deepagents),n=t.permissions??m(e,e.agent);return q({name:e.agent.id,model:t.model??I(e,e.agent),systemPrompt:e.agent.systemPrompt??_(e.agent.config.systemPrompt),backend:t.backend,checkpointer:t.checkpointer,store:t.store,middleware:f(t.middleware,p(e),s(e),i(e.workspace.runtime.retry)),responseFormat:t.responseFormat,contextSchema:t.contextSchema,interruptOn:t.interruptOn,permissions:n,tools:h(e,e.agent.id,e.agent.tools),subagents:e.agent.subagents.map(t=>{const n=e.workspace.agents.get(t),r=w(n?.config.deepagents),s=r.permissions??m(e,n);return q({name:t,description:n?.description??_(n?.config.description)??n?.id,systemPrompt:n?.systemPrompt??_(n?.config.systemPrompt),model:r.model??(n?I(e,n):void 0),middleware:r.middleware,interruptOn:r.interruptOn,permissions:s,responseFormat:r.responseFormat,tools:h(e,t,n?.tools??[]),memory:c(e,n),skills:l(e,n)})}),memory:c(e,e.agent),skills:l(e,e.agent)})}(t)),r=a(t);return!0===t.request.metadata?.openaiStream&&n.streamEvents?d(t,n.streamEvents(r,{version:"v2"}),A):A(await n.invoke(r))}}}function c(e,t){const n=b(t?.config,"memory");if(n)return n;const s=r(e.workspace).map(e=>`/memories/${e.id}.md`);return s.length>0?s:void 0}function l(e,t){const n=b(t?.config,"skills");if(n)return n;const r=(t?.skills??[]).map(t=>e.workspace.skills.get(t)?.path??t);return r.length>0?r:void 0}function p(t){return{name:"StableHarnessObserver",async wrapToolCall(n,r){const s=n.toolCall?.name;if(!s||!u.has(s))return r(n);t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.start",toolId:s,args:n.toolCall?.args}});const a="task"===s?function(t,n){const r=function(e){const t=C(e)?e:{};return _(t.subagent_type)??_(t.subagentType)}(n.toolCall?.args),s=function(e){const t=k(e.agent.config,"builtinTools")?.modelExposed;return!1===t?[]:Array.isArray(t)?t.includes("task")?e.agent.subagents:[]:["general-purpose",...e.agent.subagents]}(t);if(void 0===s||r&&s.includes(r))return;const o=r?`: ${r}`:"",a=s.length>0?s.join(", "):"none";return new e({tool_call_id:n.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:`Task delegation target is not in the workspace inventory${o}. Allowed task targets: ${a}.`})}(t,n):void 0;if(a)return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:a.content}}),a;const i=o(t,s,n);if(i)return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:i.content}}),i;try{const e=await r(n);return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:y(s,n,e)}}),e}catch(e){throw t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,error:D(e)}}),e}}}}function m(e,t){const n=k(t?.config,"builtinTools"),r=[];if(!1!==n?.filesystem){if(g(e))return}else r.push({operations:["read","write"],paths:["/**"],mode:"deny"});return g(e)||r.push({operations:["write"],paths:["/memories/**"],mode:"deny"}),r.length>0?r:void 0}function g(e){const t=k(e.workspace.runtime.memory,"deepagentsMem");return!1!==t?.write}function f(e,t,n,r=[]){return[t,n,...r,...Array.isArray(e)?e:[]]}function y(e,t,n){return"write_todos"===e?JSON.stringify({status:"recorded",args:t.toolCall?.args}):A(n)}function I(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?function(e){return"ollama"===e.provider?new n(q({model:e.model,baseUrl:_(e.config?.baseUrl),temperature:O(e.config?.temperature),numCtx:O(e.config?.numCtx),numPredict:O(e.config?.numPredict),timeout:O(e.config?.timeout),think:"boolean"==typeof e.config?.think?e.config.think:void 0})):e.model}(r):void 0}function h(n,r,s){return n.toolGateway?s.flatMap(s=>{const o=n.toolGateway?.get(s);if(!o)return[];const a=n.workspace.tools.get(s);return[t(async t=>{n.emit({type:"adapter.event",requestId:n.requestId,sessionId:n.sessionId,agentId:r,event:{adapter:"deepagents",phase:"tool.start",toolId:s}});const o=await async function(t,n,r,s){try{return await t.toolGateway.invoke({toolId:r,args:s,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:n}})}catch(t){if(function(e){return e instanceof Error&&"ToolArgumentValidationError"===e.name&&"string"==typeof e.toolId&&Array.isArray(e.issues)}(t))return new e({tool_call_id:`stable-harness-${r}-argument-guard`,name:r,status:"error",content:v(t)});throw t}}(n,r,s,t);return n.emit({type:"adapter.event",requestId:n.requestId,sessionId:n.sessionId,agentId:r,event:{adapter:"deepagents",phase:"tool.result",toolId:s}}),o instanceof e?o:A(o.output)},{name:s,description:a?.description??o.description??s,schema:a?.schema??{type:"object",additionalProperties:!0}})]}):[]}function v(e){return JSON.stringify({error:"tool_argument_validation_failed",toolId:e.toolId,issues:e.issues,retry:"Call the same tool again with arguments that satisfy the reported schema and semantic issues."})}function w(e){return C(e)?e:{}}function k(e,t){const n=C(e)?e:{};return C(n[t])?n[t]:void 0}function b(e,t){const n=C(e)?e:{},r=w(n.deepagents),s="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of s){const t=S(r[e]);if(t)return t}return S(n[t])}function A(e){if("string"==typeof e)return e;if(C(e)){const t=e.structuredResponse??e.structured_response;if(void 0!==t)return"string"==typeof t?t:JSON.stringify(t);const n=(Array.isArray(e.messages)?e.messages:[]).at(-1);if(C(n)&&"string"==typeof n.content)return n.content}return JSON.stringify(e)}function q(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function _(e){return"string"==typeof e&&e.trim()?e:void 0}function O(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function S(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function C(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function D(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ToolMessage } from "@langchain/core/messages";
|
|
2
|
+
import type { RuntimeAdapter } from "@stable-harness/core";
|
|
3
|
+
type AdapterRunInput = Parameters<RuntimeAdapter["run"]>[0];
|
|
4
|
+
export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput): {
|
|
5
|
+
name: string;
|
|
6
|
+
wrapModelCall(request: {
|
|
7
|
+
tools?: Array<{
|
|
8
|
+
name?: unknown;
|
|
9
|
+
}>;
|
|
10
|
+
toolChoice?: unknown;
|
|
11
|
+
}, handler: (request: unknown) => Promise<unknown>): Promise<unknown>;
|
|
12
|
+
};
|
|
13
|
+
export declare function validateFilesystemBuiltinCall(input: AdapterRunInput, toolId: string, request: {
|
|
14
|
+
toolCall?: {
|
|
15
|
+
id?: string;
|
|
16
|
+
};
|
|
17
|
+
}): ToolMessage<import("@langchain/core/messages").MessageStructure<import("@langchain/core/messages").MessageToolSet>> | undefined;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ToolMessage as e}from"@langchain/core/messages";const t=new Set(["ls","read_file","write_file","edit_file","glob","grep"]);export function createBuiltinToolPolicyMiddleware(e){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(t,r){if(!function(e){return n(e)||!o(e)}(e))return r(t);const l=Array.isArray(t.tools)?t.tools.filter(t=>i(e,t.name)):t.tools,s=function(e,t){return"required"===t||function(e,t){return"string"==typeof t?.function?.name&&!i(e,t.function.name)}(e,t)?"auto":t}(e,t.toolChoice);return r({...t,tools:l,toolChoice:s})}}}export function validateFilesystemBuiltinCall(o,i,r){if(n(o)&&t.has(i))return new e({tool_call_id:r.toolCall?.id??`stable-harness-${i}-policy`,name:i,content:`Filesystem builtin tool '${i}' is disabled for this agent. Do not retry filesystem tools; use the agent's registered workspace tools and already collected evidence instead.`})}function n(e){const t=r(e.agent.config,"builtinTools");return!1===t?.filesystem}function o(e){const t=r(e.agent.config,"builtinTools")?.modelExposed;return!1!==t&&(!Array.isArray(t)||t.includes("task"))}function i(e,i){return(!n(e)||!function(e){return"string"==typeof e&&t.has(e)}(i))&&("task"!==i||o(e))}function r(e,t){const n=l(e)?e:{};return l(n[t])?n[t]:void 0}function l(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{createDeepAgentsAdapter}from"./adapter.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RuntimeAdapter } from "@stable-harness/core";
|
|
2
|
+
type DeepAgentMessage = {
|
|
3
|
+
role: string;
|
|
4
|
+
content: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function buildDeepAgentRequest(input: Parameters<RuntimeAdapter["run"]>[0]): {
|
|
7
|
+
messages: DeepAgentMessage[];
|
|
8
|
+
};
|
|
9
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function buildDeepAgentRequest(t){return{messages:e(t)}}function e(e){const t=(r=e.request.metadata?.openaiMessages,Array.isArray(r)?r.flatMap(e=>{const t=function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(e)?e:{},n=function(e){if("system"===e||"user"===e||"assistant"===e||"tool"===e)return e}(t.role),r="string"==typeof t.content?t.content:"";return n&&r?[{role:n,content:r}]:[]}):[]),n=function(e){const t=(e.pluginMemories??[]).filter(e=>e.context.trim()).map(e=>`Memory namespace: ${e.namespace}\n${e.context}`).join("\n\n");return t?`Relevant long-term memory:\n${t}`:void 0}(e);var r;return t.length>0?n?[{role:"system",content:n},...t]:t:[{role:"user",content:n?`${n}\n\nUser request:\n${e.request.input}`:e.request.input}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{modelRetryMiddleware as e,toolRetryMiddleware as t}from"langchain";export function createDeepAgentsRetryMiddleware(n){const o=[],i=r(n?.model);i&&o.push(e(i));const s=function(e){const t=r(e);if(!t)return;const n=Array.isArray(e?.tools)?e.tools.filter(e=>"string"==typeof e&&e.trim().length>0):void 0;return a({...t,tools:n})}(n?.tools);return s&&o.push(t(s)),o}function r(e){var t;if(e?.enabled)return a({maxRetries:n(e.maxRetries),backoffFactor:n(e.backoffFactor),initialDelayMs:n(e.initialDelayMs),maxDelayMs:n(e.maxDelayMs),jitter:"boolean"==typeof e.jitter?e.jitter:void 0,retryOn:o(e.retryOn),onFailure:(t=e.onFailure,"continue"===t||"error"===t?t:void 0)})}function n(e){return"number"==typeof e&&Number.isFinite(e)&&e>=0?e:void 0}function o(e){const t=function(e){const t=new Set(["timeout","network","rateLimit","serverError"]);if(!Array.isArray(e))return[...t];const r=e.filter(e=>t.has(e));return r.length>0?r:[...t]}(e);return e=>t.some(t=>i(e,t))}function i(e,t){const r=s(e)?e:{},n=function(e){const t=e.status??e.statusCode??e.code;return"number"==typeof t?t:Number.isInteger(Number(t))?Number(t):void 0}(r),o=`${String(r.name??"")} ${String(r.code??"")} ${String(r.message??e)}`,a=r.cause;return("timeout"===t?/timeout|timedout|etimedout|abort/i.test(o):"network"===t?/network|fetch failed|econnreset|econnrefused|enotfound|eai_again/i.test(o):"rateLimit"===t?429===n||/rate.?limit|too many requests/i.test(o):"serverError"===t&&Boolean(n&&n>=500&&n<600))||s(a)&&i(a,t)}function s(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function a(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export async function streamDeepAgentResult(e,r,o){let i,s="";for await(const a of r){const r=t(a);r&&(s+=r,e.emit({type:"adapter.event",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,event:{adapter:"deepagents",phase:"output.delta",text:r}}));const u=n(a,o);u&&(i=u)}return i??s}function t(t){const n=o(t)?t:{};if("on_chat_model_stream"===n.event)return function(t){const n=t?.content;return"string"==typeof n?n:Array.isArray(n)&&n.map(e).filter(Boolean).join("")||void 0}(r(r(n.data)?.chunk))}function e(t){if("string"==typeof t)return t;const e=o(t)?t:{};return"string"==typeof e.text&&e.text.trim()?e.text:void 0}function n(t,e){const n=o(t)?t:{};if("on_chain_end"!==n.event)return;const i=r(n.data)?.output;return e(i)||void 0}function r(t){return o(t)?t:void 0}function o(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RuntimeAdapterContext, RuntimeAdapterResult } from "@stable-harness/core";
|
|
2
|
+
export type DeepAgentFactory = (params?: Record<string, unknown>) => {
|
|
3
|
+
invoke(input: Record<string, unknown>): Promise<unknown>;
|
|
4
|
+
streamEvents?(input: Record<string, unknown>, options?: Record<string, unknown>): AsyncIterable<unknown>;
|
|
5
|
+
};
|
|
6
|
+
export type DeepAgentsAdapterRunner = (input: RuntimeAdapterContext) => Promise<RuntimeAdapterResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stable-harness/adapter-deepagents",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist/**/*.js",
|
|
7
|
+
"dist/**/*.d.ts",
|
|
8
|
+
"package.json"
|
|
9
|
+
],
|
|
10
|
+
"main": "dist/src/index.js",
|
|
11
|
+
"types": "dist/src/index.d.ts",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@langchain/core": "^1.1.43",
|
|
14
|
+
"@langchain/ollama": "^1.2.7",
|
|
15
|
+
"langchain": "^1.3.1",
|
|
16
|
+
"@stable-harness/core": "0.0.1"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"deepagents": "^1.9.1"
|
|
20
|
+
},
|
|
21
|
+
"peerDependenciesMeta": {
|
|
22
|
+
"deepagents": {
|
|
23
|
+
"optional": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as r}from"@stable-harness/core";import{projectEvent as s,projectRuntimeTrace as a}from"@stable-harness/core";import{createOpenAiCompatibleHttpServer as n}from"@stable-harness/protocols";import{createModuleToolGateway as i}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as p}from"@stable-harness/workspace-yaml";export async function runCli(e=process.argv.slice(2)){const t=function(e){let t,o,r,s="request",a=process.cwd(),n=!1,i=!1,p=!1,l=process.env.STABLE_HARNESS_OPENAI_HOST??"127.0.0.1",m=Number(process.env.STABLE_HARNESS_OPENAI_PORT??8642),u=process.env.STABLE_HARNESS_OPENAI_API_KEY,d=Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5),h=!1;const w=[];for(let g=0;g<e.length;g+=1)0===g&&"start"===e[g]?(s="start",p=!0):"-h"===e[g]||"--help"===e[g]?h=!0:"start"!==s||"openai"!==e[g]&&"openai-compatible"!==e[g]?"-w"===e[g]||"--workspace"===e[g]?a=e[++g]??a:"--agent"===e[g]?t=e[++g]:"--tool"===e[g]?o=e[++g]:"--tool-args-json"===e[g]?r=c(e[++g]??"{}"):"--trace"===e[g]?n=!0:"--trace-json"===e[g]?i=!0:"--serve-openai"===e[g]?p=!0:"--host"===e[g]?l=e[++g]??l:"--port"===e[g]?m=Number(e[++g]??m):"--api-key"===e[g]?u=e[++g]:"--timeout-ms"===e[g]?d=Number(e[++g]??d):w.push(e[g]):p=!0;return{workspaceRoot:a,command:s,agentId:t,toolId:o,toolArgs:r,trace:n,traceJson:i,serveOpenAi:p,host:l,port:m,apiKey:u,timeoutMs:d,help:h,prompt:w.join(" ")||"hello"}}(e);if(t.help)return void process.stdout.write(["Usage:"," stable-harness -w <workspace> [--agent <id>] [prompt]"," stable-harness start -w <workspace> [--host <host>] [--port <port>] [--api-key <key>]","","Options:"," -w, --workspace <path> Workspace root."," --serve-openai Serve the OpenAI-compatible API."," --agent <id> Select an agent for a request."," --tool <id> Invoke an explicit registered tool."," --tool-args-json <json> Tool arguments for --tool."," --trace Print trace lines."," --trace-json Print trace JSON."," --timeout-ms <ms> Request timeout."," -h, --help Show this help.",""].join("\n"));const l=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),m=t.workspaceRoot;try{const e=await p(m),c=await i({tools:e.tools.values()}),u=r({workspace:e,toolGateway:c,adapters:[o()]});if(t.serveOpenAi)return clearTimeout(l),void await async function(e,t){const o=n(e,{bearerToken:t.apiKey});await new Promise(e=>o.listen(t.port,t.host,e));const r=o.address(),s="object"==typeof r&&r?r.port:t.port;process.stdout.write(`stable-harness OpenAI-compatible API listening on http://${t.host}:${s}/v1\n`)}(u,t);t.trace&&u.subscribe(e=>{const t=s(e);var o;t&&process.stdout.write(`trace:${t.agentId}:${t.label}${o=t.detail,o&&"string"==typeof o.toolId?`:${o.toolId}`:""}\n`)});const d=await u.request({input:t.prompt,agentId:t.agentId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0});if(t.trace||t.traceJson){const e=u.getRun(d.requestId),o=e?a(e):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:o})}\n`)}process.stdout.write(`${d.output}\n`)}finally{clearTimeout(l)}}function c(e){try{return JSON.parse(e)}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Invalid --tool-args-json value: ${t}`)}}(function(){const o=process.argv[1];return Boolean(o)&&e(t(import.meta.url))===e(o)})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { runCli } from "./cli.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{runCli}from"./cli.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stable-harness/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist/**/*.js",
|
|
7
|
+
"dist/**/*.d.ts",
|
|
8
|
+
"package.json"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"stable-harness": "dist/src/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"main": "dist/src/index.js",
|
|
14
|
+
"types": "dist/src/index.d.ts",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@stable-harness/adapter-deepagents": "0.0.1",
|
|
17
|
+
"@stable-harness/core": "0.0.1",
|
|
18
|
+
"@stable-harness/protocols": "0.0.1",
|
|
19
|
+
"@stable-harness/tool-gateway": "0.0.1",
|
|
20
|
+
"@stable-harness/workspace-yaml": "0.0.1"
|
|
21
|
+
}
|
|
22
|
+
}
|