stable-harness 0.0.95 → 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.
- package/README.md +4 -2
- package/docs/guides/integration-guide.md +13 -3
- package/docs/protocols/http-runtime.md +19 -0
- package/docs/protocols/langgraph-compatible.md +7 -1
- package/node_modules/@stable-harness/adapter-deepagents/package.json +2 -2
- package/node_modules/@stable-harness/adapter-langgraph/package.json +2 -2
- package/node_modules/@stable-harness/core/package.json +3 -3
- package/node_modules/@stable-harness/governance/package.json +1 -1
- package/node_modules/@stable-harness/memory/package.json +1 -1
- package/node_modules/@stable-harness/protocols/package.json +2 -2
- package/node_modules/@stable-harness/tool-gateway/package.json +1 -1
- package/node_modules/@stable-harness/workspace-yaml/package.json +2 -2
- package/package.json +9 -9
- package/packages/adapter-deepagents/package.json +2 -2
- package/packages/adapter-langgraph/package.json +2 -2
- package/packages/cli/dist/src/cli.js +1 -1
- package/packages/cli/dist/src/daemon/client.d.ts +8 -0
- package/packages/cli/dist/src/daemon/client.js +1 -0
- package/packages/cli/dist/src/server.js +1 -1
- package/packages/cli/package.json +8 -8
- package/packages/core/package.json +3 -3
- package/packages/evaluation/package.json +2 -2
- package/packages/governance/package.json +1 -1
- package/packages/memory/package.json +1 -1
- package/packages/protocols/package.json +2 -2
- package/packages/tool-gateway/package.json +1 -1
- 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
|
|
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
|
|
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.
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
14
|
+
"@stable-harness/core": "0.0.96"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
15
|
-
"@stable-harness/memory": "0.0.
|
|
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/protocols",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
13
|
+
"@stable-harness/core": "0.0.96"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/workspace-yaml",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
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.
|
|
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.
|
|
86
|
-
"@stable-harness/adapter-langgraph": "0.0.
|
|
87
|
-
"@stable-harness/core": "0.0.
|
|
88
|
-
"@stable-harness/governance": "0.0.
|
|
89
|
-
"@stable-harness/memory": "0.0.
|
|
90
|
-
"@stable-harness/protocols": "0.0.
|
|
91
|
-
"@stable-harness/tool-gateway": "0.0.
|
|
92
|
-
"@stable-harness/workspace-yaml": "0.0.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
18
|
-
"@stable-harness/adapter-langgraph": "0.0.
|
|
19
|
-
"@stable-harness/core": "0.0.
|
|
20
|
-
"@stable-harness/memory": "0.0.
|
|
21
|
-
"@stable-harness/protocols": "0.0.
|
|
22
|
-
"@stable-harness/tool-gateway": "0.0.
|
|
23
|
-
"@stable-harness/workspace-yaml": "0.0.
|
|
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
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
15
|
-
"@stable-harness/memory": "0.0.
|
|
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.
|
|
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.
|
|
13
|
+
"@stable-harness/core": "0.0.96"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/protocols",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
13
|
+
"@stable-harness/core": "0.0.96"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/workspace-yaml",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
14
|
+
"@stable-harness/core": "0.0.96"
|
|
15
15
|
}
|
|
16
16
|
}
|