stable-harness 0.0.40 → 0.0.41
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 +13 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/docs/architecture/runtime-events.md +5 -0
- package/docs/guides/index.md +2 -0
- package/docs/guides/workspace-docker-build.md +88 -0
- package/docs/protocols/langgraph-compatible.md +22 -0
- package/node_modules/@stable-harness/adapter-deepagents/dist/src/adapter.js +1 -1
- package/node_modules/@stable-harness/core/dist/index.d.ts +2 -0
- package/node_modules/@stable-harness/core/dist/index.js +1 -1
- package/node_modules/@stable-harness/core/dist/runtime/tracing/langsmith.d.ts +27 -0
- package/node_modules/@stable-harness/core/dist/runtime/tracing/langsmith.js +1 -0
- package/node_modules/@stable-harness/core/dist/runtime.d.ts +2 -0
- package/node_modules/@stable-harness/core/dist/runtime.js +1 -1
- package/node_modules/@stable-harness/core/dist/workspace/types.d.ts +1 -0
- package/node_modules/@stable-harness/tool-gateway/dist/src/module-loader.js +1 -1
- package/node_modules/@stable-harness/workspace-yaml/dist/documents.js +1 -1
- package/package.json +5 -2
- package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
- package/packages/cli/dist/src/args.d.ts +3 -1
- package/packages/cli/dist/src/args.js +1 -1
- package/packages/cli/dist/src/build.d.ts +9 -0
- package/packages/cli/dist/src/build.js +1 -0
- package/packages/cli/dist/src/cli.js +1 -1
- package/packages/cli/dist/src/index.d.ts +1 -0
- package/packages/cli/dist/src/index.js +1 -1
- package/packages/cli/dist/src/langgraph-official.js +1 -1
- package/packages/core/dist/index.d.ts +2 -0
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/runtime/tracing/langsmith.d.ts +27 -0
- package/packages/core/dist/runtime/tracing/langsmith.js +1 -0
- package/packages/core/dist/runtime.d.ts +2 -0
- package/packages/core/dist/runtime.js +1 -1
- package/packages/core/dist/workspace/types.d.ts +1 -0
- package/packages/tool-gateway/dist/src/module-loader.js +1 -1
- package/packages/workspace-yaml/dist/documents.js +1 -1
package/README.md
CHANGED
|
@@ -84,6 +84,18 @@ Then point compatible clients at:
|
|
|
84
84
|
http://127.0.0.1:8642/v1
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
Build a portable Docker runtime artifact for the workspace:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
stable-harness build --target docker -w ./examples/minimal-deepagents --output ./dist/workspace-docker
|
|
91
|
+
cd ./dist/workspace-docker
|
|
92
|
+
docker compose up --build
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The generated Compose file mounts persistent runtime data at `/data`. The build
|
|
96
|
+
copies the workspace while excluding local secrets and build output such as
|
|
97
|
+
`.env`, `.git`, `node_modules`, and `dist`.
|
|
98
|
+
|
|
87
99
|
## Embed In An App
|
|
88
100
|
|
|
89
101
|
```ts
|
|
@@ -211,6 +223,7 @@ This is constrained repair, not silent magic:
|
|
|
211
223
|
- [Documentation index](docs/guides/index.md)
|
|
212
224
|
- [Getting started](docs/guides/getting-started.md)
|
|
213
225
|
- [Workspace authoring](docs/guides/workspace-authoring.md)
|
|
226
|
+
- [Workspace Docker build](docs/guides/workspace-docker-build.md)
|
|
214
227
|
- [Integration guide](docs/guides/integration-guide.md)
|
|
215
228
|
- [Operator runbook](docs/guides/operator-runbook.md)
|
|
216
229
|
- [Adoption playbook](docs/product/adoption-playbook.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { createDeepAgentsMiddlewareSkillProvider, createLangGraphRuntimeAdapter,
|
|
|
5
5
|
export type { LangGraphNodeHandler, LangGraphNodeHandlerInput, LangGraphNodeResolver, LangGraphNodeResolverInput, LangGraphSkillMiddlewareProvider, LangGraphSkillMiddlewareProviderInput, LangGraphSkillResolverProvider, LangGraphWorkflowAdapterOptions, LangGraphWorkflowState, LangGraphWorkflowTraceEntry, } from "@stable-harness/adapter-langgraph";
|
|
6
6
|
export type { LangGraphRegistrySkillOutput } from "@stable-harness/adapter-langgraph";
|
|
7
7
|
export { createLangMemServiceProvider } from "@stable-harness/memory";
|
|
8
|
-
export { applySpecDrivenPhaseTransition, containsRecoverableResultOutput, createSpecDrivenArtifact, createSpecDrivenArtifactEvent, createSpecDrivenPhaseEvent, createSpecDrivenWorkflowPolicy, createSpecDrivenWorkflowState, projectRuntimeTrace, } from "@stable-harness/core";
|
|
8
|
+
export { applySpecDrivenPhaseTransition, containsRecoverableResultOutput, createSpecDrivenArtifact, createSpecDrivenArtifactEvent, createSpecDrivenPhaseEvent, createSpecDrivenWorkflowPolicy, createSpecDrivenWorkflowState, projectRuntimeTrace, resolveEnabledMemories, } from "@stable-harness/core";
|
|
9
9
|
export type { CompiledWorkspace, RuntimeAdapter, RuntimeEvent, RuntimeWorkflowAdapter, RuntimeRequest, RuntimeResponse, RuntimeRunRecord, RuntimeTraceEntry, StableHarnessRuntime, SpecDrivenPhaseRecord, SpecDrivenPhaseStatus, SpecDrivenPhaseTransition, SpecDrivenWorkflowState, WorkspaceAgent, WorkspaceModel, WorkspaceRuntimePolicy, WorkspaceSpecDrivenPhase, WorkspaceSpecDrivenWorkflowPolicy, WorkspaceTool, } from "@stable-harness/core";
|
|
10
10
|
export { loadWorkspaceFromYaml } from "@stable-harness/workspace-yaml";
|
|
11
11
|
export { createInMemoryToolGateway, createModuleToolGateway } from "@stable-harness/tool-gateway";
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createBackendModel as e,createDeepAgentsAdapter as r}from"@stable-harness/adapter-deepagents";import{createLangGraphRuntimeAdapter as t,createLangGraphWorkflowAdapter as a,createRegistrySkillResolverProvider as o}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as n}from"@stable-harness/core";import{createModuleToolGateway as i}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as s}from"@stable-harness/workspace-yaml";export{createDeepAgentsAdapter,createDeepAgentsMemoryMaintenanceTarget}from"@stable-harness/adapter-deepagents";export{createDeepAgentsMiddlewareSkillProvider,createLangGraphRuntimeAdapter,createLangGraphWorkflowAdapter,createRegistrySkillResolverProvider}from"@stable-harness/adapter-langgraph";export{createLangMemServiceProvider}from"@stable-harness/memory";export{applySpecDrivenPhaseTransition,containsRecoverableResultOutput,createSpecDrivenArtifact,createSpecDrivenArtifactEvent,createSpecDrivenPhaseEvent,createSpecDrivenWorkflowPolicy,createSpecDrivenWorkflowState,projectRuntimeTrace}from"@stable-harness/core";export{loadWorkspaceFromYaml}from"@stable-harness/workspace-yaml";export{createInMemoryToolGateway,createModuleToolGateway}from"@stable-harness/tool-gateway";export function createStableHarnessRuntime(e){return"string"==typeof e?createStableRuntime({workspaceRoot:e}):"workspaceRoot"in e?createStableRuntime(e):n(e)}export async function createStableRuntime(e){const r=await s(e.workspaceRoot),t=e.toolGateway??await i({tools:r.tools.values()});return n({workspace:r,toolGateway:t,qualityReviewModel:createQualityReviewModel(r),adapters:e.adapters??createRuntimeAdapters(r,e),workflowAdapters:e.workflowAdapters??createWorkflowAdapters(r,e)})}function createQualityReviewModel(r){const t=function readQualityModelRef(e){const r=isRecord(e)?e:{};return readString((isRecord(r.reviewer)?r.reviewer:r).modelRef)}(r.runtime.quality),a=t?r.models.get(t):void 0,o=a?e(a):void 0;return function isQualityReviewModel(e){return isRecord(e)&&"function"==typeof e.invoke}(o)?o:void 0}export async function requestStableRuntime(e,r){return e.request(r)}function createRuntimeAdapters(e,a){const o={deepagents:({policy:e})=>r(e.config?{config:e.config}:{}),langgraph:({policy:e})=>t({...readLangGraphOptions(e.config),name:e.name}),...a.adapterFactories},n=function runtimeAdapterPolicies(e){const r=e.runtime.adapters?.filter(e=>!1!==e.enabled);return r&&r.length>0?r:[...new Set([...e.agents.values()].map(e=>e.backend))].map(e=>({name:e}))}(e);return n.map(r=>{const t=o[r.name];if(t)return t({policy:r,workspace:e});throw new Error(`Unsupported runtime adapter: ${r.name}`)})}function createWorkflowAdapters(e,r){const t={langgraph:({name:e,options:r})=>a({...readLangGraphOptions(r),name:e}),...r.workflowAdapterFactories};return[...new Set([...e.workflows.values()].map(e=>e.adapter??"").filter(Boolean))].map(a=>{const o=t[a];return o?.({name:a,workspace:e,options:readWorkflowAdapterOptions(r,a)})}).filter(e=>Boolean(e))}function readWorkflowAdapterOptions(e,r){return e.workflowAdapterOptions?.[r]??{}}function readLangGraphOptions(e){return isRecord(e)?{...e,...void 0!==readLangGraphSkillProvider(e)?{skillProvider:readLangGraphSkillProvider(e)}:{}}:{}}function readLangGraphSkillProvider(e){if(!1===e.skillProvider)return!1;const r=function readSkillProviderConfig(e){return isRecord(e.skills)?e.skills:isRecord(e.skillProvider)?e.skillProvider:void 0}(e);if(!r)return;const t=readString(r.provider)??readString(r.name)??"registry-resolver";if(["none","disabled","false"].includes(t))return!1;if("registry-resolver"!==t)throw new Error(`Unsupported LangGraph skill provider: ${t}`);return o({..."boolean"==typeof r.includeContent?{includeContent:r.includeContent}:{},..."number"==typeof r.maxBytes&&Number.isFinite(r.maxBytes)?{maxBytes:r.maxBytes}:{}})}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
1
|
+
import{createBackendModel as e,createDeepAgentsAdapter as r}from"@stable-harness/adapter-deepagents";import{createLangGraphRuntimeAdapter as t,createLangGraphWorkflowAdapter as a,createRegistrySkillResolverProvider as o}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as n}from"@stable-harness/core";import{createModuleToolGateway as i}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as s}from"@stable-harness/workspace-yaml";export{createDeepAgentsAdapter,createDeepAgentsMemoryMaintenanceTarget}from"@stable-harness/adapter-deepagents";export{createDeepAgentsMiddlewareSkillProvider,createLangGraphRuntimeAdapter,createLangGraphWorkflowAdapter,createRegistrySkillResolverProvider}from"@stable-harness/adapter-langgraph";export{createLangMemServiceProvider}from"@stable-harness/memory";export{applySpecDrivenPhaseTransition,containsRecoverableResultOutput,createSpecDrivenArtifact,createSpecDrivenArtifactEvent,createSpecDrivenPhaseEvent,createSpecDrivenWorkflowPolicy,createSpecDrivenWorkflowState,projectRuntimeTrace,resolveEnabledMemories}from"@stable-harness/core";export{loadWorkspaceFromYaml}from"@stable-harness/workspace-yaml";export{createInMemoryToolGateway,createModuleToolGateway}from"@stable-harness/tool-gateway";export function createStableHarnessRuntime(e){return"string"==typeof e?createStableRuntime({workspaceRoot:e}):"workspaceRoot"in e?createStableRuntime(e):n(e)}export async function createStableRuntime(e){const r=await s(e.workspaceRoot),t=e.toolGateway??await i({tools:r.tools.values()});return n({workspace:r,toolGateway:t,qualityReviewModel:createQualityReviewModel(r),adapters:e.adapters??createRuntimeAdapters(r,e),workflowAdapters:e.workflowAdapters??createWorkflowAdapters(r,e)})}function createQualityReviewModel(r){const t=function readQualityModelRef(e){const r=isRecord(e)?e:{};return readString((isRecord(r.reviewer)?r.reviewer:r).modelRef)}(r.runtime.quality),a=t?r.models.get(t):void 0,o=a?e(a):void 0;return function isQualityReviewModel(e){return isRecord(e)&&"function"==typeof e.invoke}(o)?o:void 0}export async function requestStableRuntime(e,r){return e.request(r)}function createRuntimeAdapters(e,a){const o={deepagents:({policy:e})=>r(e.config?{config:e.config}:{}),langgraph:({policy:e})=>t({...readLangGraphOptions(e.config),name:e.name}),...a.adapterFactories},n=function runtimeAdapterPolicies(e){const r=e.runtime.adapters?.filter(e=>!1!==e.enabled);return r&&r.length>0?r:[...new Set([...e.agents.values()].map(e=>e.backend))].map(e=>({name:e}))}(e);return n.map(r=>{const t=o[r.name];if(t)return t({policy:r,workspace:e});throw new Error(`Unsupported runtime adapter: ${r.name}`)})}function createWorkflowAdapters(e,r){const t={langgraph:({name:e,options:r})=>a({...readLangGraphOptions(r),name:e}),...r.workflowAdapterFactories};return[...new Set([...e.workflows.values()].map(e=>e.adapter??"").filter(Boolean))].map(a=>{const o=t[a];return o?.({name:a,workspace:e,options:readWorkflowAdapterOptions(r,a)})}).filter(e=>Boolean(e))}function readWorkflowAdapterOptions(e,r){return e.workflowAdapterOptions?.[r]??{}}function readLangGraphOptions(e){return isRecord(e)?{...e,...void 0!==readLangGraphSkillProvider(e)?{skillProvider:readLangGraphSkillProvider(e)}:{}}:{}}function readLangGraphSkillProvider(e){if(!1===e.skillProvider)return!1;const r=function readSkillProviderConfig(e){return isRecord(e.skills)?e.skills:isRecord(e.skillProvider)?e.skillProvider:void 0}(e);if(!r)return;const t=readString(r.provider)??readString(r.name)??"registry-resolver";if(["none","disabled","false"].includes(t))return!1;if("registry-resolver"!==t)throw new Error(`Unsupported LangGraph skill provider: ${t}`);return o({..."boolean"==typeof r.includeContent?{includeContent:r.includeContent}:{},..."number"==typeof r.maxBytes&&Number.isFinite(r.maxBytes)?{maxBytes:r.maxBytes}:{}})}function readString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -232,6 +232,11 @@ Span projection is a view layer. It adds `spanId`, optional `parentSpanId`,
|
|
|
232
232
|
`kind`, `name`, `status`, event references, and timing from event metadata. It
|
|
233
233
|
must not create execution semantics or infer domain-specific routing.
|
|
234
234
|
|
|
235
|
+
`runtime.tracing.langsmith` is an optional export capability over this span
|
|
236
|
+
projection. It writes the stored run tree to LangSmith after request completion;
|
|
237
|
+
it is not an adapter and must not participate in planning, tool invocation, or
|
|
238
|
+
recovery decisions.
|
|
239
|
+
|
|
235
240
|
### 3.2 Category: Runtime Stream Views
|
|
236
241
|
|
|
237
242
|
#### 3.2.1 Event Group: `runtime.stream.*`
|
package/docs/guides/index.md
CHANGED
|
@@ -12,6 +12,8 @@ embed it, operate it, or explain why it exists.
|
|
|
12
12
|
workflows, memory, and protocol exposure in YAML.
|
|
13
13
|
- [Integration guide](integration-guide.md): embed the runtime inside an app,
|
|
14
14
|
run it through CLI, or expose it through HTTP/OpenAI-compatible clients.
|
|
15
|
+
- [Workspace Docker build](workspace-docker-build.md): package a workspace as a
|
|
16
|
+
portable Docker runtime with a generic persistent data mount.
|
|
15
17
|
- [Quality gates](quality-gates.md): enable plan review, execution evidence
|
|
16
18
|
review, and configured recovery loops without replacing upstream planning.
|
|
17
19
|
- [Operator runbook](operator-runbook.md): validate a workspace, inspect
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Workspace Docker Build
|
|
2
|
+
|
|
3
|
+
Stable Harness can package a workspace as a portable Docker runtime artifact.
|
|
4
|
+
This is a distribution boundary for a complete agent workspace, not a new agent
|
|
5
|
+
execution framework and not a cloud-specific deploy command.
|
|
6
|
+
|
|
7
|
+
## Build
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
stable-harness build --target docker -w ./my-agent-app --output ./dist/workspace-docker
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The output directory contains:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Dockerfile
|
|
17
|
+
docker-compose.yaml
|
|
18
|
+
.dockerignore
|
|
19
|
+
.env.example
|
|
20
|
+
stable-workspace.json
|
|
21
|
+
workspace/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`workspace/` is a copy of the source workspace. The copy excludes local build
|
|
25
|
+
and secret-bearing paths such as `.env`, `.git`, `node_modules`, and `dist`.
|
|
26
|
+
|
|
27
|
+
## Run
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd ./dist/workspace-docker
|
|
31
|
+
docker compose up --build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The generated image starts the OpenAI-compatible Stable Harness runtime:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
http://127.0.0.1:3000/v1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use another host port if `3000` is already allocated:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
STABLE_HARNESS_PORT=8642 docker compose up --build
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Persistence
|
|
47
|
+
|
|
48
|
+
The generated Compose file creates a named volume:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
stable-harness-data -> /data
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Runtime services can use `/data` for persistent memory, artifacts, run state, or
|
|
55
|
+
other runtime-owned storage. Workspace business data should stay owned by the
|
|
56
|
+
application that defines it.
|
|
57
|
+
|
|
58
|
+
## Versioning
|
|
59
|
+
|
|
60
|
+
The Dockerfile pins the Stable Harness package version used by the build
|
|
61
|
+
command. It installs that package into an isolated `/stable-runtime` npm project
|
|
62
|
+
so runtime dependencies resolve like a normal application install:
|
|
63
|
+
|
|
64
|
+
```dockerfile
|
|
65
|
+
ARG STABLE_HARNESS_PACKAGE=stable-harness@<current package version>
|
|
66
|
+
WORKDIR /stable-runtime
|
|
67
|
+
RUN npm init -y && npm install "${STABLE_HARNESS_PACKAGE}"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Override the version during image build when needed:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
docker compose build --build-arg STABLE_HARNESS_PACKAGE=stable-harness@latest
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Boundary
|
|
77
|
+
|
|
78
|
+
Stable Harness owns the generic workspace-to-Docker artifact:
|
|
79
|
+
|
|
80
|
+
- workspace inventory packaging
|
|
81
|
+
- runtime entrypoint
|
|
82
|
+
- protocol exposure
|
|
83
|
+
- generic data mount
|
|
84
|
+
- build manifest
|
|
85
|
+
|
|
86
|
+
Product layers such as Flev can consume this artifact and add their own product
|
|
87
|
+
templates, dashboard, account model, deployment target, and business data
|
|
88
|
+
layout without leaking those assumptions into Stable Harness core.
|
|
@@ -61,6 +61,28 @@ The LangGraph service is started through the official
|
|
|
61
61
|
upstream LangGraph behavior. `stable-harness` only loads the environment before
|
|
62
62
|
that server starts.
|
|
63
63
|
|
|
64
|
+
Native Stable Harness spans can also be exported to LangSmith. This is separate
|
|
65
|
+
from LangGraph's upstream tracing path: it projects stored runtime events through
|
|
66
|
+
`projectRuntimeTraceSpans(run)` and writes the resulting run tree to LangSmith at
|
|
67
|
+
request completion.
|
|
68
|
+
|
|
69
|
+
Enable native export in runtime YAML:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
apiVersion: stable-harness.dev/v1
|
|
73
|
+
kind: Runtime
|
|
74
|
+
spec:
|
|
75
|
+
routing:
|
|
76
|
+
defaultAgentId: orchestra
|
|
77
|
+
tracing:
|
|
78
|
+
langsmith:
|
|
79
|
+
enabled: true
|
|
80
|
+
projectName: stable-harness-local
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The exporter consumes runtime facts only. It does not change backend execution,
|
|
84
|
+
tool selection, delegation, recovery, or protocol behavior.
|
|
85
|
+
|
|
64
86
|
By default, `stable-harness start` reads `.env` from the workspace root for the
|
|
65
87
|
LangGraph service. Existing shell environment variables win over `.env` values.
|
|
66
88
|
For Studio, put your key in the workspace `.env` file:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as
|
|
1
|
+
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as c}from"./memory.js";import{buildDeepAgentRequest as d}from"./internal/messages.js";import{createRawToolCallParserMiddleware as l}from"./internal/raw-tool-call-parser.js";import{createBackendModel as u}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as m}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.js";export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"agent.handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const r=e.createDeepAgent?void 0:await async function loadDeepAgentsModule(){try{return await async function importOptionalPackage(e){return import(e)}("deepagents")}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${function formatError(e){return e instanceof Error?e.message:String(e)}(e)}`)}}(),n=e.createDeepAgent??function readCreateDeepAgent(e){const t=e?.createDeepAgent;if("function"==typeof t)return t;throw new Error("DeepAgents package does not export createDeepAgent.")}(r),o=n(function buildDeepAgentParams(e,t,r){const n={...readDeepAgentsConfig(t),...readDeepAgentsConfig(e.agent.config.deepagents)},o=resolveDeepAgentsSkills(e,e.agent),a=n.permissions??s(e,e.agent),p=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:n.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:n.backend??resolveDeepAgentsBackend(e,r,o),checkpointer:n.checkpointer,store:n.store,middleware:mergeMiddleware(e,e.agent,n.middleware,p),responseFormat:n.responseFormat,contextSchema:n.contextSchema,interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:a,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(e,e.agent,n),p),subagents:e.agent.subagents.map(t=>{const r=e.workspace.agents.get(t),n=readDeepAgentsConfig(r?.config.deepagents),o=n.permissions??s(e,r),a=scopedInput(e,r),p=requestScopedRepeatState(e,t);return pruneUndefined({name:t,description:r?.description??readString(r?.config.description)??r?.id,systemPrompt:buildSystemPrompt(e,r),model:n.model??(r?resolveAgentModel(e,r):void 0),middleware:mergeMiddleware(a,r,n.middleware,p),interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:o,responseFormat:n.responseFormat,tools:i(e,t,r?.tools??[],resolveAgentRepairModel(a,r,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:resolveDeepAgentsMemory(e,e.agent),skills:o})}(t,e.config,r)),a=d(t),c=function buildDeepAgentInvokeConfig(e){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit)})}(t.agent);if(!0===t.request.metadata?.openaiStream&&o.streamEvents)return g(t,o.streamEvents(a,{version:"v2",...c}),p);const l=await o.invoke(a,c);return p(l)}}}function buildSystemPrompt(e,t){const n=t?.systemPrompt??readString(t?.config.systemPrompt);return r({workspace:e.workspace,request:e.request,agent:t},n)}function resolveDeepAgentsMemory(e,t){const r=readDeepAgentsStringArray(t?.config,"memory");if(r)return r;const n=[...readAgentMemorySources(e.workspace.root,t),...c(e.workspace).map(e=>`/memories/${e.id}.md`)],o=[...new Set(n)];return o.length>0?o:void 0}function readAgentMemorySources(e,t){return(t?.memory??[]).flatMap(t=>"string"==typeof t&&t.trim()?[backendMemorySourcePath(e,t.trim())]:isRecord(t)&&"string"==typeof t.path&&t.path.trim()?[backendMemorySourcePath(e,t.path.trim())]:[])}function backendMemorySourcePath(e,r){if(r.startsWith("/"))return r;if(t.isAbsolute(r)){const n=t.relative(e,r);return n&&!n.startsWith("..")?`/${n.split(t.sep).join("/")}`:canonicalPath(r)}const n=r.split(t.sep).join("/");return n.startsWith("/")?n:`/${n}`}function resolveDeepAgentsSkills(e,r){const n=readDeepAgentsStringArray(r?.config,"skills");if(n)return n;const o=[...new Set((r?.skills??[]).map(t=>e.workspace.skills.get(t)?.path).filter(e=>"string"==typeof e&&e.trim().length>0).map(r=>function backendSkillSourcePath(e,r){const n=t.dirname(t.dirname(r)),o=t.relative(e,n);return!o||o.startsWith("..")||t.isAbsolute(o)?""===o?"/":canonicalPath(n):`/${o.split(t.sep).join("/")}`}(e.workspace.root,r)))];return o.length>0?o:void 0}function resolveDeepAgentsBackend(e,t,r){if(t?.FilesystemBackend&&r&&0!==r.length)return()=>new t.FilesystemBackend({rootDir:e.workspace.root})}function mergeMiddleware(e,t,r,s=a(e.workspace.runtime.toolGateway)){const i=Array.isArray(r)?r:[],p=scopedInput(e,t),c=new Set;return[o(p,{observedToolIds:c,repeatState:s}),n(p,{repeatState:s}),...m(e.workspace.runtime.retry),...i,l(p)]}function requestScopedRepeatState(e,t){const r=`deepagents.repeat.${t}`,n=e.requestState?.get(r);if(n)return n;const o=a(e.workspace.runtime.toolGateway);return e.requestState&&o&&e.requestState.set(r,o),o}function scopedInput(e,t){return t?{...e,agent:t}:e}function resolveAgentModel(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?u(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;if(isRepairModel(n))return n;if(!t)return;const o=resolveAgentModel(e,t);return isRepairModel(o)?o:void 0}function readDeepAgentsConfig(e){return isRecord(e)?e:{}}function readDeepAgentsStringArray(e,t){const r=isRecord(e)?e:{},n=readDeepAgentsConfig(r.deepagents),o="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of o){const t=readStringArray(n[e]);if(t)return t}return readStringArray(r[t])}function pruneUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readNumber(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function readBoolean(e){return"boolean"==typeof e?e:void 0}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function canonicalPath(t){try{return e.native(t)}catch{return t}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}
|
|
@@ -6,11 +6,13 @@ export * from "./recovery/tool-call.js";
|
|
|
6
6
|
export * from "./runtime/persistence/inspection.js";
|
|
7
7
|
export { createWorkspaceSandboxPolicy } from "./runtime/governance/sandbox.js";
|
|
8
8
|
export * from "./memory-plugins.js";
|
|
9
|
+
export { resolveEnabledMemories } from "./memory-plugins/shared.js";
|
|
9
10
|
export * from "./runtime/persistence/queue.js";
|
|
10
11
|
export * from "./runtime/policy/projection.js";
|
|
11
12
|
export * from "./runtime.js";
|
|
12
13
|
export * from "./runtime/selection-repair.js";
|
|
13
14
|
export * from "./runtime/tool-failure.js";
|
|
15
|
+
export * from "./runtime/tracing/langsmith.js";
|
|
14
16
|
export * from "./runtime/policy/tool-invocation.js";
|
|
15
17
|
export * from "./runtime/persistence/stores.js";
|
|
16
18
|
export * from "./trace.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./runtime/persistence/artifacts.js";export*from"./boundary-scan.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export{createWorkspaceSandboxPolicy}from"./runtime/governance/sandbox.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime/policy/projection.js";export*from"./runtime.js";export*from"./runtime/selection-repair.js";export*from"./runtime/tool-failure.js";export*from"./runtime/policy/tool-invocation.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workspace/tool-quality.js";export*from"./evaluations/index.js";export*from"./quality/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
|
|
1
|
+
export*from"./runtime/persistence/artifacts.js";export*from"./boundary-scan.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export{createWorkspaceSandboxPolicy}from"./runtime/governance/sandbox.js";export*from"./memory-plugins.js";export{resolveEnabledMemories}from"./memory-plugins/shared.js";export*from"./runtime/persistence/queue.js";export*from"./runtime/policy/projection.js";export*from"./runtime.js";export*from"./runtime/selection-repair.js";export*from"./runtime/tool-failure.js";export*from"./runtime/tracing/langsmith.js";export*from"./runtime/policy/tool-invocation.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workspace/tool-quality.js";export*from"./evaluations/index.js";export*from"./quality/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Client } from "langsmith";
|
|
2
|
+
import type { RuntimeCapabilityModule } from "../capabilities.js";
|
|
3
|
+
import type { RuntimeRunRecord, RuntimeStore } from "../types.js";
|
|
4
|
+
import type { WorkspaceRuntimePolicy } from "../../workspace/types.js";
|
|
5
|
+
export type LangSmithTraceClient = {
|
|
6
|
+
createRun(run: LangSmithRunCreate): Promise<void>;
|
|
7
|
+
flush?(): Promise<void>;
|
|
8
|
+
awaitPendingTraceBatches?(): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
type LangSmithRunCreate = Parameters<Client["createRun"]>[0];
|
|
11
|
+
export type RuntimeLangSmithTracingOptions = {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
projectName?: string;
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
workspaceId?: string;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
client?: LangSmithTraceClient;
|
|
19
|
+
failOnError?: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function createLangSmithTracingCapability(input: {
|
|
22
|
+
policy: WorkspaceRuntimePolicy;
|
|
23
|
+
store: RuntimeStore;
|
|
24
|
+
options?: RuntimeLangSmithTracingOptions | false;
|
|
25
|
+
}): RuntimeCapabilityModule | undefined;
|
|
26
|
+
export declare function createLangSmithRunTree(run: RuntimeRunRecord, options?: RuntimeLangSmithTracingOptions): LangSmithRunCreate;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as t}from"node:crypto";import{projectRuntimeTraceSpans as e}from"../../trace.js";export function createLangSmithTracingCapability(t){const e=function resolveOptions(t,e){if(!1===e)return{enabled:!1};const n=function readLangSmithConfig(t){const e=readRecord(t.tracing),n=readRecord(e?.langsmith);return{enabled:readBoolean(n?.enabled),projectName:readString(n?.projectName)??readString(n?.project),apiKey:readString(n?.apiKey),apiUrl:readString(n?.apiUrl),workspaceId:readString(n?.workspaceId),tags:(r=n?.tags,Array.isArray(r)?r.filter(t=>"string"==typeof t&&t.trim().length>0):void 0),failOnError:readBoolean(n?.failOnError)};var r}(t);return{...n,...e,enabled:e?.enabled??n.enabled??!1}}(t.policy,t.options);if(!e.enabled)return;const n=function createClientResolver(t){let e;return()=>(e??=async function resolveClient(t){if(t.client)return t.client;const{Client:e}=await import("langsmith");return new e({apiKey:t.apiKey,apiUrl:t.apiUrl,workspaceId:t.workspaceId,autoBatchTracing:!0})}(t),e)}(e),r=function createLangSmithExporter(t,e,n){return async r=>{const a=await n(),i=e.getRun(r);i&&(await a.createRun(createLangSmithRunTree(i,t)),await flushClient(a))}}(e,t.store,n),a=new Set,i=[];return{id:"runtime.tracing.langsmith",onEvent(t){if(!function isTerminalRequestEvent(t){return"runtime.request.completed"===t.type||"runtime.request.failed"===t.type||"runtime.request.cancelled"===t.type}(t))return;const e=r(t.requestId).catch(t=>{i.push(t)});a.add(e),e.finally(()=>a.delete(e)).catch(()=>{})},async stop(){if(await Promise.allSettled([...a]),await flushClient(await n()),e.failOnError&&i[0])throw i[0]}}}export function createLangSmithRunTree(t,n={}){const r=e(t),a=r.find(t=>"run"===t.kind)??r[0];if(!a)return function createFallbackRun(t,e){return{id:stableUuid(`run:${t.requestId}`),name:t.agentId,run_type:"chain",start_time:t.startedAt,end_time:t.completedAt,inputs:{input:t.input},outputs:t.output?{output:t.output}:void 0,error:t.error,project_name:e.projectName}}(t,n);const i=stableUuid(a.spanId);return{...toLangSmithRun(a,i,n),child_runs:childRuns(a.spanId,r,i,n)}}async function flushClient(t){await(t.flush?.()),await(t.awaitPendingTraceBatches?.())}function toLangSmithRun(t,e,n){return{id:stableUuid(t.spanId),name:t.name,run_type:"tool"===t.kind?"tool":"chain",start_time:t.startedAt,end_time:t.completedAt,inputs:{spanId:t.spanId},outputs:"failed"===t.status?void 0:{status:t.status},error:"failed"===t.status?String(t.attributes?.error??"failed"):void 0,parent_run_id:t.parentSpanId?stableUuid(t.parentSpanId):void 0,trace_id:e,project_name:n.projectName,extra:{metadata:metadataForSpan(t,n)}}}function childRuns(t,e,n,r){return e.filter(e=>e.parentSpanId===t).map(t=>({...toLangSmithRun(t,n,r),child_runs:childRuns(t.spanId,e,n,r)}))}function metadataForSpan(t,e){return{stableHarness:{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,kind:t.kind,status:t.status,startEventIndex:t.startEventIndex,endEventIndex:t.endEventIndex,durationMs:t.durationMs,events:t.events,attributes:t.attributes,tags:["stable-harness",...e.tags??[]]}}}function stableUuid(e){const n=t("sha256").update(e).digest("hex").slice(0,32);return`${n.slice(0,8)}-${n.slice(8,12)}-4${n.slice(13,16)}-8${n.slice(17,20)}-${n.slice(20,32)}`}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}function readString(t){return"string"==typeof t&&t.trim()?t.trim():void 0}function readBoolean(t){return"boolean"==typeof t?t:void 0}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApprovalQueue } from "@stable-harness/governance";
|
|
2
2
|
import type { MemoryProvider, RuntimeMemoryStore } from "@stable-harness/memory";
|
|
3
3
|
import type { QualityReviewModel } from "./quality/index.js";
|
|
4
|
+
import { createLangSmithTracingCapability } from "./runtime/tracing/langsmith.js";
|
|
4
5
|
import type { CompiledWorkspace, RuntimeCapabilityModule, RuntimeToolGateway, RuntimeAdapter, RuntimeArtifactStore, RuntimeSandboxPolicy, RuntimeStore, RuntimeProgressNarrationOptions, RuntimeWorkflowAdapter, StableHarnessRuntime } from "./types.js";
|
|
5
6
|
type RuntimeFactoryInput = {
|
|
6
7
|
workspace: CompiledWorkspace;
|
|
@@ -16,6 +17,7 @@ type RuntimeFactoryInput = {
|
|
|
16
17
|
progressNarration?: RuntimeProgressNarrationOptions | false;
|
|
17
18
|
qualityReviewModel?: QualityReviewModel;
|
|
18
19
|
capabilities?: RuntimeCapabilityModule[];
|
|
20
|
+
langSmithTracing?: false | Parameters<typeof createLangSmithTracingCapability>[0]["options"];
|
|
19
21
|
};
|
|
20
22
|
export declare function createStableHarnessRuntime(input: RuntimeFactoryInput): StableHarnessRuntime;
|
|
21
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{assertNoRawToolCallOutput as r,assertNoToolExecutionErrorOutput as a,buildAdapterErrorRecoveryPrompt as o,buildEvidenceSynthesisOutput as s,buildExecutionContractRecoveryRequest as n,buildResultRecoveryRequest as i,containsRawToolCallOutput as u,isRecoverableAdapterError as c,rawToolCallFailureMessage as l,toolCallRecoveryEnabled as p}from"./recovery/tool-call.js";import{recoverQualityReview as d,resolveQualityPolicy as m}from"./quality/index.js";import{completeRun as w,failRun as y}from"./runtime/completion.js";import{runDirectToolCall as f}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{assertNoRawToolCallOutput as r,assertNoToolExecutionErrorOutput as a,buildAdapterErrorRecoveryPrompt as o,buildEvidenceSynthesisOutput as s,buildExecutionContractRecoveryRequest as n,buildResultRecoveryRequest as i,containsRawToolCallOutput as u,isRecoverableAdapterError as c,rawToolCallFailureMessage as l,toolCallRecoveryEnabled as p}from"./recovery/tool-call.js";import{recoverQualityReview as d,resolveQualityPolicy as m}from"./quality/index.js";import{completeRun as w,failRun as y}from"./runtime/completion.js";import{runDirectToolCall as f}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as g}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as I}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as q}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as R,normalizeAdapterResult as v}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as b}from"./runtime/memory.js";import{createInMemoryRuntimeStore as k}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as A}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as x}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as h}from"./runtime/tool-failure.js";import{runWorkflowRequest as j}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const r=new Set,a=t.store??k(),s=R([b(t),A({options:t.progressNarration,policy:t.workspace.runtime}),x({policy:t.workspace.runtime,store:a,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const o=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);a.appendEvent(o);for(const e of r)e(o)},emit=e=>{emitBase(e),s.emitSideEffects(e,emitBase)},i=I({gateway:g({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),u={...t,toolGateway:i},l=h(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const r=t.request.requestId??e(),a=t.request.sessionId??e(),s=[],{agent:i,adapter:u}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):function resolveRoutedAgentId(e,t){for(const r of e.runtime.routes??[])if(routeMatches(r,t))return r.agentId;return e.runtime.defaultAgentId}(e.workspace,t.input),o=e.workspace.agents.get(a);if(!o)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:o,adapter:void 0};const s=e.adapters.find(e=>e.canRun(o));if(!s)throw new Error(`No runtime adapter can run backend ${o.backend} for agent ${o.id}`);return{agent:o,adapter:s}}(t.input,t.request,{requestId:r,sessionId:a,emit:e=>s.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,r,a,i)),s.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:r,sessionId:a,agentId:i.id,input:t.request.input});try{if(t.request.workflow){const e=await j({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:r,sessionId:a,agentId:i.id,emit:t.emit});return w({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await f({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:r,sessionId:a,agent:i,toolFailureTracker:t.toolFailureTracker});return w({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,r=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),a=r.memory,s=r.pluginMemories??[],i=e.input.workspace.runtime,u=m(e.input.workspace.runtime,e.agent),l=new Map;let p;try{p=await runAdapterOnce(e,t,e.request,a,s,l)}catch(r){if(!c(r,i))throw r;p=await runAdapterOnce(e,t,o(e.request,r,i),a,s,l)}p=await recoverAdapterResultOutput(e,t,e.request,p,a,s,i,l),p=await d(createQualityRuntimeInput(e,a,s,l),e.request,p,u),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:p});try{assertRequestExecutionContract(e)}catch(r){const o=n({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:i});if(!o)throw r;p=await runAdapterOnce(e,t,o,a,s,l),p=await recoverAdapterResultOutput(e,t,o,p,a,s,i,l),p=await d(createQualityRuntimeInput(e,a,s,l),o,p,u),assertRequestExecutionContract(e)}const y=w({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:p,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:p,response:y}),y}({...t,adapter:u,requestId:r,sessionId:a,agent:i})}catch(e){return y({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,error:e})}}({input:u,capabilities:s,store:a,emit:emit,request:t,toolFailureTracker:l}),subscribe:e=>(r.add(e),()=>r.delete(e)),...q({workspace:t.workspace,store:a,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),cancel(e,t){const r=a.getRun(e);r&&"running"===r.state&&(a.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await s.stop(),r.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,a),reviewModel:e.input.qualityReviewModel,memory:t,pluginMemories:r}}async function recoverAdapterResultOutput(e,t,o,n,c,d,m,w){let y=o;const f=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,r="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,a="object"!=typeof r||null===r||Array.isArray(r)?void 0:r.maxResultRecoveryAttempts;return"number"==typeof a&&Number.isInteger(a)&&a>0?a:3}(m);let g=0;for(let r=0;r<f;r+=1){const r=e.store.getRun(e.requestId)?.events??[],a=i({request:y,output:n.text,events:r.slice(g),availableToolIds:e.agent.tools,policy:m});if(!a)break;y=a,g=e.store.getRun(e.requestId)?.events.length??0,n=await runAdapterOnce(e,t,a,c,d,w)}if(p(m)){let t=!1;u(n.text,m)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(o.metadata)&&(n={...n,text:l(),metadata:{...n.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}});const i=s({request:o,output:n.text,events:e.store.getRun(e.requestId)?.events??[],policy:m});i&&(t=!0,n={...n,text:i,metadata:{...n.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}}),t||(r(n.text,m),a(n.text,m))}return n}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,o,s){return v(await t.run({workspace:e.input.workspace,agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:o,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,requestState:s,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function routeMatches(e,t){if(e.pattern)try{if(new RegExp(e.pattern,"iu").test(t))return!0}catch{return!1}const r=t.toLowerCase();return(e.keywords??[]).some(e=>r.includes(e.toLowerCase()))}
|
|
@@ -66,6 +66,7 @@ export type WorkspaceRuntimePolicy = {
|
|
|
66
66
|
sandbox?: Record<string, unknown>;
|
|
67
67
|
memory?: Record<string, unknown>;
|
|
68
68
|
protocols?: Record<string, unknown>;
|
|
69
|
+
tracing?: Record<string, unknown>;
|
|
69
70
|
progress?: Record<string, unknown>;
|
|
70
71
|
cli?: Record<string, unknown>;
|
|
71
72
|
quality?: string | Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await loadModuleTool(t);o&&e.push(o)}return t(e,o.options)}async function loadModuleTool(t){if(!t.sourcePath)return;const n=await import(e(o.resolve(t.sourcePath)).href),r=n[t.name??t.id]??n.default;return function hasInvoke(o){return"object"==typeof o&&null!==o&&"invoke"in o&&"function"==typeof o.invoke}(r)?{id:t.id,description:t.description??r.description,schema:t.schema??r.schema,validateArgs:r.validateArgs,invoke:(o,e)=>async function invokeWithWorkspaceCwd(o,e,t){const n=process.cwd();try{return process.chdir(t.workspaceRoot),await o(e,t)}finally{process.chdir(n)}}(r.invoke,o,e)}:void 0}
|
|
1
|
+
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await loadModuleTool(t);o&&e.push(o)}return t(e,o.options)}async function loadModuleTool(t){if(!t.sourcePath||!function isJavaScriptModule(e){const t=o.extname(e);return".mjs"===t||".js"===t||".cjs"===t}(t.sourcePath))return;const n=await import(e(o.resolve(t.sourcePath)).href),r=n[t.name??t.id]??n.default;return function hasInvoke(o){return"object"==typeof o&&null!==o&&"invoke"in o&&"function"==typeof o.invoke}(r)?{id:t.id,description:t.description??r.description,schema:t.schema??r.schema,validateArgs:r.validateArgs,invoke:(o,e)=>async function invokeWithWorkspaceCwd(o,e,t){const n=process.cwd();try{return process.chdir(t.workspaceRoot),await o(e,t)}finally{process.chdir(n)}}(r.invoke,o,e)}:void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
|
1
|
+
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.tracing&&r.tracing?{tracing:r.tracing}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stable-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Stable application runtime and operator control plane for agent workspaces.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"test:skill-mining:e2e": "node scripts/run-skill-candidate-mining-e2e.mjs",
|
|
68
68
|
"prepublishOnly": "npm run build && npm run release:check-package",
|
|
69
69
|
"prepack": "npm run release:minify",
|
|
70
|
-
"release:minify": "find dist packages -type f -name '*.js' \\( -path 'dist/*' -o -path '*/dist/*' \\) -exec sh -c 'for f do ./node_modules/.bin/terser \"$f\" --compress passes=2 --mangle keep_fnames=true --keep-fnames --keep-classnames --module --comments false --output \"$f\"; done' sh {} +",
|
|
70
|
+
"release:minify": "find dist packages -type f -name '*.js' \\( -path 'dist/*' -o -path '*/dist/*' \\) ! -path 'dist/test/*' -exec sh -c 'for f do ./node_modules/.bin/terser \"$f\" --compress passes=2 --mangle keep_fnames=true --keep-fnames --keep-classnames --module --comments false --output \"$f\"; done' sh {} +",
|
|
71
71
|
"release:check-package": "node scripts/release/check-npm-package.mjs",
|
|
72
72
|
"release:smoke": "node scripts/release/smoke-npm-install.mjs",
|
|
73
73
|
"release:pack": "npm run build && npm run release:check-package && npm pack --dry-run",
|
|
@@ -102,6 +102,9 @@
|
|
|
102
102
|
"terser": "^5.47.1",
|
|
103
103
|
"typescript": "^5.9.3"
|
|
104
104
|
},
|
|
105
|
+
"optionalDependencies": {
|
|
106
|
+
"langsmith": "^0.6.0"
|
|
107
|
+
},
|
|
105
108
|
"main": "index.js",
|
|
106
109
|
"directories": {
|
|
107
110
|
"doc": "docs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as
|
|
1
|
+
import{realpathSync as e}from"node:fs";import t from"node:path";import{buildRuntimeSystemPrompt as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as n,createObserverMiddleware as o}from"./internal/builtin-tool-policy.js";import{resolveFilesystemPermissions as s}from"./internal/builtin/permissions.js";import{createToolRepeatState as a}from"@stable-harness/core";import{buildGatewayTools as i,stringifyDeepAgentResult as p}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as c}from"./memory.js";import{buildDeepAgentRequest as d}from"./internal/messages.js";import{createRawToolCallParserMiddleware as l}from"./internal/raw-tool-call-parser.js";import{createBackendModel as u}from"./model-providers.js";import{createDeepAgentsRetryMiddleware as m}from"./retry-policy.js";import{streamDeepAgentResult as g}from"./internal/stream-events.js";export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"runtime.adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"agent.handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const r=e.createDeepAgent?void 0:await async function loadDeepAgentsModule(){try{return await async function importOptionalPackage(e){return import(e)}("deepagents")}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${function formatError(e){return e instanceof Error?e.message:String(e)}(e)}`)}}(),n=e.createDeepAgent??function readCreateDeepAgent(e){const t=e?.createDeepAgent;if("function"==typeof t)return t;throw new Error("DeepAgents package does not export createDeepAgent.")}(r),o=n(function buildDeepAgentParams(e,t,r){const n={...readDeepAgentsConfig(t),...readDeepAgentsConfig(e.agent.config.deepagents)},o=resolveDeepAgentsSkills(e,e.agent),a=n.permissions??s(e,e.agent),p=requestScopedRepeatState(e,e.agent.id);return pruneUndefined({name:e.agent.id,model:n.model??resolveAgentModel(e,e.agent),systemPrompt:buildSystemPrompt(e,e.agent),backend:n.backend??resolveDeepAgentsBackend(e,r,o),checkpointer:n.checkpointer,store:n.store,middleware:mergeMiddleware(e,e.agent,n.middleware,p),responseFormat:n.responseFormat,contextSchema:n.contextSchema,interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:a,tools:i(e,e.agent.id,e.agent.tools,resolveAgentRepairModel(e,e.agent,n),p),subagents:e.agent.subagents.map(t=>{const r=e.workspace.agents.get(t),n=readDeepAgentsConfig(r?.config.deepagents),o=n.permissions??s(e,r),a=scopedInput(e,r),p=requestScopedRepeatState(e,t);return pruneUndefined({name:t,description:r?.description??readString(r?.config.description)??r?.id,systemPrompt:buildSystemPrompt(e,r),model:n.model??(r?resolveAgentModel(e,r):void 0),middleware:mergeMiddleware(a,r,n.middleware,p),interruptOn:n.interruptOn,generalPurposeAgent:readBoolean(n.generalPurposeAgent),taskDescription:readString(n.taskDescription),permissions:o,responseFormat:n.responseFormat,tools:i(e,t,r?.tools??[],resolveAgentRepairModel(a,r,n),p),memory:resolveDeepAgentsMemory(e,r),skills:resolveDeepAgentsSkills(e,r)})}),memory:resolveDeepAgentsMemory(e,e.agent),skills:o})}(t,e.config,r)),a=d(t),c=function buildDeepAgentInvokeConfig(e){return pruneUndefined({recursionLimit:readNumber(readDeepAgentsConfig(e.config.deepagents).recursionLimit)??readNumber(e.config.recursionLimit)})}(t.agent);if(!0===t.request.metadata?.openaiStream&&o.streamEvents)return g(t,o.streamEvents(a,{version:"v2",...c}),p);const l=await o.invoke(a,c);return p(l)}}}function buildSystemPrompt(e,t){const n=t?.systemPrompt??readString(t?.config.systemPrompt);return r({workspace:e.workspace,request:e.request,agent:t},n)}function resolveDeepAgentsMemory(e,t){const r=readDeepAgentsStringArray(t?.config,"memory");if(r)return r;const n=[...readAgentMemorySources(e.workspace.root,t),...c(e.workspace).map(e=>`/memories/${e.id}.md`)],o=[...new Set(n)];return o.length>0?o:void 0}function readAgentMemorySources(e,t){return(t?.memory??[]).flatMap(t=>"string"==typeof t&&t.trim()?[backendMemorySourcePath(e,t.trim())]:isRecord(t)&&"string"==typeof t.path&&t.path.trim()?[backendMemorySourcePath(e,t.path.trim())]:[])}function backendMemorySourcePath(e,r){if(r.startsWith("/"))return r;if(t.isAbsolute(r)){const n=t.relative(e,r);return n&&!n.startsWith("..")?`/${n.split(t.sep).join("/")}`:canonicalPath(r)}const n=r.split(t.sep).join("/");return n.startsWith("/")?n:`/${n}`}function resolveDeepAgentsSkills(e,r){const n=readDeepAgentsStringArray(r?.config,"skills");if(n)return n;const o=[...new Set((r?.skills??[]).map(t=>e.workspace.skills.get(t)?.path).filter(e=>"string"==typeof e&&e.trim().length>0).map(r=>function backendSkillSourcePath(e,r){const n=t.dirname(t.dirname(r)),o=t.relative(e,n);return!o||o.startsWith("..")||t.isAbsolute(o)?""===o?"/":canonicalPath(n):`/${o.split(t.sep).join("/")}`}(e.workspace.root,r)))];return o.length>0?o:void 0}function resolveDeepAgentsBackend(e,t,r){if(t?.FilesystemBackend&&r&&0!==r.length)return()=>new t.FilesystemBackend({rootDir:e.workspace.root})}function mergeMiddleware(e,t,r,s=a(e.workspace.runtime.toolGateway)){const i=Array.isArray(r)?r:[],p=scopedInput(e,t),c=new Set;return[o(p,{observedToolIds:c,repeatState:s}),n(p,{repeatState:s}),...m(e.workspace.runtime.retry),...i,l(p)]}function requestScopedRepeatState(e,t){const r=`deepagents.repeat.${t}`,n=e.requestState?.get(r);if(n)return n;const o=a(e.workspace.runtime.toolGateway);return e.requestState&&o&&e.requestState.set(r,o),o}function scopedInput(e,t){return t?{...e,agent:t}:e}function resolveAgentModel(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?u(r):void 0}function resolveAgentRepairModel(e,t,r){const n=r.model;if(isRepairModel(n))return n;if(!t)return;const o=resolveAgentModel(e,t);return isRepairModel(o)?o:void 0}function readDeepAgentsConfig(e){return isRecord(e)?e:{}}function readDeepAgentsStringArray(e,t){const r=isRecord(e)?e:{},n=readDeepAgentsConfig(r.deepagents),o="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of o){const t=readStringArray(n[e]);if(t)return t}return readStringArray(r[t])}function pruneUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function readString(e){return"string"==typeof e&&e.trim()?e:void 0}function readNumber(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function readBoolean(e){return"boolean"==typeof e?e:void 0}function readStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function canonicalPath(t){try{return e.native(t)}catch{return t}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function isRepairModel(e){return"object"==typeof e&&null!==e&&"invoke"in e&&"function"==typeof e.invoke}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type CliArgs = {
|
|
2
2
|
workspaceRoot: string;
|
|
3
|
-
command: "request" | "start" | "stop" | "init";
|
|
3
|
+
command: "request" | "start" | "stop" | "init" | "build";
|
|
4
|
+
buildTarget?: "docker";
|
|
5
|
+
buildOutput?: string;
|
|
4
6
|
workflowRenderId?: string;
|
|
5
7
|
workflowInspectId?: string;
|
|
6
8
|
workflowRunId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function parseArgs(e){const r=function createDefaultArgs(){return{workspaceRoot:process.cwd(),command:"request",toolArgs:void 0,trace:!1,traceJson:!1,progress:!1,serveOpenAi:!1,host:process.env.STABLE_HARNESS_OPENAI_HOST,port:process.env.STABLE_HARNESS_OPENAI_PORT?Number(process.env.STABLE_HARNESS_OPENAI_PORT):void 0,apiKey:process.env.STABLE_HARNESS_OPENAI_API_KEY,timeoutMs:Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5),help:!1,prompt:"",shouldRunRequest:!1}}(),t=[];for(let
|
|
1
|
+
export function parseArgs(e){const r=function createDefaultArgs(){return{workspaceRoot:process.cwd(),command:"request",toolArgs:void 0,trace:!1,traceJson:!1,progress:!1,serveOpenAi:!1,host:process.env.STABLE_HARNESS_OPENAI_HOST,port:process.env.STABLE_HARNESS_OPENAI_PORT?Number(process.env.STABLE_HARNESS_OPENAI_PORT):void 0,apiKey:process.env.STABLE_HARNESS_OPENAI_API_KEY,timeoutMs:Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5),help:!1,prompt:"",shouldRunRequest:!1}}(),t=[];for(let o=0;o<e.length;o+=1)o=parseOneArg(e,o,r,t);return{...r,prompt:t.join(" "),shouldRunRequest:Boolean(r.toolId||r.workflowRunId||t.length>0)}}function parseOneArg(e,r,t,o){const n=function readNextArg(e,r){return{index:r+1,value:e[r+1]}}(e,r);if(0===o.length&&function parseTopLevelCommand(e,r,t){return"start"===e[r]?(t.command="start",t.serveOpenAi=!0,!0):"stop"===e[r]?(t.command="stop",!0):"init"===e[r]?(t.command="init",!0):"build"===e[r]?(t.command="build",!0):"workflow"!==e[r]||"render"!==e[r+1]&&"inspect"!==e[r+1]?"agent"===e[r]&&"render"===e[r+1]&&(Object.assign(t,function parseAgentCommand(e,r){if("render"===e[r+1])return{index:r+2,agentRenderId:e[r+2]};throw new Error("Usage: stable-harness agent render <agent-id>")}(e,r)),!0):(Object.assign(t,function parseWorkflowCommand(e,r){if("render"===e[r+1])return{index:r+2,workflowRenderId:e[r+2],workflowInspectId:void 0};if("inspect"===e[r+1])return{index:r+2,workflowRenderId:void 0,workflowInspectId:e[r+2]};throw new Error("Usage: stable-harness workflow <render|inspect> <workflow-id>")}(e,r)),!0)}(e,r,t))return function stateIndex(e,r){return"workflow"===e[r]||"agent"===e[r]?r+2:r}(e,r);if("-h"===e[r]||"--help"===e[r])t.help=!0;else if("start"===t.command&&function isProtocolName(e){return"openai"===e||"openai-compatible"===e}(e[r]))t.serveOpenAi=!0;else{if("-w"===e[r]||"--workspace"===e[r])return setString(n,t,"workspaceRoot");if("--agent"===e[r])return setString(n,t,"agentId");if("--workflow"===e[r])return setString(n,t,"workflowRunId");if("--session-id"===e[r])return setString(n,t,"sessionId");if("--tool"===e[r])return setString(n,t,"toolId");if("--tool-args-json"===e[r])return t.toolArgs=function parseJsonArg(e){try{return JSON.parse(e)}catch(e){const r=e instanceof Error?e.message:String(e);throw new Error(`Invalid --tool-args-json value: ${r}`)}}(n.value??"{}"),n.index;if("--trace"===e[r])t.trace=!0;else if("--trace-json"===e[r])t.traceJson=!0;else if("--progress"===e[r])t.progress=!0;else if("--serve-openai"===e[r])t.serveOpenAi=!0;else{if("--host"===e[r])return setString(n,t,"host");if("--port"===e[r])return t.port=Number(n.value??t.port),n.index;if("--api-key"===e[r])return setString(n,t,"apiKey");if("--target"===e[r])return function setBuildTarget(e,r){if("docker"===e.value)return r.buildTarget="docker",e.index;throw new Error("Unsupported build target. Supported targets: docker")}(n,t);if("--output"===e[r]||"-o"===e[r])return setString(n,t,"buildOutput");if("--timeout-ms"===e[r])return t.timeoutMs=Number(n.value??t.timeoutMs),n.index;o.push(e[r])}}return r}function setString(e,r,t){return"string"==typeof e.value&&Object.assign(r,{[t]:e.value}),e.index}export function helpText(){return["Usage:"," stable-harness -w <workspace> [--agent <id>] [prompt]"," stable-harness workflow render <workflow-id> -w <workspace>"," stable-harness workflow inspect <workflow-id> -w <workspace>"," stable-harness agent render <agent-id> -w <workspace>"," stable-harness init [workspace]"," stable-harness build --target docker -w <workspace> --output <dir>"," stable-harness start -w <workspace>"," stable-harness stop -w <workspace>","","Options:"," -w, --workspace <path> Workspace root."," --serve-openai Legacy alias for start."," --agent <id> Select an agent for a request."," --workflow <id> Run a configured workflow."," --session-id <id> Attach the request to an existing runtime session."," --tool <id> Invoke an explicit registered tool."," --tool-args-json <json> Tool arguments for --tool."," --trace Print trace lines."," --trace-json Print trace JSON."," --progress Legacy alias; CLI events are controlled by runtime.cli.events."," --target docker Build target for workspace artifacts."," -o, --output <dir> Build output directory."," --timeout-ms <ms> Request timeout."," -h, --help Show this help.",""].join("\n")}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CompiledWorkspace } from "@stable-harness/core";
|
|
2
|
+
export type WorkspaceBuildOptions = {
|
|
3
|
+
workspaceRoot: string;
|
|
4
|
+
outputDir?: string;
|
|
5
|
+
packageVersion?: string;
|
|
6
|
+
target?: "docker";
|
|
7
|
+
workspace: CompiledWorkspace;
|
|
8
|
+
};
|
|
9
|
+
export declare function buildWorkspaceArtifact(options: WorkspaceBuildOptions): Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cp as e,mkdir as o,readFile as r,rm as s,writeFile as t}from"node:fs/promises";import a from"node:path";import{fileURLToPath as n}from"node:url";const i="/data",c=new Set([".DS_Store",".env",".git","dist","node_modules"]);export async function buildWorkspaceArtifact(r){if("docker"!==(r.target??"docker"))throw new Error("Unsupported build target. Supported targets: docker");const l=await async function resolveStableHarnessVersion(e){if(e?.trim())return e.trim();if(process.env.STABLE_HARNESS_BUILD_VERSION?.trim())return process.env.STABLE_HARNESS_BUILD_VERSION.trim();for(const e of function packageJsonCandidates(){const e=a.dirname(n(import.meta.url));return[a.resolve(e,"../../../../package.json"),a.resolve(e,"../../package.json")]}()){const o=await readPackageVersion(e);if(o)return o}return"latest"}(r.packageVersion),p=a.resolve(r.workspaceRoot,r.outputDir??"dist/workspace-docker");return await s(p,{recursive:!0,force:!0}),await o(p,{recursive:!0}),await async function copyWorkspace(o,r,s){const t=a.resolve(s);await e(o,r,{recursive:!0,force:!0,filter:e=>function shouldCopy(e,o,r){const s=a.resolve(e);return!(s===r||s.startsWith(`${r}${a.sep}`)||s!==a.resolve(o)&&c.has(a.basename(e)))}(e,o,t)})}(r.workspaceRoot,a.join(p,"workspace"),p),await Promise.all([t(a.join(p,"Dockerfile"),dockerfile(l),"utf8"),t(a.join(p,"docker-compose.yaml"),["services:"," stable-harness:"," build: ."," ports:",' - "${STABLE_HARNESS_PORT:-3000}:3000"'," volumes:",` - stable-harness-data:${i}`,"volumes:"," stable-harness-data:",""].join("\n"),"utf8"),t(a.join(p,".dockerignore"),[".env","node_modules","dist",".git","*.log",""].join("\n"),"utf8"),t(a.join(p,".env.example"),["# Add model provider keys or runtime secrets here before deployment.","# OPENAI_API_KEY=","# ANTHROPIC_API_KEY=","# LANGSMITH_API_KEY=",""].join("\n"),"utf8"),t(a.join(p,"stable-workspace.json"),JSON.stringify(manifest(r,p,l),null,2),"utf8")]),function renderBuildSummary(e){return[`stable-harness docker workspace artifact: ${e}`,`Dockerfile: ${a.join(e,"Dockerfile")}`,`Compose: ${a.join(e,"docker-compose.yaml")}`,`Data mount: stable-harness-data -> ${i}`,"Run: docker compose up --build",""].join("\n")}(p)}function dockerfile(e){return["FROM node:24-slim",`ARG STABLE_HARNESS_PACKAGE=stable-harness@${e}`,"WORKDIR /stable-runtime",'RUN npm init -y && npm install "${STABLE_HARNESS_PACKAGE}"',"ENV PATH=/stable-runtime/node_modules/.bin:${PATH}",`ENV STABLE_HARNESS_DATA_DIR=${i}`,"WORKDIR /workspace","COPY workspace/ /workspace/","RUN if [ -f package.json ]; then npm install --omit=dev; fi",`VOLUME ["${i}"]`,"EXPOSE 3000",'CMD ["stable-harness", "start", "-w", "/workspace", "--host", "0.0.0.0", "--port", "3000"]',""].join("\n")}function manifest(e,o,r){return{target:"docker",workspaceRoot:e.workspaceRoot,defaultAgentId:e.workspace.runtime.defaultAgentId,dataDir:i,stableHarnessVersion:r,copiedWorkspaceDir:a.join(o,"workspace"),excludedNames:[...c].sort(),inventory:{agents:e.workspace.agents.size,models:e.workspace.models.size,tools:e.workspace.tools.size,skills:e.workspace.skills.size,memories:e.workspace.memories.size,workflows:e.workspace.workflows.size,evaluations:e.workspace.evaluations?.size??0}}}async function readPackageVersion(e){try{const o=JSON.parse(await r(e,"utf8"));return"string"==typeof o.version&&o.version.trim()?o.version.trim():void 0}catch{return}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createBackendModel as r,createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createLangGraphWorkflowAdapter as s}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as a}from"@stable-harness/core";import{projectEvent as i,projectRuntimeTrace as n}from"@stable-harness/core";import{createInMemoryApprovalQueue as
|
|
2
|
+
import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createBackendModel as r,createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createLangGraphWorkflowAdapter as s}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as a}from"@stable-harness/core";import{projectEvent as i,projectRuntimeTrace as n}from"@stable-harness/core";import{createInMemoryApprovalQueue as u}from"@stable-harness/governance";import{createModuleToolGateway as d}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as l}from"@stable-harness/workspace-yaml";import{helpText as p,parseArgs as c}from"./args.js";import{buildWorkspaceArtifact as f}from"./build.js";import{formatCliRuntimeEvent as m,readCliEventViewConfig as w,shouldEnableCliProgressNarration as v}from"./event-view.js";import{initWorkspace as g}from"./init.js";import{ensureCliMemoryServices as y}from"./memory/lifecycle.js";import{createCliMemoryProviders as I}from"./memory/providers.js";import{formatDetail as k,inspectWorkflow as R,renderAgent as h,renderWorkflow as b,workspaceStatus as q}from"./output.js";import{serveProtocol as A,stopProtocol as C}from"./server.js";export async function runCli(e=process.argv.slice(2)){const t=c(e);if(t.help)return void process.stdout.write(p());const r=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),s=t.workspaceRoot;try{if("init"===t.command)return void process.stdout.write(await g(t.prompt||s));const e=await l(s);if(t.workflowRenderId)return void process.stdout.write(b(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(R(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(h(e,t.agentRenderId));if("build"===t.command)return void process.stdout.write(await f({workspace:e,workspaceRoot:s,outputDir:t.buildOutput,target:t.buildTarget}));if("stop"===t.command)return clearTimeout(r),void await C(e,t);const p=await d({tools:e.tools.values(),options:{betterCall:{mode:"repair"}}});await y(e);const c=I(e),M=u(),j=w(e.runtime);let $;if($=a({workspace:e,toolGateway:p,approvals:M,memoryProviders:c,adapters:[o()],workflowAdapters:[createCliWorkflowAdapter(p,()=>$)],progressNarration:v(j,e.runtime)?{enabled:!0,style:"cli"}:void 0,qualityReviewModel:createQualityReviewModel(e)}),t.serveOpenAi)return clearTimeout(r),void await A($,t);if(!t.shouldRunRequest)return void process.stdout.write(q(e,s));t.trace&&$.subscribe(e=>{const t=i(e);t&&process.stdout.write(`trace:${t.agentId}:${t.label}${k(t.detail)}\n`)}),$.subscribe(e=>{const t=m(e,j);t&&process.stdout.write(`${t}\n`)});const S=await $.request({input:t.prompt,agentId:t.agentId,sessionId:t.sessionId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0,workflow:t.workflowRunId?{workflowId:t.workflowRunId,input:t.prompt}:void 0});if(t.trace||t.traceJson){const e=$.getRun(S.requestId),r=e?n(e):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:r})}\n`)}process.stdout.write(`${S.output}\n`)}finally{clearTimeout(r)}}function createQualityReviewModel(e){const t=function readQualityModelRef(e){const t=isRecord(e)?e:{},r=isRecord(t.reviewer)?t.reviewer:t;return"string"==typeof r.modelRef&&r.modelRef.trim()?r.modelRef.trim():void 0}(e.runtime.quality),o=t?e.models.get(t):void 0,s=o?r(o):void 0;return function isQualityReviewModel(e){return isRecord(e)&&"function"==typeof e.invoke}(s)?s:void 0}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function createCliWorkflowAdapter(e,t){return s({nodeResolvers:{tools:async({id:t,node:r,request:o,requestId:s,sessionId:a,state:i,workspace:n})=>{return(await e.invoke({toolId:t,args:(u=r.config,d=o.input,l=i.outputs,!0===u?.inputFromState?{...u,requestInput:d,outputs:l}:u&&"requiredInput"in u?u.requiredInput:u&&("args"in u||"cwd"in u||"timeoutMs"in u)?u:"object"==typeof d&&null!==d?d:{}),context:{workspaceRoot:n.root,requestId:s,sessionId:a,agentId:`workflow:${r.id}`,approvalIds:readApprovalIds(o.metadata)}})).output;var u,d,l},agents:async({id:e,node:r,request:o,sessionId:s,state:a})=>{var i,n,u,d;return(await t().request({input:(i=e,n=o.input,u=a.outputs,d=r.config,[`Workflow node agents.${i}: synthesize the workflow evidence into the requested final output.`,`Original request: ${"string"==typeof n?n:JSON.stringify(n)}`,"Requirements:","- Produce the final answer now; do not ask follow-up questions.","- Match the original request language unless workflow config explicitly says otherwise.","- Use only the workflow outputs as evidence; call out uncertainty directly.",...d?[`Workflow node config: ${JSON.stringify(d)}`]:[],"Prior workflow outputs:",JSON.stringify(u)].join("\n")),agentId:e,sessionId:s,metadata:o.metadata})).output}}})}function readApprovalIds(e){const t=e?.approvalIds??e?.approvalId;return"string"==typeof t&&t.trim()?[t.trim()]:Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.trim().length>0):void 0}(function isCliEntrypoint(){const r=process.argv[1];if(!r)return!1;try{return e(t(import.meta.url))===e(r)}catch{return!1}})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { runCli } from "./cli.js";
|
|
2
2
|
export { parseArgs } from "./args.js";
|
|
3
|
+
export { buildWorkspaceArtifact } from "./build.js";
|
|
3
4
|
export { isStableHarnessStartCommand } from "./server.js";
|
|
4
5
|
export { ensureCliMemoryServices } from "./memory/lifecycle.js";
|
|
5
6
|
export { createCliMemoryProviders } from "./memory/providers.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{runCli}from"./cli.js";export{parseArgs}from"./args.js";export{isStableHarnessStartCommand}from"./server.js";export{ensureCliMemoryServices}from"./memory/lifecycle.js";export{createCliMemoryProviders}from"./memory/providers.js";
|
|
1
|
+
export{runCli}from"./cli.js";export{parseArgs}from"./args.js";export{buildWorkspaceArtifact}from"./build.js";export{isStableHarnessStartCommand}from"./server.js";export{ensureCliMemoryServices}from"./memory/lifecycle.js";export{createCliMemoryProviders}from"./memory/providers.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdir as e,writeFile as n}from"node:fs/promises";import{createRequire as t}from"node:module";import s from"node:path";import{fileURLToPath as r,pathToFileURL as a}from"node:url";import{startServer as o}from"@langchain/langgraph-api/server";import{applyLangGraphEnvironment as i}from"./langgraph-env.js";export async function startOfficialLangGraphServer(t,c){const l=t.inspect().workspaceRoot,g=function exposedAgents(e,n){const t=new Set(e.inspect().agents),s=n&&n.length>0?n:[...t].sort();for(const e of s)if(!t.has(e))throw new Error(`LangGraph protocol references unknown agent: ${e}`);return s.map((e,n)=>({id:e,exportName:`agent_${n}_${safeIdentifier(e)}`}))}(t,c.exposeAgents),p=await async function writeBridgeModule(t,o){const i=s.join(t,".stable-harness","langgraph"),c=s.join(i,"bridge.mjs");return await e(i,{recursive:!0}),await n(c,function bridgeSource(e,n){const t=a(s.join(function packageRoot(){return s.resolve(s.dirname(r(import.meta.url)),"../../../..")}(),"dist","index.js")).toString(),o=a(u.resolve("@langchain/langgraph")).toString(),i=n.map(e=>`export const ${e.exportName} = createBridgeGraph(${JSON.stringify(e.id)});`).join("\n");return[(c={workspaceRoot:e,stableHarnessUrl:t,langGraphUrl:o},`import langgraph from ${JSON.stringify(c.langGraphUrl)};\nimport { containsRecoverableResultOutput, createStableHarnessRuntime, loadWorkspaceFromYaml } from ${JSON.stringify(c.stableHarnessUrl)};\n\nconst { END, MessagesZodState, START, StateGraph } = langgraph;\nconst workspaceRoot = ${JSON.stringify(c.workspaceRoot)};\nlet runtimePromise;\nlet workspacePromise;\n`),'function createBridgeGraph(agentId) {\n const graph = new StateGraph(MessagesZodState)\n .addNode("stable_harness", async (state, config) => {\n const runtime = await getRuntime();\n const protocolMessages = normalizeMessages(state.messages);\n const result = await runtime.request({\n input: currentTurnInput(protocolMessages),\n agentId,\n sessionId: readConfigString(config, "thread_id"),\n requestId: readConfigString(config, "run_id"),\n metadata: {\n protocol: "langgraph",\n openaiMessages: contextualMessages(protocolMessages),\n },\n });\n const content = protocolOutput(runtime, result);\n return { messages: [{ type: "ai", content }] };\n })\n .addEdge(START, "stable_harness")\n .addEdge("stable_harness", END);\n const compiled = graph.compile();\n compiled.getGraphAsync = async () => createInspectionGraph(agentId);\n return compiled;\n}\n\nfunction getRuntime() {\n runtimePromise ??= createStableHarnessRuntime(workspaceRoot);\n return runtimePromise;\n}\n','\nfunction currentTurnInput(messages) {\n const message = lastUserMessage(messages) ?? messages.at(-1);\n const content = message?.content ?? "";\n const context = recentContext(messages.slice(0, -1));\n return context ? [\n "Recent conversation context:",\n context,\n "",\n "Current user request:",\n content,\n ].join("\\n") : content;\n}\n\nfunction contextualMessages(messages) {\n const lastUserIndex = messages.findLastIndex((message) => message.role === "user");\n if (lastUserIndex < 0) return messages;\n const context = recentContext(messages.slice(0, lastUserIndex));\n if (!context) return messages;\n return messages.map((message, index) => index === lastUserIndex ? {\n ...message,\n content: [\n "Recent conversation context:",\n context,\n "",\n "Current user request:",\n message.content,\n ].join("\\n"),\n } : message);\n}\n\nfunction lastUserMessage(messages) {\n return [...messages].reverse().find((entry) => entry.role === "user");\n}\n\nfunction recentContext(messages) {\n return messages\n .filter((message) => message.content.trim())\n .slice(-6)\n .map((message) => `${message.role}: ${compactText(message.content)}`)\n .join("\\n\\n");\n}\n\nfunction compactText(value) {\n const normalized = value.replace(/\\s+/gu, " ").trim();\n return normalized.length > 4000 ? `${normalized.slice(0, 4000)}...` : normalized;\n}\n\nfunction normalizeMessages(messages) {\n if (!Array.isArray(messages)) return [];\n return messages.flatMap((message) => {\n const role = messageRole(message);\n const content = messageContent(message);\n return role && content ? [{ role, content }] : [];\n });\n}\n\nfunction messageRole(message) {\n const value = message?.role ?? message?.type;\n if (value === "human") return "user";\n if (value === "ai") return "assistant";\n return value === "system" || value === "user" || value === "assistant" || value === "tool"\n ? value\n : undefined;\n}\n\nfunction messageContent(message) {\n const content = message?.content;\n if (typeof content === "string") return content;\n if (Array.isArray(content)) {\n return content.map((part) => {\n if (typeof part === "string") return part;\n if (typeof part?.text === "string") return part.text;\n if (typeof part?.content === "string") return part.content;\n return "";\n }).filter(Boolean).join("\\n");\n }\n return content == null ? "" : JSON.stringify(content);\n}\n\nfunction readConfigString(config, key) {\n const value = config?.configurable?.[key];\n return typeof value === "string" && value ? value : undefined;\n}\n','function protocolOutput(runtime, result) {\n if (!containsRecoverableResultOutput(result.output, runtime.getRuntimePolicy?.() ?? {})) {\n return result.output;\n }\n return traceFallbackOutput(runtime.inspectRequest(result.requestId)) ?? [\n "The model returned recoverable tool-call or tool-error text instead of a final answer.",\n "stable-harness could not find a completed tool result to project as the Studio response.",\n ].join(" ");\n}\n\nfunction traceFallbackOutput(inspection) {\n const timeline = Array.isArray(inspection?.timeline) ? inspection.timeline : [];\n for (const item of [...timeline].reverse()) {\n const event = item?.event;\n const adapterEvent = event?.type === "runtime.adapter.event" ? event.event : undefined;\n const text = extractText(adapterEvent?.output);\n if (isUsableOutput(text)) return text;\n }\n return undefined;\n}\n\nfunction extractText(value) {\n if (typeof value === "string") {\n const parsed = parseJson(value);\n return parsed === undefined ? value : extractText(parsed);\n }\n if (!value || typeof value !== "object") return undefined;\n if (typeof value.content === "string") return value.content;\n if (typeof value.text === "string") return value.text;\n if (typeof value.output === "string") return extractText(value.output);\n if (typeof value.structuredResponse === "string") return value.structuredResponse;\n const messages = Array.isArray(value.messages) ? value.messages : Array.isArray(value.update?.messages) ? value.update.messages : [];\n for (const message of [...messages].reverse()) {\n const text = extractText(message?.kwargs ?? message);\n if (text) return text;\n }\n return undefined;\n}\n\nfunction parseJson(value) {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction isUsableOutput(value) {\n return typeof value === "string"\n && value.trim().length > 0\n && !containsRecoverableResultOutput(value, { recovery: { toolCall: { enabled: true } } });\n}\n\n','async function createInspectionGraph(agentId) {\n const workspace = await getWorkspace();\n const agent = workspace.agents.get(agentId);\n const snapshot = agent ? {\n tools: agent.tools,\n subagents: agent.subagents,\n skills: agent.skills ?? [],\n } : { tools: [], subagents: [], skills: [] };\n return {\n toJSON() {\n return inventoryGraph(agentId, snapshot);\n },\n };\n}\n\nfunction getWorkspace() {\n workspacePromise ??= loadWorkspaceFromYaml(workspaceRoot);\n return workspacePromise;\n}\n\nfunction inventoryGraph(agentId, snapshot) {\n const nodes = [\n schemaNode("__start__"),\n runnableNode(agentId, "stable-harness agent"),\n ...snapshot.subagents.map((id) => runnableNode("agent_" + id, "agent:" + id)),\n ...snapshot.tools.map((id) => runnableNode("tool_" + id, "tool:" + id)),\n ...snapshot.skills.map((id) => runnableNode("skill_" + id, "skill:" + id)),\n schemaNode("__end__"),\n ];\n const edges = [\n edge("__start__", agentId, false),\n ...snapshot.subagents.map((id) => edge(agentId, "agent_" + id, true)),\n ...snapshot.tools.map((id) => edge(agentId, "tool_" + id, true)),\n ...snapshot.skills.map((id) => edge(agentId, "skill_" + id, true)),\n edge(agentId, "__end__", true),\n ];\n return { nodes, edges };\n}\n\nfunction schemaNode(id) {\n return {\n id,\n type: "schema",\n data: { "$schema": "https://json-schema.org/draft/2020-12/schema" },\n };\n}\n\nfunction runnableNode(id, label) {\n return {\n id,\n type: "runnable",\n data: {\n id: ["stable-harness", label],\n name: label,\n },\n };\n}\n\nfunction edge(source, target, conditional) {\n return { source, target, conditional };\n}\n',i,""].join("\n");var c}(t,o)),{file:c,relativePath:`./${s.relative(t,c).split(s.sep).join("/")}`}}(l,g);await i(l,c);const m=Object.fromEntries(g.map(e=>[e.id,`${p.relativePath}:${e.exportName}`])),d=await o({host:c.host,port:c.port,nWorkers:c.nWorkers,cwd:l,graphs:m});return{url:`http://${d.host}`,cleanup:d.cleanup}}const u=t(import.meta.url);function safeIdentifier(e){const n=e.replace(/[^A-Za-z0-9_$]/gu,"_");return/^[A-Za-z_$]/u.test(n)?n:`_${n}`}
|
|
1
|
+
import{mkdir as e,writeFile as n}from"node:fs/promises";import{createRequire as t}from"node:module";import s from"node:path";import{fileURLToPath as r,pathToFileURL as a}from"node:url";import{startServer as o}from"@langchain/langgraph-api/server";import{applyLangGraphEnvironment as i}from"./langgraph-env.js";export async function startOfficialLangGraphServer(t,c){const l=t.inspect().workspaceRoot,m=function exposedAgents(e,n){const t=new Set(e.inspect().agents),s=n&&n.length>0?n:[...t].sort();for(const e of s)if(!t.has(e))throw new Error(`LangGraph protocol references unknown agent: ${e}`);return s.map((e,n)=>({id:e,exportName:`agent_${n}_${safeIdentifier(e)}`}))}(t,c.exposeAgents),g=await async function writeBridgeModule(t,o){const i=s.join(t,".stable-harness","langgraph"),c=s.join(i,"bridge.mjs");return await e(i,{recursive:!0}),await n(c,function bridgeSource(e,n){const t=a(s.join(function packageRoot(){return s.resolve(s.dirname(r(import.meta.url)),"../../../..")}(),"dist","index.js")).toString(),o=a(u.resolve("@langchain/langgraph")).toString(),i=n.map(e=>`export const ${e.exportName} = createBridgeGraph(${JSON.stringify(e.id)});`).join("\n");return[(c={workspaceRoot:e,stableHarnessUrl:t,langGraphUrl:o},`import langgraph from ${JSON.stringify(c.langGraphUrl)};\nimport { containsRecoverableResultOutput, createStableHarnessRuntime, loadWorkspaceFromYaml, resolveEnabledMemories } from ${JSON.stringify(c.stableHarnessUrl)};\n\nconst { END, MessagesZodState, START, StateGraph } = langgraph;\nconst workspaceRoot = ${JSON.stringify(c.workspaceRoot)};\nlet runtimePromise;\nlet workspacePromise;\n`),'function createBridgeGraph(agentId) {\n const graph = new StateGraph(MessagesZodState)\n .addNode("stable_harness", async (state, config) => {\n const runtime = await getRuntime();\n const protocolMessages = normalizeMessages(state.messages);\n const result = await runtime.request({\n input: currentTurnInput(protocolMessages),\n agentId,\n sessionId: readConfigString(config, "thread_id"),\n requestId: readConfigString(config, "run_id"),\n metadata: {\n protocol: "langgraph",\n openaiMessages: contextualMessages(protocolMessages),\n },\n });\n const content = protocolOutput(runtime, result);\n return { messages: [{ type: "ai", content }] };\n })\n .addEdge(START, "stable_harness")\n .addEdge("stable_harness", END);\n const compiled = graph.compile();\n compiled.getGraphAsync = async () => createInspectionGraph(agentId);\n return compiled;\n}\n\nfunction getRuntime() {\n runtimePromise ??= createStableHarnessRuntime(workspaceRoot);\n return runtimePromise;\n}\n','\nfunction currentTurnInput(messages) {\n const message = lastUserMessage(messages) ?? messages.at(-1);\n const content = message?.content ?? "";\n const context = recentContext(messages.slice(0, -1));\n return context ? [\n "Recent conversation context:",\n context,\n "",\n "Current user request:",\n content,\n ].join("\\n") : content;\n}\n\nfunction contextualMessages(messages) {\n const lastUserIndex = messages.findLastIndex((message) => message.role === "user");\n if (lastUserIndex < 0) return messages;\n const context = recentContext(messages.slice(0, lastUserIndex));\n if (!context) return messages;\n return messages.map((message, index) => index === lastUserIndex ? {\n ...message,\n content: [\n "Recent conversation context:",\n context,\n "",\n "Current user request:",\n message.content,\n ].join("\\n"),\n } : message);\n}\n\nfunction lastUserMessage(messages) {\n return [...messages].reverse().find((entry) => entry.role === "user");\n}\n\nfunction recentContext(messages) {\n return messages\n .filter((message) => message.content.trim())\n .slice(-6)\n .map((message) => `${message.role}: ${compactText(message.content)}`)\n .join("\\n\\n");\n}\n\nfunction compactText(value) {\n const normalized = value.replace(/\\s+/gu, " ").trim();\n return normalized.length > 4000 ? `${normalized.slice(0, 4000)}...` : normalized;\n}\n\nfunction normalizeMessages(messages) {\n if (!Array.isArray(messages)) return [];\n return messages.flatMap((message) => {\n const role = messageRole(message);\n const content = messageContent(message);\n return role && content ? [{ role, content }] : [];\n });\n}\n\nfunction messageRole(message) {\n const value = message?.role ?? message?.type;\n if (value === "human") return "user";\n if (value === "ai") return "assistant";\n return value === "system" || value === "user" || value === "assistant" || value === "tool"\n ? value\n : undefined;\n}\n\nfunction messageContent(message) {\n const content = message?.content;\n if (typeof content === "string") return content;\n if (Array.isArray(content)) {\n return content.map((part) => {\n if (typeof part === "string") return part;\n if (typeof part?.text === "string") return part.text;\n if (typeof part?.content === "string") return part.content;\n return "";\n }).filter(Boolean).join("\\n");\n }\n return content == null ? "" : JSON.stringify(content);\n}\n\nfunction readConfigString(config, key) {\n const value = config?.configurable?.[key];\n return typeof value === "string" && value ? value : undefined;\n}\n','function protocolOutput(runtime, result) {\n if (!containsRecoverableResultOutput(result.output, runtime.getRuntimePolicy?.() ?? {})) {\n return result.output;\n }\n return traceFallbackOutput(runtime.inspectRequest(result.requestId)) ?? [\n "The model returned recoverable tool-call or tool-error text instead of a final answer.",\n "stable-harness could not find a completed tool result to project as the Studio response.",\n ].join(" ");\n}\n\nfunction traceFallbackOutput(inspection) {\n const timeline = Array.isArray(inspection?.timeline) ? inspection.timeline : [];\n for (const item of [...timeline].reverse()) {\n const event = item?.event;\n const adapterEvent = event?.type === "runtime.adapter.event" ? event.event : undefined;\n const text = extractText(adapterEvent?.output);\n if (isUsableOutput(text)) return text;\n }\n return undefined;\n}\n\nfunction extractText(value) {\n if (typeof value === "string") {\n const parsed = parseJson(value);\n return parsed === undefined ? value : extractText(parsed);\n }\n if (!value || typeof value !== "object") return undefined;\n if (typeof value.content === "string") return value.content;\n if (typeof value.text === "string") return value.text;\n if (typeof value.output === "string") return extractText(value.output);\n if (typeof value.structuredResponse === "string") return value.structuredResponse;\n const messages = Array.isArray(value.messages) ? value.messages : Array.isArray(value.update?.messages) ? value.update.messages : [];\n for (const message of [...messages].reverse()) {\n const text = extractText(message?.kwargs ?? message);\n if (text) return text;\n }\n return undefined;\n}\n\nfunction parseJson(value) {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction isUsableOutput(value) {\n return typeof value === "string"\n && value.trim().length > 0\n && !containsRecoverableResultOutput(value, { recovery: { toolCall: { enabled: true } } });\n}\n\n','async function createInspectionGraph(agentId) {\n const workspace = await getWorkspace();\n const agent = workspace.agents.get(agentId);\n const snapshot = agent ? {\n tools: agent.tools,\n subagents: agent.subagents,\n skills: agent.skills ?? [],\n memories: resolveInspectionMemories(workspace, agent),\n } : { tools: [], subagents: [], skills: [], memories: [] };\n return {\n toJSON() {\n return inventoryGraph(agentId, snapshot);\n },\n };\n}\n\nfunction getWorkspace() {\n workspacePromise ??= loadWorkspaceFromYaml(workspaceRoot);\n return workspacePromise;\n}\n\nfunction inventoryGraph(agentId, snapshot) {\n const nodes = [\n schemaNode("__start__"),\n runnableNode(agentId, "stable-harness agent"),\n ...snapshot.subagents.map((id) => runnableNode("agent_" + id, "agent:" + id)),\n ...snapshot.tools.map((id) => runnableNode("tool_" + id, "tool:" + id)),\n ...snapshot.skills.map((id) => runnableNode("skill_" + id, "skill:" + id)),\n ...snapshot.memories.map((id) => runnableNode("memory_" + safeNodeId(id), "memory:" + id)),\n schemaNode("__end__"),\n ];\n const edges = [\n edge("__start__", agentId, false),\n ...snapshot.subagents.map((id) => edge(agentId, "agent_" + id, true)),\n ...snapshot.tools.map((id) => edge(agentId, "tool_" + id, true)),\n ...snapshot.skills.map((id) => edge(agentId, "skill_" + id, true)),\n ...snapshot.memories.map((id) => edge(agentId, "memory_" + safeNodeId(id), true)),\n edge(agentId, "__end__", true),\n ];\n return { nodes, edges };\n}\n\nfunction resolveInspectionMemories(workspace, agent) {\n const runtimeMemories = resolveEnabledMemories(workspace, "all").map((memory) => memory.id);\n const agentMemories = Array.isArray(agent.memory) ? agent.memory.flatMap((memory, index) => {\n if (typeof memory === "string" && memory.trim()) return [memory.trim()];\n if (typeof memory?.path === "string" && memory.path.trim()) return [memory.path.trim()];\n return ["agent-memory-" + index];\n }) : [];\n return [...new Set([...agentMemories, ...runtimeMemories])];\n}\n\nfunction schemaNode(id) {\n return {\n id,\n type: "schema",\n data: { "$schema": "https://json-schema.org/draft/2020-12/schema" },\n };\n}\n\nfunction runnableNode(id, label) {\n return {\n id,\n type: "runnable",\n data: {\n id: ["stable-harness", label],\n name: label,\n },\n };\n}\n\nfunction edge(source, target, conditional) {\n return { source, target, conditional };\n}\n\nfunction safeNodeId(value) {\n return String(value).replace(/[^A-Za-z0-9_$]/gu, "_");\n}\n',i,""].join("\n");var c}(t,o)),{file:c,relativePath:`./${s.relative(t,c).split(s.sep).join("/")}`}}(l,m);await i(l,c);const p=Object.fromEntries(m.map(e=>[e.id,`${g.relativePath}:${e.exportName}`])),d=await o({host:c.host,port:c.port,nWorkers:c.nWorkers,cwd:l,graphs:p});return{url:`http://${d.host}`,cleanup:d.cleanup}}const u=t(import.meta.url);function safeIdentifier(e){const n=e.replace(/[^A-Za-z0-9_$]/gu,"_");return/^[A-Za-z_$]/u.test(n)?n:`_${n}`}
|
|
@@ -6,11 +6,13 @@ export * from "./recovery/tool-call.js";
|
|
|
6
6
|
export * from "./runtime/persistence/inspection.js";
|
|
7
7
|
export { createWorkspaceSandboxPolicy } from "./runtime/governance/sandbox.js";
|
|
8
8
|
export * from "./memory-plugins.js";
|
|
9
|
+
export { resolveEnabledMemories } from "./memory-plugins/shared.js";
|
|
9
10
|
export * from "./runtime/persistence/queue.js";
|
|
10
11
|
export * from "./runtime/policy/projection.js";
|
|
11
12
|
export * from "./runtime.js";
|
|
12
13
|
export * from "./runtime/selection-repair.js";
|
|
13
14
|
export * from "./runtime/tool-failure.js";
|
|
15
|
+
export * from "./runtime/tracing/langsmith.js";
|
|
14
16
|
export * from "./runtime/policy/tool-invocation.js";
|
|
15
17
|
export * from "./runtime/persistence/stores.js";
|
|
16
18
|
export * from "./trace.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./runtime/persistence/artifacts.js";export*from"./boundary-scan.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export{createWorkspaceSandboxPolicy}from"./runtime/governance/sandbox.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime/policy/projection.js";export*from"./runtime.js";export*from"./runtime/selection-repair.js";export*from"./runtime/tool-failure.js";export*from"./runtime/policy/tool-invocation.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workspace/tool-quality.js";export*from"./evaluations/index.js";export*from"./quality/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
|
|
1
|
+
export*from"./runtime/persistence/artifacts.js";export*from"./boundary-scan.js";export*from"./execution-contract.js";export*from"./recovery/tool-call.js";export*from"./runtime/persistence/inspection.js";export{createWorkspaceSandboxPolicy}from"./runtime/governance/sandbox.js";export*from"./memory-plugins.js";export{resolveEnabledMemories}from"./memory-plugins/shared.js";export*from"./runtime/persistence/queue.js";export*from"./runtime/policy/projection.js";export*from"./runtime.js";export*from"./runtime/selection-repair.js";export*from"./runtime/tool-failure.js";export*from"./runtime/tracing/langsmith.js";export*from"./runtime/policy/tool-invocation.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workspace/tool-quality.js";export*from"./evaluations/index.js";export*from"./quality/index.js";export*from"./spec-driven/index.js";export*from"./workflows/index.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Client } from "langsmith";
|
|
2
|
+
import type { RuntimeCapabilityModule } from "../capabilities.js";
|
|
3
|
+
import type { RuntimeRunRecord, RuntimeStore } from "../types.js";
|
|
4
|
+
import type { WorkspaceRuntimePolicy } from "../../workspace/types.js";
|
|
5
|
+
export type LangSmithTraceClient = {
|
|
6
|
+
createRun(run: LangSmithRunCreate): Promise<void>;
|
|
7
|
+
flush?(): Promise<void>;
|
|
8
|
+
awaitPendingTraceBatches?(): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
type LangSmithRunCreate = Parameters<Client["createRun"]>[0];
|
|
11
|
+
export type RuntimeLangSmithTracingOptions = {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
projectName?: string;
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
workspaceId?: string;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
client?: LangSmithTraceClient;
|
|
19
|
+
failOnError?: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function createLangSmithTracingCapability(input: {
|
|
22
|
+
policy: WorkspaceRuntimePolicy;
|
|
23
|
+
store: RuntimeStore;
|
|
24
|
+
options?: RuntimeLangSmithTracingOptions | false;
|
|
25
|
+
}): RuntimeCapabilityModule | undefined;
|
|
26
|
+
export declare function createLangSmithRunTree(run: RuntimeRunRecord, options?: RuntimeLangSmithTracingOptions): LangSmithRunCreate;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as t}from"node:crypto";import{projectRuntimeTraceSpans as e}from"../../trace.js";export function createLangSmithTracingCapability(t){const e=function resolveOptions(t,e){if(!1===e)return{enabled:!1};const n=function readLangSmithConfig(t){const e=readRecord(t.tracing),n=readRecord(e?.langsmith);return{enabled:readBoolean(n?.enabled),projectName:readString(n?.projectName)??readString(n?.project),apiKey:readString(n?.apiKey),apiUrl:readString(n?.apiUrl),workspaceId:readString(n?.workspaceId),tags:(r=n?.tags,Array.isArray(r)?r.filter(t=>"string"==typeof t&&t.trim().length>0):void 0),failOnError:readBoolean(n?.failOnError)};var r}(t);return{...n,...e,enabled:e?.enabled??n.enabled??!1}}(t.policy,t.options);if(!e.enabled)return;const n=function createClientResolver(t){let e;return()=>(e??=async function resolveClient(t){if(t.client)return t.client;const{Client:e}=await import("langsmith");return new e({apiKey:t.apiKey,apiUrl:t.apiUrl,workspaceId:t.workspaceId,autoBatchTracing:!0})}(t),e)}(e),r=function createLangSmithExporter(t,e,n){return async r=>{const a=await n(),i=e.getRun(r);i&&(await a.createRun(createLangSmithRunTree(i,t)),await flushClient(a))}}(e,t.store,n),a=new Set,i=[];return{id:"runtime.tracing.langsmith",onEvent(t){if(!function isTerminalRequestEvent(t){return"runtime.request.completed"===t.type||"runtime.request.failed"===t.type||"runtime.request.cancelled"===t.type}(t))return;const e=r(t.requestId).catch(t=>{i.push(t)});a.add(e),e.finally(()=>a.delete(e)).catch(()=>{})},async stop(){if(await Promise.allSettled([...a]),await flushClient(await n()),e.failOnError&&i[0])throw i[0]}}}export function createLangSmithRunTree(t,n={}){const r=e(t),a=r.find(t=>"run"===t.kind)??r[0];if(!a)return function createFallbackRun(t,e){return{id:stableUuid(`run:${t.requestId}`),name:t.agentId,run_type:"chain",start_time:t.startedAt,end_time:t.completedAt,inputs:{input:t.input},outputs:t.output?{output:t.output}:void 0,error:t.error,project_name:e.projectName}}(t,n);const i=stableUuid(a.spanId);return{...toLangSmithRun(a,i,n),child_runs:childRuns(a.spanId,r,i,n)}}async function flushClient(t){await(t.flush?.()),await(t.awaitPendingTraceBatches?.())}function toLangSmithRun(t,e,n){return{id:stableUuid(t.spanId),name:t.name,run_type:"tool"===t.kind?"tool":"chain",start_time:t.startedAt,end_time:t.completedAt,inputs:{spanId:t.spanId},outputs:"failed"===t.status?void 0:{status:t.status},error:"failed"===t.status?String(t.attributes?.error??"failed"):void 0,parent_run_id:t.parentSpanId?stableUuid(t.parentSpanId):void 0,trace_id:e,project_name:n.projectName,extra:{metadata:metadataForSpan(t,n)}}}function childRuns(t,e,n,r){return e.filter(e=>e.parentSpanId===t).map(t=>({...toLangSmithRun(t,n,r),child_runs:childRuns(t.spanId,e,n,r)}))}function metadataForSpan(t,e){return{stableHarness:{requestId:t.requestId,sessionId:t.sessionId,agentId:t.agentId,kind:t.kind,status:t.status,startEventIndex:t.startEventIndex,endEventIndex:t.endEventIndex,durationMs:t.durationMs,events:t.events,attributes:t.attributes,tags:["stable-harness",...e.tags??[]]}}}function stableUuid(e){const n=t("sha256").update(e).digest("hex").slice(0,32);return`${n.slice(0,8)}-${n.slice(8,12)}-4${n.slice(13,16)}-8${n.slice(17,20)}-${n.slice(20,32)}`}function readRecord(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}function readString(t){return"string"==typeof t&&t.trim()?t.trim():void 0}function readBoolean(t){return"boolean"==typeof t?t:void 0}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApprovalQueue } from "@stable-harness/governance";
|
|
2
2
|
import type { MemoryProvider, RuntimeMemoryStore } from "@stable-harness/memory";
|
|
3
3
|
import type { QualityReviewModel } from "./quality/index.js";
|
|
4
|
+
import { createLangSmithTracingCapability } from "./runtime/tracing/langsmith.js";
|
|
4
5
|
import type { CompiledWorkspace, RuntimeCapabilityModule, RuntimeToolGateway, RuntimeAdapter, RuntimeArtifactStore, RuntimeSandboxPolicy, RuntimeStore, RuntimeProgressNarrationOptions, RuntimeWorkflowAdapter, StableHarnessRuntime } from "./types.js";
|
|
5
6
|
type RuntimeFactoryInput = {
|
|
6
7
|
workspace: CompiledWorkspace;
|
|
@@ -16,6 +17,7 @@ type RuntimeFactoryInput = {
|
|
|
16
17
|
progressNarration?: RuntimeProgressNarrationOptions | false;
|
|
17
18
|
qualityReviewModel?: QualityReviewModel;
|
|
18
19
|
capabilities?: RuntimeCapabilityModule[];
|
|
20
|
+
langSmithTracing?: false | Parameters<typeof createLangSmithTracingCapability>[0]["options"];
|
|
19
21
|
};
|
|
20
22
|
export declare function createStableHarnessRuntime(input: RuntimeFactoryInput): StableHarnessRuntime;
|
|
21
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{assertNoRawToolCallOutput as r,assertNoToolExecutionErrorOutput as a,buildAdapterErrorRecoveryPrompt as o,buildEvidenceSynthesisOutput as s,buildExecutionContractRecoveryRequest as n,buildResultRecoveryRequest as i,containsRawToolCallOutput as u,isRecoverableAdapterError as c,rawToolCallFailureMessage as l,toolCallRecoveryEnabled as p}from"./recovery/tool-call.js";import{recoverQualityReview as d,resolveQualityPolicy as m}from"./quality/index.js";import{completeRun as w,failRun as y}from"./runtime/completion.js";import{runDirectToolCall as f}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{assertExecutionContract as t}from"./execution-contract.js";import{assertNoRawToolCallOutput as r,assertNoToolExecutionErrorOutput as a,buildAdapterErrorRecoveryPrompt as o,buildEvidenceSynthesisOutput as s,buildExecutionContractRecoveryRequest as n,buildResultRecoveryRequest as i,containsRawToolCallOutput as u,isRecoverableAdapterError as c,rawToolCallFailureMessage as l,toolCallRecoveryEnabled as p}from"./recovery/tool-call.js";import{recoverQualityReview as d,resolveQualityPolicy as m}from"./quality/index.js";import{completeRun as w,failRun as y}from"./runtime/completion.js";import{runDirectToolCall as f}from"./runtime/direct-tool-call.js";import{createApprovalGatedToolGateway as g}from"./runtime/governance/approval-gate.js";import{createSandboxedToolGateway as I}from"./runtime/governance/sandbox.js";import{createRuntimeInspectionMethods as q}from"./runtime/inspection/methods.js";import{createRuntimeCapabilityRegistry as R,normalizeAdapterResult as v}from"./runtime/capabilities.js";import{createMemoryRuntimeCapability as b}from"./runtime/memory.js";import{createInMemoryRuntimeStore as k}from"./runtime/persistence/stores.js";import{createProgressNarrationCapability as A}from"./runtime/progress-narration.js";import{repairRuntimeSelection as C}from"./runtime/selection-repair.js";import{createLangSmithTracingCapability as x}from"./runtime/tracing/langsmith.js";import{createToolFailureTracker as h}from"./runtime/tool-failure.js";import{runWorkflowRequest as j}from"./workflows/runtime.js";export function createStableHarnessRuntime(t){const r=new Set,a=t.store??k(),s=R([b(t),A({options:t.progressNarration,policy:t.workspace.runtime}),x({policy:t.workspace.runtime,store:a,options:t.langSmithTracing}),...t.capabilities??[]]),emitBase=t=>{const o=function enrichRuntimeEvent(t){return{...t,eventId:t.eventId??e(),emittedAt:t.emittedAt??(new Date).toISOString()}}(t);a.appendEvent(o);for(const e of r)e(o)},emit=e=>{emitBase(e),s.emitSideEffects(e,emitBase)},i=I({gateway:g({gateway:t.toolGateway,approvals:t.approvals,workspace:t.workspace,emit:emit}),workspace:t.workspace,sandbox:t.sandbox,emit:emit}),u={...t,toolGateway:i},l=h(function readToolFailurePolicy(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const t=e.failurePolicy;return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}(t.workspace.runtime.toolGateway));return{request:async t=>async function runRuntimeRequest(t){const r=t.request.requestId??e(),a=t.request.sessionId??e(),s=[],{agent:i,adapter:u}=await async function resolveExecution(e,t,r){const a=t.agentId?await async function resolveRequestedAgentId(e,t,r){if(e.agents.has(t))return t;const a=await C({id:t,candidates:[...e.agents.values()].map(e=>({id:e.id,description:e.description})),trace:{...r,agentId:t,layer:"agent",owner:"stable_runtime_policy"}});return a.ok?a.id:t}(e.workspace,t.agentId,r):function resolveRoutedAgentId(e,t){for(const r of e.runtime.routes??[])if(routeMatches(r,t))return r.agentId;return e.runtime.defaultAgentId}(e.workspace,t.input),o=e.workspace.agents.get(a);if(!o)throw new Error(`Agent ${a} is not defined in the workspace`);if(t.toolCall||t.workflow)return{agent:o,adapter:void 0};const s=e.adapters.find(e=>e.canRun(o));if(!s)throw new Error(`No runtime adapter can run backend ${o.backend} for agent ${o.id}`);return{agent:o,adapter:s}}(t.input,t.request,{requestId:r,sessionId:a,emit:e=>s.push(e)});t.store.createRun(function createRunRecord(e,t,r,a){return{requestId:t,sessionId:r,agentId:a.id,input:e.input,state:"running",parentRunId:e.parentRunId,metadata:e.metadata,artifacts:[],startedAt:(new Date).toISOString(),events:[]}}(t.request,r,a,i)),s.forEach(t.emit),t.emit({type:"runtime.request.started",requestId:r,sessionId:a,agentId:i.id,input:t.request.input});try{if(t.request.workflow){const e=await j({workspace:t.input.workspace,adapters:t.input.workflowAdapters??[],toolGateway:t.input.toolGateway,request:{input:t.request.input,...t.request.workflow},requestId:r,sessionId:a,agentId:i.id,emit:t.emit});return w({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,result:e,artifacts:t.input.artifacts})}if(t.request.toolCall){const e=await f({gateway:t.input.toolGateway,workspace:t.input.workspace,emit:t.emit,request:t.request,requestId:r,sessionId:a,agent:i,toolFailureTracker:t.toolFailureTracker});return w({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,result:e,artifacts:t.input.artifacts})}return await async function runAdapterRequest(e){if(!e.adapter)throw new Error(`No runtime adapter can run backend ${e.agent.backend} for agent ${e.agent.id}`);const t=e.adapter,r=await e.capabilities.beforeAdapterRun(createCapabilityContext(e)),a=r.memory,s=r.pluginMemories??[],i=e.input.workspace.runtime,u=m(e.input.workspace.runtime,e.agent),l=new Map;let p;try{p=await runAdapterOnce(e,t,e.request,a,s,l)}catch(r){if(!c(r,i))throw r;p=await runAdapterOnce(e,t,o(e.request,r,i),a,s,l)}p=await recoverAdapterResultOutput(e,t,e.request,p,a,s,i,l),p=await d(createQualityRuntimeInput(e,a,s,l),e.request,p,u),await e.capabilities.beforeAdapterResultContract({...createCapabilityContext(e),result:p});try{assertRequestExecutionContract(e)}catch(r){const o=n({request:e.request,events:e.store.getRun(e.requestId)?.events??[],policy:i});if(!o)throw r;p=await runAdapterOnce(e,t,o,a,s,l),p=await recoverAdapterResultOutput(e,t,o,p,a,s,i,l),p=await d(createQualityRuntimeInput(e,a,s,l),o,p,u),assertRequestExecutionContract(e)}const y=w({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,result:p,artifacts:e.input.artifacts});return await e.capabilities.afterAdapterResponse({...createCapabilityContext(e),result:p,response:y}),y}({...t,adapter:u,requestId:r,sessionId:a,agent:i})}catch(e){return y({store:t.store,emit:t.emit,requestId:r,sessionId:a,agent:i,error:e})}}({input:u,capabilities:s,store:a,emit:emit,request:t,toolFailureTracker:l}),subscribe:e=>(r.add(e),()=>r.delete(e)),...q({workspace:t.workspace,store:a,artifacts:t.artifacts,approvals:t.approvals,emit:emit}),cancel(e,t){const r=a.getRun(e);r&&"running"===r.state&&(a.updateRun(e,{state:"cancelled",completedAt:(new Date).toISOString()}),emit({type:"runtime.request.cancelled",requestId:e,sessionId:r.sessionId,agentId:r.agentId,reason:t}))},async stop(){await s.stop(),r.clear()}}}function createCapabilityContext(e){return{workspace:e.input.workspace,store:e.store,emit:e.emit,request:e.request,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent}}function createQualityRuntimeInput(e,t,r,a){return{workspace:e.input.workspace,agent:e.agent,request:e.request,requestId:e.requestId,sessionId:e.sessionId,events:e.store.getRun(e.requestId)?.events??[],emit:e.emit,getEvents:()=>e.store.getRun(e.requestId)?.events??[],runAdapter:o=>runAdapterOnce(e,e.adapter,o,t,r,a),reviewModel:e.input.qualityReviewModel,memory:t,pluginMemories:r}}async function recoverAdapterResultOutput(e,t,o,n,c,d,m,w){let y=o;const f=function resultRecoveryAttempts(e){const t="object"!=typeof e||null===e||Array.isArray(e)?void 0:e.recovery,r="object"!=typeof t||null===t||Array.isArray(t)?void 0:t.toolCall,a="object"!=typeof r||null===r||Array.isArray(r)?void 0:r.maxResultRecoveryAttempts;return"number"==typeof a&&Number.isInteger(a)&&a>0?a:3}(m);let g=0;for(let r=0;r<f;r+=1){const r=e.store.getRun(e.requestId)?.events??[],a=i({request:y,output:n.text,events:r.slice(g),availableToolIds:e.agent.tools,policy:m});if(!a)break;y=a,g=e.store.getRun(e.requestId)?.events.length??0,n=await runAdapterOnce(e,t,a,c,d,w)}if(p(m)){let t=!1;u(n.text,m)&&function rawToolCallFailureReturnsMessage(e){return"message"===("object"!=typeof e?.toolCallRecovery||null===e.toolCallRecovery||Array.isArray(e.toolCallRecovery)?{}:e.toolCallRecovery).onFailure}(o.metadata)&&(n={...n,text:l(),metadata:{...n.metadata,toolCallRecovery:{failed:!0,reason:"raw_tool_call_output"}}});const i=s({request:o,output:n.text,events:e.store.getRun(e.requestId)?.events??[],policy:m});i&&(t=!0,n={...n,text:i,metadata:{...n.metadata,toolCallRecovery:{synthesized:!0,reason:"raw_tool_call_output_with_evidence"}}}),t||(r(n.text,m),a(n.text,m))}return n}function assertRequestExecutionContract(e){t({store:e.store,emit:e.emit,requestId:e.requestId,sessionId:e.sessionId,agent:e.agent,metadata:e.request.metadata})}async function runAdapterOnce(e,t,r,a,o,s){return v(await t.run({workspace:e.input.workspace,agent:e.agent,request:r,requestId:e.requestId,sessionId:e.sessionId,memory:a,pluginMemories:o,toolGateway:e.input.toolGateway,toolFailureTracker:e.input.toolFailureTracker,requestState:s,getEvents:()=>e.store.getRun(e.requestId)?.events??[],emit:e.emit}))}function routeMatches(e,t){if(e.pattern)try{if(new RegExp(e.pattern,"iu").test(t))return!0}catch{return!1}const r=t.toLowerCase();return(e.keywords??[]).some(e=>r.includes(e.toLowerCase()))}
|
|
@@ -66,6 +66,7 @@ export type WorkspaceRuntimePolicy = {
|
|
|
66
66
|
sandbox?: Record<string, unknown>;
|
|
67
67
|
memory?: Record<string, unknown>;
|
|
68
68
|
protocols?: Record<string, unknown>;
|
|
69
|
+
tracing?: Record<string, unknown>;
|
|
69
70
|
progress?: Record<string, unknown>;
|
|
70
71
|
cli?: Record<string, unknown>;
|
|
71
72
|
quality?: string | Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await loadModuleTool(t);o&&e.push(o)}return t(e,o.options)}async function loadModuleTool(t){if(!t.sourcePath)return;const n=await import(e(o.resolve(t.sourcePath)).href),r=n[t.name??t.id]??n.default;return function hasInvoke(o){return"object"==typeof o&&null!==o&&"invoke"in o&&"function"==typeof o.invoke}(r)?{id:t.id,description:t.description??r.description,schema:t.schema??r.schema,validateArgs:r.validateArgs,invoke:(o,e)=>async function invokeWithWorkspaceCwd(o,e,t){const n=process.cwd();try{return process.chdir(t.workspaceRoot),await o(e,t)}finally{process.chdir(n)}}(r.invoke,o,e)}:void 0}
|
|
1
|
+
import o from"node:path";import{pathToFileURL as e}from"node:url";import{createInMemoryToolGateway as t}from"./in-memory.js";export async function createModuleToolGateway(o){const e=[];for(const t of o.tools){const o=await loadModuleTool(t);o&&e.push(o)}return t(e,o.options)}async function loadModuleTool(t){if(!t.sourcePath||!function isJavaScriptModule(e){const t=o.extname(e);return".mjs"===t||".js"===t||".cjs"===t}(t.sourcePath))return;const n=await import(e(o.resolve(t.sourcePath)).href),r=n[t.name??t.id]??n.default;return function hasInvoke(o){return"object"==typeof o&&null!==o&&"invoke"in o&&"function"==typeof o.invoke}(r)?{id:t.id,description:t.description??r.description,schema:t.schema??r.schema,validateArgs:r.validateArgs,invoke:(o,e)=>async function invokeWithWorkspaceCwd(o,e,t){const n=process.cwd();try{return process.chdir(t.workspaceRoot),await o(e,t)}finally{process.chdir(n)}}(r.invoke,o,e)}:void 0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|
|
1
|
+
import{assertSpecDrivenWorkflowPolicy as e,createSpecDrivenWorkflowPolicy as r}from"@stable-harness/core";function assertRecord(e,r){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error(`${r} must be an object`);return e}function readName(e,r){const t=e.metadata?.name;if("string"==typeof t&&t.trim())return t.trim();if(r)return r;throw new Error(`Document kind ${String(e.kind)} requires metadata.name`)}function readDescription(e){const r=e.metadata?.description;return"string"==typeof r&&r.trim()?r.trim():void 0}function readOptionalString(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function toStringArray(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.trim().length>0):[]}function resolveValue(e){if("string"!=typeof e)return e;const r=e.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return r?process.env[r[1]]??r[2]??"":e}export function compileRuntime(e){const r=assertRecord(e.spec,"Runtime.spec"),t=assertRecord(r.routing??{},"Runtime.spec.routing");return{defaultAgentId:"string"==typeof t.defaultAgentId&&t.defaultAgentId.trim()?t.defaultAgentId.trim():"orchestra",...void 0!==t.routes?{routes:readAgentRoutes(t.routes)}:{},...readOptionalString(r.workspaceId)?{workspaceId:readOptionalString(r.workspaceId)}:{},...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...void 0!==r.adapters?{adapters:readAdapters(r.adapters)}:{},..."object"==typeof r.workflowRouting&&r.workflowRouting?{workflowRouting:readWorkflowRouting(r.workflowRouting)}:{},..."object"==typeof r.specDrivenWorkflow&&r.specDrivenWorkflow?{specDrivenWorkflow:readSpecDrivenWorkflow(r.specDrivenWorkflow)}:{},..."object"==typeof r.approvals&&r.approvals?{approvals:r.approvals}:{},..."object"==typeof r.recovery&&r.recovery?{recovery:r.recovery}:{},..."object"==typeof r.retry&&r.retry?{retry:r.retry}:{},..."object"==typeof r.toolGateway&&r.toolGateway?{toolGateway:r.toolGateway}:{},..."object"==typeof r.memory&&r.memory?{memory:r.memory}:{},..."object"==typeof r.protocols&&r.protocols?{protocols:r.protocols}:{},..."object"==typeof r.tracing&&r.tracing?{tracing:r.tracing}:{},..."object"==typeof r.progress&&r.progress?{progress:r.progress}:{},..."object"==typeof r.cli&&r.cli?{cli:r.cli}:{},..."string"==typeof r.quality||"object"==typeof r.quality&&r.quality?{quality:r.quality}:{},..."object"==typeof r.workspaceValidation&&r.workspaceValidation?{workspaceValidation:r.workspaceValidation}:{},..."object"==typeof r.responseLanguage&&r.responseLanguage?{responseLanguage:r.responseLanguage}:{},..."object"==typeof r.responsePresentation&&r.responsePresentation?{responsePresentation:r.responsePresentation}:{}}}function readAgentRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.routing.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.routing.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.agentId);if(!t||!o)throw new Error("Runtime.spec.routing.routes[] requires id and agentId");const n=void 0===r.keywords?void 0:function assertStringArray(e,r){if(!Array.isArray(e))throw new Error(`${r} must be an array`);return e.map(e=>{if("string"!=typeof e||!e.trim())throw new Error(`${r} must contain non-empty strings`);return e.trim()})}(r.keywords,"Runtime.spec.routing.routes[].keywords"),i=readOptionalString(r.pattern);if(!(n&&0!==n.length||i))throw new Error("Runtime.spec.routing.routes[] requires keywords or pattern");return{id:t,agentId:o,...n&&n.length>0?{keywords:n}:{},...i?{pattern:i}:{},...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{}}})}function readSpecDrivenWorkflow(t){const o=assertRecord(t,"Runtime.spec.specDrivenWorkflow"),n=r({enabled:!0===o.enabled,constitution:readOptionalString(o.constitution),artifactsDir:readOptionalString(o.artifactsDir),phases:void 0===o.phases?void 0:readSpecDrivenPhases(o.phases),..."object"==typeof o.gates&&o.gates?{gates:o.gates}:{},..."object"==typeof o.config&&o.config?{config:o.config}:{}});return e(n),n}function readSpecDrivenPhases(e){if(!Array.isArray(e))throw new Error("Runtime.spec.specDrivenWorkflow.phases must be an array");return e.map(e=>{if("string"==typeof e&&e.trim())return{id:e.trim()};const r=assertRecord(e,"Runtime.spec.specDrivenWorkflow.phases[]"),t=readOptionalString(r.id);if(!t)throw new Error("Runtime.spec.specDrivenWorkflow.phases[] requires id");return{id:t,...readOptionalString(r.artifactKind)?{artifactKind:readOptionalString(r.artifactKind)}:{},..."boolean"==typeof r.required?{required:r.required}:{},...readOptionalString(r.gate)?{gate:readOptionalString(r.gate)}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}})}export function compileAgent(e,r){const t=assertRecord(e.spec,"Agent.spec"),o=readName(e),n=readOptionalString(t.backend);if(!n)throw new Error(`Agent ${o} requires spec.backend`);const i="object"==typeof t.config&&t.config?t.config:{},a="string"==typeof t.systemPrompt?t.systemPrompt:"string"==typeof i.systemPrompt?i.systemPrompt:void 0;return{id:o,...readDescription(e)?{description:readDescription(e)}:{},sourcePath:r,backend:n,..."string"==typeof t.modelRef&&t.modelRef.trim()?{modelRef:(s=t.modelRef,s.replace(/^[^/]+\//u,""))}:{},...void 0!==a?{systemPrompt:a}:{},tools:toStringArray(t.tools),skills:toStringArray(t.skills),memory:Array.isArray(t.memory)?t.memory:[],subagents:toStringArray(t.subagents),...void 0!==t.edges?{edges:readAgentEdges(t.edges,o)}:{},config:i};var s}export function compileModel(e){return compileModelSpec(assertRecord(e.spec,"Model.spec"),readName(e))}export function compileModelSpec(e,r){const t="string"==typeof e.name&&e.name.trim()?e.name.trim():r??"default",o=resolveValue(e.provider),n=resolveValue(e.model),i="string"==typeof o&&o.trim()?o.trim():"unknown",a="string"==typeof n&&n.trim()?n.trim():t,s={...e};return delete s.name,delete s.provider,delete s.model,{id:t,provider:i,model:a,config:Object.fromEntries(Object.entries(s).map(([e,r])=>[e,resolveValue(r)]))}}export function compileTool(e,r){const t=assertRecord(e.spec,"Tool.spec");return{id:readName(e),...r?{sourcePath:r}:{},..."string"==typeof t.description?{description:t.description}:{},...void 0!==t.schema?{schema:t.schema}:{},...void 0!==t.outputSchema?{outputSchema:t.outputSchema}:{},..."object"==typeof t.metadata&&t.metadata?{metadata:t.metadata}:{},..."string"==typeof t.implementation?{implementation:t.implementation}:{}}}export function compileMemory(e){const r=assertRecord(e.spec,"Memory.spec"),t=readName(e),o={...r};return delete o.provider,delete o.profile,delete o.mode,delete o.enabled,delete o.prompts,{id:t,provider:readOptionalString(r.provider)??"langmem",...readOptionalString(r.profile)?{profile:readOptionalString(r.profile)}:{},...readOptionalString(r.mode)?{mode:readOptionalString(r.mode)}:{},enabled:!1!==r.enabled,..."object"==typeof r.prompts&&r.prompts?{prompts:readMemoryPrompts(r.prompts)}:{},...Object.keys(o).length>0?{config:o}:{}}}function readWorkflowRouting(e){const r=assertRecord(e,"Runtime.spec.workflowRouting"),t=void 0===r.routes?void 0:function readWorkflowRoutes(e){if(!Array.isArray(e))throw new Error("Runtime.spec.workflowRouting.routes must be an array");return e.map(e=>{const r=assertRecord(e,"Runtime.spec.workflowRouting.routes[]"),t=readOptionalString(r.id),o=readOptionalString(r.workflowId);if(!t||!o)throw new Error("Runtime.spec.workflowRouting.routes[] requires id and workflowId");return{id:t,workflowId:o,...readOptionalString(r.description)?{description:readOptionalString(r.description)}:{},..."object"==typeof r.metadata&&r.metadata?{metadata:r.metadata}:{}}})}(r.routes);return{...readOptionalString(r.defaultWorkflowId)?{defaultWorkflowId:readOptionalString(r.defaultWorkflowId)}:{},...t?{routes:t}:{}}}function readAdapters(e){if(!Array.isArray(e))throw new Error("Runtime.spec.adapters must be an array");return e.map(readAdapter)}function readAgentEdges(e,r){if(!Array.isArray(e))throw new Error(`Agent ${r} spec.edges must be an array`);return e.map(e=>{const t=assertRecord(e,`Agent ${r} spec.edges[]`),o=readOptionalString(t.from),n=readOptionalString(t.to);if(!o||!n)throw new Error(`Agent ${r} spec.edges[] requires from and to`);return{from:o,to:n,...readOptionalString(t.condition)?{condition:readOptionalString(t.condition)}:{}}})}function readAdapter(e){if("string"==typeof e&&e.trim())return{name:e.trim()};const r=assertRecord(e,"Runtime.spec.adapters[]"),t=readOptionalString(r.name)??readOptionalString(r.id)??readOptionalString(r.backend);if(!t)throw new Error("Runtime.spec.adapters[] requires name");return{name:t,..."boolean"==typeof r.enabled?{enabled:r.enabled}:{},..."object"==typeof r.config&&r.config?{config:r.config}:{}}}function readMemoryPrompts(e){const r=assertRecord(e,"Memory.spec.prompts");return{...readOptionalString(r.semantic)?{semantic:readOptionalString(r.semantic)}:{},...readOptionalString(r.episodic)?{episodic:readOptionalString(r.episodic)}:{},...readOptionalString(r.procedural)?{procedural:readOptionalString(r.procedural)}:{}}}
|