stable-harness 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/index.d.ts +28 -6
  2. package/dist/index.js +1 -1
  3. package/package.json +14 -9
  4. package/packages/adapter-deepagents/dist/src/adapter.d.ts +1 -0
  5. package/packages/adapter-deepagents/dist/src/adapter.js +1 -1
  6. package/packages/adapter-deepagents/dist/src/index.d.ts +1 -0
  7. package/packages/adapter-deepagents/dist/src/index.js +1 -1
  8. package/packages/adapter-deepagents/dist/src/{builtin-tool-policy.d.ts → internal/builtin-tool-policy.d.ts} +16 -0
  9. package/packages/adapter-deepagents/dist/src/internal/builtin-tool-policy.js +1 -0
  10. package/packages/adapter-deepagents/dist/src/internal/gateway-tools.d.ts +4 -0
  11. package/packages/adapter-deepagents/dist/src/internal/gateway-tools.js +1 -0
  12. package/packages/adapter-deepagents/dist/src/internal/trace-projection.d.ts +16 -0
  13. package/packages/adapter-deepagents/dist/src/internal/trace-projection.js +1 -0
  14. package/packages/adapter-deepagents/dist/src/memory.d.ts +5 -0
  15. package/packages/adapter-deepagents/dist/src/memory.js +1 -0
  16. package/packages/adapter-deepagents/dist/src/retry-policy.js +1 -1
  17. package/packages/adapter-langgraph/dist/src/graph.d.ts +3 -0
  18. package/packages/adapter-langgraph/dist/src/graph.js +1 -0
  19. package/packages/adapter-langgraph/dist/src/index.d.ts +8 -0
  20. package/packages/adapter-langgraph/dist/src/index.js +1 -0
  21. package/packages/adapter-langgraph/dist/src/runtime.d.ts +3 -0
  22. package/packages/adapter-langgraph/dist/src/runtime.js +1 -0
  23. package/packages/adapter-langgraph/dist/src/skill-providers.d.ts +29 -0
  24. package/packages/adapter-langgraph/dist/src/skill-providers.js +1 -0
  25. package/packages/adapter-langgraph/dist/src/types.d.ts +60 -0
  26. package/packages/adapter-langgraph/dist/src/types.js +1 -0
  27. package/packages/adapter-langgraph/package.json +16 -0
  28. package/packages/cli/dist/src/args.d.ts +22 -0
  29. package/packages/cli/dist/src/args.js +1 -0
  30. package/packages/cli/dist/src/cli.js +1 -1
  31. package/packages/cli/dist/src/langgraph-official.d.ts +11 -0
  32. package/packages/cli/dist/src/langgraph-official.js +1 -0
  33. package/packages/cli/dist/src/output.d.ts +8 -0
  34. package/packages/cli/dist/src/output.js +1 -0
  35. package/packages/cli/dist/src/server.d.ts +3 -0
  36. package/packages/cli/dist/src/server.js +1 -0
  37. package/packages/cli/package.json +1 -0
  38. package/packages/core/dist/execution-contract.d.ts +1 -0
  39. package/packages/core/dist/execution-contract.js +1 -1
  40. package/packages/core/dist/index.d.ts +5 -4
  41. package/packages/core/dist/index.js +1 -1
  42. package/packages/core/dist/memory-plugins/maintenance.d.ts +42 -0
  43. package/packages/core/dist/memory-plugins/maintenance.js +1 -0
  44. package/packages/core/dist/memory-plugins/shared.d.ts +8 -0
  45. package/packages/core/dist/memory-plugins/shared.js +1 -0
  46. package/packages/core/dist/memory-plugins.d.ts +5 -48
  47. package/packages/core/dist/memory-plugins.js +1 -1
  48. package/packages/core/dist/recovery/tool-call.d.ts +13 -0
  49. package/packages/core/dist/recovery/tool-call.js +1 -0
  50. package/packages/core/dist/runtime/completion.d.ts +17 -0
  51. package/packages/core/dist/runtime/completion.js +1 -0
  52. package/packages/core/dist/runtime/direct-tool-call.d.ts +10 -0
  53. package/packages/core/dist/runtime/direct-tool-call.js +1 -0
  54. package/packages/core/dist/runtime/events.d.ts +147 -0
  55. package/packages/core/dist/runtime/events.js +1 -0
  56. package/packages/core/dist/runtime/memory.d.ts +23 -0
  57. package/packages/core/dist/runtime/memory.js +1 -0
  58. package/packages/core/dist/{artifacts.d.ts → runtime/persistence/artifacts.d.ts} +1 -1
  59. package/packages/core/dist/{inspection.d.ts → runtime/persistence/inspection.d.ts} +1 -1
  60. package/packages/core/dist/{queue.d.ts → runtime/persistence/queue.d.ts} +1 -1
  61. package/packages/core/dist/{stores.d.ts → runtime/persistence/stores.d.ts} +1 -1
  62. package/packages/core/dist/runtime/tool-gateway.d.ts +35 -0
  63. package/packages/core/dist/runtime/tool-gateway.js +1 -0
  64. package/packages/core/dist/runtime/types.d.ts +168 -0
  65. package/packages/core/dist/runtime/types.js +1 -0
  66. package/packages/core/dist/runtime.d.ts +6 -3
  67. package/packages/core/dist/runtime.js +1 -1
  68. package/packages/core/dist/trace.js +1 -1
  69. package/packages/core/dist/types.d.ts +17 -426
  70. package/packages/core/dist/workflows/index.d.ts +70 -0
  71. package/packages/core/dist/workflows/index.js +1 -0
  72. package/packages/core/dist/workflows/runtime.d.ts +12 -0
  73. package/packages/core/dist/workflows/runtime.js +1 -0
  74. package/packages/core/dist/workspace/types.d.ts +92 -0
  75. package/packages/core/dist/workspace/types.js +1 -0
  76. package/packages/governance/dist/src/types.d.ts +1 -1
  77. package/packages/protocols/dist/src/http-server.js +1 -1
  78. package/packages/protocols/dist/src/in-process-client.js +1 -1
  79. package/packages/protocols/dist/src/openai-compatible.js +1 -1
  80. package/packages/protocols/dist/src/openai-payload.d.ts +74 -0
  81. package/packages/protocols/dist/src/openai-payload.js +1 -0
  82. package/packages/protocols/dist/src/openai-stream.d.ts +39 -0
  83. package/packages/protocols/dist/src/openai-stream.js +1 -0
  84. package/packages/tool-gateway/dist/src/argument-guard.js +1 -1
  85. package/packages/tool-gateway/dist/src/schema-validation.d.ts +3 -0
  86. package/packages/tool-gateway/dist/src/schema-validation.js +1 -0
  87. package/packages/workspace-yaml/dist/discovery.d.ts +4 -0
  88. package/packages/workspace-yaml/dist/discovery.js +1 -0
  89. package/packages/workspace-yaml/dist/documents.d.ts +16 -0
  90. package/packages/workspace-yaml/dist/documents.js +1 -0
  91. package/packages/workspace-yaml/dist/loader.js +1 -1
  92. package/packages/workspace-yaml/dist/workflows.d.ts +16 -0
  93. package/packages/workspace-yaml/dist/workflows.js +1 -0
  94. package/packages/adapter-deepagents/dist/src/builtin-tool-policy.js +0 -1
  95. /package/packages/adapter-deepagents/dist/src/{messages.d.ts → internal/messages.d.ts} +0 -0
  96. /package/packages/adapter-deepagents/dist/src/{messages.js → internal/messages.js} +0 -0
  97. /package/packages/adapter-deepagents/dist/src/{stream-events.d.ts → internal/stream-events.d.ts} +0 -0
  98. /package/packages/adapter-deepagents/dist/src/{stream-events.js → internal/stream-events.js} +0 -0
  99. /package/packages/core/dist/{artifacts.js → runtime/persistence/artifacts.js} +0 -0
  100. /package/packages/core/dist/{inspection.js → runtime/persistence/inspection.js} +0 -0
  101. /package/packages/core/dist/{queue.js → runtime/persistence/queue.js} +0 -0
  102. /package/packages/core/dist/{stores.js → runtime/persistence/stores.js} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,13 +1,35 @@
1
- import type { RuntimeAdapter, RuntimeRequest, StableHarnessRuntime } from "@stable-harness/core";
2
- export { createDeepAgentsAdapter } from "@stable-harness/adapter-deepagents";
3
- export { createStableHarnessRuntime } from "@stable-harness/core";
1
+ import { createStableHarnessRuntime as createCoreStableHarnessRuntime } from "@stable-harness/core";
2
+ import type { CompiledWorkspace, RuntimeAdapter, RuntimeRequest, RuntimeToolGateway, RuntimeWorkflowAdapter, StableHarnessRuntime, WorkspaceAdapterPolicy } from "@stable-harness/core";
3
+ export { createDeepAgentsAdapter, createDeepAgentsMemoryMaintenanceTarget } from "@stable-harness/adapter-deepagents";
4
+ export { createDeepAgentsMiddlewareSkillProvider, createLangGraphRuntimeAdapter, createLangGraphWorkflowAdapter, createRegistrySkillResolverProvider, } from "@stable-harness/adapter-langgraph";
5
+ export type { LangGraphNodeHandler, LangGraphNodeHandlerInput, LangGraphNodeResolver, LangGraphNodeResolverInput, LangGraphSkillMiddlewareProvider, LangGraphSkillMiddlewareProviderInput, LangGraphSkillResolverProvider, LangGraphWorkflowAdapterOptions, LangGraphWorkflowState, LangGraphWorkflowTraceEntry, } from "@stable-harness/adapter-langgraph";
6
+ export type { LangGraphRegistrySkillOutput } from "@stable-harness/adapter-langgraph";
4
7
  export { createLangMemServiceProvider } from "@stable-harness/memory";
5
- export type { CompiledWorkspace, RuntimeAdapter, RuntimeEvent, RuntimeRequest, RuntimeResponse, RuntimeRunRecord, StableHarnessRuntime, WorkspaceAgent, WorkspaceModel, WorkspaceRuntimePolicy, WorkspaceTool, } from "@stable-harness/core";
8
+ export type { CompiledWorkspace, RuntimeAdapter, RuntimeEvent, RuntimeWorkflowAdapter, RuntimeRequest, RuntimeResponse, RuntimeRunRecord, StableHarnessRuntime, WorkspaceAgent, WorkspaceModel, WorkspaceRuntimePolicy, WorkspaceTool, } from "@stable-harness/core";
6
9
  export { loadWorkspaceFromYaml } from "@stable-harness/workspace-yaml";
7
10
  export { createInMemoryToolGateway, createModuleToolGateway } from "@stable-harness/tool-gateway";
8
11
  export type { ModuleToolDescriptor, ToolGateway, ToolGatewayContext, ToolGatewayInvokeRequest, ToolGatewayInvokeResult, ToolGatewayTool, } from "@stable-harness/tool-gateway";
