stable-harness 0.0.94 → 0.0.96

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.
Files changed (37) hide show
  1. package/README.md +4 -2
  2. package/docs/guides/integration-guide.md +13 -3
  3. package/docs/protocols/http-runtime.md +19 -0
  4. package/docs/protocols/langgraph-compatible.md +7 -1
  5. package/node_modules/@stable-harness/adapter-deepagents/package.json +2 -2
  6. package/node_modules/@stable-harness/adapter-langgraph/package.json +2 -2
  7. package/node_modules/@stable-harness/core/dist/recovery/raw-args.d.ts +12 -0
  8. package/node_modules/@stable-harness/core/dist/recovery/raw-args.js +1 -0
  9. package/node_modules/@stable-harness/core/dist/runtime/recovery/adapter-result.d.ts +3 -1
  10. package/node_modules/@stable-harness/core/dist/runtime/recovery/adapter-result.js +1 -1
  11. package/node_modules/@stable-harness/core/dist/runtime.js +1 -1
  12. package/node_modules/@stable-harness/core/package.json +3 -3
  13. package/node_modules/@stable-harness/governance/package.json +1 -1
  14. package/node_modules/@stable-harness/memory/package.json +1 -1
  15. package/node_modules/@stable-harness/protocols/package.json +2 -2
  16. package/node_modules/@stable-harness/tool-gateway/package.json +1 -1
  17. package/node_modules/@stable-harness/workspace-yaml/package.json +2 -2
  18. package/package.json +9 -9
  19. package/packages/adapter-deepagents/package.json +2 -2
  20. package/packages/adapter-langgraph/package.json +2 -2
  21. package/packages/cli/dist/src/cli.js +1 -1
  22. package/packages/cli/dist/src/daemon/client.d.ts +8 -0
  23. package/packages/cli/dist/src/daemon/client.js +1 -0
  24. package/packages/cli/dist/src/server.js +1 -1
  25. package/packages/cli/package.json +8 -8
  26. package/packages/core/dist/recovery/raw-args.d.ts +12 -0
  27. package/packages/core/dist/recovery/raw-args.js +1 -0
  28. package/packages/core/dist/runtime/recovery/adapter-result.d.ts +3 -1
  29. package/packages/core/dist/runtime/recovery/adapter-result.js +1 -1
  30. package/packages/core/dist/runtime.js +1 -1
  31. package/packages/core/package.json +3 -3
  32. package/packages/evaluation/package.json +2 -2
  33. package/packages/governance/package.json +1 -1
  34. package/packages/memory/package.json +1 -1
  35. package/packages/protocols/package.json +2 -2
  36. package/packages/tool-gateway/package.json +1 -1
  37. package/packages/workspace-yaml/package.json +2 -2
package/README.md CHANGED
@@ -77,15 +77,17 @@ stable-harness agent render orchestra -w ./examples/minimal-deepagents
77
77
  stable-harness workflow render review-shell -w ./examples/minimal-deepagents
78
78
  ```
79
79
 
80
- Start the OpenAI-compatible facade:
80
+ Start the runtime daemon and protocol facades:
81
81
 
82
82
  ```bash
83
83
  stable-harness start -w ./examples/minimal-deepagents --port 8642
84
84
  ```
85
85
 
86
- Then point compatible clients at:
86
+ Then point first-party clients at the Stable Runtime control plane and
87
+ OpenAI-compatible clients at `/v1`:
87
88
 
88
89
  ```text
90
+ http://127.0.0.1:8641
89
91
  http://127.0.0.1:8642/v1
90
92
  ```
91
93
 
@@ -22,8 +22,10 @@ stable-harness workflow render review-shell -w ./workspace
22
22
  stable-harness workflow inspect review-shell -w ./workspace
23
23
  ```
24
24
 
25
- The CLI is intentionally thin. It loads the workspace, creates the tool gateway,
26
- starts memory services, registers adapters, and calls the core runtime.
25
+ The CLI is intentionally thin. When the Stable Runtime daemon for the workspace
26
+ is already running, request commands submit work through HTTP and consume
27
+ runtime updates through SSE. When no daemon is available, the CLI falls back to
28
+ an in-process runtime for local development.
27
29
 
28
30
  ## Embedded Runtime
29
31
 
@@ -78,7 +80,15 @@ Start the server:
78
80
  stable-harness start -w ./workspace --host 127.0.0.1 --port 8642
79
81
  ```
80
82
 
81
- Point compatible clients at:
83
+ `stable-harness start` exposes the first-party Stable Runtime control plane,
84
+ the OpenAI-compatible facade, and the LangGraph-compatible server when enabled
85
+ by runtime config. Point first-party clients at:
86
+
87
+ ```text
88
+ http://127.0.0.1:8641
89
+ ```
90
+
91
+ Point OpenAI-compatible clients at:
82
92
 
83
93
  ```text
84
94
  http://127.0.0.1:8642/v1
@@ -10,6 +10,25 @@ contract, not as new runtime semantics.
10
10
 
11
11
  ## HTTP Commands And Queries
12
12
 
13
+ `stable-harness start` exposes this protocol by default at:
14
+
15
+ ```text
16
+ http://127.0.0.1:8641
17
+ ```
18
+
19
+ Configure it from runtime YAML:
20
+
21
+ ```yaml
22
+ apiVersion: stable-harness.dev/v1
23
+ kind: Runtime
24
+ spec:
25
+ protocols:
26
+ stableRuntime:
27
+ enabled: true
28
+ host: 127.0.0.1
29
+ port: 8641
30
+ ```
31
+
13
32
  `POST /requests` is a protocol adapter over `RuntimeRequest`. It may pass these
14
33
  stable fields through to the runtime:
15
34
 
@@ -16,10 +16,12 @@ upstream LangGraph.
16
16
 
17
17
  ## Defaults
18
18
 
19
- `stable-harness start` starts both services by default:
19
+ `stable-harness start` starts the Stable Runtime control plane plus both
20
+ ecosystem facades by default:
20
21
 
21
22
  | Service | Default host | Default port |
22
23
  | --- | --- | --- |
24
+ | Stable Runtime HTTP + SSE | `127.0.0.1` | `8641` |
23
25
  | OpenAI-compatible | `127.0.0.1` | `8642` |
24
26
  | LangGraph-compatible | `127.0.0.1` | `2024` |
25
27
 
@@ -30,6 +32,10 @@ apiVersion: stable-harness.dev/v1
30
32
  kind: Runtime
31
33
  spec:
32
34
  protocols:
35
+ stableRuntime:
36
+ enabled: true
37
+ host: 127.0.0.1
38
+ port: 8641
33
39
  openaiCompatible:
34
40
  enabled: true
35
41
  host: 127.0.0.1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/adapter-deepagents",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -15,7 +15,7 @@
15
15
  "@langchain/node-vfs": "^0.1.4",
16
16
  "@langchain/ollama": "^1.2.7",
17
17
  "@langchain/openai": "^1.4.5",
18
- "@stable-harness/core": "0.0.94",
18
+ "@stable-harness/core": "0.0.96",
19
19
  "deepagents": "^1.10.1",
20
20
  "langchain": "^1.4.0"
21
21
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/adapter-langgraph",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,6 +11,6 @@
11
11
  "types": "dist/src/index.d.ts",
12
12
  "peerDependencies": {
13
13
  "@langchain/langgraph": "^1.3.0",
14
- "@stable-harness/core": "0.0.94"
14
+ "@stable-harness/core": "0.0.96"
15
15
  }
16
16
  }
