stable-harness 0.0.101 → 0.0.103
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 -0
- package/docs/guides/index.md +1 -0
- package/docs/guides/integration-guide.md +27 -5
- package/docs/protocols/agent-protocols.md +73 -0
- package/docs/protocols/http-runtime.md +3 -3
- 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/dist/src/agent-protocols.d.ts +7 -0
- package/node_modules/@stable-harness/protocols/dist/src/agent-protocols.js +1 -0
- package/node_modules/@stable-harness/protocols/dist/src/index.d.ts +2 -0
- package/node_modules/@stable-harness/protocols/dist/src/index.js +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/console/session.js +1 -1
- 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/dist/src/agent-protocols.d.ts +7 -0
- package/packages/protocols/dist/src/agent-protocols.js +1 -0
- package/packages/protocols/dist/src/index.d.ts +2 -0
- package/packages/protocols/dist/src/index.js +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
|
@@ -97,6 +97,9 @@ http://127.0.0.1:8641
|
|
|
97
97
|
http://127.0.0.1:8642/v1
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
ACP, A2A, and AG-UI facades are available when enabled in runtime YAML through
|
|
101
|
+
the combined `agentProtocols` server.
|
|
102
|
+
|
|
100
103
|
For request commands, the CLI is daemon-first. It prints whether it connected to
|
|
101
104
|
the workspace daemon or fell back to an in-process local runtime.
|
|
102
105
|
Console mode uses the same daemon-first behavior and keeps slash commands such
|
|
@@ -236,6 +239,7 @@ This is constrained repair, not silent magic:
|
|
|
236
239
|
- Stable Runtime HTTP + SSE: [docs/protocols/http-runtime.md](docs/protocols/http-runtime.md)
|
|
237
240
|
- OpenAI-compatible facade: [docs/protocols/openai-compatible.md](docs/protocols/openai-compatible.md)
|
|
238
241
|
- LangGraph-compatible facade: [docs/protocols/langgraph-compatible.md](docs/protocols/langgraph-compatible.md)
|
|
242
|
+
- ACP, A2A, and AG-UI facades: [docs/protocols/agent-protocols.md](docs/protocols/agent-protocols.md)
|
|
239
243
|
|
|
240
244
|
## Documentation
|
|
241
245
|
|
package/docs/guides/index.md
CHANGED
|
@@ -40,6 +40,7 @@ embed it, operate it, or explain why it exists.
|
|
|
40
40
|
- [OpenAI-compatible protocol](../protocols/openai-compatible.md)
|
|
41
41
|
- [LangGraph-compatible protocol](../protocols/langgraph-compatible.md)
|
|
42
42
|
- [HTTP runtime protocol](../protocols/http-runtime.md)
|
|
43
|
+
- [ACP, A2A, and AG-UI protocol facades](../protocols/agent-protocols.md)
|
|
43
44
|
|
|
44
45
|
The short version: keep execution semantics upstream-native, define product
|
|
45
46
|
inventory in YAML, and use Stable Harness for lifecycle, governance,
|
|
@@ -105,8 +105,9 @@ stable-harness start -w ./workspace --host 127.0.0.1 --port 8642
|
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
`stable-harness start` exposes the first-party Stable Runtime control plane,
|
|
108
|
-
the OpenAI-compatible facade,
|
|
109
|
-
by runtime config. Point first-party clients
|
|
108
|
+
the OpenAI-compatible facade, the LangGraph-compatible server, and optional
|
|
109
|
+
ACP/A2A/AG-UI facades when enabled by runtime config. Point first-party clients
|
|
110
|
+
at:
|
|
110
111
|
|
|
111
112
|
```text
|
|
112
113
|
http://127.0.0.1:8641
|
|
@@ -130,12 +131,33 @@ artifacts, memory lifecycle, runtime inspection, and real-time control-plane
|
|
|
130
131
|
updates.
|
|
131
132
|
|
|
132
133
|
This is the first-party protocol for Studio and product shells. OpenAI
|
|
133
|
-
compatible `/v1
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
compatible `/v1`, LangGraph-compatible, ACP, A2A, and AG-UI servers are
|
|
135
|
+
ecosystem facades that map to this protocol instead of adding new runtime
|
|
136
|
+
semantics.
|
|
136
137
|
|
|
137
138
|
See [Stable Runtime HTTP + SSE](../protocols/http-runtime.md).
|
|
138
139
|
|
|
140
|
+
## ACP, A2A, and AG-UI Facades
|
|
141
|
+
|
|
142
|
+
Enable the combined agent protocol server when an external client already
|
|
143
|
+
speaks one of these protocols:
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
apiVersion: stable-harness.dev/v1
|
|
147
|
+
kind: Runtime
|
|
148
|
+
spec:
|
|
149
|
+
protocols:
|
|
150
|
+
agentProtocols:
|
|
151
|
+
enabled: true
|
|
152
|
+
host: 127.0.0.1
|
|
153
|
+
port: 8650
|
|
154
|
+
protocols: [acp, a2a, agui]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The server exposes A2A over HTTP+JSON/SSE, AG-UI over HTTP+SSE, and ACP over a
|
|
158
|
+
documented HTTP JSON-RPC custom transport. See
|
|
159
|
+
[ACP, A2A, and AG-UI Protocol Facades](../protocols/agent-protocols.md).
|
|
160
|
+
|
|
139
161
|
## Backend Adapters
|
|
140
162
|
|
|
141
163
|
Adapters translate Stable Harness runtime requests into upstream backend calls.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ACP, A2A, and AG-UI Protocol Facades
|
|
2
|
+
|
|
3
|
+
Stable Harness exposes ACP, A2A, and AG-UI as protocol adapters over the native
|
|
4
|
+
Stable Runtime request, event, and inspection surfaces. These adapters must not
|
|
5
|
+
add routing heuristics, backend execution semantics, or workspace-specific
|
|
6
|
+
behavior.
|
|
7
|
+
|
|
8
|
+
Enable the combined protocol server from runtime YAML:
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
apiVersion: stable-harness.dev/v1
|
|
12
|
+
kind: Runtime
|
|
13
|
+
spec:
|
|
14
|
+
protocols:
|
|
15
|
+
agentProtocols:
|
|
16
|
+
enabled: true
|
|
17
|
+
host: 127.0.0.1
|
|
18
|
+
port: 8650
|
|
19
|
+
protocols: [acp, a2a, agui]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can also enable a single protocol by configuring one of `acp`, `a2a`, or
|
|
23
|
+
`agui` with `enabled: true`. The CLI starts one combined HTTP server for the
|
|
24
|
+
enabled adapter set.
|
|
25
|
+
|
|
26
|
+
## A2A
|
|
27
|
+
|
|
28
|
+
A2A is exposed as an HTTP+JSON and SSE facade:
|
|
29
|
+
|
|
30
|
+
- `GET /.well-known/agent-card.json`
|
|
31
|
+
- `GET /a2a/agent-card.json`
|
|
32
|
+
- `POST /a2a/message:send`
|
|
33
|
+
- `POST /a2a/message:stream`
|
|
34
|
+
- `POST /a2a/rpc`
|
|
35
|
+
- `GET /a2a/tasks`
|
|
36
|
+
- `GET /a2a/tasks/:id`
|
|
37
|
+
- `POST /a2a/tasks/:id:cancel`
|
|
38
|
+
|
|
39
|
+
`message:send` and JSON-RPC `SendMessage` map to a native `RuntimeRequest`.
|
|
40
|
+
Streaming responses subscribe to native runtime events and project them as A2A
|
|
41
|
+
status updates.
|
|
42
|
+
|
|
43
|
+
## AG-UI
|
|
44
|
+
|
|
45
|
+
AG-UI is exposed as an HTTP+SSE event stream:
|
|
46
|
+
|
|
47
|
+
- `GET /ag-ui/capabilities`
|
|
48
|
+
- `POST /ag-ui/runs`
|
|
49
|
+
|
|
50
|
+
`POST /ag-ui/runs` emits `RunStarted`, protocol `Custom` events for Stable
|
|
51
|
+
Runtime events, `TextMessageChunk` for final assistant output, and `RunFinished`
|
|
52
|
+
or `RunError`.
|
|
53
|
+
|
|
54
|
+
## ACP
|
|
55
|
+
|
|
56
|
+
ACP's standard transport is JSON-RPC over stdio. Stable Harness currently
|
|
57
|
+
exposes ACP over an HTTP JSON-RPC endpoint as a documented custom transport:
|
|
58
|
+
|
|
59
|
+
- `GET /acp/capabilities`
|
|
60
|
+
- `POST /acp`
|
|
61
|
+
|
|
62
|
+
Supported methods:
|
|
63
|
+
|
|
64
|
+
- `initialize`
|
|
65
|
+
- `session/new`
|
|
66
|
+
- `session/load`
|
|
67
|
+
- `session/list`
|
|
68
|
+
- `session/prompt`
|
|
69
|
+
- `session/cancel`
|
|
70
|
+
|
|
71
|
+
`session/prompt` maps to a native `RuntimeRequest` and returns the ACP stop
|
|
72
|
+
reason plus Stable Harness request metadata. A future stdio entrypoint can reuse
|
|
73
|
+
the same JSON-RPC method handler without changing runtime semantics.
|
|
@@ -4,9 +4,9 @@ The native Stable Runtime protocol is the product control-plane contract. It is
|
|
|
4
4
|
the source of truth for first-party clients such as Studio, operator dashboards,
|
|
5
5
|
and embedded product shells.
|
|
6
6
|
|
|
7
|
-
OpenAI-compatible `/v1
|
|
8
|
-
facades.
|
|
9
|
-
|
|
7
|
+
OpenAI-compatible `/v1`, LangGraph-compatible, ACP, A2A, and AG-UI servers are
|
|
8
|
+
ecosystem facades. They adapt external protocols to this contract rather than
|
|
9
|
+
adding new runtime semantics.
|
|
10
10
|
|
|
11
11
|
## HTTP Commands And Queries
|
|
12
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/adapter-deepagents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103",
|
|
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.103",
|
|
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.103"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103",
|
|
15
|
+
"@stable-harness/memory": "0.0.103"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
2
|
+
import type { StableHarnessRuntime } from "@stable-harness/core";
|
|
3
|
+
export type AgentProtocolServerOptions = {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
enabledProtocols?: Array<"acp" | "a2a" | "agui">;
|
|
6
|
+
};
|
|
7
|
+
export declare function createAgentProtocolHttpServer(runtime: StableHarnessRuntime, options?: AgentProtocolServerOptions): import("node:http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createServer as e}from"node:http";export function createAgentProtocolHttpServer(t,s={}){const a=new Set(s.enabledProtocols??["acp","a2a","agui"]);return e(async(e,n)=>{try{if("GET"===e.method&&"/health"===e.url)return void sendJson(n,200,{ok:!0,protocols:[...a]});if(a.has("a2a")&&await async function handleA2a(e,t,s,a){if("GET"===t.method&&("/.well-known/agent-card.json"===t.url||"/a2a/agent-card.json"===t.url))return sendJson(s,200,function createAgentCard(e,t){const s=e.inspect();return{protocolVersion:"1.0",name:s.workspaceRoot.split(/[\\/]/u).filter(Boolean).at(-1)??"stable-harness",description:"Stable Harness runtime agent endpoint",version:"0.0.0",url:t.baseUrl?`${t.baseUrl.replace(/\/$/u,"")}/a2a`:"/a2a",preferredTransport:"HTTP+JSON",capabilities:{streaming:!0},defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],skills:s.agents.map(e=>({id:e,name:e,description:e}))}}(e,a)),!0;const n=matchPath(t.url,/^\/a2a\/tasks\/([^/]+)$/u);if("GET"===t.method&&n){const t=e.inspectRequest(n);return sendJson(s,t?200:404,t?{task:toA2aTask(t)}:{error:"task_not_found"}),!0}if("GET"===t.method&&"/a2a/tasks"===t.url)return sendJson(s,200,{tasks:e.listRequests().map(toA2aTaskSummary)}),!0;const r=matchPath(t.url,/^\/a2a\/tasks\/([^/]+):cancel$/u);return"POST"===t.method&&r?(e.cancel(r,"a2a_cancel"),sendJson(s,200,{task:e.inspectRequest(r)}),!0):"POST"===t.method&&"/a2a/message:send"===t.url?(sendJson(s,200,{task:toA2aTask(await e.request(toA2aRuntimeRequest(await readJson(t))))}),!0):"POST"===t.method&&"/a2a/message:stream"===t.url?(await streamA2a(e,await readJson(t),s),!0):"POST"===t.method&&"/a2a/rpc"===t.url&&(await async function handleA2aRpc(e,t,s){if("SendMessage"===t.method){const a=await e.request(toA2aRuntimeRequest(readRecord(t.params)??{}));return void sendJson(s,200,jsonRpcResult(t.id,{task:toA2aTask(a)}))}if("SendStreamingMessage"!==t.method){if("GetTask"===t.method){const a=readString(readRecord(t.params)?.id),n=a?e.inspectRequest(a):void 0;return void sendJson(s,n?200:404,n?jsonRpcResult(t.id,toA2aTask(n)):jsonRpcError(t.id,-32004,"task_not_found"))}"ListTasks"!==t.method?sendJson(s,404,jsonRpcError(t.id,-32601,"method_not_found")):sendJson(s,200,jsonRpcResult(t.id,{tasks:e.listRequests().map(toA2aTaskSummary)}))}else await streamA2a(e,readRecord(t.params)??{},s,t.id)}(e,await readJson(t),s),!0)}(t,e,n,s))return;if(a.has("agui")&&await async function handleAgui(e,t,s){return"GET"===t.method&&"/ag-ui/capabilities"===t.url?(sendJson(s,200,{protocol:"ag-ui",transports:["http+sse"],events:["RunStarted","TextMessageChunk","Custom","RunFinished","RunError"]}),!0):"POST"===t.method&&"/ag-ui/runs"===t.url&&(await async function streamAgui(e,t,s){const a=readString(t.runId)??crypto.randomUUID(),n=readString(t.threadId)??readString(t.sessionId)??`thread-${a}`,r=readPromptText(t);writeSseHeaders(s),writeSse(s,{type:"RunStarted",threadId:n,runId:a,input:{messages:t.messages,input:r}});const o=e.subscribe(e=>{e.requestId===a&&writeSse(s,function toAguiEvent(e){return"runtime.progress.narration"===e.type?{type:"Custom",name:"stable-harness.progress",value:e}:"runtime.tool.direct.started"===e.type?{type:"ToolCallStart",toolCallId:`${e.requestId}:${e.toolId}`,toolCallName:e.toolId}:"runtime.tool.direct.completed"===e.type?{type:"ToolCallResult",messageId:`${e.requestId}-message`,toolCallId:`${e.requestId}:${e.toolId}`,content:e.output,role:"tool"}:{type:"Custom",name:`stable-harness.${e.type}`,value:e}}(e))});try{const o=await e.request({input:r,requestId:a,sessionId:n,agentId:readString(t.agentId),metadata:{protocol:"ag-ui"}}),i=`${a}-message`;o.output&&writeSse(s,{type:"TextMessageChunk",messageId:i,role:"assistant",delta:o.output}),writeSse(s,{type:"RunFinished",threadId:n,runId:a,outcome:{type:"completed"===o.state?"success":"interrupt"},result:o.output})}catch(e){writeSse(s,{type:"RunError",threadId:n,runId:a,message:errorMessage(e)})}finally{o(),s.end()}}(e,await readJson(t),s),!0)}(t,e,n))return;if(a.has("acp")&&await async function handleAcp(e,t,s){if("GET"===t.method&&"/acp/capabilities"===t.url)return sendJson(s,200,{protocolVersion:1,agentCapabilities:{loadSession:!0,promptCapabilities:{embeddedContext:!0},_meta:{transport:"http-jsonrpc"}},agentInfo:{name:"stable-harness",title:"Stable Harness",version:"0.0.0"}}),!0;if("POST"===t.method&&"/acp"===t.url){const a=await readJson(t),n=await async function handleAcpMessage(e,t){if(!t.id&&"session/cancel"===t.method){const s=readString(readRecord(t.params)?.sessionId);return void(s&&e.listRequests({sessionId:s,state:"running"}).forEach(t=>e.cancel(t.requestId,"acp_cancel")))}if("initialize"===t.method)return jsonRpcResult(t.id,{protocolVersion:1,agentCapabilities:{loadSession:!0,promptCapabilities:{embeddedContext:!0},_meta:{transport:"http-jsonrpc"}},agentInfo:{name:"stable-harness",title:"Stable Harness",version:"0.0.0"}});if("session/new"===t.method)return jsonRpcResult(t.id,{sessionId:`acp-${crypto.randomUUID()}`});if("session/load"===t.method)return jsonRpcResult(t.id,{sessionId:readString(readRecord(t.params)?.sessionId)});if("session/list"===t.method)return jsonRpcResult(t.id,{sessions:e.listSessions()});if("session/prompt"===t.method){const s=readRecord(t.params)??{},a=await e.request({input:readPromptText(s),sessionId:readString(s.sessionId),agentId:readString(s.agentId),metadata:{protocol:"acp",transport:"http-jsonrpc"}});return jsonRpcResult(t.id,{stopReason:"completed"===a.state?"end_turn":"refusal",_meta:{requestId:a.requestId,output:a.output}})}return jsonRpcError(t.id,-32601,"method_not_found")}(e,a);return n?sendJson(s,200,n):s.writeHead(204).end(),!0}return!1}(t,e,n))return;sendJson(n,404,{error:"not_found"})}catch(e){sendJson(n,400,{error:errorMessage(e)})}})}async function streamA2a(e,t,s,a){const n=toA2aRuntimeRequest(t);writeSseHeaders(s);const r=e.subscribe(e=>{e.requestId===n.requestId&&writeSse(s,{jsonrpc:"2.0",id:a,result:{event:toA2aEvent(e)}})});try{const t=await e.request(n);writeSse(s,{jsonrpc:"2.0",id:a,result:{task:toA2aTask(t),final:!0}})}finally{r(),s.end()}}function toA2aRuntimeRequest(e){const t=readRecord(e.message)??e;return{input:readPromptText(t),requestId:readString(e.requestId)??readString(t.messageId),sessionId:readString(e.taskId)??readString(t.taskId)??readString(t.contextId),agentId:readString(e.agentId)??readString(e.metadata&&readRecord(e.metadata)?.agentId),metadata:{protocol:"a2a",configuration:e.configuration,metadata:e.metadata}}}function toA2aTask(e){const t="state"in e?e.state:e.summary.state,s="output"in e?e.output:e.output??"",a="requestId"in e?e.requestId:e.summary.requestId;return{id:a,contextId:"sessionId"in e?e.sessionId:e.summary.sessionId,status:{state:"completed"===t?"completed":t,message:s?{role:"agent",messageId:`${a}-response`,parts:[{kind:"text",text:s}]}:void 0}}}function toA2aTaskSummary(e){return{id:e.requestId,contextId:e.sessionId,status:{state:e.state},metadata:{agentId:e.agentId}}}function toA2aEvent(e){return{kind:"status-update",taskId:e.requestId,contextId:e.sessionId,status:{state:e.type},metadata:e}}function readPromptText(e){return"string"==typeof e.input?e.input:"string"==typeof e.text?e.text:"string"==typeof e.prompt?e.prompt:Array.isArray(e.parts)?e.parts.map(readPartText).filter(Boolean).join("\n"):Array.isArray(e.messages)?readPromptText(readRecord(e.messages.at(-1))??{}):Array.isArray(e.content)?e.content.map(readPartText).filter(Boolean).join("\n"):"string"==typeof e.content?e.content:""}function readPartText(e){const t=readRecord(e);return t?readString(t.text)??readString(t.content)??"":"string"==typeof e?e:""}function matchPath(e,t){const s=(e??"").match(t);return s?.[1]?decodeURIComponent(s[1]):void 0}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function jsonRpcResult(e,t){return{jsonrpc:"2.0",id:e,result:t}}function jsonRpcError(e,t,s){return{jsonrpc:"2.0",id:e,error:{code:t,message:s}}}function sendJson(e,t,s){e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(s))}function writeSseHeaders(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function writeSse(e,t){e.write(`data: ${JSON.stringify(t)}\n\n`)}async function readJson(e){const t=[];for await(const s of e)t.push(Buffer.isBuffer(s)?s:Buffer.from(s));return t.length>0?JSON.parse(Buffer.concat(t).toString("utf8")):{}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { createInProcessClient } from "./in-process-client.js";
|
|
2
|
+
export { createAgentProtocolHttpServer } from "./agent-protocols.js";
|
|
3
|
+
export type { AgentProtocolServerOptions } from "./agent-protocols.js";
|
|
2
4
|
export { createHttpServer } from "./http-server.js";
|
|
3
5
|
export { createOpenAiCompatibleHttpServer } from "./openai-compatible.js";
|
|
4
6
|
export type { OpenAiCompatibleServerOptions } from "./openai-compatible.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{createInProcessClient}from"./in-process-client.js";export{createHttpServer}from"./http-server.js";export{createOpenAiCompatibleHttpServer}from"./openai-compatible.js";
|
|
1
|
+
export{createInProcessClient}from"./in-process-client.js";export{createAgentProtocolHttpServer}from"./agent-protocols.js";export{createHttpServer}from"./http-server.js";export{createOpenAiCompatibleHttpServer}from"./openai-compatible.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/protocols",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103"
|
|
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.103",
|
|
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.103"
|
|
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.103",
|
|
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.103",
|
|
86
|
+
"@stable-harness/adapter-langgraph": "0.0.103",
|
|
87
|
+
"@stable-harness/core": "0.0.103",
|
|
88
|
+
"@stable-harness/governance": "0.0.103",
|
|
89
|
+
"@stable-harness/memory": "0.0.103",
|
|
90
|
+
"@stable-harness/protocols": "0.0.103",
|
|
91
|
+
"@stable-harness/tool-gateway": "0.0.103",
|
|
92
|
+
"@stable-harness/workspace-yaml": "0.0.103",
|
|
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.103",
|
|
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.103",
|
|
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.103",
|
|
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.103"
|
|
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 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 l}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as d}from"@stable-harness/workspace-yaml";import{helpText as c,parseArgs as p}from"./args.js";import{buildWorkspaceArtifact as m}from"./build.js";import{runConsole as f}from"./console/session.js";import{formatCliRuntimeEvent as w,readCliEventViewConfig as v,shouldEnableCliProgressNarration as g}from"./event-view.js";import{initWorkspace as y}from"./init.js";import{runRequestThroughDaemon as I}from"./daemon/client.js";import{ensureCliMemoryServices as R}from"./memory/lifecycle.js";import{createCliMemoryProviders as k}from"./memory/providers.js";import{formatDetail as h,inspectWorkflow as b,renderAgent as q,renderWorkflow as A,workspaceStatus as C}from"./output.js";import{serveProtocol as j,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 y(t.prompt||s));const e=await d(s);if(t.workflowRenderId)return void process.stdout.write(A(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(b(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(q(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=v(e.runtime),createRuntime=()=>async function createCliRuntime(e,t,r){const s=await l({tools:e.tools.values(),options:{betterCall:{mode:"repair"}}}),a=u(),n=await async function createCliMemoryProvidersForCommand(e,t){return
|
|
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 l}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as d}from"@stable-harness/workspace-yaml";import{helpText as c,parseArgs as p}from"./args.js";import{buildWorkspaceArtifact as m}from"./build.js";import{runConsole as f}from"./console/session.js";import{formatCliRuntimeEvent as w,readCliEventViewConfig as v,shouldEnableCliProgressNarration as g}from"./event-view.js";import{initWorkspace as y}from"./init.js";import{runRequestThroughDaemon as I}from"./daemon/client.js";import{ensureCliMemoryServices as R}from"./memory/lifecycle.js";import{createCliMemoryProviders as k}from"./memory/providers.js";import{formatDetail as h,inspectWorkflow as b,renderAgent as q,renderWorkflow as A,workspaceStatus as C}from"./output.js";import{serveProtocol as j,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 y(t.prompt||s));const e=await d(s);if(t.workflowRenderId)return void process.stdout.write(A(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(b(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(q(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=v(e.runtime),createRuntime=()=>async function createCliRuntime(e,t,r){const s=await l({tools:e.tools.values(),options:{betterCall:{mode:"repair"}}}),a=u(),n=await async function createCliMemoryProvidersForCommand(e,t){return"console"===t.command||t.serveOpenAi||t.shouldRunRequest&&!t.toolId?(await R(e),k(e)):[]}(e,t);let d;return d=i({workspace:e,toolGateway:s,approvals:a,memoryProviders:n,adapters:[o()],workflowAdapters:[createCliWorkflowAdapter(s,()=>d)],progressNarration:g(r,e.runtime)?{enabled:!0,style:"cli"}:void 0,qualityReviewModel:createQualityReviewModel(e)}),d}(e,t,c);if("console"===t.command)return clearTimeout(r),void await f({args:t,runtimePolicy:e.runtime,eventView:c,createRuntime:createRuntime});if(t.shouldRunRequest&&!t.serveOpenAi&&await I({args:t,runtimePolicy:e.runtime,eventView:c}))return;t.shouldRunRequest&&!t.serveOpenAi&&process.stderr.write("stable-harness runtime: no matching daemon found; running in-process\n");const p=await createRuntime();if(t.serveOpenAi)return clearTimeout(r),void await j(p,t);if(!t.shouldRunRequest)return void process.stdout.write(C(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}${h(t.detail)}\n`)}),e.subscribe(e=>{const t=w(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,l=o.input,d=a.outputs,!0===u?.inputFromState?{...u,requestInput:l,outputs:d}:u&&"requiredInput"in u?u.requiredInput:u&&("args"in u||"cwd"in u||"timeoutMs"in u)?u:"object"==typeof l&&null!==l?l:{}),context:{workspaceRoot:n.root,requestId:s,sessionId:i,agentId:`workflow:${r.id}`,approvalIds:readApprovalIds(o.metadata)}})).output;var u,l,d},agents:async({id:e,node:r,request:o,sessionId:s,state:i})=>{var a,n,u,l;return(await t().request({input:(a=e,n=o.input,u=i.outputs,l=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.",...l?[`Workflow node config: ${JSON.stringify(l)}`]:[],"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});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{createInterface as s}from"node:readline/promises";import{stdin as n,stdout as t}from"node:process";import{daemonBaseUrl as o,isDaemonAvailable as i}from"../daemon/client.js";import{formatCliRuntimeEvent as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{createInterface as s}from"node:readline/promises";import{stdin as n,stdout as t}from"node:process";import{daemonBaseUrl as o,isDaemonAvailable as i}from"../daemon/client.js";import{formatCliRuntimeEvent as r}from"../event-view.js";export async function runConsole(a){const c=await async function createConsoleClient(e){const s=o(e.runtimePolicy);return await i(s,e.args.workspaceRoot)?function createDaemonConsoleClient(e,s){return{mode:"daemon",baseUrl:e,request:s=>async function postJson(e,s){const n=await fetch(e,{method:"POST",body:JSON.stringify(s)});if(!n.ok)throw new Error(`HTTP ${n.status}`);return await n.json()}(`${e}/requests`,s),health:async()=>(await getJson(`${e}/health`)).ok?"ok":"unhealthy",sessions:()=>getJson(`${e}/sessions`),requests:s=>getJson(`${e}/requests${s?`?sessionId=${encodeURIComponent(s)}`:""}`),inspectRequest:async s=>{const n=await fetch(`${e}/requests/${encodeURIComponent(s)}`);return n.ok?await n.json():void 0},memories:s=>getJson(`${e}/memories${s?`?namespace=${encodeURIComponent(s)}`:""}`),clearSession:async s=>(await async function deleteJson(e){const s=await fetch(e,{method:"DELETE"});if(!s.ok)throw new Error(`HTTP ${s.status}`);return await s.json()}(`${e}/sessions/${encodeURIComponent(s)}`)).deletedCount,debug:()=>getJson(`${e}/inspect`),stream:(n,t)=>function streamDaemonEvents(e,s,n,t){const o=new AbortController;return fetch(`${e}/events?requestId=${encodeURIComponent(s)}`,{signal:o.signal}).then(async e=>{const s=e.body?.getReader();if(!s)return;let o="";for(;;){const{value:e,done:i}=await s.read();if(i)return;o+=Buffer.from(e).toString("utf8");const a=o.split("\n\n");o=a.pop()??"";for(const e of a){const s=e.split("\n").find(e=>e.startsWith("data: "))?.slice(6);if(!s)continue;const o=r(JSON.parse(s),n);o&&t(o)}}}).catch(e=>{o.signal.aborted||process.stderr.write(`stable-harness console event stream failed: ${String(e)}\n`)}),{close:()=>o.abort()}}(e,n,s,t)}}(s,e.eventView):function createLocalConsoleClient(e,s){return{mode:"local",request:s=>e.request(s),health:async()=>"ok",sessions:async()=>e.listSessions(),requests:async s=>e.listRequests(s?{sessionId:s}:void 0),inspectRequest:async s=>e.inspectRequest(s),memories:async s=>e.listMemories(s?{namespace:s}:{}),clearSession:async s=>e.deleteSession(s).deletedCount,debug:async()=>e.inspect(),stream:(n,t)=>({close:e.subscribe(e=>{if(e.requestId===n){const n=r(e,s);n&&t(n)}})})}}(await e.createRuntime(),e.eventView)}(a);let d=a.args.sessionId??e(),u=a.args.agentId;process.stderr.write(`stable-harness console: ${"daemon"===c.mode?`connected to daemon at ${c.baseUrl}`:"no matching daemon found; running in-process"}\n`),process.stdout.write(`session ${d}\n`);const l=s({input:n,output:t,terminal:process.stdout.isTTY});try{const e=process.stdout.isTTY?await async function runInteractiveLoop(e){let{sessionId:s,agentId:n}=e;for(;;){const t=await e.rl.question("stable> "),o=await handleConsoleLineSafely({client:e.client,line:t.trim(),sessionId:s,agentId:n,eventView:e.eventView});if(o.done)return o;s=o.sessionId,n=o.agentId}}({rl:l,client:c,sessionId:d,agentId:u,eventView:a.eventView}):await async function runPipedLoop(e){let{sessionId:s,agentId:n}=e;for await(const t of e.rl){const o=await handleConsoleLineSafely({client:e.client,line:t.trim(),sessionId:s,agentId:n,eventView:e.eventView});if(o.done)return o;s=o.sessionId,n=o.agentId}return{done:!0,sessionId:s,agentId:n}}({rl:l,client:c,sessionId:d,agentId:u,eventView:a.eventView});d=e.sessionId,u=e.agentId}catch(e){if(!function isEndOfInput(e){return e instanceof Error&&e.message.includes("closed")}(e))throw e}finally{l.close()}}async function handleConsoleLineSafely(s){try{return await async function handleConsoleLine(s){const n=function parseConsoleCommand(e){if(!e.startsWith("/"))return;const[s="",...n]=e.slice(1).trim().split(/\s+/u);return{name:s,args:n.join(" ").trim()}}(s.line);return s.line?n?await async function runConsoleCommand(s){const{client:n,command:t}=s;if("exit"===t.name||"quit"===t.name)return{...s,done:!0};if("help"===t.name)!function printHelp(){process.stdout.write(["/help Show console commands.","/session [id] Show or switch session.","/new Create and switch to a new session.","/sessions List known sessions.","/agent [id] Show or switch selected agent.","/tool <id> [json] Invoke a tool in the current session.","/requests [all] List current-session or all requests.","/memory [namespace] List memory records.","/clear Delete current session requests.","/health Check runtime health.","/debug Print runtime inspection JSON.","/exit Leave console.",""].join("\n"))}();else if("health"===t.name)process.stdout.write(`${await n.health()}\n`);else if("debug"===t.name)process.stdout.write(`${JSON.stringify(await n.debug())}\n`);else{if("session"===t.name)return switchSession(s,t.args);if("new"===t.name)return switchSession(s,e());if("agent"===t.name)return function switchAgent(e,s){const n=s.trim()||void 0;return process.stdout.write(`agent ${n??"default"}\n`),{done:!1,sessionId:e.sessionId,agentId:n}}(s,t.args);"sessions"===t.name?printJsonLines(await n.sessions(),"sessionId"):"requests"===t.name?printJsonLines(await n.requests("all"===t.args?void 0:s.sessionId),"requestId"):"memory"===t.name||"memories"===t.name?printJsonLines(await n.memories(t.args||void 0),"id"):"clear"===t.name?process.stdout.write(`cleared ${await n.clearSession(s.sessionId)} requests from ${s.sessionId}\n`):"tool"===t.name?await async function runConsoleTool(e){const s=e.command.args.match(/^(\S+)(?:\s+([\s\S]+))?$/u);s?.[1]?await runConsoleRequest(e.client,{input:"",sessionId:e.sessionId,...e.agentId?{agentId:e.agentId}:{},toolCall:{toolId:s[1],args:s[2]?JSON.parse(s[2]):{}}}):process.stdout.write("usage: /tool <tool-id> [json-args]\n")}(s):process.stdout.write(`unknown command: /${t.name}\n`)}return{done:!1,sessionId:s.sessionId,agentId:s.agentId}}({...s,command:n}):(await runConsoleRequest(s.client,await async function withSessionHistory(e,s){if(!s.sessionId||s.toolCall||s.workflow)return s;const n=await async function buildSessionHistory(e,s){const n=(await e.requests(s)).filter(e=>"completed"===e.state).slice(-6),t=[];for(const s of n){const n=await e.inspectRequest(s.requestId),o=readHistoryInput(n),i=n?.output?.trim();o&&i&&t.push({role:"user",content:o},{role:"assistant",content:i})}return t.slice(-12)}(e,s.sessionId);return{...s,metadata:{...s.metadata,consoleSession:!0,openaiMessages:[...n,{role:"user",content:s.input}],openaiSessionHistory:n.length>0}}}(s.client,{input:s.line,sessionId:s.sessionId,...s.agentId?{agentId:s.agentId}:{}})),{done:!1,sessionId:s.sessionId,agentId:s.agentId}):{done:!1,sessionId:s.sessionId,agentId:s.agentId}}(s)}catch(e){return process.stdout.write(`error: ${function errorMessage(e){return e instanceof Error?e.message:String(e)}(e)}\n`),{done:!1,sessionId:s.sessionId,agentId:s.agentId}}}async function runConsoleRequest(s,n){const t=n.requestId??e(),o=s.stream(t,e=>process.stdout.write(`${e}\n`));try{const e=await s.request({...n,requestId:t});process.stdout.write(`${e.output}\n`)}finally{o.close()}}function readHistoryInput(e){const s=Array.isArray(e?.metadata?.openaiMessages)?e.metadata.openaiMessages:[],n=s.map(e=>"object"==typeof e&&e?e:{}).filter(e=>"user"===e.role&&"string"==typeof e.content&&e.content.trim()).at(-1)?.content;return"string"==typeof n?n:e?.input.trim()||void 0}function switchSession(e,s){const n=s.trim()||e.sessionId;return process.stdout.write(`session ${n}\n`),{done:!1,sessionId:n,agentId:e.agentId}}function printJsonLines(e,s){if(0!==e.length)for(const n of e){const e="object"==typeof n&&n?n:{};process.stdout.write(`${String(e[s]??"")} ${JSON.stringify(n)}\n`)}else process.stdout.write("none\n")}async function getJson(e){const s=await fetch(e);if(!s.ok)throw new Error(`HTTP ${s.status}`);return await s.json()}
|
|
@@ -1 +1 @@
|
|
|
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
|
|
1
|
+
import{execFile as t}from"node:child_process";import{promisify as r}from"node:util";import{createAgentProtocolHttpServer as o,createHttpServer as e,createOpenAiCompatibleHttpServer as n}from"@stable-harness/protocols";import{startOfficialLangGraphServer as s}from"./langgraph-official.js";const i="127.0.0.1",a=r(t);export async function serveProtocol(t,r){const o=createConfiguredServers(t,r),e=[];let n=0;for(const r of o)if("http"===r.kind){if(!await listen(r)){process.stdout.write(`stable-harness ${r.protocol} API already running on ${serverUrl(r)}\n`);continue}e.push(()=>closeHttpServer(r.server)),n+=1;const t=r.server.address(),o="object"==typeof t&&t?t.port:r.port;process.stdout.write(`stable-harness ${r.protocol} API listening on ${serverUrl({...r,port:o})}\n`)}else{const o=await startLangGraphServer(t,r);if(!o){process.stdout.write(`stable-harness ${r.protocol} API already running on http://${r.config.host}:${r.config.port}\n`);continue}e.push(o.cleanup),n+=1,process.stdout.write(`stable-harness ${r.protocol} API listening on ${o.url}\n`)}0!==n&&await async function waitForShutdown(t){const r=setInterval(()=>{},864e5);await new Promise(o=>{const shutdown=()=>{clearInterval(r),Promise.allSettled(t.map(t=>t())).finally(()=>process.exit(0))};process.once("SIGINT",shutdown),process.once("SIGTERM",shutdown)})}(e)}export async function stopProtocol(t,r){const o=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}),e=await Promise.all(o.map(async t=>({target:t,pids:await stableHarnessListenerPids(t.port)}))),n=[...new Set(e.flatMap(t=>t.pids))];for(const t of n)process.kill(t,"SIGTERM");for(const{target:t,pids:r}of e)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 o=readRecord(t.getRuntimePolicy().protocols)??{},e=protocolConfig(o,"stableRuntime","stable-runtime","http")??{},n=protocolConfig(o,"openaiCompatible","openai-compatible","openai")??{},s=function agentProtocolConfig(t){const r=protocolConfig(t,"agentProtocols","agent-protocols");if(r)return enabled(r)?r:void 0;const o=["acp","a2a","agui"].filter(r=>enabled(protocolConfig(t,r)??{enabled:!1}));return o.length>0?{protocols:o}:void 0}(o),i=protocolConfig(o,"langgraph")??{};return[...enabled(e)?[stableRuntimeServer(t,e,r)]:[],...enabled(n)?[openAiServer(t,n,r)]:[],...s?[agentProtocolServer(t,s,r)]:[],...enabled(i)?[langGraphServer(i)]:[]]}function stableRuntimeServer(t,r,o){return{kind:"http",protocol:"stable-runtime",server:e(t),host:o.host??configString(r.host)??i,port:configNumber(r.port)??configNumber(process.env.STABLE_HARNESS_RUNTIME_PORT)??8641}}function openAiServer(t,r,o){const e=configString(r.host)??i,s=o.port??configNumber(r.port)??8642,a=o.host??e,c=configString(r.bearerToken)??configString(r.apiKey)??o.apiKey;return{kind:"http",protocol:"openai-compatible",server:n(t,{bearerToken:c}),host:a,port:s,...c?{bearerToken:c}:{}}}function agentProtocolServer(t,r,e){const n=configString(r.host)??i,s=configNumber(r.port)??8650,a=e.host??n;return{kind:"http",protocol:"agent-protocols",server:o(t,{baseUrl:`http://${a}:${s}`,enabledProtocols:configProtocolIds(r.protocols)}),host:a,port:s}}function langGraphServer(t){const r=configString(t.host)??i,o=configNumber(t.port)??2024,e=configStringArray(t.exposeAgents);return{kind:"langgraph",protocol:"langgraph-compatible",config:{host:r,port:o,nWorkers:configNumber(t.nWorkers)??10,...e?{exposeAgents:e}:{},...void 0!==t.env?{env:t.env}:{},...void 0!==t.envFile?{envFile:t.envFile}:{}}}}function protocolConfig(t,...r){for(const o of r){const r=readRecord(t[o]);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 configStringArray(t){if(Array.isArray(t)&&t.every(t=>"string"==typeof t))return t.filter(t=>t.trim()).map(t=>t.trim())}function configProtocolIds(t){const r=configStringArray(t)?.filter(t=>"acp"===t||"a2a"===t||"agui"===t);return r&&r.length>0?r: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,o)=>{t.server.once("error",o),t.server.listen(t.port,t.host,()=>{t.server.off("error",o),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):"openai-compatible"===t.protocol?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):await async function isAgentProtocolServerAlreadyRunning(t){const r=await fetchJson(`http://${t.host}:${t.port}/health`);return!0===r?.ok&&Array.isArray(r.protocols)}(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 s(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`:"agent-protocols"===t.protocol?`${r}/acp / ${r}/a2a / ${r}/ag-ui`: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 o=await fetch(t,{headers:r});if(!o.ok)return;return await o.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,o,e){return isAddressInUse(t)?new Error([`stable-harness ${r} port is already in use: ${o}:${e}.`,`Use --port <port>, update config/runtime/workspace.yaml, or stop the process currently listening on ${o}:${e}.`].join("\n")):t}async function stableHarnessListenerPids(t){const r=await async function listenerPids(t){try{const{stdout:r}=await a("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 a("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 o,e="";for(const n of t)'"'!==n&&"'"!==n||void 0!==o?n!==o?/\s/u.test(n)&&void 0===o?e&&(r.push(e),e=""):e+=n:o=void 0:o=n;return e&&r.push(e),r}(t),o=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 o>=0&&r.slice(o+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,o)=>{t.close(t=>{t?o(t):r()})})}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103",
|
|
18
|
+
"@stable-harness/adapter-langgraph": "0.0.103",
|
|
19
|
+
"@stable-harness/core": "0.0.103",
|
|
20
|
+
"@stable-harness/memory": "0.0.103",
|
|
21
|
+
"@stable-harness/protocols": "0.0.103",
|
|
22
|
+
"@stable-harness/tool-gateway": "0.0.103",
|
|
23
|
+
"@stable-harness/workspace-yaml": "0.0.103"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103",
|
|
15
|
+
"@stable-harness/memory": "0.0.103"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/evaluation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
2
|
+
import type { StableHarnessRuntime } from "@stable-harness/core";
|
|
3
|
+
export type AgentProtocolServerOptions = {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
enabledProtocols?: Array<"acp" | "a2a" | "agui">;
|
|
6
|
+
};
|
|
7
|
+
export declare function createAgentProtocolHttpServer(runtime: StableHarnessRuntime, options?: AgentProtocolServerOptions): import("node:http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createServer as e}from"node:http";export function createAgentProtocolHttpServer(t,s={}){const a=new Set(s.enabledProtocols??["acp","a2a","agui"]);return e(async(e,n)=>{try{if("GET"===e.method&&"/health"===e.url)return void sendJson(n,200,{ok:!0,protocols:[...a]});if(a.has("a2a")&&await async function handleA2a(e,t,s,a){if("GET"===t.method&&("/.well-known/agent-card.json"===t.url||"/a2a/agent-card.json"===t.url))return sendJson(s,200,function createAgentCard(e,t){const s=e.inspect();return{protocolVersion:"1.0",name:s.workspaceRoot.split(/[\\/]/u).filter(Boolean).at(-1)??"stable-harness",description:"Stable Harness runtime agent endpoint",version:"0.0.0",url:t.baseUrl?`${t.baseUrl.replace(/\/$/u,"")}/a2a`:"/a2a",preferredTransport:"HTTP+JSON",capabilities:{streaming:!0},defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],skills:s.agents.map(e=>({id:e,name:e,description:e}))}}(e,a)),!0;const n=matchPath(t.url,/^\/a2a\/tasks\/([^/]+)$/u);if("GET"===t.method&&n){const t=e.inspectRequest(n);return sendJson(s,t?200:404,t?{task:toA2aTask(t)}:{error:"task_not_found"}),!0}if("GET"===t.method&&"/a2a/tasks"===t.url)return sendJson(s,200,{tasks:e.listRequests().map(toA2aTaskSummary)}),!0;const r=matchPath(t.url,/^\/a2a\/tasks\/([^/]+):cancel$/u);return"POST"===t.method&&r?(e.cancel(r,"a2a_cancel"),sendJson(s,200,{task:e.inspectRequest(r)}),!0):"POST"===t.method&&"/a2a/message:send"===t.url?(sendJson(s,200,{task:toA2aTask(await e.request(toA2aRuntimeRequest(await readJson(t))))}),!0):"POST"===t.method&&"/a2a/message:stream"===t.url?(await streamA2a(e,await readJson(t),s),!0):"POST"===t.method&&"/a2a/rpc"===t.url&&(await async function handleA2aRpc(e,t,s){if("SendMessage"===t.method){const a=await e.request(toA2aRuntimeRequest(readRecord(t.params)??{}));return void sendJson(s,200,jsonRpcResult(t.id,{task:toA2aTask(a)}))}if("SendStreamingMessage"!==t.method){if("GetTask"===t.method){const a=readString(readRecord(t.params)?.id),n=a?e.inspectRequest(a):void 0;return void sendJson(s,n?200:404,n?jsonRpcResult(t.id,toA2aTask(n)):jsonRpcError(t.id,-32004,"task_not_found"))}"ListTasks"!==t.method?sendJson(s,404,jsonRpcError(t.id,-32601,"method_not_found")):sendJson(s,200,jsonRpcResult(t.id,{tasks:e.listRequests().map(toA2aTaskSummary)}))}else await streamA2a(e,readRecord(t.params)??{},s,t.id)}(e,await readJson(t),s),!0)}(t,e,n,s))return;if(a.has("agui")&&await async function handleAgui(e,t,s){return"GET"===t.method&&"/ag-ui/capabilities"===t.url?(sendJson(s,200,{protocol:"ag-ui",transports:["http+sse"],events:["RunStarted","TextMessageChunk","Custom","RunFinished","RunError"]}),!0):"POST"===t.method&&"/ag-ui/runs"===t.url&&(await async function streamAgui(e,t,s){const a=readString(t.runId)??crypto.randomUUID(),n=readString(t.threadId)??readString(t.sessionId)??`thread-${a}`,r=readPromptText(t);writeSseHeaders(s),writeSse(s,{type:"RunStarted",threadId:n,runId:a,input:{messages:t.messages,input:r}});const o=e.subscribe(e=>{e.requestId===a&&writeSse(s,function toAguiEvent(e){return"runtime.progress.narration"===e.type?{type:"Custom",name:"stable-harness.progress",value:e}:"runtime.tool.direct.started"===e.type?{type:"ToolCallStart",toolCallId:`${e.requestId}:${e.toolId}`,toolCallName:e.toolId}:"runtime.tool.direct.completed"===e.type?{type:"ToolCallResult",messageId:`${e.requestId}-message`,toolCallId:`${e.requestId}:${e.toolId}`,content:e.output,role:"tool"}:{type:"Custom",name:`stable-harness.${e.type}`,value:e}}(e))});try{const o=await e.request({input:r,requestId:a,sessionId:n,agentId:readString(t.agentId),metadata:{protocol:"ag-ui"}}),i=`${a}-message`;o.output&&writeSse(s,{type:"TextMessageChunk",messageId:i,role:"assistant",delta:o.output}),writeSse(s,{type:"RunFinished",threadId:n,runId:a,outcome:{type:"completed"===o.state?"success":"interrupt"},result:o.output})}catch(e){writeSse(s,{type:"RunError",threadId:n,runId:a,message:errorMessage(e)})}finally{o(),s.end()}}(e,await readJson(t),s),!0)}(t,e,n))return;if(a.has("acp")&&await async function handleAcp(e,t,s){if("GET"===t.method&&"/acp/capabilities"===t.url)return sendJson(s,200,{protocolVersion:1,agentCapabilities:{loadSession:!0,promptCapabilities:{embeddedContext:!0},_meta:{transport:"http-jsonrpc"}},agentInfo:{name:"stable-harness",title:"Stable Harness",version:"0.0.0"}}),!0;if("POST"===t.method&&"/acp"===t.url){const a=await readJson(t),n=await async function handleAcpMessage(e,t){if(!t.id&&"session/cancel"===t.method){const s=readString(readRecord(t.params)?.sessionId);return void(s&&e.listRequests({sessionId:s,state:"running"}).forEach(t=>e.cancel(t.requestId,"acp_cancel")))}if("initialize"===t.method)return jsonRpcResult(t.id,{protocolVersion:1,agentCapabilities:{loadSession:!0,promptCapabilities:{embeddedContext:!0},_meta:{transport:"http-jsonrpc"}},agentInfo:{name:"stable-harness",title:"Stable Harness",version:"0.0.0"}});if("session/new"===t.method)return jsonRpcResult(t.id,{sessionId:`acp-${crypto.randomUUID()}`});if("session/load"===t.method)return jsonRpcResult(t.id,{sessionId:readString(readRecord(t.params)?.sessionId)});if("session/list"===t.method)return jsonRpcResult(t.id,{sessions:e.listSessions()});if("session/prompt"===t.method){const s=readRecord(t.params)??{},a=await e.request({input:readPromptText(s),sessionId:readString(s.sessionId),agentId:readString(s.agentId),metadata:{protocol:"acp",transport:"http-jsonrpc"}});return jsonRpcResult(t.id,{stopReason:"completed"===a.state?"end_turn":"refusal",_meta:{requestId:a.requestId,output:a.output}})}return jsonRpcError(t.id,-32601,"method_not_found")}(e,a);return n?sendJson(s,200,n):s.writeHead(204).end(),!0}return!1}(t,e,n))return;sendJson(n,404,{error:"not_found"})}catch(e){sendJson(n,400,{error:errorMessage(e)})}})}async function streamA2a(e,t,s,a){const n=toA2aRuntimeRequest(t);writeSseHeaders(s);const r=e.subscribe(e=>{e.requestId===n.requestId&&writeSse(s,{jsonrpc:"2.0",id:a,result:{event:toA2aEvent(e)}})});try{const t=await e.request(n);writeSse(s,{jsonrpc:"2.0",id:a,result:{task:toA2aTask(t),final:!0}})}finally{r(),s.end()}}function toA2aRuntimeRequest(e){const t=readRecord(e.message)??e;return{input:readPromptText(t),requestId:readString(e.requestId)??readString(t.messageId),sessionId:readString(e.taskId)??readString(t.taskId)??readString(t.contextId),agentId:readString(e.agentId)??readString(e.metadata&&readRecord(e.metadata)?.agentId),metadata:{protocol:"a2a",configuration:e.configuration,metadata:e.metadata}}}function toA2aTask(e){const t="state"in e?e.state:e.summary.state,s="output"in e?e.output:e.output??"",a="requestId"in e?e.requestId:e.summary.requestId;return{id:a,contextId:"sessionId"in e?e.sessionId:e.summary.sessionId,status:{state:"completed"===t?"completed":t,message:s?{role:"agent",messageId:`${a}-response`,parts:[{kind:"text",text:s}]}:void 0}}}function toA2aTaskSummary(e){return{id:e.requestId,contextId:e.sessionId,status:{state:e.state},metadata:{agentId:e.agentId}}}function toA2aEvent(e){return{kind:"status-update",taskId:e.requestId,contextId:e.sessionId,status:{state:e.type},metadata:e}}function readPromptText(e){return"string"==typeof e.input?e.input:"string"==typeof e.text?e.text:"string"==typeof e.prompt?e.prompt:Array.isArray(e.parts)?e.parts.map(readPartText).filter(Boolean).join("\n"):Array.isArray(e.messages)?readPromptText(readRecord(e.messages.at(-1))??{}):Array.isArray(e.content)?e.content.map(readPartText).filter(Boolean).join("\n"):"string"==typeof e.content?e.content:""}function readPartText(e){const t=readRecord(e);return t?readString(t.text)??readString(t.content)??"":"string"==typeof e?e:""}function matchPath(e,t){const s=(e??"").match(t);return s?.[1]?decodeURIComponent(s[1]):void 0}function readRecord(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function jsonRpcResult(e,t){return{jsonrpc:"2.0",id:e,result:t}}function jsonRpcError(e,t,s){return{jsonrpc:"2.0",id:e,error:{code:t,message:s}}}function sendJson(e,t,s){e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(s))}function writeSseHeaders(e){e.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"})}function writeSse(e,t){e.write(`data: ${JSON.stringify(t)}\n\n`)}async function readJson(e){const t=[];for await(const s of e)t.push(Buffer.isBuffer(s)?s:Buffer.from(s));return t.length>0?JSON.parse(Buffer.concat(t).toString("utf8")):{}}function errorMessage(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { createInProcessClient } from "./in-process-client.js";
|
|
2
|
+
export { createAgentProtocolHttpServer } from "./agent-protocols.js";
|
|
3
|
+
export type { AgentProtocolServerOptions } from "./agent-protocols.js";
|
|
2
4
|
export { createHttpServer } from "./http-server.js";
|
|
3
5
|
export { createOpenAiCompatibleHttpServer } from "./openai-compatible.js";
|
|
4
6
|
export type { OpenAiCompatibleServerOptions } from "./openai-compatible.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{createInProcessClient}from"./in-process-client.js";export{createHttpServer}from"./http-server.js";export{createOpenAiCompatibleHttpServer}from"./openai-compatible.js";
|
|
1
|
+
export{createInProcessClient}from"./in-process-client.js";export{createAgentProtocolHttpServer}from"./agent-protocols.js";export{createHttpServer}from"./http-server.js";export{createOpenAiCompatibleHttpServer}from"./openai-compatible.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stable-harness/protocols",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103"
|
|
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.103",
|
|
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.103"
|
|
15
15
|
}
|
|
16
16
|
}
|