9
- export declare function createStableRuntime(input: {
12
+ type RuntimeAssemblyInput = {
10
13
  workspaceRoot: string;
11
14
  adapters?: RuntimeAdapter[];
12
- }): Promise<StableHarnessRuntime>;
15
+ adapterFactories?: Record<string, RuntimeAdapterFactory>;
16
+ workflowAdapters?: RuntimeWorkflowAdapter[];
17
+ workflowAdapterFactories?: Record<string, RuntimeWorkflowAdapterFactory>;
18
+ workflowAdapterOptions?: Record<string, unknown>;
19
+ toolGateway?: RuntimeToolGateway;
20
+ };
21
+ type RuntimeAdapterFactory = (input: {
22
+ policy: WorkspaceAdapterPolicy;
23
+ workspace: CompiledWorkspace;
24
+ }) => RuntimeAdapter;
25
+ type RuntimeWorkflowAdapterFactory = (input: {
26
+ name: string;
27
+ workspace: CompiledWorkspace;
28
+ options: unknown;
29
+ }) => RuntimeWorkflowAdapter | undefined;
30
+ type CoreRuntimeInput = Parameters<typeof createCoreStableHarnessRuntime>[0];
31
+ export declare function createStableHarnessRuntime(workspaceRoot: string): Promise<StableHarnessRuntime>;
32
+ export declare function createStableHarnessRuntime(input: RuntimeAssemblyInput): Promise<StableHarnessRuntime>;
33
+ export declare function createStableHarnessRuntime(input: CoreRuntimeInput): StableHarnessRuntime;
34
+ export declare function createStableRuntime(input: RuntimeAssemblyInput): Promise<StableHarnessRuntime>;
13
35
  export declare function requestStableRuntime(runtime: StableHarnessRuntime, request: RuntimeRequest): Promise<import("@stable-harness/core").RuntimeResponse>;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{createDeepAgentsAdapter as e}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as a}from"@stable-harness/core";import{loadWorkspaceFromYaml as r}from"@stable-harness/workspace-yaml";export{createDeepAgentsAdapter}from"@stable-harness/adapter-deepagents";export{createStableHarnessRuntime}from"@stable-harness/core";export{createLangMemServiceProvider}from"@stable-harness/memory";export{loadWorkspaceFromYaml}from"@stable-harness/workspace-yaml";export{createInMemoryToolGateway,createModuleToolGateway}from"@stable-harness/tool-gateway";export async function createStableRuntime(t){const s=await r(t.workspaceRoot);return a({workspace:s,adapters:t.adapters??[e()]})}export async function requestStableRuntime(e,a){return e.request(a)}