@@ -0,0 +1,12 @@
1
+ import type { RuntimeRequest, RuntimeToolGateway, WorkspaceAgent } from "../types.js";
2
+ import type { CompiledWorkspace } from "../workspace/types.js";
3
+ export type RawArgsRecoveryInput = {
4
+ request: RuntimeRequest;
5
+ output: string;
6
+ agent: WorkspaceAgent;
7
+ workspace: CompiledWorkspace;
8
+ toolGateway?: RuntimeToolGateway;
9
+ policy: unknown;
10
+ };
11
+ export declare function buildRawArgsRecoveryRequest(input: RawArgsRecoveryInput): RuntimeRequest | undefined;
12
+ export declare function hasUniqueRawArgsTool(input: Omit<RawArgsRecoveryInput, "request">): boolean;
@@ -0,0 +1 @@
1
+ export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=findUniqueRawArgsTool(e);return t?{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}:void 0}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(findUniqueRawArgsTool(e))}function findUniqueRawArgsTool(e){const t=function parseStandaloneJsonObject(e){const t=e.trim(),r=t.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),o=r??t;if(o.startsWith("{")&&o.endsWith("}")&&!(o.length>6e3))try{const e=JSON.parse(o);return isRecord(e)?e:void 0}catch{return}}(e.output);if(!t)return;const r=e.agent.tools.filter(r=>function schemaMatchesArgs(e,t){if(!isRecord(e)||"object"!==e.type||!isRecord(e.properties))return!1;if(function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}(e.required).some(e=>!(e in t)))return!1;const r=e.properties;return(!1!==e.additionalProperties||!Object.keys(t).some(e=>!(e in r)))&&Object.entries(t).every(([e,t])=>function propertyAcceptsValue(e,t){return!isRecord(e)||"string"!=typeof e.type||("string"===e.type?"string"==typeof t:"number"===e.type?"number"==typeof t:"integer"===e.type?Number.isInteger(t):"boolean"===e.type?"boolean"==typeof t:"array"===e.type?Array.isArray(t):"object"!==e.type||isRecord(t))}(r[e],t))}(e.workspace.tools.get(r)?.schema??e.toolGateway?.get(r)?.schema,t));return 1===r.length?{toolId:r[0],args:t}:void 0}function toolCallRecoveryEnabled(e){return!!(isRecord(e)&&isRecord(e.recovery)&&isRecord(e.recovery.toolCall))&&!0===e.recovery.toolCall.enabled}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1,4 +1,4 @@
1
- import type { RuntimeEvent, RuntimeOutput, RuntimeRequest, RuntimeStore, WorkspaceAgent } from "../../types.js";
1
+ import type { CompiledWorkspace, RuntimeEvent, RuntimeOutput, RuntimeRequest, RuntimeStore, RuntimeToolGateway, WorkspaceAgent } from "../../types.js";
2
2
  export declare function recoverAdapterResultOutput(input: {
3
3
  request: RuntimeRequest;
4
4
  result: RuntimeOutput;
@@ -8,5 +8,7 @@ export declare function recoverAdapterResultOutput(input: {
8
8
  requestId: string;
9
9
  sessionId: string;
10
10
  agent: WorkspaceAgent;
11
+ workspace: CompiledWorkspace;
12
+ toolGateway?: RuntimeToolGateway;
11
13
  runAdapter: (request: RuntimeRequest) => Promise<RuntimeOutput>;
12
14
  }): Promise<RuntimeOutput>;
@@ -1 +1 @@
1
- import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{assertNoProgressOnlyToolIntentOutput as t,assertNoRawToolCallOutput as o,assertNoRawToolResultOutput as r,assertNoToolExecutionErrorOutput as a,buildEvidenceSynthesisOutput as s,buildResultRecoveryRequest as l,containsRawToolCallOutput as i,rawToolCallFailureMessage as u,rawToolCallOutputPreview as n,toolCallRecoveryEnabled as c}from"../../recovery/tool-call.js";export async function recoverAdapterResultOutput(n){let p=n.result,d=n.request;const y=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(n.recoveryPolicy);for(let e=0;e<y;e+=1){const t=n.store.getRun(n.requestId)?.events??[],o=l({request:d,output:p.text,events:t,availableToolIds:n.agent.tools,policy:n.recoveryPolicy});if(!o)break;d=o,emitRepair(n,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(p.text,n.agent.tools)),p=await n.runAdapter(o),emitRepair(n,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(p.text,n.agent.tools))}return function finalizeRecoveredOutput(l,n){if(!c(l.recoveryPolicy))return n;let p=!1;if(i(n.text,l.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(l.request.metadata)){const e=n.text;n={...n,text:u(),metadata:{...n.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(l,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,l.agent.tools))}const d=s({request:l.request,output:n.text,events:l.store.getRun(l.requestId)?.events??[],policy:l.recoveryPolicy});return d&&(p=!0,n={...n,text:d,metadata:{...n.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(l,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),p||(i(n.text,l.recoveryPolicy)&&emitRepair(l,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(n.text,l.agent.tools)),o(n.text,l.recoveryPolicy),t(n.text,l.agent.tools,l.recoveryPolicy),r(n.text,l.store.getRun(l.requestId)?.events??[],l.recoveryPolicy),a(n.text,l.recoveryPolicy),e({output:n.text,events:l.store.getRun(l.requestId)?.events??[],availableToolIds:l.agent.tools})),n}(n,p)}function emitRepair(e,t,o,r,a,s,l){const i={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...l?{diagnostics:l}:{}};e.emit("runtime.repair.started"===t?{type:t,...i}:{type:t,...i,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:n(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])new RegExp(`(?:^|[^A-Za-z0-9_-])${escapeRegexp(r)}(?:$|[^A-Za-z0-9_-])`,"u").test(e)&&o.add(r);return[...o]}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}
1
+ import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{buildRawArgsRecoveryRequest as t,hasUniqueRawArgsTool as o}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as r,assertNoRawToolCallOutput as a,assertNoRawToolResultOutput as s,assertNoToolExecutionErrorOutput as l,buildEvidenceSynthesisOutput as i,buildResultRecoveryRequest as u,containsRawToolCallOutput as n,rawToolCallFailureMessage as c,rawToolCallOutputPreview as p,toolCallRecoveryEnabled as y}from"../../recovery/tool-call.js";export async function recoverAdapterResultOutput(d){let v=d.result,m=d.request;const g=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(d.recoveryPolicy);let R=!1;for(let e=0;;e+=1){const o=d.store.getRun(d.requestId)?.events??[],r=R?void 0:t({request:m,output:v.text,agent:d.agent,workspace:d.workspace,toolGateway:d.toolGateway,policy:d.recoveryPolicy}),a=e<g?u({request:m,output:v.text,events:o,availableToolIds:d.agent.tools,policy:d.recoveryPolicy}):void 0,s=r??a;if(!s)break;s===r&&(R=!0),m=s,emitRepair(d,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(v.text,d.agent.tools)),v=await d.runAdapter(s),emitRepair(d,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(v.text,d.agent.tools))}return function finalizeRecoveredOutput(t,u){if(!y(t.recoveryPolicy))return u;let d=!1;if(n(u.text,t.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(t.request.metadata)){const e=u.text;u={...u,text:c(),metadata:{...u.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,t.agent.tools))}const v=i({request:t.request,output:u.text,events:t.store.getRun(t.requestId)?.events??[],policy:t.recoveryPolicy});return v&&(d=!0,u={...u,text:v,metadata:{...u.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(t,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),d||(n(u.text,t.recoveryPolicy)&&emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(u.text,t.agent.tools)),a(u.text,t.recoveryPolicy),function assertNoRawArgsToolOutput(e,t){if(o({output:t,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,policy:e.recoveryPolicy}))throw new Error(`Adapter returned raw tool argument JSON as the final answer after recovery. The backend must execute the matching tool instead. Output preview: ${p(t)}`)}(t,u.text),r(u.text,t.agent.tools,t.recoveryPolicy),s(u.text,t.store.getRun(t.requestId)?.events??[],t.recoveryPolicy),l(u.text,t.recoveryPolicy),e({output:u.text,events:t.store.getRun(t.requestId)?.events??[],availableToolIds:t.agent.tools})),u}(d,v)}function emitRepair(e,t,o,r,a,s,l){const i={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...l?{diagnostics:l}:{}};e.emit("runtime.repair.started"===t?{type:t,...i}:{type:t,...i,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:p(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])new RegExp(`(?:^|[^A-Za-z0-9_-])${escapeRegexp(r)}(?:$|[^A-Za-z0-9_-])`,"u").test(e)&&o.add(r);return[...o]}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildAdapterErrorRecoveryPrompt as r,buildExecutionContractRecoveryRequest as a,isRecoverableAdapterError as s}from"./recovery/tool-call.js";import{recoverQualityReview as n,resolveQualityPolicy as o}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as d}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as m}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as w}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as g,normalizeAdapterResult as y}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as f}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as I}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as q}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as R}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as v}from"./runtime/progress-narration.js";import{repairRuntimeSelection as k}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as b}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as A}from"./runtime/tool-failure.js";import{runWorkflowRequest as C}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const y=new Set,x=t.store??R(),j=g([f(t),v({options:t.progressNarration,policy:t.workspace.runtime}),b({policy:t.workspace.runtime,store:x,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);x.appendEvent(r);for(const e of y)e(r)},emit=e=>{emitBase(e),j.emitSideEffects(e,emitBase)},E=l({gateway:m({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),h={...t,toolGateway:E},S=A(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),m=t.request.sessionId??e(),l=[],{agent:w,adapter:g}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await k({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,s=e.workspace.agents.get(a);if(!s)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:s,adapter:void 0};const n=e.adapters.find(e=>e.canRun(s));if(!n)throw new Error(`No runtime adapter can run backend ${s.backend} for agent ${s.id}`);return{agent:s,adapter:n}}(t.input,t.request,{requestId:p,sessionId:m,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,m,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:m,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await C({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:m,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await d({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:m,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,d=c.pluginMemories??[],m=I({workspace:e.input.workspace,agent:e.agent}),l=o(e.input.workspace.runtime,e.agent),w=new Map;let g;try{g=await runAdapterOnce(e,t,e.request,p,d,w,m)}catch(a){if(!s(a,m))throw a;e.emit(repairStarted(e,"adapter_error",1,errorMessage(a))),g=await runAdapterOnce(e,t,r(e.request,a,m),p,d,w,m),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(a)))}g=await i({...e,request:e.request,result:g,recoveryPolicy:m,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),g=await n(createQualityRuntimeInput(e,p,d,w,m),e.request,g,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:g});try{assertRequestExecutionContract(e)}catch(r){const s=a({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:m});if(!s)throw r;e.emit(repairStarted(e,"execution_contract",1,errorMessage(r))),g=await runAdapterOnce(e,t,s,p,d,w,m),g=await i({...e,request:s,result:g,recoveryPolicy:m,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),g=await n(createQualityRuntimeInput(e,p,d,w,m),s,g,l),assertRequestExecutionContract(e),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(r)))}const y=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:g,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:g,response:y}),y}({...t,adapter:g,requestId:p,sessionId:m,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,error:e})}}({input:h,capabilities:j,store:x,emit:emit,request:t,toolFailureTracker:S}),subscribe:e=>(y.add(e),()=>y.delete(e)),...w({workspace:t.workspace,store:x,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:x,emit:emit}),...q({memory:t.memory}),cancel(e,t){const r=x.getRun(e);r&&"running"===r.state&&(x.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await j.stop(),y.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:n=>runAdapterOnce(e,e.adapter,n,t,r,a,s),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,s,n,o){return y(await t.run({workspace:{...e.input.workspace,runtime:o},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:s,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:n,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,s){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:s}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
1
+ import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildAdapterErrorRecoveryPrompt as r,buildExecutionContractRecoveryRequest as a,isRecoverableAdapterError as s}from"./recovery/tool-call.js";import{recoverQualityReview as o,resolveQualityPolicy as n}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as d}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as m}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as w}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as y,normalizeAdapterResult as g}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as f}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as I}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as q}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as R}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as v}from"./runtime/progress-narration.js";import{repairRuntimeSelection as k}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as b}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as A}from"./runtime/tool-failure.js";import{runWorkflowRequest as C}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const g=new Set,x=t.store??R(),j=y([f(t),v({options:t.progressNarration,policy:t.workspace.runtime}),b({policy:t.workspace.runtime,store:x,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);x.appendEvent(r);for(const e of g)e(r)},emit=e=>{emitBase(e),j.emitSideEffects(e,emitBase)},E=l({gateway:m({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),h={...t,toolGateway:E},G=A(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),m=t.request.sessionId??e(),l=[],{agent:w,adapter:y}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await k({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,s=e.workspace.agents.get(a);if(!s)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:s,adapter:void 0};const o=e.adapters.find(e=>e.canRun(s));if(!o)throw new Error(`No runtime adapter can run backend ${s.backend} for agent ${s.id}`);return{agent:s,adapter:o}}(t.input,t.request,{requestId:p,sessionId:m,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,m,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:m,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await C({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:m,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await d({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:m,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,d=c.pluginMemories??[],m=I({workspace:e.input.workspace,agent:e.agent}),l=n(e.input.workspace.runtime,e.agent),w=new Map;let y;try{y=await runAdapterOnce(e,t,e.request,p,d,w,m)}catch(a){if(!s(a,m))throw a;e.emit(repairStarted(e,"adapter_error",1,errorMessage(a))),y=await runAdapterOnce(e,t,r(e.request,a,m),p,d,w,m),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(a)))}y=await i({...e,request:e.request,result:y,recoveryPolicy:m,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),y=await o(createQualityRuntimeInput(e,p,d,w,m),e.request,y,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:y});try{assertRequestExecutionContract(e)}catch(r){const s=a({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:m});if(!s)throw r;e.emit(repairStarted(e,"execution_contract",1,errorMessage(r))),y=await runAdapterOnce(e,t,s,p,d,w,m),y=await i({...e,request:s,result:y,recoveryPolicy:m,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),y=await o(createQualityRuntimeInput(e,p,d,w,m),s,y,l),assertRequestExecutionContract(e),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(r)))}const g=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:y,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:y,response:g}),g}({...t,adapter:y,requestId:p,sessionId:m,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,error:e})}}({input:h,capabilities:j,store:x,emit:emit,request:t,toolFailureTracker:G}),subscribe:e=>(g.add(e),()=>g.delete(e)),...w({workspace:t.workspace,store:x,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:x,emit:emit}),...q({memory:t.memory}),cancel(e,t){const r=x.getRun(e);r&&"running"===r.state&&(x.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await j.stop(),g.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,a,s),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,s,o,n){return g(await t.run({workspace:{...e.input.workspace,runtime:n},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:s,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:o,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,s){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:s}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/core",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,7 +11,7 @@
11
11
  ".": "./dist/index.js"
12
12
  },
13
13
  "peerDependencies": {
14
- "@stable-harness/governance": "0.0.94",
15
- "@stable-harness/memory": "0.0.94"
14
+ "@stable-harness/governance": "0.0.96",
15
+ "@stable-harness/memory": "0.0.96"
16
16
  }
17
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/governance",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/memory",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/protocols",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -10,6 +10,6 @@
10
10
  "main": "dist/src/index.js",
11
11
  "types": "dist/src/index.d.ts",
12
12
  "peerDependencies": {
13
- "@stable-harness/core": "0.0.94"
13
+ "@stable-harness/core": "0.0.96"
14
14
  }
15
15
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/tool-gateway",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/workspace-yaml",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,6 +11,6 @@
11
11
  ".": "./dist/index.js"
12
12
  },
13
13
  "peerDependencies": {
14
- "@stable-harness/core": "0.0.94"
14
+ "@stable-harness/core": "0.0.96"
15
15
  }
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stable-harness",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "description": "Stable application runtime and operator control plane for agent workspaces.",
6
6
  "license": "Apache-2.0",
@@ -82,14 +82,14 @@
82
82
  "@langchain/node-vfs": "^0.1.4",
83
83
  "@langchain/ollama": "^1.2.7",
84
84
  "@langchain/openai": "^1.4.5",
85
- "@stable-harness/adapter-deepagents": "0.0.94",
86
- "@stable-harness/adapter-langgraph": "0.0.94",
87
- "@stable-harness/core": "0.0.94",
88
- "@stable-harness/governance": "0.0.94",
89
- "@stable-harness/memory": "0.0.94",
90
- "@stable-harness/protocols": "0.0.94",
91
- "@stable-harness/tool-gateway": "0.0.94",
92
- "@stable-harness/workspace-yaml": "0.0.94",
85
+ "@stable-harness/adapter-deepagents": "0.0.96",
86
+ "@stable-harness/adapter-langgraph": "0.0.96",
87
+ "@stable-harness/core": "0.0.96",
88
+ "@stable-harness/governance": "0.0.96",
89
+ "@stable-harness/memory": "0.0.96",
90
+ "@stable-harness/protocols": "0.0.96",
91
+ "@stable-harness/tool-gateway": "0.0.96",
92
+ "@stable-harness/workspace-yaml": "0.0.96",
93
93
  "deepagents": "^1.10.1",
94
94
  "langchain": "^1.4.0",
95
95
  "yaml": "^2.8.2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/adapter-deepagents",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -15,7 +15,7 @@
15
15
  "@langchain/node-vfs": "^0.1.4",
16
16
  "@langchain/ollama": "^1.2.7",
17
17
  "@langchain/openai": "^1.4.5",
18
- "@stable-harness/core": "0.0.94",
18
+ "@stable-harness/core": "0.0.96",
19
19
  "deepagents": "^1.10.1",
20
20
  "langchain": "^1.4.0"
21
21
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/adapter-langgraph",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,6 +11,6 @@
11
11
  "types": "dist/src/index.d.ts",
12
12
  "peerDependencies": {
13
13
  "@langchain/langgraph": "^1.3.0",
14
- "@stable-harness/core": "0.0.94"
14
+ "@stable-harness/core": "0.0.96"
15
15
  }
16
16
  }
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createBackendModel as r,createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createLangGraphWorkflowAdapter as s}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as a}from"@stable-harness/core";import{projectEvent as i,projectRuntimeTrace as n}from"@stable-harness/core";import{createInMemoryApprovalQueue as u}from"@stable-harness/governance";import{createModuleToolGateway as d}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as l}from"@stable-harness/workspace-yaml";import{helpText as p,parseArgs as c}from"./args.js";import{buildWorkspaceArtifact as m}from"./build.js";import{formatCliRuntimeEvent as f,readCliEventViewConfig as w,shouldEnableCliProgressNarration as v}from"./event-view.js";import{initWorkspace as g}from"./init.js";import{ensureCliMemoryServices as y}from"./memory/lifecycle.js";import{createCliMemoryProviders as I}from"./memory/providers.js";import{formatDetail as k,inspectWorkflow as R,renderAgent as h,renderWorkflow as b,workspaceStatus as q}from"./output.js";import{serveProtocol as A,stopProtocol as C}from"./server.js";export async function runCli(e=process.argv.slice(2)){const t=c(e);if(t.help)return void process.stdout.write(p());const r=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),s=t.workspaceRoot;try{if("init"===t.command)return void process.stdout.write(await g(t.prompt||s));const e=await l(s);if(t.workflowRenderId)return void process.stdout.write(b(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(R(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(h(e,t.agentRenderId));if("build"===t.command)return void process.stdout.write(await m({workspace:e,workspaceRoot:s,outputDir:t.buildOutput,target:t.buildTarget}));if("stop"===t.command)return clearTimeout(r),void await C(e,t);const p=await d({tools:e.tools.values(),options:{betterCall:{mode:"repair"}}}),c=u(),M=w(e.runtime),j=await async function createCliMemoryProvidersForCommand(e,t){return t.serveOpenAi||t.shouldRunRequest&&!t.toolId?(await y(e),I(e)):[]}(e,t);let $;if($=a({workspace:e,toolGateway:p,approvals:c,memoryProviders:j,adapters:[o()],workflowAdapters:[createCliWorkflowAdapter(p,()=>$)],progressNarration:v(M,e.runtime)?{enabled:!0,style:"cli"}:void 0,qualityReviewModel:createQualityReviewModel(e)}),t.serveOpenAi)return clearTimeout(r),void await A($,t);if(!t.shouldRunRequest)return void process.stdout.write(q(e,s));t.trace&&$.subscribe(e=>{const t=i(e);t&&process.stdout.write(`trace:${t.agentId}:${t.label}${k(t.detail)}\n`)}),$.subscribe(e=>{const t=f(e,M);t&&process.stdout.write(`${t}\n`)});const S=await $.request({input:t.prompt,agentId:t.agentId,sessionId:t.sessionId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0,workflow:t.workflowRunId?{workflowId:t.workflowRunId,input:t.prompt}:void 0});if(t.trace||t.traceJson){const e=$.getRun(S.requestId),r=e?n(e):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:r})}\n`)}process.stdout.write(`${S.output}\n`)}finally{clearTimeout(r)}}function createQualityReviewModel(e){const t=function readQualityModelRef(e){const t=isRecord(e)?e:{},r=isRecord(t.reviewer)?t.reviewer:t;return"string"==typeof r.modelRef&&r.modelRef.trim()?r.modelRef.trim():void 0}(e.runtime.quality),o=t?e.models.get(t):void 0,s=o?r(o):void 0;return function isQualityReviewModel(e){return isRecord(e)&&"function"==typeof e.invoke}(s)?s:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function createCliWorkflowAdapter(e,t){return s({nodeResolvers:{tools:async({id:t,node:r,request:o,requestId:s,sessionId:a,state:i,workspace:n})=>{return(await e.invoke({toolId:t,args:(u=r.config,d=o.input,l=i.outputs,!0===u?.inputFromState?{...u,requestInput:d,outputs:l}:u&&"requiredInput"in u?u.requiredInput:u&&("args"in u||"cwd"in u||"timeoutMs"in u)?u:"object"==typeof d&&null!==d?d:{}),context:{workspaceRoot:n.root,requestId:s,sessionId:a,agentId:`workflow:${r.id}`,approvalIds:readApprovalIds(o.metadata)}})).output;var u,d,l},agents:async({id:e,node:r,request:o,sessionId:s,state:a})=>{var i,n,u,d;return(await t().request({input:(i=e,n=o.input,u=a.outputs,d=r.config,[`Workflow node agents.${i}: synthesize the workflow evidence into the requested final output.`,`Original request: ${"string"==typeof n?n:JSON.stringify(n)}`,"Requirements:","- Produce the final answer now; do not ask follow-up questions.","- Match the original request language unless workflow config explicitly says otherwise.","- Use only the workflow outputs as evidence; call out uncertainty directly.",...d?[`Workflow node config: ${JSON.stringify(d)}`]:[],"Prior workflow outputs:",JSON.stringify(u)].join("\n")),agentId:e,sessionId:s,metadata:o.metadata})).output}}})}function readApprovalIds(e){const t=e?.approvalIds??e?.approvalId;return"string"==typeof t&&t.trim()?[t.trim()]:Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.trim().length>0):void 0}(function isCliEntrypoint(){const r=process.argv[1];if(!r)return!1;try{return e(t(import.meta.url))===e(r)}catch{return!1}})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
2
+ import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createBackendModel as r,createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createLangGraphWorkflowAdapter as s}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as i}from"@stable-harness/core";import{projectEvent as a,projectRuntimeTrace as n}from"@stable-harness/core";import{createInMemoryApprovalQueue as u}from"@stable-harness/governance";import{createModuleToolGateway as d}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as l}from"@stable-harness/workspace-yaml";import{helpText as c,parseArgs as p}from"./args.js";import{buildWorkspaceArtifact as m}from"./build.js";import{formatCliRuntimeEvent as f,readCliEventViewConfig as w,shouldEnableCliProgressNarration as v}from"./event-view.js";import{initWorkspace as g}from"./init.js";import{runRequestThroughDaemon as y}from"./daemon/client.js";import{ensureCliMemoryServices as I}from"./memory/lifecycle.js";import{createCliMemoryProviders as k}from"./memory/providers.js";import{formatDetail as R,inspectWorkflow as h,renderAgent as b,renderWorkflow as q,workspaceStatus as A}from"./output.js";import{serveProtocol as C,stopProtocol as M}from"./server.js";export async function runCli(e=process.argv.slice(2)){const t=p(e);if(t.help)return void process.stdout.write(c());const r=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),s=t.workspaceRoot;try{if("init"===t.command)return void process.stdout.write(await g(t.prompt||s));const e=await l(s);if(t.workflowRenderId)return void process.stdout.write(q(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(h(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(b(e,t.agentRenderId));if("build"===t.command)return void process.stdout.write(await m({workspace:e,workspaceRoot:s,outputDir:t.buildOutput,target:t.buildTarget}));if("stop"===t.command)return clearTimeout(r),void await M(e,t);const c=w(e.runtime);if(t.shouldRunRequest&&!t.serveOpenAi&&await y({args:t,runtimePolicy:e.runtime,eventView:c}))return;const p=await d({tools:e.tools.values(),options:{betterCall:{mode:"repair"}}}),j=u(),$=await async function createCliMemoryProvidersForCommand(e,t){return t.serveOpenAi||t.shouldRunRequest&&!t.toolId?(await I(e),k(e)):[]}(e,t);let P;if(P=i({workspace:e,toolGateway:p,approvals:j,memoryProviders:$,adapters:[o()],workflowAdapters:[createCliWorkflowAdapter(p,()=>P)],progressNarration:v(c,e.runtime)?{enabled:!0,style:"cli"}:void 0,qualityReviewModel:createQualityReviewModel(e)}),t.serveOpenAi)return clearTimeout(r),void await C(P,t);if(!t.shouldRunRequest)return void process.stdout.write(A(e,s));await async function runInProcessRequest(e,t,r){t.trace&&e.subscribe(e=>{const t=a(e);t&&process.stdout.write(`trace:${t.agentId}:${t.label}${R(t.detail)}\n`)}),e.subscribe(e=>{const t=f(e,r);t&&process.stdout.write(`${t}\n`)});const o=await e.request({input:t.prompt,agentId:t.agentId,sessionId:t.sessionId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0,workflow:t.workflowRunId?{workflowId:t.workflowRunId,input:t.prompt}:void 0});if(t.trace||t.traceJson){const r=e.getRun(o.requestId),s=r?n(r):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:s})}\n`)}process.stdout.write(`${o.output}\n`)}(P,t,c)}finally{clearTimeout(r)}}function createQualityReviewModel(e){const t=function readQualityModelRef(e){const t=isRecord(e)?e:{},r=isRecord(t.reviewer)?t.reviewer:t;return"string"==typeof r.modelRef&&r.modelRef.trim()?r.modelRef.trim():void 0}(e.runtime.quality),o=t?e.models.get(t):void 0,s=o?r(o):void 0;return function isQualityReviewModel(e){return isRecord(e)&&"function"==typeof e.invoke}(s)?s:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function createCliWorkflowAdapter(e,t){return s({nodeResolvers:{tools:async({id:t,node:r,request:o,requestId:s,sessionId:i,state:a,workspace:n})=>{return(await e.invoke({toolId:t,args:(u=r.config,d=o.input,l=a.outputs,!0===u?.inputFromState?{...u,requestInput:d,outputs:l}:u&&"requiredInput"in u?u.requiredInput:u&&("args"in u||"cwd"in u||"timeoutMs"in u)?u:"object"==typeof d&&null!==d?d:{}),context:{workspaceRoot:n.root,requestId:s,sessionId:i,agentId:`workflow:${r.id}`,approvalIds:readApprovalIds(o.metadata)}})).output;var u,d,l},agents:async({id:e,node:r,request:o,sessionId:s,state:i})=>{var a,n,u,d;return(await t().request({input:(a=e,n=o.input,u=i.outputs,d=r.config,[`Workflow node agents.${a}: synthesize the workflow evidence into the requested final output.`,`Original request: ${"string"==typeof n?n:JSON.stringify(n)}`,"Requirements:","- Produce the final answer now; do not ask follow-up questions.","- Match the original request language unless workflow config explicitly says otherwise.","- Use only the workflow outputs as evidence; call out uncertainty directly.",...d?[`Workflow node config: ${JSON.stringify(d)}`]:[],"Prior workflow outputs:",JSON.stringify(u)].join("\n")),agentId:e,sessionId:s,metadata:o.metadata})).output}}})}function readApprovalIds(e){const t=e?.approvalIds??e?.approvalId;return"string"==typeof t&&t.trim()?[t.trim()]:Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.trim().length>0):void 0}(function isCliEntrypoint(){const r=process.argv[1];if(!r)return!1;try{return e(t(import.meta.url))===e(r)}catch{return!1}})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
@@ -0,0 +1,8 @@
1
+ import { type WorkspaceRuntimePolicy } from "@stable-harness/core";
2
+ import type { CliArgs } from "../args.js";
3
+ import { type CliEventViewConfig } from "../event-view.js";
4
+ export declare function runRequestThroughDaemon(input: {
5
+ args: CliArgs;
6
+ runtimePolicy: WorkspaceRuntimePolicy;
7
+ eventView: CliEventViewConfig;
8
+ }): Promise<boolean>;
@@ -0,0 +1 @@
1
+ import{randomUUID as t}from"node:crypto";import e from"node:path";import{formatCliRuntimeEvent as r}from"../event-view.js";export async function runRequestThroughDaemon(n){const o=function daemonBaseUrl(t){const e=function protocolConfig(t,...e){for(const r of e){const e=readRecord(t[r]);if(e)return e}}(readRecord(t.protocols)??{},"stableRuntime","stable-runtime","http")??{};return`http://${function configString(t){if("string"!=typeof t||!t.trim())return;const e=t.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return e?process.env[e[1]]??e[2]:t}(e.host)??process.env.STABLE_HARNESS_RUNTIME_HOST??"127.0.0.1"}:${configNumber(e.port)??configNumber(process.env.STABLE_HARNESS_RUNTIME_PORT)??8641}`}(n.runtimePolicy);if(!await async function isDaemonAvailable(t,r){try{const n=await fetch(`${t}/inspect`,{signal:AbortSignal.timeout(300)});if(!n.ok)return!1;const o=await n.json();return Array.isArray(o.agents)&&Array.isArray(o.runs)&&o.workspaceRoot===e.resolve(r)}catch{return!1}}(o,n.args.workspaceRoot))return!1;const s=t(),a=function streamDaemonEvents(t,e,n){const o=new AbortController;return async function readDaemonEventStream(t,e,n,o){try{const s=await fetch(`${t}/events?requestId=${encodeURIComponent(e)}`,{signal:o}),a=s.body?.getReader();if(!a)return;await async function readSseMessages(t,e){let r="";for(;;){const{value:n,done:o}=await t.read();if(o)return;r+=Buffer.from(n).toString("utf8");const s=r.split("\n\n");r=s.pop()??"";for(const t of s){const r=parseSseEvent(t);r&&e(r)}}}(a,t=>{const e=r(t,n);e&&process.stdout.write(`${e}\n`)})}catch(t){o.aborted||process.stderr.write(`stable-harness daemon event stream failed: ${function errorMessage(t){return t instanceof Error?t.message:String(t)}(t)}\n`)}}(t,e,n,o.signal),{close:()=>o.abort()}}(o,s,n.eventView);try{const t=await async function postRuntimeRequest(t,e,r){const n=await fetch(`${t}/requests`,{method:"POST",body:JSON.stringify(toRuntimeRequest(e,r))});if(!n.ok)throw new Error(`stable-harness daemon request failed: HTTP ${n.status}`);return await n.json()}(o,n.args,s);return(n.args.trace||n.args.traceJson)&&await async function printDaemonTrace(t,e,r){const n=await fetch(`${t}/runs/${encodeURIComponent(e)}/trace`);if(!n.ok)return;const o=await n.json();if(r)process.stdout.write(`${JSON.stringify({trace:o})}\n`);else for(const t of o)process.stdout.write(`trace:${t.agentId}:${t.label}${t.detail?` ${JSON.stringify(t.detail)}`:""}\n`)}(o,t.requestId,n.args.traceJson),process.stdout.write(`${t.output}\n`),!0}finally{a.close()}}function toRuntimeRequest(t,e){return{input:t.prompt,requestId:e,...t.agentId?{agentId:t.agentId}:{},...t.sessionId?{sessionId:t.sessionId}:{},...t.toolId?{toolCall:{toolId:t.toolId,args:t.toolArgs}}:{},...t.workflowRunId?{workflow:{workflowId:t.workflowRunId,input:t.prompt}}:{}}}function parseSseEvent(t){const e=t.split("\n").find(t=>t.startsWith("data: "))?.slice(6);return e?JSON.parse(e):void 0}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}function configNumber(t){return"number"==typeof t&&Number.isFinite(t)?t:"string"==typeof t&&t.trim()?Number(t):void 0}
@@ -1 +1 @@
1
- import{execFile as t}from"node:child_process";import{promisify as r}from"node:util";import{createOpenAiCompatibleHttpServer as e}from"@stable-harness/protocols";import{startOfficialLangGraphServer as n}from"./langgraph-official.js";const o="127.0.0.1",s=r(t);export async function serveProtocol(t,r){const e=createConfiguredServers(t,r),n=[];let o=0;for(const r of e)if("http"===r.kind){if(!await listen(r)){process.stdout.write(`stable-harness ${r.protocol} API already running on http://${r.host}:${r.port}/v1\n`);continue}n.push(()=>closeHttpServer(r.server)),o+=1;const t=r.server.address(),e="object"==typeof t&&t?t.port:r.port;process.stdout.write(`stable-harness ${r.protocol} API listening on http://${r.host}:${e}/v1\n`)}else{const e=await startLangGraphServer(t,r);if(!e){process.stdout.write(`stable-harness ${r.protocol} API already running on http://${r.config.host}:${r.config.port}\n`);continue}n.push(e.cleanup),o+=1,process.stdout.write(`stable-harness ${r.protocol} API listening on ${e.url}\n`)}0!==o&&await async function waitForShutdown(t){const r=setInterval(()=>{},864e5);await new Promise(e=>{const shutdown=()=>{clearInterval(r),Promise.allSettled(t.map(t=>t())).finally(()=>process.exit(0))};process.once("SIGINT",shutdown),process.once("SIGTERM",shutdown)})}(n)}export async function stopProtocol(t,r){const e=createConfiguredServers({getRuntimePolicy:()=>t.runtime},r).map(t=>"http"===t.kind?{protocol:t.protocol,host:t.host,port:t.port}:{protocol:t.protocol,host:t.config.host,port:t.config.port}),n=await Promise.all(e.map(async t=>({target:t,pids:await stableHarnessListenerPids(t.port)}))),o=[...new Set(n.flatMap(t=>t.pids))];for(const t of o)process.kill(t,"SIGTERM");for(const{target:t,pids:r}of n)0!==r.length?process.stdout.write(`stable-harness ${t.protocol} API stopped on ${t.host}:${t.port} pid=${r.join(",")}\n`):process.stdout.write(`stable-harness ${t.protocol} API not running on ${t.host}:${t.port}\n`)}function createConfiguredServers(t,r){const e=readRecord(t.getRuntimePolicy().protocols)??{},n=protocolConfig(e,"openaiCompatible","openai-compatible","openai")??{},o=protocolConfig(e,"langgraph")??{};return[...enabled(n)?[openAiServer(t,n,r)]:[],...enabled(o)?[langGraphServer(o)]:[]]}function openAiServer(t,r,n){const s=configString(r.host)??o,i=n.port??configNumber(r.port)??8642,a=n.host??s,c=configString(r.bearerToken)??configString(r.apiKey)??n.apiKey;return{kind:"http",protocol:"openai-compatible",server:e(t,{bearerToken:c}),host:a,port:i,...c?{bearerToken:c}:{}}}function langGraphServer(t){const r=configString(t.host)??o,e=configNumber(t.port)??2024,n=function configStringArray(t){if(Array.isArray(t)&&t.every(t=>"string"==typeof t))return t.filter(t=>t.trim()).map(t=>t.trim())}(t.exposeAgents);return{kind:"langgraph",protocol:"langgraph-compatible",config:{host:r,port:e,nWorkers:configNumber(t.nWorkers)??10,...n?{exposeAgents:n}:{},...void 0!==t.env?{env:t.env}:{},...void 0!==t.envFile?{envFile:t.envFile}:{}}}}function protocolConfig(t,...r){for(const e of r){const r=readRecord(t[e]);if(r)return r}}function enabled(t){return!1!==t.enabled}function configString(t){if("string"!=typeof t||!t.trim())return;const r=t.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]:t}function configNumber(t){return"number"==typeof t&&Number.isFinite(t)?t:"string"==typeof t&&t.trim()?Number(t):void 0}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}async function listen(t){try{return await new Promise((r,e)=>{t.server.once("error",e),t.server.listen(t.port,t.host,()=>{t.server.off("error",e),r()})}),!0}catch(r){if(isAddressInUse(r)&&await async function isOpenAiServerAlreadyRunning(t){const r=await fetchJson(`http://${t.host}:${t.port}/v1/capabilities`,{...t.bearerToken?{authorization:`Bearer ${t.bearerToken}`}:{}});return"stable_harness.capabilities"===r?.object}(t))return!1;throw portConflictError(r,t.protocol,t.host,t.port)}}async function startLangGraphServer(t,r){if(!await isLangGraphServerAlreadyRunning(r))try{return await n(t,r.config)}catch(t){if(isAddressInUse(t)&&await isLangGraphServerAlreadyRunning(r))return;throw portConflictError(t,r.protocol,r.config.host,r.config.port)}}async function isLangGraphServerAlreadyRunning(t){const r=await fetchJson(`http://${t.config.host}:${t.config.port}/ok`);return!0===r?.ok}async function fetchJson(t,r={}){try{const e=await fetch(t,{headers:r});if(!e.ok)return;return await e.json()}catch{return}}function isAddressInUse(t){return"EADDRINUSE"===function readErrorCode(t){return"object"==typeof t&&null!==t&&"code"in t?t.code:void 0}(t)||String(t).includes("EADDRINUSE")}function portConflictError(t,r,e,n){return isAddressInUse(t)?new Error([`stable-harness ${r} port is already in use: ${e}:${n}.`,`Use --port <port>, update config/runtime/workspace.yaml, or stop the process currently listening on ${e}:${n}.`].join("\n")):t}async function stableHarnessListenerPids(t){const r=await async function listenerPids(t){try{const{stdout:r}=await s("lsof",[`-tiTCP:${t}`,"-sTCP:LISTEN"]);return r.split(/\s+/u).map(t=>Number(t)).filter(t=>Number.isInteger(t)&&t>0)}catch{return[]}}(t);return(await Promise.all(r.map(async t=>{const r=await async function processCommand(t){try{const{stdout:r}=await s("ps",["-p",String(t),"-o","command="]);return r.trim()}catch{return""}}(t);return isStableHarnessStartCommand(r)?t:void 0}))).filter(t=>"number"==typeof t)}export function isStableHarnessStartCommand(t){if(function hasUnsafeCommandCharacters(t){return/[\u0000-\u001F\u007F;|`&<>]/u.test(t)}(t))return!1;const r=function splitCommandLine(t){const r=[];let e,n="";for(const o of t)'"'!==o&&"'"!==o||void 0!==e?o!==e?/\s/u.test(o)&&void 0===e?n&&(r.push(n),n=""):n+=o:e=void 0:e=o;return n&&r.push(n),r}(t),e=function stableHarnessCommandIndex(t){return isStableHarnessExecutableToken(t[0]??"")?0:function isNodeExecutableToken(t){const r=t.split(/[\\/]/u).at(-1);return"node"===r||"nodejs"===r}(t[0]??"")&&(isStableHarnessExecutableToken(t[1]??"")||function isStableHarnessScriptToken(t){if(hasTraversalSegment(t))return!1;const r=t.replaceAll("\\","/");return r.includes("/stable-harness/")&&r.endsWith("/packages/cli/dist/src/cli.js")}(t[1]??""))?1:-1}(r);return e>=0&&r.slice(e+1).includes("start")}function isStableHarnessExecutableToken(t){if(hasTraversalSegment(t))return!1;const r=t.split(/[\\/]/u).at(-1);return"stable-harness"===r||"botbotgo"===r}function hasTraversalSegment(t){return t.split(/[\\/]/u).some(t=>"."===t||".."===t)}async function closeHttpServer(t){await new Promise((r,e)=>{t.close(t=>{t?e(t):r()})})}
1
+ import{execFile as t}from"node:child_process";import{promisify as r}from"node:util";import{createHttpServer as e,createOpenAiCompatibleHttpServer as n}from"@stable-harness/protocols";import{startOfficialLangGraphServer as o}from"./langgraph-official.js";const s="127.0.0.1",i=r(t);export async function serveProtocol(t,r){const e=createConfiguredServers(t,r),n=[];let o=0;for(const r of e)if("http"===r.kind){if(!await listen(r)){process.stdout.write(`stable-harness ${r.protocol} API already running on ${serverUrl(r)}\n`);continue}n.push(()=>closeHttpServer(r.server)),o+=1;const t=r.server.address(),e="object"==typeof t&&t?t.port:r.port;process.stdout.write(`stable-harness ${r.protocol} API listening on ${serverUrl({...r,port:e})}\n`)}else{const e=await startLangGraphServer(t,r);if(!e){process.stdout.write(`stable-harness ${r.protocol} API already running on http://${r.config.host}:${r.config.port}\n`);continue}n.push(e.cleanup),o+=1,process.stdout.write(`stable-harness ${r.protocol} API listening on ${e.url}\n`)}0!==o&&await async function waitForShutdown(t){const r=setInterval(()=>{},864e5);await new Promise(e=>{const shutdown=()=>{clearInterval(r),Promise.allSettled(t.map(t=>t())).finally(()=>process.exit(0))};process.once("SIGINT",shutdown),process.once("SIGTERM",shutdown)})}(n)}export async function stopProtocol(t,r){const e=createConfiguredServers({getRuntimePolicy:()=>t.runtime},r).map(t=>"http"===t.kind?{protocol:t.protocol,host:t.host,port:t.port}:{protocol:t.protocol,host:t.config.host,port:t.config.port}),n=await Promise.all(e.map(async t=>({target:t,pids:await stableHarnessListenerPids(t.port)}))),o=[...new Set(n.flatMap(t=>t.pids))];for(const t of o)process.kill(t,"SIGTERM");for(const{target:t,pids:r}of n)0!==r.length?process.stdout.write(`stable-harness ${t.protocol} API stopped on ${t.host}:${t.port} pid=${r.join(",")}\n`):process.stdout.write(`stable-harness ${t.protocol} API not running on ${t.host}:${t.port}\n`)}function createConfiguredServers(t,r){const e=readRecord(t.getRuntimePolicy().protocols)??{},n=protocolConfig(e,"stableRuntime","stable-runtime","http")??{},o=protocolConfig(e,"openaiCompatible","openai-compatible","openai")??{},s=protocolConfig(e,"langgraph")??{};return[...enabled(n)?[stableRuntimeServer(t,n,r)]:[],...enabled(o)?[openAiServer(t,o,r)]:[],...enabled(s)?[langGraphServer(s)]:[]]}function stableRuntimeServer(t,r,n){return{kind:"http",protocol:"stable-runtime",server:e(t),host:n.host??configString(r.host)??s,port:configNumber(r.port)??configNumber(process.env.STABLE_HARNESS_RUNTIME_PORT)??8641}}function openAiServer(t,r,e){const o=configString(r.host)??s,i=e.port??configNumber(r.port)??8642,a=e.host??o,c=configString(r.bearerToken)??configString(r.apiKey)??e.apiKey;return{kind:"http",protocol:"openai-compatible",server:n(t,{bearerToken:c}),host:a,port:i,...c?{bearerToken:c}:{}}}function langGraphServer(t){const r=configString(t.host)??s,e=configNumber(t.port)??2024,n=function configStringArray(t){if(Array.isArray(t)&&t.every(t=>"string"==typeof t))return t.filter(t=>t.trim()).map(t=>t.trim())}(t.exposeAgents);return{kind:"langgraph",protocol:"langgraph-compatible",config:{host:r,port:e,nWorkers:configNumber(t.nWorkers)??10,...n?{exposeAgents:n}:{},...void 0!==t.env?{env:t.env}:{},...void 0!==t.envFile?{envFile:t.envFile}:{}}}}function protocolConfig(t,...r){for(const e of r){const r=readRecord(t[e]);if(r)return r}}function enabled(t){return!1!==t.enabled}function configString(t){if("string"!=typeof t||!t.trim())return;const r=t.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]:t}function configNumber(t){return"number"==typeof t&&Number.isFinite(t)?t:"string"==typeof t&&t.trim()?Number(t):void 0}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}async function listen(t){try{return await new Promise((r,e)=>{t.server.once("error",e),t.server.listen(t.port,t.host,()=>{t.server.off("error",e),r()})}),!0}catch(r){if(isAddressInUse(r)&&await async function isHttpServerAlreadyRunning(t){return"stable-runtime"===t.protocol?await async function isStableRuntimeServerAlreadyRunning(t){const r=await fetchJson(`http://${t.host}:${t.port}/inspect`);return Array.isArray(r?.agents)&&Array.isArray(r?.runs)}(t):await async function isOpenAiServerAlreadyRunning(t){const r=await fetchJson(`http://${t.host}:${t.port}/v1/capabilities`,{...t.bearerToken?{authorization:`Bearer ${t.bearerToken}`}:{}});return"stable_harness.capabilities"===r?.object}(t)}(t))return!1;throw portConflictError(r,t.protocol,t.host,t.port)}}async function startLangGraphServer(t,r){if(!await isLangGraphServerAlreadyRunning(r))try{return await o(t,r.config)}catch(t){if(isAddressInUse(t)&&await isLangGraphServerAlreadyRunning(r))return;throw portConflictError(t,r.protocol,r.config.host,r.config.port)}}function serverUrl(t){const r=`http://${t.host}:${t.port}`;return"openai-compatible"===t.protocol?`${r}/v1`:r}async function isLangGraphServerAlreadyRunning(t){const r=await fetchJson(`http://${t.config.host}:${t.config.port}/ok`);return!0===r?.ok}async function fetchJson(t,r={}){try{const e=await fetch(t,{headers:r});if(!e.ok)return;return await e.json()}catch{return}}function isAddressInUse(t){return"EADDRINUSE"===function readErrorCode(t){return"object"==typeof t&&null!==t&&"code"in t?t.code:void 0}(t)||String(t).includes("EADDRINUSE")}function portConflictError(t,r,e,n){return isAddressInUse(t)?new Error([`stable-harness ${r} port is already in use: ${e}:${n}.`,`Use --port <port>, update config/runtime/workspace.yaml, or stop the process currently listening on ${e}:${n}.`].join("\n")):t}async function stableHarnessListenerPids(t){const r=await async function listenerPids(t){try{const{stdout:r}=await i("lsof",[`-tiTCP:${t}`,"-sTCP:LISTEN"]);return r.split(/\s+/u).map(t=>Number(t)).filter(t=>Number.isInteger(t)&&t>0)}catch{return[]}}(t);return(await Promise.all(r.map(async t=>{const r=await async function processCommand(t){try{const{stdout:r}=await i("ps",["-p",String(t),"-o","command="]);return r.trim()}catch{return""}}(t);return isStableHarnessStartCommand(r)?t:void 0}))).filter(t=>"number"==typeof t)}export function isStableHarnessStartCommand(t){if(function hasUnsafeCommandCharacters(t){return/[\u0000-\u001F\u007F;|`&<>]/u.test(t)}(t))return!1;const r=function splitCommandLine(t){const r=[];let e,n="";for(const o of t)'"'!==o&&"'"!==o||void 0!==e?o!==e?/\s/u.test(o)&&void 0===e?n&&(r.push(n),n=""):n+=o:e=void 0:e=o;return n&&r.push(n),r}(t),e=function stableHarnessCommandIndex(t){return isStableHarnessExecutableToken(t[0]??"")?0:function isNodeExecutableToken(t){const r=t.split(/[\\/]/u).at(-1);return"node"===r||"nodejs"===r}(t[0]??"")&&(isStableHarnessExecutableToken(t[1]??"")||function isStableHarnessScriptToken(t){if(hasTraversalSegment(t))return!1;const r=t.replaceAll("\\","/");return r.includes("/stable-harness/")&&r.endsWith("/packages/cli/dist/src/cli.js")}(t[1]??""))?1:-1}(r);return e>=0&&r.slice(e+1).includes("start")}function isStableHarnessExecutableToken(t){if(hasTraversalSegment(t))return!1;const r=t.split(/[\\/]/u).at(-1);return"stable-harness"===r||"botbotgo"===r}function hasTraversalSegment(t){return t.split(/[\\/]/u).some(t=>"."===t||".."===t)}async function closeHttpServer(t){await new Promise((r,e)=>{t.close(t=>{t?e(t):r()})})}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/cli",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -14,12 +14,12 @@
14
14
  "types": "dist/src/index.d.ts",
15
15
  "peerDependencies": {
16
16
  "@langchain/langgraph-api": "^1.2.1",
17
- "@stable-harness/adapter-deepagents": "0.0.94",
18
- "@stable-harness/adapter-langgraph": "0.0.94",
19
- "@stable-harness/core": "0.0.94",
20
- "@stable-harness/memory": "0.0.94",
21
- "@stable-harness/protocols": "0.0.94",
22
- "@stable-harness/tool-gateway": "0.0.94",
23
- "@stable-harness/workspace-yaml": "0.0.94"
17
+ "@stable-harness/adapter-deepagents": "0.0.96",
18
+ "@stable-harness/adapter-langgraph": "0.0.96",
19
+ "@stable-harness/core": "0.0.96",
20
+ "@stable-harness/memory": "0.0.96",
21
+ "@stable-harness/protocols": "0.0.96",
22
+ "@stable-harness/tool-gateway": "0.0.96",
23
+ "@stable-harness/workspace-yaml": "0.0.96"
24
24
  }
25
25
  }
@@ -0,0 +1,12 @@
1
+ import type { RuntimeRequest, RuntimeToolGateway, WorkspaceAgent } from "../types.js";
2
+ import type { CompiledWorkspace } from "../workspace/types.js";
3
+ export type RawArgsRecoveryInput = {
4
+ request: RuntimeRequest;
5
+ output: string;
6
+ agent: WorkspaceAgent;
7
+ workspace: CompiledWorkspace;
8
+ toolGateway?: RuntimeToolGateway;
9
+ policy: unknown;
10
+ };
11
+ export declare function buildRawArgsRecoveryRequest(input: RawArgsRecoveryInput): RuntimeRequest | undefined;
12
+ export declare function hasUniqueRawArgsTool(input: Omit<RawArgsRecoveryInput, "request">): boolean;
@@ -0,0 +1 @@
1
+ export function buildRawArgsRecoveryRequest(e){if(!toolCallRecoveryEnabled(e.policy))return;const t=findUniqueRawArgsTool(e);return t?{...e.request,input:[e.request.input,"","Stable runtime recovery: your previous final answer was a JSON argument object for a declared tool, not the final answer.",`Matched configured tool: ${t.toolId}`,"Continue the same user request by calling that tool through the backend's normal structured tool-calling mechanism with the JSON arguments below.","If the tool call succeeds, synthesize the final user-facing answer from the executed evidence.","Do not print JSON argument objects, raw tool-call markup, plans, or future-intent text as the final answer.","","Previous JSON arguments:",JSON.stringify(t.args)].join("\n"),metadata:{...e.request.metadata,stableHarnessRecovery:"tool_call"}}:void 0}export function hasUniqueRawArgsTool(e){return toolCallRecoveryEnabled(e.policy)&&Boolean(findUniqueRawArgsTool(e))}function findUniqueRawArgsTool(e){const t=function parseStandaloneJsonObject(e){const t=e.trim(),r=t.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/iu)?.[1]?.trim(),o=r??t;if(o.startsWith("{")&&o.endsWith("}")&&!(o.length>6e3))try{const e=JSON.parse(o);return isRecord(e)?e:void 0}catch{return}}(e.output);if(!t)return;const r=e.agent.tools.filter(r=>function schemaMatchesArgs(e,t){if(!isRecord(e)||"object"!==e.type||!isRecord(e.properties))return!1;if(function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}(e.required).some(e=>!(e in t)))return!1;const r=e.properties;return(!1!==e.additionalProperties||!Object.keys(t).some(e=>!(e in r)))&&Object.entries(t).every(([e,t])=>function propertyAcceptsValue(e,t){return!isRecord(e)||"string"!=typeof e.type||("string"===e.type?"string"==typeof t:"number"===e.type?"number"==typeof t:"integer"===e.type?Number.isInteger(t):"boolean"===e.type?"boolean"==typeof t:"array"===e.type?Array.isArray(t):"object"!==e.type||isRecord(t))}(r[e],t))}(e.workspace.tools.get(r)?.schema??e.toolGateway?.get(r)?.schema,t));return 1===r.length?{toolId:r[0],args:t}:void 0}function toolCallRecoveryEnabled(e){return!!(isRecord(e)&&isRecord(e.recovery)&&isRecord(e.recovery.toolCall))&&!0===e.recovery.toolCall.enabled}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1,4 +1,4 @@
1
- import type { RuntimeEvent, RuntimeOutput, RuntimeRequest, RuntimeStore, WorkspaceAgent } from "../../types.js";
1
+ import type { CompiledWorkspace, RuntimeEvent, RuntimeOutput, RuntimeRequest, RuntimeStore, RuntimeToolGateway, WorkspaceAgent } from "../../types.js";
2
2
  export declare function recoverAdapterResultOutput(input: {
3
3
  request: RuntimeRequest;
4
4
  result: RuntimeOutput;
@@ -8,5 +8,7 @@ export declare function recoverAdapterResultOutput(input: {
8
8
  requestId: string;
9
9
  sessionId: string;
10
10
  agent: WorkspaceAgent;
11
+ workspace: CompiledWorkspace;
12
+ toolGateway?: RuntimeToolGateway;
11
13
  runAdapter: (request: RuntimeRequest) => Promise<RuntimeOutput>;
12
14
  }): Promise<RuntimeOutput>;
@@ -1 +1 @@
1
- import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{assertNoProgressOnlyToolIntentOutput as t,assertNoRawToolCallOutput as o,assertNoRawToolResultOutput as r,assertNoToolExecutionErrorOutput as a,buildEvidenceSynthesisOutput as s,buildResultRecoveryRequest as l,containsRawToolCallOutput as i,rawToolCallFailureMessage as u,rawToolCallOutputPreview as n,toolCallRecoveryEnabled as c}from"../../recovery/tool-call.js";export async function recoverAdapterResultOutput(n){let p=n.result,d=n.request;const y=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(n.recoveryPolicy);for(let e=0;e<y;e+=1){const t=n.store.getRun(n.requestId)?.events??[],o=l({request:d,output:p.text,events:t,availableToolIds:n.agent.tools,policy:n.recoveryPolicy});if(!o)break;d=o,emitRepair(n,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(p.text,n.agent.tools)),p=await n.runAdapter(o),emitRepair(n,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(p.text,n.agent.tools))}return function finalizeRecoveredOutput(l,n){if(!c(l.recoveryPolicy))return n;let p=!1;if(i(n.text,l.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(l.request.metadata)){const e=n.text;n={...n,text:u(),metadata:{...n.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(l,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,l.agent.tools))}const d=s({request:l.request,output:n.text,events:l.store.getRun(l.requestId)?.events??[],policy:l.recoveryPolicy});return d&&(p=!0,n={...n,text:d,metadata:{...n.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(l,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),p||(i(n.text,l.recoveryPolicy)&&emitRepair(l,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(n.text,l.agent.tools)),o(n.text,l.recoveryPolicy),t(n.text,l.agent.tools,l.recoveryPolicy),r(n.text,l.store.getRun(l.requestId)?.events??[],l.recoveryPolicy),a(n.text,l.recoveryPolicy),e({output:n.text,events:l.store.getRun(l.requestId)?.events??[],availableToolIds:l.agent.tools})),n}(n,p)}function emitRepair(e,t,o,r,a,s,l){const i={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...l?{diagnostics:l}:{}};e.emit("runtime.repair.started"===t?{type:t,...i}:{type:t,...i,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:n(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])new RegExp(`(?:^|[^A-Za-z0-9_-])${escapeRegexp(r)}(?:$|[^A-Za-z0-9_-])`,"u").test(e)&&o.add(r);return[...o]}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}
1
+ import{assertNoDeclaredActionOmissionOutput as e}from"../../recovery/control-omission.js";import{buildRawArgsRecoveryRequest as t,hasUniqueRawArgsTool as o}from"../../recovery/raw-args.js";import{assertNoProgressOnlyToolIntentOutput as r,assertNoRawToolCallOutput as a,assertNoRawToolResultOutput as s,assertNoToolExecutionErrorOutput as l,buildEvidenceSynthesisOutput as i,buildResultRecoveryRequest as u,containsRawToolCallOutput as n,rawToolCallFailureMessage as c,rawToolCallOutputPreview as p,toolCallRecoveryEnabled as y}from"../../recovery/tool-call.js";export async function recoverAdapterResultOutput(d){let v=d.result,m=d.request;const g=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,o="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,r="object"!=typeof o||null===o||Array.isArray(o)?void 0:o.maxResultRecoveryAttempts;return"number"==typeof r&&Number.isInteger(r)&&r>0?r:3}(d.recoveryPolicy);let R=!1;for(let e=0;;e+=1){const o=d.store.getRun(d.requestId)?.events??[],r=R?void 0:t({request:m,output:v.text,agent:d.agent,workspace:d.workspace,toolGateway:d.toolGateway,policy:d.recoveryPolicy}),a=e<g?u({request:m,output:v.text,events:o,availableToolIds:d.agent.tools,policy:d.recoveryPolicy}):void 0,s=r??a;if(!s)break;s===r&&(R=!0),m=s,emitRepair(d,"runtime.repair.started","result_output",e+1,"recoverable_result_output",void 0,repairDiagnostics(v.text,d.agent.tools)),v=await d.runAdapter(s),emitRepair(d,"runtime.repair.completed","result_output",e+1,"recoverable_result_output","retried",repairDiagnostics(v.text,d.agent.tools))}return function finalizeRecoveredOutput(t,u){if(!y(t.recoveryPolicy))return u;let d=!1;if(n(u.text,t.recoveryPolicy)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(t.request.metadata)){const e=u.text;u={...u,text:c(),metadata:{...u.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}},emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(e,t.agent.tools))}const v=i({request:t.request,output:u.text,events:t.store.getRun(t.requestId)?.events??[],policy:t.recoveryPolicy});return v&&(d=!0,u={...u,text:v,metadata:{...u.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}},emitRepair(t,"runtime.repair.completed","evidence_synthesis",void 0,"raw_tool_call_output_with_evidence","synthesized")),d||(n(u.text,t.recoveryPolicy)&&emitRepair(t,"runtime.repair.completed","result_output",void 0,"raw_tool_call_output","blocked",repairDiagnostics(u.text,t.agent.tools)),a(u.text,t.recoveryPolicy),function assertNoRawArgsToolOutput(e,t){if(o({output:t,agent:e.agent,workspace:e.workspace,toolGateway:e.toolGateway,policy:e.recoveryPolicy}))throw new Error(`Adapter returned raw tool argument JSON as the final answer after recovery. The backend must execute the matching tool instead. Output preview: ${p(t)}`)}(t,u.text),r(u.text,t.agent.tools,t.recoveryPolicy),s(u.text,t.store.getRun(t.requestId)?.events??[],t.recoveryPolicy),l(u.text,t.recoveryPolicy),e({output:u.text,events:t.store.getRun(t.requestId)?.events??[],availableToolIds:t.agent.tools})),u}(d,v)}function emitRepair(e,t,o,r,a,s,l){const i={requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:o,attempt:r,reason:a,...l?{diagnostics:l}:{}};e.emit("runtime.repair.started"===t?{type:t,...i}:{type:t,...i,outcome:s??"retried"})}function repairDiagnostics(e,t){return{outputPreview:p(e),toolCandidateIds:visibleToolCandidates(e,t)}}function visibleToolCandidates(e,t){const o=new Set;for(const r of t??[])new RegExp(`(?:^|[^A-Za-z0-9_-])${escapeRegexp(r)}(?:$|[^A-Za-z0-9_-])`,"u").test(e)&&o.add(r);return[...o]}function escapeRegexp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildAdapterErrorRecoveryPrompt as r,buildExecutionContractRecoveryRequest as a,isRecoverableAdapterError as s}from"./recovery/tool-call.js";import{recoverQualityReview as n,resolveQualityPolicy as o}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as d}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as m}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as w}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as g,normalizeAdapterResult as y}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as f}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as I}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as q}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as R}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as v}from"./runtime/progress-narration.js";import{repairRuntimeSelection as k}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as b}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as A}from"./runtime/tool-failure.js";import{runWorkflowRequest as C}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const y=new Set,x=t.store??R(),j=g([f(t),v({options:t.progressNarration,policy:t.workspace.runtime}),b({policy:t.workspace.runtime,store:x,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);x.appendEvent(r);for(const e of y)e(r)},emit=e=>{emitBase(e),j.emitSideEffects(e,emitBase)},E=l({gateway:m({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),h={...t,toolGateway:E},S=A(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),m=t.request.sessionId??e(),l=[],{agent:w,adapter:g}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await k({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,s=e.workspace.agents.get(a);if(!s)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:s,adapter:void 0};const n=e.adapters.find(e=>e.canRun(s));if(!n)throw new Error(`No runtime adapter can run backend ${s.backend} for agent ${s.id}`);return{agent:s,adapter:n}}(t.input,t.request,{requestId:p,sessionId:m,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,m,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:m,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await C({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:m,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await d({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:m,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,d=c.pluginMemories??[],m=I({workspace:e.input.workspace,agent:e.agent}),l=o(e.input.workspace.runtime,e.agent),w=new Map;let g;try{g=await runAdapterOnce(e,t,e.request,p,d,w,m)}catch(a){if(!s(a,m))throw a;e.emit(repairStarted(e,"adapter_error",1,errorMessage(a))),g=await runAdapterOnce(e,t,r(e.request,a,m),p,d,w,m),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(a)))}g=await i({...e,request:e.request,result:g,recoveryPolicy:m,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),g=await n(createQualityRuntimeInput(e,p,d,w,m),e.request,g,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:g});try{assertRequestExecutionContract(e)}catch(r){const s=a({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:m});if(!s)throw r;e.emit(repairStarted(e,"execution_contract",1,errorMessage(r))),g=await runAdapterOnce(e,t,s,p,d,w,m),g=await i({...e,request:s,result:g,recoveryPolicy:m,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),g=await n(createQualityRuntimeInput(e,p,d,w,m),s,g,l),assertRequestExecutionContract(e),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(r)))}const y=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:g,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:g,response:y}),y}({...t,adapter:g,requestId:p,sessionId:m,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,error:e})}}({input:h,capabilities:j,store:x,emit:emit,request:t,toolFailureTracker:S}),subscribe:e=>(y.add(e),()=>y.delete(e)),...w({workspace:t.workspace,store:x,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:x,emit:emit}),...q({memory:t.memory}),cancel(e,t){const r=x.getRun(e);r&&"running"===r.state&&(x.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await j.stop(),y.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:n=>runAdapterOnce(e,e.adapter,n,t,r,a,s),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,s,n,o){return y(await t.run({workspace:{...e.input.workspace,runtime:o},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:s,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:n,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,s){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:s}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
1
+ import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{buildAdapterErrorRecoveryPrompt as r,buildExecutionContractRecoveryRequest as a,isRecoverableAdapterError as s}from"./recovery/tool-call.js";import{recoverQualityReview as o,resolveQualityPolicy as n}from"./quality/index.js";import{recoverAdapterResultOutput as i}from"./runtime/recovery/adapter-result.js";import{completeRun as u,failRun as c}from"./runtime/completion.js";import{createRuntimeAdministrationMethods as p}from"./runtime/admin/administration.js";import{runDirectToolCall as d}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as m}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as l}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as w}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as y,normalizeAdapterResult as g}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as f}from"./runtime/memory.js";import{resolveToolCallRecoveryPolicy as I}from"./runtime/recovery/tool-call-policy.js";import{createRuntimeMemoryAdministration as q}from"./runtime/admin/memory.js";import{createInMemoryRuntimeStore as R}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as v}from"./runtime/progress-narration.js";import{repairRuntimeSelection as k}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as b}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as A}from"./runtime/tool-failure.js";import{runWorkflowRequest as C}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const g=new Set,x=t.store??R(),j=y([f(t),v({options:t.progressNarration,policy:t.workspace.runtime}),b({policy:t.workspace.runtime,store:x,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const r=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);x.appendEvent(r);for(const e of g)e(r)},emit=e=>{emitBase(e),j.emitSideEffects(e,emitBase)},E=l({gateway:m({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),h={...t,toolGateway:E},G=A(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const p=t.request.requestId??e(),m=t.request.sessionId??e(),l=[],{agent:w,adapter:y}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await k({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):e.workspace.runtime.defaultAgentId,s=e.workspace.agents.get(a);if(!s)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:s,adapter:void 0};const o=e.adapters.find(e=>e.canRun(s));if(!o)throw new Error(`No runtime adapter can run backend ${s.backend} for agent ${s.id}`);return{agent:s,adapter:o}}(t.input,t.request,{requestId:p,sessionId:m,emit:e=>l.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,p,m,w)),l.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:p,sessionId:m,agentId:w.id,input:t.request.input});try{if(t.request.workflow){const e=await C({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:p,sessionId:m,agentId:w.id,emit:t.emit});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await d({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:p,sessionId:m,agent:w,toolFailureTracker:t.toolFailureTracker,toolGuardrails:t.input.toolGuardrails,events:t.store.getRun(p)?.events??[]});return u({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,c=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),p=c.memory,d=c.pluginMemories??[],m=I({workspace:e.input.workspace,agent:e.agent}),l=n(e.input.workspace.runtime,e.agent),w=new Map;let y;try{y=await runAdapterOnce(e,t,e.request,p,d,w,m)}catch(a){if(!s(a,m))throw a;e.emit(repairStarted(e,"adapter_error",1,errorMessage(a))),y=await runAdapterOnce(e,t,r(e.request,a,m),p,d,w,m),e.emit(repairCompleted(e,"adapter_error","retried",1,errorMessage(a)))}y=await i({...e,request:e.request,result:y,recoveryPolicy:m,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),y=await o(createQualityRuntimeInput(e,p,d,w,m),e.request,y,l),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:y});try{assertRequestExecutionContract(e)}catch(r){const s=a({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:m});if(!s)throw r;e.emit(repairStarted(e,"execution_contract",1,errorMessage(r))),y=await runAdapterOnce(e,t,s,p,d,w,m),y=await i({...e,request:s,result:y,recoveryPolicy:m,workspace:e.input.workspace,toolGateway:e.input.toolGateway,runAdapter:r=>runAdapterOnce(e,t,r,p,d,w,m)}),y=await o(createQualityRuntimeInput(e,p,d,w,m),s,y,l),assertRequestExecutionContract(e),e.emit(repairCompleted(e,"execution_contract","retried",1,errorMessage(r)))}const g=u({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:y,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:y,response:g}),g}({...t,adapter:y,requestId:p,sessionId:m,agent:w})}catch(e){return c({store:t.store,emit:t.emit,requestId:p,sessionId:m,agent:w,error:e})}}({input:h,capabilities:j,store:x,emit:emit,request:t,toolFailureTracker:G}),subscribe:e=>(g.add(e),()=>g.delete(e)),...w({workspace:t.workspace,store:x,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),...p({store:x,emit:emit}),...q({memory:t.memory}),cancel(e,t){const r=x.getRun(e);r&&"running"===r.state&&(x.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await j.stop(),g.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a,s){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,a,s),reviewModel:e.input.qualityReviewModel,executionEvaluatorRules:e.input.executionEvaluatorRules,memory:t,pluginMemories:r}}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,s,o,n){return g(await t.run({workspace:{...e.input.workspace,runtime:n},agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:s,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,toolGuardrails:e.input.toolGuardrails,executionEvaluatorRules:e.input.executionEvaluatorRules,requestState:o,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function repairStarted(e,t,r,a){return{type:"runtime.repair.started",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,attempt:r,reason:a}}function repairCompleted(e,t,r,a,s){return{type:"runtime.repair.completed",requestId:e.requestId,sessionId:e.sessionId,agentId:e.agent.id,layer:t,outcome:r,attempt:a,reason:s}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/core",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,7 +11,7 @@
11
11
  ".": "./dist/index.js"
12
12
  },
13
13
  "peerDependencies": {
14
- "@stable-harness/governance": "0.0.94",
15
- "@stable-harness/memory": "0.0.94"
14
+ "@stable-harness/governance": "0.0.96",
15
+ "@stable-harness/memory": "0.0.96"
16
16
  }
17
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/evaluation",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -10,6 +10,6 @@
10
10
  "main": "dist/src/index.js",
11
11
  "types": "dist/src/index.d.ts",
12
12
  "peerDependencies": {
13
- "@stable-harness/core": "0.0.94"
13
+ "@stable-harness/core": "0.0.96"
14
14
  }
15
15
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/governance",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/memory",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/protocols",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -10,6 +10,6 @@
10
10
  "main": "dist/src/index.js",
11
11
  "types": "dist/src/index.d.ts",
12
12
  "peerDependencies": {
13
- "@stable-harness/core": "0.0.94"
13
+ "@stable-harness/core": "0.0.96"
14
14
  }
15
15
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/tool-gateway",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stable-harness/workspace-yaml",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*.js",
@@ -11,6 +11,6 @@
11
11
  ".": "./dist/index.js"
12
12
  },
13
13
  "peerDependencies": {
14
- "@stable-harness/core": "0.0.94"
14
+ "@stable-harness/core": "0.0.96"
15
15
  }
16
16
  }