ts-agent-lib 0.1.0
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 +120 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# ts-agent-lib
|
|
2
|
+
|
|
3
|
+
Minimal, domain-agnostic DAG scheduler/executor for step-based workflows. It runs a plan of steps with dependencies, supports cancellation and event streaming, and stays decoupled from any specific domain (LLM, agent, etc.).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i ts-agent-lib
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 5-minute example (DAG + dataflow)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import {
|
|
15
|
+
DagExecutor,
|
|
16
|
+
PlanBuilder,
|
|
17
|
+
StepStatus,
|
|
18
|
+
type StepHandler
|
|
19
|
+
} from "ts-agent-lib";
|
|
20
|
+
|
|
21
|
+
// 1) Define a plan.
|
|
22
|
+
const builder = new PlanBuilder();
|
|
23
|
+
builder.addStep({ id: "pick-files", action: "pick" });
|
|
24
|
+
builder.addStep({ id: "edit-files", action: "edit", deps: ["pick-files"] });
|
|
25
|
+
const plan = builder.build();
|
|
26
|
+
|
|
27
|
+
// 2) Define handlers.
|
|
28
|
+
const handlers: Record<string, StepHandler> = {
|
|
29
|
+
pick: async (step) => ({
|
|
30
|
+
stepId: step.id,
|
|
31
|
+
status: StepStatus.COMPLETED,
|
|
32
|
+
output: ["src/app.ts", "src/utils.ts"]
|
|
33
|
+
}),
|
|
34
|
+
edit: async (step, ctx) => {
|
|
35
|
+
const deps = ctx.getDependencyOutputs<string[]>();
|
|
36
|
+
const files = deps["pick-files"] ?? [];
|
|
37
|
+
|
|
38
|
+
// Use files to do work...
|
|
39
|
+
return {
|
|
40
|
+
stepId: step.id,
|
|
41
|
+
status: StepStatus.COMPLETED,
|
|
42
|
+
output: { edited: files.length }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 3) Execute.
|
|
48
|
+
const executor = new DagExecutor({ maxParallelSteps: 4, failFast: false });
|
|
49
|
+
const state = await executor.executeAsync(plan, handlers);
|
|
50
|
+
|
|
51
|
+
// 4) Inspect results.
|
|
52
|
+
const edited = state.steps.get("edit-files")?.output;
|
|
53
|
+
console.log("edit result", edited);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Dataflow across dependencies
|
|
57
|
+
|
|
58
|
+
Step handlers receive a `StepContext` with read-only access to the plan and the current execution results:
|
|
59
|
+
|
|
60
|
+
- `getStep(stepId)` returns the immutable plan step.
|
|
61
|
+
- `getResult(stepId)` returns a copy of the latest `StepResult` (or undefined).
|
|
62
|
+
- `requireResult(stepId)` throws if the result is missing.
|
|
63
|
+
- `getDependencyResults()` returns completed dependency results keyed by dep id.
|
|
64
|
+
- `getDependencyOutputs()` returns completed dependency outputs keyed by dep id.
|
|
65
|
+
|
|
66
|
+
Behavior:
|
|
67
|
+
|
|
68
|
+
- Only **completed** dependencies appear in `getDependencyResults()` / `getDependencyOutputs()`.
|
|
69
|
+
- Outputs are user data; the executor does not clone or sanitize them.
|
|
70
|
+
- Results returned by the context are shallow copies, so handler code cannot mutate executor state.
|
|
71
|
+
|
|
72
|
+
## Cancellation and failFast
|
|
73
|
+
|
|
74
|
+
Use `AbortController` to cancel an execution. Pending steps become `cancelled`. Handlers should check `ctx.isCancelled()` or `ctx.signal?.aborted` and return promptly.
|
|
75
|
+
|
|
76
|
+
`failFast: true` stops scheduling new steps after the first failure. (Running steps are not cancelled today; see roadmap.)
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const controller = new AbortController();
|
|
80
|
+
setTimeout(() => controller.abort(), 5_000);
|
|
81
|
+
|
|
82
|
+
const state = await new DagExecutor().executeAsync(plan, handlers, {
|
|
83
|
+
cancelSignal: controller.signal
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Events and observers
|
|
88
|
+
|
|
89
|
+
You can observe execution events via `onEvent` or by iterating `streamExecute`:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
for await (const event of executor.streamExecute(plan, handlers)) {
|
|
93
|
+
console.log(event.type);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Events include: `execution_started`, `step_scheduled`, `step_started`, `step_completed`, `step_failed`, `step_blocked`, `step_cancelled`, `execution_completed`, and `execution_cancelled`.
|
|
98
|
+
|
|
99
|
+
## Validation
|
|
100
|
+
|
|
101
|
+
The library exposes zod schemas for validation at boundaries:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { StepSchema, ExecutionStateSchema } from "ts-agent-lib";
|
|
105
|
+
|
|
106
|
+
const step = StepSchema.parse({ id: "x", action: "work" });
|
|
107
|
+
const state = ExecutionStateSchema.parse({
|
|
108
|
+
executionId: "exec-1",
|
|
109
|
+
status: "completed",
|
|
110
|
+
steps: { x: { stepId: "x", status: "completed" } }
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Roadmap (design stubs)
|
|
115
|
+
|
|
116
|
+
- Execution snapshots: JSON-serializable snapshots with `serializeExecutionState` / `deserializeExecutionState`, plus resume support. Proposed semantics: steps marked `running` in a snapshot resume as `pending`, and snapshots referencing unknown step IDs raise an error.
|
|
117
|
+
- Fail-fast cancellation: when `failFast` is enabled, abort a shared signal so running steps can exit early.
|
|
118
|
+
- Explainable blocked steps: add a `blockedReason` on results or on `step_blocked` events.
|
|
119
|
+
- Optional step policies: minimal retry/timeout helpers.
|
|
120
|
+
- Optional concurrency lanes: per-action caps in addition to global `maxParallelSteps`.
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts-agent-lib",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Minimal, decoupled DAG execution core for agent workflows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dukefromearth/ts-agent-lib"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/dukefromearth/ts-agent-lib/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/dukefromearth/ts-agent-lib#readme",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18.17"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"main": "dist/index.cjs",
|
|
22
|
+
"module": "dist/index.js",
|
|
23
|
+
"types": "dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"require": "./dist/index.cjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"keywords": [
|
|
33
|
+
"dag",
|
|
34
|
+
"workflow",
|
|
35
|
+
"scheduler",
|
|
36
|
+
"executor",
|
|
37
|
+
"orchestration"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"test": "vitest run"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.7",
|
|
46
|
+
"tsup": "^8.3.5",
|
|
47
|
+
"typescript": "^5.7.3",
|
|
48
|
+
"vitest": "^2.1.8"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"zod": "^4.3.6"
|
|
52
|
+
}
|
|
53
|
+
}
|