1
+ import{createDeepAgentsAdapter as e}from"@stable-harness/adapter-deepagents";import{createLangGraphRuntimeAdapter as r,createLangGraphWorkflowAdapter as t,createRegistrySkillResolverProvider as a}from"@stable-harness/adapter-langgraph";import{createStableHarnessRuntime as o}from"@stable-harness/core";import{createModuleToolGateway as n}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{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):o(e)}export async function createStableRuntime(e){const r=await s(e.workspaceRoot),t=e.toolGateway??await n({tools:r.tools.values()});return o({workspace:r,toolGateway:t,adapters:e.adapters??i(r,e),workflowAdapters:e.workflowAdapters??l(r,e)})}export async function requestStableRuntime(e,r){return e.request(r)}function i(t,a){const o={deepagents:({policy:r})=>e(r.config?{config:r.config}:{}),langgraph:({policy:e})=>r({...c(e.config),name:e.name}),...a.adapterFactories},n=function(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}))}(t);return n.map(e=>{const r=o[e.name];if(r)return r({policy:e,workspace:t});throw new Error(`Unsupported runtime adapter: ${e.name}`)})}function l(e,r){const a={langgraph:({name:e,options:r})=>t({...c(r),name:e}),...r.workflowAdapterFactories};return[...new Set([...e.workflows.values()].map(e=>e.adapter??"").filter(Boolean))].map(t=>{const o=a[t];return o?.({name:t,workspace:e,options:p(r,t)})}).filter(e=>Boolean(e))}function p(e,r){return e.workflowAdapterOptions?.[r]??{}}function c(e){return d(e)?{...e,...void 0!==m(e)?{skillProvider:m(e)}:{}}:{}}function m(e){if(!1===e.skillProvider)return!1;const r=function(e){return d(e.skills)?e.skills:d(e.skillProvider)?e.skillProvider:void 0}(e);if(!r)return;const t=u(r.provider)??u(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 a({..."boolean"==typeof r.includeContent?{includeContent:r.includeContent}:{},..."number"==typeof r.maxBytes&&Number.isFinite(r.maxBytes)?{maxBytes:r.maxBytes}:{}})}function u(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function d(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stable-harness",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "description": "Stable application runtime and operator control plane for agent workspaces.",
6
6
  "license": "MIT",
@@ -50,20 +50,23 @@
50
50
  "build:chmod": "chmod +x dist/cli.js packages/cli/dist/src/cli.js",
51
51
  "check": "tsc -b --pretty false",
52
52
  "check:rules": "node scripts/check-project-rules.mjs",
53
- "compare:tool-calling": "node scripts/compare-granite-tool-calling.mjs",
54
- "compare:granite-tools": "node scripts/compare-granite-tool-calling.mjs",
55
- "benchmark:bfcl-tool-guard": "node scripts/benchmark-bfcl-tool-guard.mjs",
56
- "benchmark:retry-policy": "node scripts/benchmark-retry-policy.mjs",
57
- "benchmark:tool-guard": "node scripts/benchmark-tool-argument-guard.mjs",
58
- "benchmark:tool-guard:matrix": "node scripts/benchmark-tool-argument-guard-matrix.mjs",
53
+ "compare:tool-calling": "node scripts/benchmarks/compare-granite-tool-calling.mjs",
54
+ "compare:granite-tools": "node scripts/benchmarks/compare-granite-tool-calling.mjs",
55
+ "benchmark:bfcl-tool-guard": "node scripts/benchmarks/bfcl-tool-guard.mjs",
56
+ "benchmark:backend-comparison": "node scripts/benchmarks/backend-comparison.mjs",
57
+ "benchmark:retry-policy": "node scripts/benchmarks/retry-policy.mjs",
58
+ "benchmark:tool-guard": "node scripts/benchmarks/tool-argument-guard.mjs",
59
+ "benchmark:tool-guard:matrix": "node scripts/benchmarks/tool-argument-guard-matrix.mjs",
59
60
  "test:langmem:sqlite:e2e": "node scripts/run-langmem-sqlite-e2e.mjs",
60
61
  "validate:workspace": "node scripts/validate-workspace.mjs",
61
- "test": "node --test dist/test/*.test.js dist/test/memory/*.test.js dist/test/retry/*.test.js dist/test/workspace/*.test.js",
62
+ "test": "rm -rf dist/test && tsc -b test/tsconfig.json && node --test dist/test/*.test.js dist/test/adapter/*.test.js dist/test/compat/*.test.js dist/test/memory/*.test.js dist/test/protocol/*.test.js dist/test/retry/*.test.js dist/test/runtime/*.test.js dist/test/sdk/*.test.js dist/test/workspace/*.test.js",
62
63
  "test:langmem:maintenance:e2e": "node scripts/run-langmem-maintenance-e2e.mjs",
63
64
  "test:skill-mining:e2e": "node scripts/run-skill-candidate-mining-e2e.mjs",
65
+ "prepublishOnly": "npm run build && npm run release:check-package",
64
66
  "prepack": "npm run release:minify",
65
67
  "release:minify": "find dist packages -type f -name '*.js' \\( -path 'dist/*' -o -path '*/dist/*' \\) -exec sh -c 'for f do ./node_modules/.bin/terser \"$f\" --compress passes=2 --mangle --module --toplevel --comments false --output \"$f\"; done' sh {} +",
66
- "release:pack": "npm pack --dry-run",
68
+ "release:check-package": "node scripts/release/check-npm-package.mjs",
69
+ "release:pack": "npm run build && npm run release:check-package && npm pack --dry-run",
67
70
  "release:publish": "npm publish --access public --registry https://registry.npmjs.org/",
68
71
  "example:minimal": "node dist/examples/minimal-deepagents/run.js"
69
72
  },
@@ -73,8 +76,10 @@
73
76
  "dependencies": {
74
77
  "@botbotgo/better-call": "^0.1.1",
75
78
  "@langchain/core": "^1.1.43",
79
+ "@langchain/langgraph": "^1.3.0",
76
80
  "@langchain/ollama": "^1.2.7",
77
81
  "@stable-harness/adapter-deepagents": "file:packages/adapter-deepagents",
82
+ "@stable-harness/adapter-langgraph": "file:packages/adapter-langgraph",
78
83
  "@stable-harness/core": "file:packages/core",
79
84
  "@stable-harness/governance": "file:packages/governance",
80
85
  "@stable-harness/memory": "file:packages/memory",
@@ -3,6 +3,7 @@ import type { DeepAgentFactory, DeepAgentsAdapterRunner } from "./types.js";
3
3
  type DeepAgentsAdapterOptions = {
4
4
  runner?: DeepAgentsAdapterRunner;
5
5
  createDeepAgent?: DeepAgentFactory;
6
+ config?: Record<string, unknown>;
6
7
  };
7
8
  export declare function createDeepAgentsAdapter(options?: DeepAgentsAdapterOptions): RuntimeAdapter;
8
9
  export {};
@@ -1 +1 @@
1
- import{ToolMessage as e}from"@langchain/core/messages";import{tool as t}from"@langchain/core/tools";import{ChatOllama as n}from"@langchain/ollama";import{resolveDeepAgentsNativeMemories as r}from"@stable-harness/core";import{createBuiltinToolPolicyMiddleware as s,validateFilesystemBuiltinCall as o}from"./builtin-tool-policy.js";import{buildDeepAgentRequest as a}from"./messages.js";import{createDeepAgentsRetryMiddleware as i}from"./retry-policy.js";import{streamDeepAgentResult as d}from"./stream-events.js";const u=new Set(["write_todos","task","ls","read_file","write_file","edit_file","glob","grep"]);export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(t){if(t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"handoff",modelRef:t.agent.modelRef,tools:t.agent.tools,subagents:t.agent.subagents}}),e.runner)return e.runner(t);const n=(e.createDeepAgent??await async function(){try{const e=(await async function(){return new Function("specifier","return import(specifier)")("deepagents")}()).createDeepAgent;if("function"==typeof e)return e}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${D(e)}`)}throw new Error("DeepAgents package does not export createDeepAgent.")}())(function(e){const t=w(e.agent.config.deepagents),n=t.permissions??m(e,e.agent);return q({name:e.agent.id,model:t.model??I(e,e.agent),systemPrompt:e.agent.systemPrompt??_(e.agent.config.systemPrompt),backend:t.backend,checkpointer:t.checkpointer,store:t.store,middleware:f(t.middleware,p(e),s(e),i(e.workspace.runtime.retry)),responseFormat:t.responseFormat,contextSchema:t.contextSchema,interruptOn:t.interruptOn,permissions:n,tools:h(e,e.agent.id,e.agent.tools),subagents:e.agent.subagents.map(t=>{const n=e.workspace.agents.get(t),r=w(n?.config.deepagents),s=r.permissions??m(e,n);return q({name:t,description:n?.description??_(n?.config.description)??n?.id,systemPrompt:n?.systemPrompt??_(n?.config.systemPrompt),model:r.model??(n?I(e,n):void 0),middleware:r.middleware,interruptOn:r.interruptOn,permissions:s,responseFormat:r.responseFormat,tools:h(e,t,n?.tools??[]),memory:c(e,n),skills:l(e,n)})}),memory:c(e,e.agent),skills:l(e,e.agent)})}(t)),r=a(t);return!0===t.request.metadata?.openaiStream&&n.streamEvents?d(t,n.streamEvents(r,{version:"v2"}),A):A(await n.invoke(r))}}}function c(e,t){const n=b(t?.config,"memory");if(n)return n;const s=r(e.workspace).map(e=>`/memories/${e.id}.md`);return s.length>0?s:void 0}function l(e,t){const n=b(t?.config,"skills");if(n)return n;const r=(t?.skills??[]).map(t=>e.workspace.skills.get(t)?.path??t);return r.length>0?r:void 0}function p(t){return{name:"StableHarnessObserver",async wrapToolCall(n,r){const s=n.toolCall?.name;if(!s||!u.has(s))return r(n);t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.start",toolId:s,args:n.toolCall?.args}});const a="task"===s?function(t,n){const r=function(e){const t=C(e)?e:{};return _(t.subagent_type)??_(t.subagentType)}(n.toolCall?.args),s=function(e){const t=k(e.agent.config,"builtinTools")?.modelExposed;return!1===t?[]:Array.isArray(t)?t.includes("task")?e.agent.subagents:[]:["general-purpose",...e.agent.subagents]}(t);if(void 0===s||r&&s.includes(r))return;const o=r?`: ${r}`:"",a=s.length>0?s.join(", "):"none";return new e({tool_call_id:n.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:`Task delegation target is not in the workspace inventory${o}. Allowed task targets: ${a}.`})}(t,n):void 0;if(a)return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:a.content}}),a;const i=o(t,s,n);if(i)return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:i.content}}),i;try{const e=await r(n);return t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,output:y(s,n,e)}}),e}catch(e){throw t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:"tool.result",toolId:s,error:D(e)}}),e}}}}function m(e,t){const n=k(t?.config,"builtinTools"),r=[];if(!1!==n?.filesystem){if(g(e))return}else r.push({operations:["read","write"],paths:["/**"],mode:"deny"});return g(e)||r.push({operations:["write"],paths:["/memories/**"],mode:"deny"}),r.length>0?r:void 0}function g(e){const t=k(e.workspace.runtime.memory,"deepagentsMem");return!1!==t?.write}function f(e,t,n,r=[]){return[t,n,...r,...Array.isArray(e)?e:[]]}function y(e,t,n){return"write_todos"===e?JSON.stringify({status:"recorded",args:t.toolCall?.args}):A(n)}function I(e,t){const r=t.modelRef?e.workspace.models.get(t.modelRef):void 0;return r?function(e){return"ollama"===e.provider?new n(q({model:e.model,baseUrl:_(e.config?.baseUrl),temperature:O(e.config?.temperature),numCtx:O(e.config?.numCtx),numPredict:O(e.config?.numPredict),timeout:O(e.config?.timeout),think:"boolean"==typeof e.config?.think?e.config.think:void 0})):e.model}(r):void 0}function h(n,r,s){return n.toolGateway?s.flatMap(s=>{const o=n.toolGateway?.get(s);if(!o)return[];const a=n.workspace.tools.get(s);return[t(async t=>{n.emit({type:"adapter.event",requestId:n.requestId,sessionId:n.sessionId,agentId:r,event:{adapter:"deepagents",phase:"tool.start",toolId:s}});const o=await async function(t,n,r,s){try{return await t.toolGateway.invoke({toolId:r,args:s,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:n}})}catch(t){if(function(e){return e instanceof Error&&"ToolArgumentValidationError"===e.name&&"string"==typeof e.toolId&&Array.isArray(e.issues)}(t))return new e({tool_call_id:`stable-harness-${r}-argument-guard`,name:r,status:"error",content:v(t)});throw t}}(n,r,s,t);return n.emit({type:"adapter.event",requestId:n.requestId,sessionId:n.sessionId,agentId:r,event:{adapter:"deepagents",phase:"tool.result",toolId:s}}),o instanceof e?o:A(o.output)},{name:s,description:a?.description??o.description??s,schema:a?.schema??{type:"object",additionalProperties:!0}})]}):[]}function v(e){return JSON.stringify({error:"tool_argument_validation_failed",toolId:e.toolId,issues:e.issues,retry:"Call the same tool again with arguments that satisfy the reported schema and semantic issues."})}function w(e){return C(e)?e:{}}function k(e,t){const n=C(e)?e:{};return C(n[t])?n[t]:void 0}function b(e,t){const n=C(e)?e:{},r=w(n.deepagents),s="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of s){const t=S(r[e]);if(t)return t}return S(n[t])}function A(e){if("string"==typeof e)return e;if(C(e)){const t=e.structuredResponse??e.structured_response;if(void 0!==t)return"string"==typeof t?t:JSON.stringify(t);const n=(Array.isArray(e.messages)?e.messages:[]).at(-1);if(C(n)&&"string"==typeof n.content)return n.content}return JSON.stringify(e)}function q(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function _(e){return"string"==typeof e&&e.trim()?e:void 0}function O(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function S(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function C(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function D(e){return e instanceof Error?e.message:String(e)}
1
+ import{ChatOllama as e}from"@langchain/ollama";import{createBuiltinToolPolicyMiddleware as t,createObserverMiddleware as n,resolveFilesystemPermissions as r}from"./internal/builtin-tool-policy.js";import{buildGatewayTools as o,stringifyDeepAgentResult as s}from"./internal/gateway-tools.js";import{resolveDeepAgentsNativeMemories as i}from"./memory.js";import{buildDeepAgentRequest as a}from"./internal/messages.js";import{createDeepAgentsRetryMiddleware as m}from"./retry-policy.js";import{streamDeepAgentResult as c}from"./internal/stream-events.js";export function createDeepAgentsAdapter(e={}){return{name:"deepagents",canRun:e=>"deepagents"===e.backend,async run(i){if(i.emit({type:"adapter.event",requestId:i.requestId,sessionId:i.sessionId,agentId:i.agent.id,event:{adapter:"deepagents",phase:"handoff",modelRef:i.agent.modelRef,tools:i.agent.tools,subagents:i.agent.subagents}}),e.runner)return e.runner(i);const g=(e.createDeepAgent??await async function(){try{const e=(await async function(){return new Function("specifier","return import(specifier)")("deepagents")}()).createDeepAgent;if("function"==typeof e)return e}catch(e){throw new Error(`DeepAgents package is required for the default adapter path: ${function(e){return e instanceof Error?e.message:String(e)}(e)}`)}throw new Error("DeepAgents package does not export createDeepAgent.")}())(function(e,s){const i={...f(s),...f(e.agent.config.deepagents)},a=i.permissions??r(e,e.agent);return y({name:e.agent.id,model:i.model??d(e,e.agent),systemPrompt:e.agent.systemPrompt??k(e.agent.config.systemPrompt),backend:i.backend,checkpointer:i.checkpointer,store:i.store,middleware:l(i.middleware,n(e),t(e),m(e.workspace.runtime.retry)),responseFormat:i.responseFormat,contextSchema:i.contextSchema,interruptOn:i.interruptOn,permissions:a,tools:o(e,e.agent.id,e.agent.tools),subagents:e.agent.subagents.map(t=>{const n=e.workspace.agents.get(t),s=f(n?.config.deepagents),i=s.permissions??r(e,n);return y({name:t,description:n?.description??k(n?.config.description)??n?.id,systemPrompt:n?.systemPrompt??k(n?.config.systemPrompt),model:s.model??(n?d(e,n):void 0),middleware:s.middleware,interruptOn:s.interruptOn,permissions:i,responseFormat:s.responseFormat,tools:o(e,t,n?.tools??[]),memory:p(e,n),skills:u(e,n)})}),memory:p(e,e.agent),skills:u(e,e.agent)})}(i,e.config)),v=a(i);if(!0===i.request.metadata?.openaiStream&&g.streamEvents)return c(i,g.streamEvents(v,{version:"v2"}),s);const w=await g.invoke(v);return s(w)}}}function p(e,t){const n=g(t?.config,"memory");if(n)return n;const r=i(e.workspace).map(e=>`/memories/${e.id}.md`);return r.length>0?r:void 0}function u(e,t){const n=g(t?.config,"skills");if(n)return n;const r=(t?.skills??[]).map(t=>e.workspace.skills.get(t)?.path??t);return r.length>0?r:void 0}function l(e,t,n,r=[]){return[t,n,...r,...Array.isArray(e)?e:[]]}function d(t,n){const r=n.modelRef?t.workspace.models.get(n.modelRef):void 0;return r?function(t){return"ollama"===t.provider?new e(y({model:t.model,baseUrl:k(t.config?.baseUrl),temperature:v(t.config?.temperature),numCtx:v(t.config?.numCtx),numPredict:v(t.config?.numPredict),timeout:v(t.config?.timeout),think:"boolean"==typeof t.config?.think?t.config.think:void 0})):t.model}(r):void 0}function f(e){return b(e)?e:{}}function g(e,t){const n=b(e)?e:{},r=f(n.deepagents),o="memory"===t?["memory","memorySources"]:["skills","skillSources"];for(const e of o){const t=w(r[e]);if(t)return t}return w(n[t])}function y(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function k(e){return"string"==typeof e&&e.trim()?e:void 0}function v(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function w(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e):void 0}function b(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
@@ -1,2 +1,3 @@
1
1
  export { createDeepAgentsAdapter } from "./adapter.js";
2
+ export { createDeepAgentsMemoryMaintenanceTarget, resolveDeepAgentsNativeMemories } from "./memory.js";
2
3
  export type { DeepAgentFactory, DeepAgentsAdapterRunner } from "./types.js";
@@ -1 +1 @@
1
- export{createDeepAgentsAdapter}from"./adapter.js";
1
+ export{createDeepAgentsAdapter}from"./adapter.js";export{createDeepAgentsMemoryMaintenanceTarget,resolveDeepAgentsNativeMemories}from"./memory.js";
@@ -1,5 +1,6 @@
1
1
  import { ToolMessage } from "@langchain/core/messages";
2
2
  import type { RuntimeAdapter } from "@stable-harness/core";
3
+ import type { WorkspaceAgent } from "@stable-harness/core";
3
4
  type AdapterRunInput = Parameters<RuntimeAdapter["run"]>[0];
4
5
  export declare function createBuiltinToolPolicyMiddleware(input: AdapterRunInput): {
5
6
  name: string;
@@ -15,4 +16,19 @@ export declare function validateFilesystemBuiltinCall(input: AdapterRunInput, to
15
16
  id?: string;
16
17
  };
17
18
  }): ToolMessage<import("@langchain/core/messages").MessageStructure<import("@langchain/core/messages").MessageToolSet>> | undefined;
19
+ export declare function createObserverMiddleware(input: AdapterRunInput): {
20
+ name: string;
21
+ wrapToolCall(request: {
22
+ toolCall?: {
23
+ id?: string;
24
+ name?: string;
25
+ args?: unknown;
26
+ };
27
+ }, handler: (request: unknown) => Promise<unknown>): Promise<unknown>;
28
+ };
29
+ export declare function resolveFilesystemPermissions(input: AdapterRunInput, agent: WorkspaceAgent | undefined): {
30
+ operations: string[];
31
+ paths: string[];
32
+ mode: string;
33
+ }[] | undefined;
18
34
  export {};
@@ -0,0 +1 @@
1
+ import{ToolMessage as t}from"@langchain/core/messages";import{stringifyDeepAgentResult as e}from"./gateway-tools.js";import{traceProjectionForBuiltinTool as o}from"./trace-projection.js";const r=new Set(["ls","read_file","write_file","edit_file","glob","grep"]),n=new Set(["write_todos","task",...r]);export function createBuiltinToolPolicyMiddleware(t){return{name:"StableHarnessBuiltinToolPolicy",async wrapModelCall(e,o){if(!function(t){return l(t)||!u(t)}(t))return o(e);const r=Array.isArray(e.tools)?e.tools.filter(e=>c(t,e.name)):e.tools,n=function(t,e){return"required"===e||function(t,e){return"string"==typeof e?.function?.name&&!c(t,e.function.name)}(t,e)?"auto":e}(t,e.toolChoice);return o({...e,tools:r,toolChoice:n})}}}export function validateFilesystemBuiltinCall(e,o,n){if(l(e)&&r.has(o))return new t({tool_call_id:n.toolCall?.id??`stable-harness-${o}-policy`,name:o,content:`Filesystem builtin tool '${o}' is disabled for this agent. Do not retry filesystem tools; use the agent's registered workspace tools and already collected evidence instead.`})}export function createObserverMiddleware(e){return{name:"StableHarnessObserver",async wrapToolCall(o,r){const a=o.toolCall?.name;if(!a||!n.has(a))return r(o);s(e,a,"tool.start",o.toolCall?.args);const l="task"===a?function(e,o){const r=function(t){const e=g(t)?t:{};return f(e.subagent_type)??f(e.subagentType)}(o.toolCall?.args),n=function(t){const e=d(t.agent.config,"builtinTools")?.modelExposed;return!1===e?[]:Array.isArray(e)?e.includes("task")?t.agent.subagents:[]:["general-purpose",...t.agent.subagents]}(e);if(void 0===n||r&&n.includes(r))return;const s=r?`: ${r}`:"",a=n.length>0?n.join(", "):"none";return new t({tool_call_id:o.toolCall?.id??"stable-harness-task-policy",name:"task",status:"error",content:`Task delegation target is not in the workspace inventory${s}. Allowed task targets: ${a}.`})}(e,o):void 0;if(l)return s(e,a,"tool.result",o.toolCall?.args,{output:l.content}),l;const u=validateFilesystemBuiltinCall(e,a,o);if(u)return s(e,a,"tool.result",o.toolCall?.args,{output:u.content}),u;const c=function(t,e){if("write_todos"!==t)return e;const o=g(e.toolCall?.args)?e.toolCall.args:{},r=function(t){if(!Array.isArray(t)&&"string"==typeof t&&t.trim())try{const e=JSON.parse(t);return Array.isArray(e)?e:void 0}catch{return}}(o.todos);return r?{...e,toolCall:{...e.toolCall,args:{...o,todos:r}}}:e}(a,o);try{const t=await r(c);return s(e,a,"tool.result",o.toolCall?.args,{output:i(a,c,t)}),t}catch(t){throw s(e,a,"tool.result",o.toolCall?.args,{error:p(t)}),t}}}}export function resolveFilesystemPermissions(t,e){const o=d(e?.config,"builtinTools"),r=[];if(!1!==o?.filesystem){if(a(t))return}else r.push(...function(t,e){return(e?.skills??[]).map(e=>t.workspace.skills.get(e)?.path).filter(t=>"string"==typeof t&&t.startsWith("/")).map(t=>({operations:["read"],paths:[t],mode:"allow"}))}(t,e)),r.push({operations:["read"],paths:["/memories/**"],mode:"allow"}),r.push({operations:["read","write"],paths:["/**"],mode:"deny"});return a(t)||r.push({operations:["write"],paths:["/memories/**"],mode:"deny"}),r.length>0?r:void 0}function s(t,e,r,n,s={}){t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:{adapter:"deepagents",phase:r,toolId:e,..."tool.start"===r?{args:n}:{},...s,...o(e,r,n)}})}function a(t){const e=d(t.workspace.runtime.memory,"deepagentsMem");return!1!==e?.write}function i(t,o,r){return"write_todos"===t?JSON.stringify({status:"recorded",args:o.toolCall?.args}):e(r)}function l(t){const e=d(t.agent.config,"builtinTools");return!1===e?.filesystem}function u(t){const e=d(t.agent.config,"builtinTools")?.modelExposed;return!1!==e&&(!Array.isArray(e)||e.includes("task"))}function c(t,e){return(!l(t)||!function(t){return"string"==typeof t&&r.has(t)}(e))&&("task"!==e||u(t))}function d(t,e){const o=g(t)?t:{};return g(o[e])?o[e]:void 0}function f(t){return"string"==typeof t&&t.trim()?t:void 0}function g(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function p(t){return t instanceof Error?t.message:String(t)}
@@ -0,0 +1,4 @@
1
+ import { ToolMessage } from "@langchain/core/messages";
2
+ import type { RuntimeAdapter } from "@stable-harness/core";
3
+ export declare function buildGatewayTools(input: Parameters<RuntimeAdapter["run"]>[0], agentId: string, toolIds: string[]): import("@langchain/core/tools").DynamicTool<string | ToolMessage<import("@langchain/core/messages").MessageStructure<import("@langchain/core/messages").MessageToolSet>>, unknown>[];
4
+ export declare function stringifyDeepAgentResult(result: unknown): string;
@@ -0,0 +1 @@
1
+ import{ToolMessage as e}from"@langchain/core/messages";import{tool as t}from"@langchain/core/tools";export function buildGatewayTools(s,n,a){return s.toolGateway?a.flatMap(a=>{const i=s.toolGateway?.get(a);if(!i)return[];const u=s.workspace.tools.get(a);return[t(async t=>{s.emit({type:"adapter.event",requestId:s.requestId,sessionId:s.sessionId,agentId:n,event:{adapter:"deepagents",phase:"tool.start",toolId:a}});const i=await async function(t,s,n,a){try{return await t.toolGateway.invoke({toolId:n,args:a,context:{workspaceRoot:t.workspace.root,requestId:t.requestId,sessionId:t.sessionId,agentId:s}})}catch(s){if(function(e){return e instanceof Error&&"ToolArgumentValidationError"===e.name&&"string"==typeof e.toolId&&Array.isArray(e.issues)}(s))return new e({tool_call_id:`stable-harness-${n}-argument-guard`,name:n,status:"error",content:r(s)});if(t.workspace.runtime.retry?.tools?.enabled)throw s;return new e({tool_call_id:`stable-harness-${n}-execution-error`,name:n,status:"error",content:JSON.stringify({error:"tool_execution_failed",toolId:n,message:o(s),retry:"Use the error as evidence, adjust the tool arguments if possible, or return a final answer with the blocker."})})}}(s,n,a,t);return s.emit({type:"adapter.event",requestId:s.requestId,sessionId:s.sessionId,agentId:n,event:{adapter:"deepagents",phase:"tool.result",toolId:a}}),i instanceof e?i:stringifyDeepAgentResult(i.output)},{name:a,description:u?.description??i.description??a,schema:u?.schema??{type:"object",additionalProperties:!0}})]}):[]}export function stringifyDeepAgentResult(e){if("string"==typeof e)return e;if(s(e)){const t=e.structuredResponse??e.structured_response;if(void 0!==t)return"string"==typeof t?t:JSON.stringify(t);const r=(Array.isArray(e.messages)?e.messages:[]).at(-1);if(s(r)&&"string"==typeof r.content)return r.content}return JSON.stringify(e)}function r(e){return JSON.stringify({error:"tool_argument_validation_failed",toolId:e.toolId,issues:e.issues,retry:"Call the same tool again with arguments that satisfy the reported schema and semantic issues."})}function s(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function o(e){return e instanceof Error?e.message:String(e)}
@@ -0,0 +1,16 @@
1
+ export declare function traceProjectionForBuiltinTool(toolId: string, phase: "tool.start" | "tool.result", args: unknown): {
2
+ traceType: string;
3
+ traceLabel: string;
4
+ subagentType: string | undefined;
5
+ todos?: undefined;
6
+ } | {
7
+ traceType: string;
8
+ traceLabel: string;
9
+ todos: any[];
10
+ subagentType?: undefined;
11
+ } | {
12
+ traceType?: undefined;
13
+ traceLabel?: undefined;
14
+ subagentType?: undefined;
15
+ todos?: undefined;
16
+ };
@@ -0,0 +1 @@
1
+ export function traceProjectionForBuiltinTool(o,r,n){return"task"===o?{traceType:"delegation",traceLabel:"tool.start"===r?"delegation.start":"delegation.completed",subagentType:t(n)}:"write_todos"===o&&"tool.result"===r?{traceType:"plan",traceLabel:"plan.updated",todos:e(n)}:{}}function t(t){const e=o(t)?t:{};return r(e.subagent_type)??r(e.subagentType)}function e(t){const e=o(t)?t:{};return Array.isArray(e.todos)?e.todos:[]}function o(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function r(t){return"string"==typeof t&&t.trim()?t:void 0}
@@ -0,0 +1,5 @@
1
+ import type { CompiledWorkspace, MemoryMaintenanceResult, MemoryMaintenanceTarget, MemoryMaintenanceTargetInput } from "@stable-harness/core";
2
+ export declare function resolveDeepAgentsNativeMemories(workspace: CompiledWorkspace): import("@stable-harness/core").WorkspaceMemory[];
3
+ export declare function createDeepAgentsMemoryMaintenanceTarget(input?: {
4
+ run?: (context: MemoryMaintenanceTargetInput) => Promise<MemoryMaintenanceResult>;
5
+ }): MemoryMaintenanceTarget;
@@ -0,0 +1 @@
1
+ import{resolveEnabledMemories as e}from"@stable-harness/core";export function resolveDeepAgentsNativeMemories(n){return!1===function(e,n,o){const t=r(e[n])??r(e[n.toLowerCase()]);return"boolean"==typeof t?.[o]?t[o]:void 0}(n.runtime.memory??{},"deepagentsMem","read")?[]:e(n,"all")}export function createDeepAgentsMemoryMaintenanceTarget(e={}){return{name:"deepagentsMem",run:async r=>e.run?e.run(r):{operations:[],metadata:{skipped:!0,reason:"No DeepAgents memory maintainer configured"}}}}function r(e){return"object"!=typeof e||null===e||Array.isArray(e)?void 0:e}
@@ -1 +1 @@
1
- import{modelRetryMiddleware as e,toolRetryMiddleware as t}from"langchain";export function createDeepAgentsRetryMiddleware(n){const o=[],i=r(n?.model);i&&o.push(e(i));const s=function(e){const t=r(e);if(!t)return;const n=Array.isArray(e?.tools)?e.tools.filter(e=>"string"==typeof e&&e.trim().length>0):void 0;return a({...t,tools:n})}(n?.tools);return s&&o.push(t(s)),o}function r(e){var t;if(e?.enabled)return a({maxRetries:n(e.maxRetries),backoffFactor:n(e.backoffFactor),initialDelayMs:n(e.initialDelayMs),maxDelayMs:n(e.maxDelayMs),jitter:"boolean"==typeof e.jitter?e.jitter:void 0,retryOn:o(e.retryOn),onFailure:(t=e.onFailure,"continue"===t||"error"===t?t:void 0)})}function n(e){return"number"==typeof e&&Number.isFinite(e)&&e>=0?e:void 0}function o(e){const t=function(e){const t=new Set(["timeout","network","rateLimit","serverError"]);if(!Array.isArray(e))return[...t];const r=e.filter(e=>t.has(e));return r.length>0?r:[...t]}(e);return e=>t.some(t=>i(e,t))}function i(e,t){const r=s(e)?e:{},n=function(e){const t=e.status??e.statusCode??e.code;return"number"==typeof t?t:Number.isInteger(Number(t))?Number(t):void 0}(r),o=`${String(r.name??"")} ${String(r.code??"")} ${String(r.message??e)}`,a=r.cause;return("timeout"===t?/timeout|timedout|etimedout|abort/i.test(o):"network"===t?/network|fetch failed|econnreset|econnrefused|enotfound|eai_again/i.test(o):"rateLimit"===t?429===n||/rate.?limit|too many requests/i.test(o):"serverError"===t&&Boolean(n&&n>=500&&n<600))||s(a)&&i(a,t)}function s(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function a(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}
1
+ import{modelRetryMiddleware as e,toolRetryMiddleware as t}from"langchain";export function createDeepAgentsRetryMiddleware(n){const o=[],i=r(n?.model);i&&o.push(e(i));const a=function(e){const t=r(e);if(!t)return;const n=Array.isArray(e?.tools)?e.tools.filter(e=>"string"==typeof e&&e.trim().length>0):void 0;return s({...t,tools:n})}(n?.tools);return a&&o.push(t(a)),o}function r(e){var t;if(e?.enabled)return s({maxRetries:n(e.maxRetries),backoffFactor:n(e.backoffFactor),initialDelayMs:n(e.initialDelayMs),maxDelayMs:n(e.maxDelayMs),jitter:"boolean"==typeof e.jitter?e.jitter:void 0,retryOn:o(e.retryOn),onFailure:(t=e.onFailure,"continue"===t||"error"===t?t:void 0)})}function n(e){return"number"==typeof e&&Number.isFinite(e)&&e>=0?e:void 0}function o(e){const t=function(e){const t=new Set(["timeout","network","rateLimit","serverError"]);if(!Array.isArray(e))return[...t];const r=e.filter(e=>t.has(e));return r.length>0?r:[...t]}(e);return e=>t.some(t=>i(e,t))}function i(e,t){const r=a(e)?e:{},n=function(e){const t=e.status??e.statusCode??e.code;return"number"==typeof t?t:Number.isInteger(Number(t))?Number(t):void 0}(r),o=`${String(r.name??"")} ${String(r.code??"")} ${String(r.message??e)}`,s=r.cause;return("timeout"===t?/timeout|timedout|etimedout|abort/i.test(o):"network"===t?/network|fetch failed|terminated|connection error|econnreset|econnrefused|enotfound|eai_again/i.test(o):"rateLimit"===t?429===n||/rate.?limit|too many requests/i.test(o):"serverError"===t&&Boolean(n&&n>=500&&n<600))||a(s)&&i(s,t)}function a(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function s(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}
@@ -0,0 +1,3 @@
1
+ import { type RuntimeOutput, type RuntimeWorkflowAdapterInput } from "@stable-harness/core";
2
+ import type { LangGraphWorkflowAdapterOptions } from "./types.js";
3
+ export declare function runLangGraphWorkflow(input: RuntimeWorkflowAdapterInput, options: LangGraphWorkflowAdapterOptions, adapterName: string): Promise<RuntimeOutput>;
@@ -0,0 +1 @@
1
+ import{Annotation as o,END as e,START as t,StateGraph as n}from"@langchain/langgraph";import{compileWorkflowPlan as r}from"@stable-harness/core";import{resolveSkillProvider as a}from"./skill-providers.js";export async function runLangGraphWorkflow(a,s,u){!function(o){if(o.cycles.length>0)throw new Error(`LangGraph workflow adapter does not enable cyclic graphs by default: ${o.workflowId}`);if(o.unreachableNodes.length>0)throw new Error(`LangGraph workflow has unreachable nodes: ${o.unreachableNodes.join(", ")}`)}(r(a.workflow));const f=function(a,d,s){let u=new n(o.Root({input:o,outputs:o({reducer:(o,e)=>({...o,...e}),default:()=>({})}),trace:o({reducer:(o,e)=>[...o,...e],default:()=>[]})}));for(const o of a.workflow.nodes)u=u.addNode(o.id,async e=>i({input:a,node:o,state:e,options:d,adapterName:s}));u=u.addEdge(t,a.workflow.entry??a.workflow.nodes[0].id),u=function(o,e){for(const t of e.workflow.edges)t.condition||(o=o.addEdge(t.from,t.to));return o}(u,a),u=function(o,e,t){for(const[n,r]of function(o){const e=new Map;for(const t of o.workflow.edges){if(!t.condition)continue;const o=e.get(t.from)??[];o.push({condition:t.condition,to:t.to}),e.set(t.from,o)}return e}(e)){const a=t.conditionalRouters?.[n];if(!a)throw new Error(`LangGraph workflow conditional edges from ${n} require a conditional router`);o=o.addConditionalEdges(n,async o=>a({...e,from:n,edges:r,state:o}),Object.fromEntries(r.map(o=>[o.condition,o.to])))}return o}(u,a,d);for(const o of r(a.workflow).terminalNodes)u=u.addEdge(o,e);return u.compile()}(a,s,u);a.emit({adapter:u,phase:"langgraph.invoke",workflowId:a.workflow.id});const l=await f.invoke({input:a.request.input,outputs:{},trace:[]});return{text:d(l),metadata:{workflowId:a.workflow.id,adapter:u,outputs:l.outputs,trace:l.trace}}}async function i(o){const e=await function(o,e){const t=e.nodeHandlers?.[o.id]??e.nodeHandlers?.[o.use];if(t)return t;const n=function(o){const e=o.indexOf(".");if(!(e<=0||e===o.length-1))return{kind:o.slice(0,e),id:o.slice(e+1)}}(o.use);if("workflows"===n?.kind&&e.enableSubworkflows)return o=>async function(o,e){const t=o.workspace.workflows.get(o.id);if(!t)throw new Error(`LangGraph subworkflow is not defined: ${o.id}`);const n=function(o){const e=o?.subworkflowDepth;return"number"==typeof e&&Number.isFinite(e)?e:0}(o.request.metadata),r=e.maxSubworkflowDepth??8;if(n>=r)throw new Error(`LangGraph subworkflow depth exceeded ${r}`);return(await runLangGraphWorkflow({...o,workflow:t,request:{...o.request,input:o.state,metadata:{...o.request.metadata,subworkflowDepth:n+1}}},e,e.name??"langgraph")).text}({...o,id:n.id},e);const r=n?e.nodeResolvers?.[n.kind]:void 0;if(r&&n)return o=>r({...o,kind:n.kind,id:n.id});const i="skills"===n?.kind?a(e):void 0;if(i&&n)return o=>i.resolve({...o,kind:n.kind,id:n.id});const d=e.defaultNodeHandler;if(d)return d;throw new Error(`LangGraph workflow node ${o.id} (${o.use}) has no handler or resolver`)}(o.node,o.options)({...o.input,node:o.node,state:o.state});return o.input.emit({adapter:o.adapterName,phase:"node.completed",workflowId:o.input.workflow.id,nodeId:o.node.id}),{outputs:{[o.node.id]:e},trace:[{nodeId:o.node.id,use:o.node.use,output:e}]}}function d(o){const e=o.trace.at(-1)?.output;return"string"==typeof e?e:JSON.stringify(e??o.outputs)}
@@ -0,0 +1,8 @@
1
+ import type { RuntimeWorkflowAdapter } from "@stable-harness/core";
2
+ import { createLangGraphRuntimeAdapter } from "./runtime.js";
3
+ import { createDeepAgentsMiddlewareSkillProvider, createRegistrySkillResolverProvider } from "./skill-providers.js";
4
+ import type { LangGraphWorkflowAdapterOptions } from "./types.js";
5
+ export type { LangGraphConditionalRouter, LangGraphConditionalRouterInput, LangGraphNodeHandler, LangGraphNodeHandlerInput, LangGraphNodeResolver, LangGraphNodeResolverInput, LangGraphSkillMiddlewareProvider, LangGraphSkillMiddlewareProviderInput, LangGraphSkillResolverProvider, LangGraphWorkflowAdapterOptions, LangGraphWorkflowState, LangGraphWorkflowTraceEntry, } from "./types.js";
6
+ export type { LangGraphRegistrySkillOutput } from "./skill-providers.js";
7
+ export { createDeepAgentsMiddlewareSkillProvider, createLangGraphRuntimeAdapter, createRegistrySkillResolverProvider, };
8
+ export declare function createLangGraphWorkflowAdapter(options?: LangGraphWorkflowAdapterOptions): RuntimeWorkflowAdapter;
@@ -0,0 +1 @@
1
+ import{runLangGraphWorkflow as r}from"./graph.js";import{createLangGraphRuntimeAdapter as e}from"./runtime.js";import{createDeepAgentsMiddlewareSkillProvider as a,createRegistrySkillResolverProvider as t}from"./skill-providers.js";export{a as createDeepAgentsMiddlewareSkillProvider,e as createLangGraphRuntimeAdapter,t as createRegistrySkillResolverProvider};export function createLangGraphWorkflowAdapter(e={}){const a=e.name??"langgraph";return{name:a,run:t=>r(t,e,a)}}
@@ -0,0 +1,3 @@
1
+ import type { RuntimeAdapter } from "@stable-harness/core";
2
+ import type { LangGraphWorkflowAdapterOptions } from "./types.js";
3
+ export declare function createLangGraphRuntimeAdapter(options?: LangGraphWorkflowAdapterOptions): RuntimeAdapter;
@@ -0,0 +1 @@
1
+ import{runLangGraphWorkflow as e}from"./graph.js";export function createLangGraphRuntimeAdapter(t={}){const r=t.name??"langgraph";return{name:r,canRun:e=>e.backend===r,run:o=>async function(t,r,o){return e({workspace:t.workspace,workflow:n(t.agent,o),request:{input:t.request.input,metadata:t.request.metadata},requestId:t.requestId,sessionId:t.sessionId,toolGateway:t.toolGateway,emit:e=>t.emit({type:"adapter.event",requestId:t.requestId,sessionId:t.sessionId,agentId:t.agent.id,event:e})},r,o)}(o,t,r)}}function n(e,n){const r=e.edges??[],s=r.length>0?t(e):t(e).slice(0,1);return function(e,n){const t=new Set;for(const r of n){if(t.has(r.id))throw new Error(`LangGraph agent ${e.id} has duplicate graph node ${r.id}`);t.add(r.id)}for(const n of e.edges??[])if(!t.has(n.from)||!t.has(n.to))throw new Error(`LangGraph agent ${e.id} edge references unknown node ${n.from}->${n.to}`)}({...e,edges:r},s),{id:e.id,...e.description?{description:e.description}:{},...e.sourcePath?{sourcePath:e.sourcePath}:{},adapter:n,entry:o(e,s),nodes:s,edges:r,...Object.keys(e.config).length>0?{config:e.config}:{}}}function t(e){return[...e.subagents.map(e=>r("agents",e)),...(e.skills??[]).map(e=>r("skills",e)),...e.tools.map(e=>r("tools",e))]}function r(e,n){return{id:n,use:`${e}.${n}`}}function o(e,n){return e.edges?.[0]?.from??n[0]?.id}
@@ -0,0 +1,29 @@
1
+ import type { LangGraphSkillMiddlewareProvider, LangGraphSkillResolverProvider } from "./types.js";
2
+ type RegistrySkillResolverOptions = {
3
+ includeContent?: boolean;
4
+ maxBytes?: number;
5
+ };
6
+ type DeepAgentsSkillsModule = {
7
+ createSkillsMiddleware?: (options: Record<string, unknown>) => unknown;
8
+ FilesystemBackend?: new (options: {
9
+ rootDir: string;
10
+ }) => unknown;
11
+ };
12
+ type DeepAgentsMiddlewareProviderOptions = {
13
+ backend?: unknown;
14
+ sources?: string[];
15
+ importDeepAgents?: () => Promise<DeepAgentsSkillsModule>;
16
+ };
17
+ export type LangGraphRegistrySkillOutput = {
18
+ id: string;
19
+ path: string;
20
+ description?: string;
21
+ allowedTools: string[];
22
+ content?: string;
23
+ };
24
+ export declare function createRegistrySkillResolverProvider(options?: RegistrySkillResolverOptions): LangGraphSkillResolverProvider;
25
+ export declare function createDeepAgentsMiddlewareSkillProvider(options?: DeepAgentsMiddlewareProviderOptions): LangGraphSkillMiddlewareProvider;
26
+ export declare function resolveSkillProvider(options: {
27
+ skillProvider?: LangGraphSkillResolverProvider | false;
28
+ }): LangGraphSkillResolverProvider | undefined;
29
+ export {};
@@ -0,0 +1 @@
1
+ import{readFile as e}from"node:fs/promises";import r from"node:path";export function createRegistrySkillResolverProvider(e={}){return{name:"registry-resolver",resolve:r=>async function(e,r){const o=e.workspace.skills.get(e.id);if(!o)throw new Error(`LangGraph skill resolver cannot find skill ${e.id}`);return{id:o.id,path:o.path,...o.description?{description:o.description}:{},allowedTools:o.allowedTools,...!1===r.includeContent?{}:{content:await t(o,r.maxBytes)}}}(r,e)}}export function createDeepAgentsMiddlewareSkillProvider(e={}){return{name:"deepagents-middleware",async createMiddleware(r){const t=await async function(e){return e.importDeepAgents?e.importDeepAgents():new Function("specifier","return import(specifier)")("deepagents")}(e),i=t.createSkillsMiddleware;if("function"!=typeof i)throw new Error("deepagents does not export createSkillsMiddleware");return i({backend:e.backend??o(t,r.workspace.root),sources:e.sources??n(r)})}}}export function resolveSkillProvider(e){if(!1!==e.skillProvider)return e.skillProvider??createRegistrySkillResolverProvider()}async function t(r,t=1048576){const o=await e(r.path,"utf8");if(Buffer.byteLength(o,"utf8")>t)throw new Error(`Skill ${r.id} exceeds registry resolver size limit of ${t} bytes`);return o}function o(e,r){if("function"!=typeof e.FilesystemBackend)throw new Error("deepagents does not export FilesystemBackend");return new e.FilesystemBackend({rootDir:r})}function n(e){const t=new Set([...(o=e.agent,o?.skills??[]),...i(e)]);var o;const n=new Set;for(const o of t){const t=e.workspace.skills.get(o);t&&n.add(s(r.relative(e.workspace.root,r.dirname(r.dirname(t.path)))))}return[...n].filter(e=>e&&!e.startsWith(".."))}function i(e){return e.workflow.nodes.map(e=>e.use.match(/^skills\.([^./][^.]*)$/u)?.[1]).filter(e=>Boolean(e))}function s(e){return e.split(r.sep).join("/")}
@@ -0,0 +1,60 @@
1
+ import type { RuntimeWorkflowAdapterInput, WorkspaceAgent, WorkspaceWorkflowNode } from "@stable-harness/core";
2
+ export type LangGraphWorkflowState = {
3
+ input?: unknown;
4
+ outputs: Record<string, unknown>;
5
+ trace: LangGraphWorkflowTraceEntry[];
6
+ };
7
+ export type LangGraphWorkflowTraceEntry = {
8
+ nodeId: string;
9
+ use: string;
10
+ output: unknown;
11
+ };
12
+ export type LangGraphNodeHandlerInput = RuntimeWorkflowAdapterInput & {
13
+ node: WorkspaceWorkflowNode;
14
+ state: LangGraphWorkflowState;
15
+ };
16
+ export type LangGraphNodeHandler = (input: LangGraphNodeHandlerInput) => Promise<unknown> | unknown;
17
+ export type LangGraphNodeResolverInput = LangGraphNodeHandlerInput & {
18
+ kind: string;
19
+ id: string;
20
+ };
21
+ export type LangGraphNodeResolver = (input: LangGraphNodeResolverInput) => Promise<unknown> | unknown;
22
+ export type LangGraphSkillResolverProvider = {
23
+ name: string;
24
+ resolve(input: LangGraphNodeResolverInput): Promise<unknown> | unknown;
25
+ };
26
+ export type LangGraphSkillMiddlewareProviderInput = RuntimeWorkflowAdapterInput & {
27
+ agent?: WorkspaceAgent;
28
+ };
29
+ export type LangGraphSkillMiddlewareProvider = {
30
+ name: string;
31
+ createMiddleware(input: LangGraphSkillMiddlewareProviderInput): Promise<unknown> | unknown;
32
+ };
33
+ export type LangGraphConditionalRouterInput = RuntimeWorkflowAdapterInput & {
34
+ from: string;
35
+ edges: Array<{
36
+ condition: string;
37
+ to: string;
38
+ }>;
39
+ state: LangGraphWorkflowState;
40
+ };
41
+ export type LangGraphConditionalRouter = (input: LangGraphConditionalRouterInput) => Promise<string> | string;
42
+ export type LangGraphWorkflowAdapterOptions = {
43
+ name?: string;
44
+ nodeHandlers?: Record<string, LangGraphNodeHandler>;
45
+ nodeResolvers?: Record<string, LangGraphNodeResolver>;
46
+ skillProvider?: LangGraphSkillResolverProvider | false;
47
+ defaultNodeHandler?: LangGraphNodeHandler;
48
+ conditionalRouters?: Record<string, LangGraphConditionalRouter>;
49
+ enableSubworkflows?: boolean;
50
+ maxSubworkflowDepth?: number;
51
+ };
52
+ export type LangGraphCompiled = {
53
+ invoke(input: LangGraphWorkflowState): Promise<LangGraphWorkflowState>;
54
+ };
55
+ export type LangGraphBuilder = {
56
+ addNode(name: string, handler: (state: LangGraphWorkflowState) => Promise<Partial<LangGraphWorkflowState>>): LangGraphBuilder;
57
+ addEdge(from: string, to: string): LangGraphBuilder;
58
+ addConditionalEdges(from: string, router: (state: LangGraphWorkflowState) => Promise<string>, pathMap: Record<string, string>): LangGraphBuilder;
59
+ compile(): LangGraphCompiled;
60
+ };
@@ -0,0 +1 @@
1
+ export{};
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@stable-harness/adapter-langgraph",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "files": [
6
+ "dist/**/*.js",
7
+ "dist/**/*.d.ts",
8
+ "package.json"
9
+ ],
10
+ "main": "dist/src/index.js",
11
+ "types": "dist/src/index.d.ts",
12
+ "dependencies": {
13
+ "@langchain/langgraph": "^1.3.0",
14
+ "@stable-harness/core": "0.0.1"
15
+ }
16
+ }
@@ -0,0 +1,22 @@
1
+ export type CliArgs = {
2
+ workspaceRoot: string;
3
+ command: "request" | "start";
4
+ workflowRenderId?: string;
5
+ workflowInspectId?: string;
6
+ agentRenderId?: string;
7
+ agentId?: string;
8
+ toolId?: string;
9
+ toolArgs: unknown;
10
+ trace: boolean;
11
+ traceJson: boolean;
12
+ serveOpenAi: boolean;
13
+ host: string;
14
+ port: number;
15
+ apiKey?: string;
16
+ timeoutMs: number;
17
+ help: boolean;
18
+ prompt: string;
19
+ shouldRunRequest: boolean;
20
+ };
21
+ export declare function parseArgs(argv: string[]): CliArgs;
22
+ export declare function helpText(): string;
@@ -0,0 +1 @@
1
+ export function parseArgs(s){let a,i,l,d,w,c,p="request",u=process.cwd(),f=!1,g=!1,h=!1,k=process.env.STABLE_HARNESS_OPENAI_HOST??"127.0.0.1",I=Number(process.env.STABLE_HARNESS_OPENAI_PORT??8642),v=process.env.STABLE_HARNESS_OPENAI_API_KEY,S=Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5),m=!1;const x=[];for(let E=0;E<s.length;E+=1){const R=o(s,E);if(0===E&&"start"===s[E])p="start",h=!0;else if(0===E&&"workflow"===s[E]){const r=e(s,E);a=r.workflowRenderId,i=r.workflowInspectId,E=r.index}else if(0===E&&"agent"===s[E]){const e=r(s,E);l=e.agentRenderId,E=e.index}else"-h"===s[E]||"--help"===s[E]?m=!0:"start"===p&&t(s[E])?h=!0:"-w"===s[E]||"--workspace"===s[E]?(u=R.value??u,E=R.index):"--agent"===s[E]?(d=R.value,E=R.index):"--tool"===s[E]?(w=R.value,E=R.index):"--tool-args-json"===s[E]?(c=n(R.value??"{}"),E=R.index):"--trace"===s[E]?f=!0:"--trace-json"===s[E]?g=!0:"--serve-openai"===s[E]?h=!0:"--host"===s[E]?(k=R.value??k,E=R.index):"--port"===s[E]?(I=Number(R.value??I),E=R.index):"--api-key"===s[E]?(v=R.value,E=R.index):"--timeout-ms"===s[E]?(S=Number(R.value??S),E=R.index):x.push(s[E])}return{workspaceRoot:u,command:p,workflowRenderId:a,workflowInspectId:i,agentRenderId:l,agentId:d,toolId:w,toolArgs:c,trace:f,traceJson:g,serveOpenAi:h,host:k,port:I,apiKey:v,timeoutMs:S,help:m,prompt:x.join(" "),shouldRunRequest:Boolean(w||x.length>0)}}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 start -w <workspace>","","Options:"," -w, --workspace <path> Workspace root."," --serve-openai Legacy alias for start."," --agent <id> Select an agent for a request."," --tool <id> Invoke an explicit registered tool."," --tool-args-json <json> Tool arguments for --tool."," --trace Print trace lines."," --trace-json Print trace JSON."," --timeout-ms <ms> Request timeout."," -h, --help Show this help.",""].join("\n")}function e(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>")}function r(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>")}function o(e,r){return{index:r+1,value:e[r+1]}}function n(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}`)}}function t(e){return"openai"===e||"openai-compatible"===e}
@@ -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{createDeepAgentsAdapter as o}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as r}from"@stable-harness/core";import{projectEvent as s,projectRuntimeTrace as a}from"@stable-harness/core";import{createOpenAiCompatibleHttpServer as n}from"@stable-harness/protocols";import{createModuleToolGateway as i}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as p}from"@stable-harness/workspace-yaml";export async function runCli(e=process.argv.slice(2)){const t=function(e){let t,o,r,s="request",a=process.cwd(),n=!1,i=!1,p=!1,l=process.env.STABLE_HARNESS_OPENAI_HOST??"127.0.0.1",m=Number(process.env.STABLE_HARNESS_OPENAI_PORT??8642),u=process.env.STABLE_HARNESS_OPENAI_API_KEY,d=Number(process.env.STABLE_HARNESS_CLI_TIMEOUT_MS??3e5),h=!1;const w=[];for(let g=0;g<e.length;g+=1)0===g&&"start"===e[g]?(s="start",p=!0):"-h"===e[g]||"--help"===e[g]?h=!0:"start"!==s||"openai"!==e[g]&&"openai-compatible"!==e[g]?"-w"===e[g]||"--workspace"===e[g]?a=e[++g]??a:"--agent"===e[g]?t=e[++g]:"--tool"===e[g]?o=e[++g]:"--tool-args-json"===e[g]?r=c(e[++g]??"{}"):"--trace"===e[g]?n=!0:"--trace-json"===e[g]?i=!0:"--serve-openai"===e[g]?p=!0:"--host"===e[g]?l=e[++g]??l:"--port"===e[g]?m=Number(e[++g]??m):"--api-key"===e[g]?u=e[++g]:"--timeout-ms"===e[g]?d=Number(e[++g]??d):w.push(e[g]):p=!0;return{workspaceRoot:a,command:s,agentId:t,toolId:o,toolArgs:r,trace:n,traceJson:i,serveOpenAi:p,host:l,port:m,apiKey:u,timeoutMs:d,help:h,prompt:w.join(" ")||"hello"}}(e);if(t.help)return void process.stdout.write(["Usage:"," stable-harness -w <workspace> [--agent <id>] [prompt]"," stable-harness start -w <workspace> [--host <host>] [--port <port>] [--api-key <key>]","","Options:"," -w, --workspace <path> Workspace root."," --serve-openai Serve the OpenAI-compatible API."," --agent <id> Select an agent for a request."," --tool <id> Invoke an explicit registered tool."," --tool-args-json <json> Tool arguments for --tool."," --trace Print trace lines."," --trace-json Print trace JSON."," --timeout-ms <ms> Request timeout."," -h, --help Show this help.",""].join("\n"));const l=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),m=t.workspaceRoot;try{const e=await p(m),c=await i({tools:e.tools.values()}),u=r({workspace:e,toolGateway:c,adapters:[o()]});if(t.serveOpenAi)return clearTimeout(l),void await async function(e,t){const o=n(e,{bearerToken:t.apiKey});await new Promise(e=>o.listen(t.port,t.host,e));const r=o.address(),s="object"==typeof r&&r?r.port:t.port;process.stdout.write(`stable-harness OpenAI-compatible API listening on http://${t.host}:${s}/v1\n`)}(u,t);t.trace&&u.subscribe(e=>{const t=s(e);var o;t&&process.stdout.write(`trace:${t.agentId}:${t.label}${o=t.detail,o&&"string"==typeof o.toolId?`:${o.toolId}`:""}\n`)});const d=await u.request({input:t.prompt,agentId:t.agentId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0});if(t.trace||t.traceJson){const e=u.getRun(d.requestId),o=e?a(e):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:o})}\n`)}process.stdout.write(`${d.output}\n`)}finally{clearTimeout(l)}}function c(e){try{return JSON.parse(e)}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Invalid --tool-args-json value: ${t}`)}}(function(){const o=process.argv[1];return Boolean(o)&&e(t(import.meta.url))===e(o)})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
2
+ import{realpathSync as e}from"node:fs";import{fileURLToPath as t}from"node:url";import{createDeepAgentsAdapter as r}from"@stable-harness/adapter-deepagents";import{createStableHarnessRuntime as o}from"@stable-harness/core";import{projectEvent as s,projectRuntimeTrace as a}from"@stable-harness/core";import{createModuleToolGateway as n}from"@stable-harness/tool-gateway";import{loadWorkspaceFromYaml as i}from"@stable-harness/workspace-yaml";import{helpText as c,parseArgs as p}from"./args.js";import{formatDetail as l,inspectWorkflow as d,renderAgent as u,renderWorkflow as m,workspaceStatus as f}from"./output.js";import{serveProtocol as w}from"./server.js";export async function runCli(e=process.argv.slice(2)){const t=p(e);if(t.help)return void process.stdout.write(c());const g=setTimeout(()=>{process.stderr.write(`stable-harness request timed out after ${t.timeoutMs}ms\n`),process.exit(124)},t.timeoutMs),I=t.workspaceRoot;try{const e=await i(I);if(t.workflowRenderId)return void process.stdout.write(m(e,t.workflowRenderId));if(t.workflowInspectId)return void process.stdout.write(d(e,t.workflowInspectId));if(t.agentRenderId)return void process.stdout.write(u(e,t.agentRenderId));const c=await n({tools:e.tools.values()}),p=o({workspace:e,toolGateway:c,adapters:[r()]});if(t.serveOpenAi)return clearTimeout(g),void await w(p,t);if(!t.shouldRunRequest)return void process.stdout.write(f(e,I));t.trace&&p.subscribe(e=>{const t=s(e);t&&process.stdout.write(`trace:${t.agentId}:${t.label}${l(t.detail)}\n`)});const v=await p.request({input:t.prompt,agentId:t.agentId,toolCall:t.toolId?{toolId:t.toolId,args:t.toolArgs}:void 0});if(t.trace||t.traceJson){const e=p.getRun(v.requestId),r=e?a(e):[];t.traceJson&&process.stdout.write(`${JSON.stringify({trace:r})}\n`)}process.stdout.write(`${v.output}\n`)}finally{clearTimeout(g)}}(function(){const r=process.argv[1];return Boolean(r)&&e(t(import.meta.url))===e(r)})()&&runCli().catch(e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});
@@ -0,0 +1,11 @@
1
+ import type { createStableHarnessRuntime } from "@stable-harness/core";
2
+ export type LangGraphOfficialConfig = {
3
+ host: string;
4
+ port: number;
5
+ nWorkers: number;
6
+ exposeAgents?: string[];
7
+ };
8
+ export declare function startOfficialLangGraphServer(runtime: ReturnType<typeof createStableHarnessRuntime>, config: LangGraphOfficialConfig): Promise<{
9
+ url: string;
10
+ cleanup: () => Promise<void>;
11
+ }>;
@@ -0,0 +1 @@
1
+ import{mkdir as n,writeFile as e}from"node:fs/promises";import{createRequire as t}from"node:module";import s from"node:path";import{fileURLToPath as a,pathToFileURL as r}from"node:url";import{startServer as o}from"@langchain/langgraph-api/server";export async function startOfficialLangGraphServer(t,c){const u=t.inspect().workspaceRoot,l=function(n,e){const t=new Set(n.inspect().agents),s=e&&e.length>0?e:[...t].sort();for(const n of s)if(!t.has(n))throw new Error(`LangGraph protocol references unknown agent: ${n}`);return s.map((n,e)=>({id:n,exportName:`agent_${e}_${g(n)}`}))}(t,c.exposeAgents),m=await async function(t,o){const g=s.join(t,".stable-harness","langgraph"),c=s.join(g,"bridge.mjs");return await n(g,{recursive:!0}),await e(c,function(n,e){const t=r(s.join(s.resolve(s.dirname(a(import.meta.url)),"../../../.."),"dist","index.js")).toString(),o=r(i.resolve("@langchain/langgraph")).toString(),g=e.map(n=>`export const ${n.exportName} = createBridgeGraph(${JSON.stringify(n.id)});`).join("\n");return`import langgraph from ${JSON.stringify(o)};\nimport { createStableHarnessRuntime } from ${JSON.stringify(t)};\n\nconst { END, MessagesAnnotation, START, StateGraph } = langgraph;\nconst workspaceRoot = ${JSON.stringify(n)};\nlet runtimePromise;\n\nfunction createBridgeGraph(agentId) {\n const graph = new StateGraph(MessagesAnnotation)\n .addNode("stable_harness", async (state, config) => {\n const runtime = await getRuntime();\n const result = await runtime.request({\n input: lastMessageText(state.messages),\n agentId,\n sessionId: readConfigString(config, "thread_id"),\n requestId: readConfigString(config, "run_id"),\n metadata: {\n protocol: "langgraph",\n openaiMessages: normalizeMessages(state.messages),\n executionContract: { enabled: false },\n toolCallRecovery: { onFailure: "message" },\n },\n });\n return { messages: [{ type: "ai", content: result.output }] };\n })\n .addEdge(START, "stable_harness")\n .addEdge("stable_harness", END);\n return graph.compile();\n}\n\nfunction getRuntime() {\n runtimePromise ??= createStableHarnessRuntime(workspaceRoot);\n return runtimePromise;\n}\n\nfunction lastMessageText(messages) {\n const message = Array.isArray(messages) ? messages.at(-1) : undefined;\n const content = message?.content;\n if (typeof content === "string") return content;\n return content == null ? "" : JSON.stringify(content);\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 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\n${g}\n`}(t,o)),{file:c,relativePath:`./${s.relative(t,c).split(s.sep).join("/")}`}}(u,l),p=Object.fromEntries(l.map(n=>[n.id,`${m.relativePath}:${n.exportName}`])),f=await o({host:c.host,port:c.port,nWorkers:c.nWorkers,cwd:u,graphs:p});return{url:`http://${f.host}`,cleanup:f.cleanup}}const i=t(import.meta.url);function g(n){const e=n.replace(/[^A-Za-z0-9_$]/gu,"_");return/^[A-Za-z_$]/u.test(e)?e:`_${e}`}
@@ -0,0 +1,8 @@
1
+ import type { loadWorkspaceFromYaml } from "@stable-harness/workspace-yaml";
2
+ type LoadedWorkspace = Awaited<ReturnType<typeof loadWorkspaceFromYaml>>;
3
+ export declare function workspaceStatus(workspace: LoadedWorkspace, workspaceRoot: string): string;
4
+ export declare function renderWorkflow(workspace: LoadedWorkspace, workflowId: string | undefined): string;
5
+ export declare function renderAgent(workspace: LoadedWorkspace, agentId: string | undefined): string;
6
+ export declare function inspectWorkflow(workspace: LoadedWorkspace, workflowId: string | undefined): string;
7
+ export declare function formatDetail(detail: Record<string, unknown> | undefined): string;
8
+ export {};
@@ -0,0 +1 @@
1
+ import{compileWorkflowPlan as r,renderAgentMermaid as o,renderWorkflowMermaid as e}from"@stable-harness/core";export function workspaceStatus(r,o){return[`stable-harness workspace: ${r.runtime.workspaceId??o}`,`root: ${r.root}`,`default agent: ${r.runtime.defaultAgentId}`,`agents: ${[...r.agents.keys()].sort().join(", ")||"none"}`,`workflows: ${[...r.workflows.keys()].sort().join(", ")||"none"}`,`default workflow: ${r.runtime.workflowRouting?.defaultWorkflowId??"none"}`,`workflow routes: ${t(r)}`,`tools: ${r.tools.size}`,"","Run a request with:"," stable-harness [prompt]"," stable-harness --agent <id> [prompt]"," stable-harness workflow render <workflow-id>"," stable-harness workflow inspect <workflow-id>"," stable-harness agent render <agent-id>"," stable-harness start",""].join("\n")}export function renderWorkflow(r,o){const t=n(r,o,"render");return`${e(t)}\n`}export function renderAgent(r,e){if(!e)throw new Error("Usage: stable-harness agent render <agent-id>");return`${o(r,e)}\n`}export function inspectWorkflow(o,e){const t=n(o,e,"inspect");return`${JSON.stringify({workflow:t,plan:r(t)},null,2)}\n`}export function formatDetail(r){return r&&"string"==typeof r.toolId?`:${r.toolId}`:""}function n(r,o,e){if(!o)throw new Error(`Usage: stable-harness workflow ${e} <workflow-id>`);const n=r.workflows.get(o);if(!n)throw new Error(`Workflow is not defined: ${o}`);return n}function t(r){return(r.runtime.workflowRouting?.routes??[]).map(r=>r.id).sort().join(", ")||"none"}
@@ -0,0 +1,3 @@
1
+ import type { createStableHarnessRuntime } from "@stable-harness/core";
2
+ import type { CliArgs } from "./args.js";
3
+ export declare function serveProtocol(runtime: ReturnType<typeof createStableHarnessRuntime>, args: CliArgs): Promise<void>;
@@ -0,0 +1 @@
1
+ import{createOpenAiCompatibleHttpServer as t}from"@stable-harness/protocols";import{startOfficialLangGraphServer as o}from"./langgraph-official.js";const e="127.0.0.1";export async function serveProtocol(t,e){const a=function(t,o){const e=p(t.getRuntimePolicy().protocols)??{},a=s(e,"openaiCompatible","openai-compatible","openai")??{},c=s(e,"langgraph")??{};return[...i(a)?[r(t,a,o)]:[],...i(c)?[n(c)]:[]]}(t,e),c=[];for(const e of a)if("http"===e.kind){await l(e),c.push(()=>f(e.server));const t=e.server.address(),o="object"==typeof t&&t?t.port:e.port;process.stdout.write(`stable-harness ${e.protocol} API listening on http://${e.host}:${o}/v1\n`)}else{const r=await o(t,e.config);c.push(r.cleanup),process.stdout.write(`stable-harness ${e.protocol} API listening on ${r.url}\n`)}await async function(t){const o=setInterval(()=>{},864e5);await new Promise(e=>{const r=()=>{clearInterval(o),Promise.allSettled(t.map(t=>t())).finally(()=>process.exit(0))};process.once("SIGINT",r),process.once("SIGTERM",r)})}(c)}function r(o,r,n){const s=a(r.host)??e,i=c(r.port)??8642,p=a(r.bearerToken)??a(r.apiKey)??n.apiKey;return{kind:"http",protocol:"openai-compatible",server:t(o,{bearerToken:p}),host:s,port:i}}function n(t){const o=a(t.host)??e,r=c(t.port)??2024,n=function(t){if(Array.isArray(t)&&t.every(t=>"string"==typeof t))return t.filter(t=>t.trim()).map(t=>t.trim())}(t.exposeAgents);return{kind:"langgraph",protocol:"langgraph-compatible",config:{host:o,port:r,nWorkers:c(t.nWorkers)??10,...n?{exposeAgents:n}:{}}}}function s(t,...o){for(const e of o){const o=p(t[e]);if(o)return o}}function i(t){return!1!==t.enabled}function a(t){if("string"!=typeof t||!t.trim())return;const o=t.match(/^\$\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-(.*))?\}$/u);return o?process.env[o[1]]??o[2]:t}function c(t){return"number"==typeof t&&Number.isFinite(t)?t:"string"==typeof t&&t.trim()?Number(t):void 0}function p(t){return"object"!=typeof t||null===t||Array.isArray(t)?void 0:t}async function l(t){await new Promise(o=>t.server.listen(t.port,t.host,o))}async function f(t){await new Promise((o,e)=>{t.close(t=>{t?e(t):o()})})}
@@ -13,6 +13,7 @@
13
13
  "main": "dist/src/index.js",
14
14
  "types": "dist/src/index.d.ts",
15
15
  "dependencies": {
16
+ "@langchain/langgraph-api": "^1.2.1",
16
17
  "@stable-harness/adapter-deepagents": "0.0.1",
17
18
  "@stable-harness/core": "0.0.1",
18
19
  "@stable-harness/protocols": "0.0.1",
@@ -5,4 +5,5 @@ export declare function assertExecutionContract(input: {
5
5
  requestId: string;
6
6
  sessionId: string;
7
7
  agent: WorkspaceAgent;
8
+ metadata?: Record<string, unknown>;
8
9
  }): void;
@@ -1 +1 @@
1
- export function assertExecutionContract(n){!function(n){if(!e(n.agent).requiresPlan)return;const o=n.store.getRun(n.requestId);if(!(o?.events??[]).flatMap(t).includes("write_todos"))throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_plan"}),new Error("Execution contract requires a planning checkpoint: write_todos")}(n),function(n){const o=function(t){const n=e(t).requiredEvidenceTools;return Array.isArray(n)?n.filter(e=>"string"==typeof e):[]}(n.agent);if(0===o.length)return;const r=n.store.getRun(n.requestId),i=new Set((r?.events??[]).flatMap(t)),s=o.filter(e=>!i.has(e));if(0!==s.length)throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_required_evidence",missingEvidenceTools:s}),new Error(`Execution contract missing required evidence tools: ${s.join(", ")}`)}(n)}function e(e){return n(e.config.executionContract)?e.config.executionContract:{}}function t(e){return"tool.completed"===e.type?[e.toolId]:"adapter.event"===e.type&&n(e.event)&&"tool.result"===e.event.phase&&"string"==typeof e.event.toolId?[e.event.toolId]:[]}function n(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
1
+ export function assertExecutionContract(r){(function(e){const t=n(e?.executionContract)?e.executionContract:void 0;return!1===t?.enabled})(r.metadata)||(function(n){const r=e(n.agent);if(!r.requiresPlan)return;const i=o(r.planEvidenceTools);if(0===i.length)throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"invalid_plan_contract"}),new Error("Execution contract requires plan evidence tools when requiresPlan is enabled");const s=n.store.getRun(n.requestId),c=new Set((s?.events??[]).flatMap(t));if(!i.some(e=>c.has(e)))throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_plan"}),new Error(`Execution contract requires a planning checkpoint from one of: ${i.join(", ")}`)}(r),function(n){const r=o(e(n.agent).requiredEvidenceTools);if(0===r.length)return;const i=n.store.getRun(n.requestId),s=new Set((i?.events??[]).flatMap(t)),c=r.filter(e=>!s.has(e));if(0!==c.length)throw n.emit({type:"execution.contract.failed",requestId:n.requestId,sessionId:n.sessionId,agentId:n.agent.id,reason:"missing_required_evidence",missingEvidenceTools:c}),new Error(`Execution contract missing required evidence tools: ${c.join(", ")}`)}(r))}function e(e){return n(e.config.executionContract)?e.config.executionContract:{}}function t(e){return"tool.completed"===e.type?[e.toolId]:"adapter.event"===e.type&&n(e.event)&&"tool.result"===e.event.phase&&"string"==typeof e.event.toolId?[e.event.toolId]:[]}function n(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function o(e){return Array.isArray(e)?e.filter(e=>"string"==typeof e&&e.length>0):[]}
@@ -1,9 +1,10 @@
1
- export * from "./artifacts.js";
1
+ export * from "./runtime/persistence/artifacts.js";
2
2
  export * from "./execution-contract.js";
3
- export * from "./inspection.js";
3
+ export * from "./runtime/persistence/inspection.js";
4
4
  export * from "./memory-plugins.js";
5
- export * from "./queue.js";
5
+ export * from "./runtime/persistence/queue.js";
6
6
  export * from "./runtime.js";
7
- export * from "./stores.js";
7
+ export * from "./runtime/persistence/stores.js";
8
8
  export * from "./trace.js";
9
9
  export * from "./types.js";
10
+ export * from "./workflows/index.js";
@@ -1 +1 @@
1
- export*from"./artifacts.js";export*from"./execution-contract.js";export*from"./inspection.js";export*from"./memory-plugins.js";export*from"./queue.js";export*from"./runtime.js";export*from"./stores.js";export*from"./trace.js";export*from"./types.js";
1
+ export*from"./runtime/persistence/artifacts.js";export*from"./execution-contract.js";export*from"./runtime/persistence/inspection.js";export*from"./memory-plugins.js";export*from"./runtime/persistence/queue.js";export*from"./runtime.js";export*from"./runtime/persistence/stores.js";export*from"./trace.js";export*from"./types.js";export*from"./workflows/index.js";