@arnilo/prism 0.0.4 → 0.0.5
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/CHANGELOG.md +18 -0
- package/README.md +34 -10
- package/dist/agents.js +146 -19
- package/dist/cli-init.d.ts +41 -0
- package/dist/cli-init.js +390 -0
- package/dist/cli-runner.d.ts +7 -1
- package/dist/cli-runner.js +13 -1
- package/dist/content.d.ts +19 -0
- package/dist/content.js +197 -69
- package/dist/contracts.d.ts +94 -9
- package/dist/contracts.js +8 -0
- package/dist/feedback.d.ts +48 -0
- package/dist/feedback.js +230 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/providers/media.d.ts +3 -1
- package/dist/providers/media.js +11 -1
- package/dist/testing/feedback.d.ts +6 -0
- package/dist/testing/feedback.js +37 -0
- package/dist/testing/persistence-schema.d.ts +3 -3
- package/dist/testing/persistence-schema.js +32 -2
- package/dist/testing/run-ledger-conformance.js +7 -1
- package/docs/a2a.md +73 -0
- package/docs/agent-events.md +4 -6
- package/docs/agent-loops.md +1 -1
- package/docs/agent-session-runtime.md +14 -16
- package/docs/cli-rpc.md +35 -7
- package/docs/coding-agent-tools.md +2 -2
- package/docs/coding-security.md +7 -3
- package/docs/compaction-observational-memory.md +2 -0
- package/docs/context-and-skills.md +1 -0
- package/docs/credentials-and-redaction.md +2 -2
- package/docs/database-persistence.md +9 -6
- package/docs/evaluations.md +122 -0
- package/docs/extensions.md +2 -2
- package/docs/host-security.md +20 -3
- package/docs/index.md +29 -17
- package/docs/mcp-tools.md +49 -4
- package/docs/migration.md +33 -3
- package/docs/multimodal-content.md +14 -6
- package/docs/observability.md +14 -6
- package/docs/performance.md +209 -0
- package/docs/postgres-persistence.md +6 -4
- package/docs/provider-conformance.md +1 -0
- package/docs/provider-packages.md +2 -0
- package/docs/providers/ai-sdk.md +113 -0
- package/docs/public-contracts.md +6 -5
- package/docs/rag.md +113 -0
- package/docs/release-and-install.md +100 -77
- package/docs/review-coverage-2026-07-15.md +193 -0
- package/docs/runs-and-usage.md +41 -4
- package/docs/server.md +139 -0
- package/docs/settings-auth-trust-security.md +5 -5
- package/docs/sqlite-persistence.md +4 -3
- package/docs/supervisors.md +71 -0
- package/docs/workflow-orchestration-primitives.md +19 -3
- package/docs/workflows.md +97 -23
- package/docs/working-and-semantic-memory.md +169 -0
- package/package.json +12 -2
- package/templates/init/README.md.tmpl +28 -0
- package/templates/init/env.example.tmpl +1 -0
- package/templates/init/gitignore.tmpl +11 -0
- package/templates/init/optional/evals-example.ts.tmpl +17 -0
- package/templates/init/optional/workflows-example.ts.tmpl +27 -0
- package/templates/init/package.json.tmpl +22 -0
- package/templates/init/providers.json +76 -0
- package/templates/init/src/agent.ts.tmpl +10 -0
- package/templates/init/src/index.ts.tmpl +12 -0
- package/templates/init/src/tests/agent.test.ts.tmpl +24 -0
- package/templates/init/tsconfig.json.tmpl +15 -0
|
@@ -8,6 +8,10 @@ Interactive TUI (**C-012**) is **out of scope** for Plan 057 and deferred. Workf
|
|
|
8
8
|
|
|
9
9
|
**Final Task 7 architecture (2026-07-14):** DAG/coordinator semantics remain package-local. Reusable versioned checkpoints, atomic leases, and bounded async event fan-in live in core as `CheckpointStore`, `LeaseStore`, and `EventMultiplexer`. Workflow adapters are thin domain facades; lease fencing plus checkpoint CAS prevents stale-worker commits.
|
|
10
10
|
|
|
11
|
+
**Phase 8 addendum (2026-07-15):** `@arnilo/prism-workflows` extends the same checkpoint JSON/state machine with `suspended` and terminal `denied` statuses, `suspend()`, persisted suspension/resume records, and `workflow_suspended` / `workflow_resumed` events. An approved resume requires the displayed checkpoint `expectedVersion`; the first checkpoint write CAS-claims it before node execution. Suspended runs are absent from coordinator `queued`/`running` polls, so no worker or polling loop remains active. No SQL migration or second approval store is required.
|
|
12
|
+
|
|
13
|
+
**Phase 11 addendum (2026-07-16):** schedules use a separate generic checkpoint namespace plus per-fire `LeaseStore` claims and deterministic queued-run IDs; SQLite/PostgreSQL need no workflow-specific table or migration. Background execution remains `enqueueWorkflow` + the existing coordinator. Nested workflow nodes call the same runner with inherited policy/ownership/checkpoint/event seams. Shared JSON state is validated, redacted, byte/history bounded, and checkpointed by version. Replay creates a new checkpoint with immutable source lineage and copied terminal evidence; approval-bearing prior paths cannot be copied.
|
|
14
|
+
|
|
11
15
|
## When to use it
|
|
12
16
|
|
|
13
17
|
- **Workflow package authors** should start here, then follow [Agent/session runtime](agent-session-runtime.md), [Agent loops](agent-loops.md), [Runs and usage ledger](runs-and-usage.md), [CLI/RPC](cli-rpc.md), and [Database persistence](database-persistence.md).
|
|
@@ -121,7 +125,7 @@ Static review of `src/agents.ts`, `src/agent-loops.ts`, `src/rpc.ts`, `src/cli-r
|
|
|
121
125
|
| Event fan-in | Generic core multiplexer | Package queue duplication | **Core multiplexer + package facade** | One bounded/abort-aware implementation |
|
|
122
126
|
| Distributed ownership | Process-local active map | Generic leases + package coordinator | **LeaseStore + fenced checkpoint CAS** | Atomic claims and monotonic fences prevent split brain across processes |
|
|
123
127
|
| Host control (no TUI) | Interactive terminal package | Public APIs + optional RPC/`CommandDefinition` | **Public APIs + optional commands** | Replaces former TUI Tasks for feature completeness |
|
|
124
|
-
| Approval prompts | Core `ApprovalHandler` |
|
|
128
|
+
| Approval prompts | Core `ApprovalHandler` | Durable workflow suspension + host `ExecutionPolicy` | **Checkpoint suspension** | Survives restart; approved tool execution still rechecks current host policy |
|
|
125
129
|
| Interactive TUI | Ship in Plan 057 | Defer C-012 | **Defer** | Explicit product decision after Task 0 |
|
|
126
130
|
|
|
127
131
|
## Locked package adapter contracts (Task 1)
|
|
@@ -435,6 +439,12 @@ runRpcServer({
|
|
|
435
439
|
| Workflow `maxCheckpointBytes` | Full checkpoint blob | 1 MiB | Resume metadata only; not full transcripts |
|
|
436
440
|
| Workflow event buffer | Per run merge queue | 2048 | Coalesce node status; drop with `workflow_event_overflow` |
|
|
437
441
|
| Workflow list/status page size | Status helper default | 100 | Bounded run listing for hosts |
|
|
442
|
+
| Nested depth | Default / hard | 8 / 32 | Prevent recursive composition exhaustion |
|
|
443
|
+
| Shared state | Default / hard bytes | 64 KiB / 512 KiB | Keep node context/checkpoints bounded |
|
|
444
|
+
| State history | Default / hard snapshots | 32 / 128 | Preserve replay state without unbounded history |
|
|
445
|
+
| Replay lineage | Default / hard depth | 8 / 32 | Prevent replay-chain abuse |
|
|
446
|
+
| Schedule input | Default / hard bytes | 256 KiB / 1 MiB | Bound persisted trigger payload |
|
|
447
|
+
| Schedule due claims | Default / hard per poll | 16 / 256 | Bound one poll; idle waits 1s by default |
|
|
438
448
|
|
|
439
449
|
## Threat model and design matrix
|
|
440
450
|
|
|
@@ -444,7 +454,7 @@ runRpcServer({
|
|
|
444
454
|
| 2 | Unbounded fan-out (dynamic list) | Workflow package | Cap `maxFanOut`; fail `node_failed` when exceeded |
|
|
445
455
|
| 3 | Resumed checkpoint tampered (wrong tenant/version) | Workflow adapter | Fail closed; no partial node execution |
|
|
446
456
|
| 4 | Checkpoint contains secrets | Workflow + redactor | Redact before persist; `redacted: true` metadata |
|
|
447
|
-
| 5 | Shell/tool approval during workflow | Host +
|
|
457
|
+
| 5 | Shell/tool approval during workflow | Host + workflow | Opt-in tool approval suspends before side effects; resume uses ownership + expected-version CAS, then rechecks current `ExecutionPolicy` with workflow/node metadata |
|
|
448
458
|
| 6 | Cancel during node execution | Workflow | `signal` abort → in-flight `session.abort()`; checkpoint marks `aborted` |
|
|
449
459
|
| 7 | Untrusted workflow definition file | Host | Load from trusted path only; schema-validate before `runWorkflow` |
|
|
450
460
|
| 8 | Node output passed to next node | Workflow | Size-bound; type validate; redact at boundary |
|
|
@@ -452,6 +462,12 @@ runRpcServer({
|
|
|
452
462
|
| 10 | Cross-tenant list/status query | Workflow adapter | Scope by ownership; never return other tenants' runs |
|
|
453
463
|
| 11 | RPC workflow cancel races session abort | Workflow commands | Cancel is idempotent; fails closed if run unknown/unauthorized |
|
|
454
464
|
| 12 | 1000-node workflow checkpoint growth | Workflow | Store ready set + bounded outputs only; no full transcript duplication |
|
|
465
|
+
| 13 | Two reviewers resume one suspension | Workflow adapter | Expected-version CAS claims checkpoint before execution; one succeeds, stale reviewer fails |
|
|
466
|
+
| 14 | Forged/cross-tenant resume | Workflow + host | Ownership and definition hash checked; declared schema requires host validator; payload redacted before persistence |
|
|
467
|
+
| 15 | Duplicate/crashed schedule fire | Workflow schedules | Per-fire lease, deterministic run ID, queued checkpoint idempotency, schedule CAS |
|
|
468
|
+
| 16 | Nested workflow broadens capability | Workflow runner | Child inherits parent tool/agent/policy/ownership/signal seams; bounded inherited depth |
|
|
469
|
+
| 17 | Replay mutates evidence or reuses approval | Workflow replay | New checkpoint + immutable lineage; source untouched; copied approval-bearing path rejected |
|
|
470
|
+
| 18 | State/history resource exhaustion | Workflow runner/checkpoint | Host validation plus state byte/history and aggregate checkpoint ceilings |
|
|
455
471
|
|
|
456
472
|
## Final primitive decisions (Task 1, superseded where noted by Task 6)
|
|
457
473
|
|
|
@@ -547,7 +563,7 @@ await session.run("Hi", { signal: AbortSignal.timeout(60_000) });
|
|
|
547
563
|
- Workflow agent nodes call public `AgentSession` APIs only; no imports from `src/agents.ts` internals.
|
|
548
564
|
- Workflow checkpoints adapt `ProductionPersistenceStore.checkpoints` (or any `CheckpointStore`); no raw database handles enter the workflow package.
|
|
549
565
|
- Multimodal and credential packages from Plan 056 compose unchanged in workflow examples (Task 4).
|
|
550
|
-
-
|
|
566
|
+
- `@arnilo/prism-workflows` is available directly and through `prism-sdk`/`prism-all`; installation does not start a worker or workflow.
|
|
551
567
|
- C-012 interactive TUI remains a future optional package if needed; it is not required for workflow feature completeness.
|
|
552
568
|
|
|
553
569
|
## Related APIs
|
package/docs/workflows.md
CHANGED
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-workflows` is an optional package for typed, bounded DAG orchestration over Prism sessions, tools, events, and persistence seams. Hosts define acyclic workflows with agent/function/tool/conditional/fan-out/join nodes; the package runs a Kahn-style scheduler with a bounded worker pool, emits package-local `WorkflowEvent`s, checkpoints progress, and can coordinate queued runs across multiple host processes using durable leases and fencing.
|
|
5
|
+
`@arnilo/prism-workflows` is an optional package for typed, bounded DAG orchestration over Prism sessions, tools, events, and persistence seams. Hosts define acyclic workflows with agent/function/tool/conditional/fan-out/join/nested-workflow nodes; the package runs a Kahn-style scheduler with a bounded worker pool, emits package-local `WorkflowEvent`s, checkpoints progress, and can coordinate queued runs across multiple host processes using durable leases and fencing.
|
|
6
6
|
|
|
7
7
|
Primary exports:
|
|
8
8
|
|
|
9
9
|
| Export | Purpose |
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| `defineWorkflow` / `buildGraph` | Validate definitions (acyclicity, edge refs, limits) and build deterministic successor/indegree maps |
|
|
12
|
-
| `agentNode`, `functionNode`, `toolNode`, `conditionalNode`, `fanOutNode`, `joinNode` | Typed node factories |
|
|
13
|
-
| `runWorkflow` / `resumeWorkflow` | Execute
|
|
12
|
+
| `agentNode`, `functionNode`, `toolNode`, `conditionalNode`, `fanOutNode`, `joinNode`, `workflowNode` | Typed node factories, including composition through the same runner |
|
|
13
|
+
| `runWorkflow` / `resumeWorkflow` / `suspend` / `replayWorkflow` | Execute, durably suspend, exactly-once resume, or create an immutable-lineage replay from a succeeded node |
|
|
14
14
|
| `createMemoryWorkflowCheckpoints` | In-process `WorkflowCheckpointAdapter` over core `createMemoryCheckpointStore()` |
|
|
15
15
|
| `createWorkflowCheckpoints` | Adapt core `CheckpointStore` (including SQLite/PostgreSQL persistence capabilities) to workflow checkpoint shapes |
|
|
16
16
|
| `createWorkflowEventBus` | Bounded pub/sub for `WorkflowEvent` with overflow policy |
|
|
17
17
|
| `getWorkflowRun` / `listWorkflowRuns` / `cancelWorkflowRun` | Status, paginated list, and cancel helpers |
|
|
18
|
-
| `createWorkflowCommands` | Optional `CommandDefinition[]` for
|
|
19
|
-
| `enqueueWorkflow` / `createWorkflowCoordinator` | Persist queued work and atomically claim/renew/execute it across processes using `LeaseStore` |
|
|
18
|
+
| `createWorkflowCommands` | Optional `CommandDefinition[]` for direct/background/replay/status/list/cancel/resume and, when selected, schedule control |
|
|
19
|
+
| `enqueueWorkflow` / `startWorkflowBackground` / `createWorkflowCoordinator` | Persist queued work and atomically claim/renew/execute it across processes using `LeaseStore` |
|
|
20
|
+
| `createWorkflowSchedules` | Explicit ownership-scoped one-time/interval/host-calculated schedules over existing checkpoint/lease stores |
|
|
20
21
|
|
|
21
22
|
Included through `@arnilo/prism-sdk` and `@arnilo/prism-all`; installing either profile does not start workflows. Interactive TUI is out of scope (C-012 deferred).
|
|
22
23
|
|
|
@@ -40,6 +41,11 @@ Use `createWorkflowCoordinator()` when multiple processes share SQLite/PostgreSQ
|
|
|
40
41
|
| `limits.maxConcurrency` | Default 8 |
|
|
41
42
|
| `limits.maxNodeOutputBytes` | Default 4 MiB |
|
|
42
43
|
| `limits.maxCheckpointBytes` | Default 1 MiB |
|
|
44
|
+
| `limits.maxNestedDepth` / hard cap | 8 / 32; inherited by child workflows |
|
|
45
|
+
| `limits.maxStateBytes` / hard cap | 64 KiB / 512 KiB |
|
|
46
|
+
| `limits.maxStateHistory` / hard cap | 32 / 128 state snapshots; updates stop before evidence would be discarded |
|
|
47
|
+
| `limits.maxReplayDepth` / hard cap | 8 / 32 lineage generations |
|
|
48
|
+
| `state.initial` / `state.schema` | Initial shared JSON object and optional host-validated schema |
|
|
43
49
|
|
|
44
50
|
`runWorkflow(workflow, input, options?)`:
|
|
45
51
|
|
|
@@ -56,23 +62,38 @@ Use `createWorkflowCoordinator()` when multiple processes share SQLite/PostgreSQ
|
|
|
56
62
|
| `signal` | Cancels the run and in-flight agent sessions |
|
|
57
63
|
| `onEvent` | Synchronous `WorkflowEvent` sink |
|
|
58
64
|
| `runId` | Caller-supplied id; otherwise generated (`wfr_…`) |
|
|
65
|
+
| `resume` | For suspended runs: `{ decision: "approve" | "deny", input?, expectedVersion }`; version is mandatory for an exact-once CAS claim |
|
|
66
|
+
| `validateResume` | Host validator for resume input; required when `suspend()` declares `resumeSchema` |
|
|
67
|
+
| `validateState` | Host validator for every initial/restored/updated state; required when workflow declares `state.schema` |
|
|
68
|
+
| `initialState` | Optional host initial state override; nested workflows receive parent state automatically |
|
|
59
69
|
|
|
60
|
-
`resumeWorkflow(workflow, { runId }, options)`
|
|
70
|
+
A function node returns `suspend({ reason, data?, resumeSchema? })` to persist `status: "suspended"`. Its next invocation receives `ctx.resume` only after an approved resume. `resumeWorkflow(workflow, { runId }, options)` validates schema/version/ownership/`definitionHash`, claims the checkpoint before node execution, and continues the suspended node. Denial persists terminal `denied` status without invoking it. Existing failed/aborted checkpoint resume remains available without a human decision.
|
|
71
|
+
|
|
72
|
+
Every node receives bounded `ctx.state`, `ctx.stateVersion`, and async `ctx.updateState(patch, { mode: "merge" | "replace" })`. Updates serialize, validate, redact, and snapshot before checkpoint save. `workflowNode({ workflow })` runs its child with the same ownership, agent/tool registries, execution policy, redactor, signal, checkpoints, and event bus; child state replaces parent state after success.
|
|
73
|
+
|
|
74
|
+
`replayWorkflow(workflow, { sourceRunId, fromNodeId, runId? }, options)` requires a succeeded source/node, creates a new checkpoint, copies terminal evidence outside the selected node's downstream closure, restores selected-node pre-state, and records `{ sourceRunId, fromNodeId, rootRunId, depth }`. Source evidence is untouched. Copying any prior nested/tool approval is rejected; replay from that approval node or earlier so Phase 8 approval executes again.
|
|
61
75
|
|
|
62
76
|
`createWorkflowCoordinator({ coordinatorId, workflows, checkpoints, leases, ... })` polls queued/running checkpoints with bounded pages, atomically claims each run, renews its lease, and aborts/fences work after lease loss. Key controls: `leaseTtlMs` (default 30s), `renewalIntervalMs` (default TTL/3), `pollIntervalMs` (default 1s), `maxConcurrentRuns` (default 4), and `pageSize` (default 100, maximum 500).
|
|
63
77
|
|
|
78
|
+
`createWorkflowSchedules({ store, leases, checkpoints, workflows, ownership, ownerId, calculators? })` is inert until its host calls `pollOnce()` or `run({ signal })`. Ownership requires `tenantId` plus `accountId` or `userId`. Methods are `create`, `get`, `list`, `pause`, `resume`, `trigger`, `delete`, `pollOnce`, and `run`. A record has one required `nextRunAt`, optional fixed `intervalMs` or registered `calculatorId` (never both), bounded input/metadata, status, version, and last-fire attribution. Manual trigger requires an idempotency key. Scheduled run IDs derive from schedule ID plus fire timestamp, so retry after enqueue-before-advance finds the same queued checkpoint instead of duplicating it. Defaults: page 100/hard 500, due claims 16/hard 256, input 256 KiB/hard 1 MiB, poll 1s, fire lease 30s.
|
|
79
|
+
|
|
64
80
|
## Outputs / response / events
|
|
65
81
|
|
|
66
82
|
`runWorkflow` / `resumeWorkflow` resolve to `WorkflowRunResult`:
|
|
67
83
|
|
|
68
84
|
| Field | Notes |
|
|
69
85
|
| --- | --- |
|
|
70
|
-
| `runId`, `workflowId`, `status` | `succeeded` / `failed` / `aborted` |
|
|
86
|
+
| `runId`, `workflowId`, `status` | `queued` / `running` / `suspended` / `succeeded` / `failed` / `denied` / `aborted` |
|
|
71
87
|
| `outputs` | Map of succeeded node outputs |
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
88
|
+
| `state` | Final/current bounded shared JSON state |
|
|
89
|
+
| `lineage` | Replay source/root/node/depth record when this is a replay |
|
|
90
|
+
| `suspension` | Current/persisted `{ nodeId, reason, data?, resumeSchema?, requestedAt }` |
|
|
91
|
+
| `resume` | Attributable resume decision/input/version/time record |
|
|
92
|
+
| `version` | Checkpoint CAS identity shown to reviewers and required on suspended resume |
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
Schedule `onEvent` receives bounded-attribution `schedule_fired` or metadata-only `schedule_failed`; schedule input is never copied into these events.
|
|
95
|
+
|
|
96
|
+
Package-local `WorkflowEvent` types: `workflow_started`, `workflow_suspended`, `workflow_resumed`, `workflow_finished`, `node_started`, `node_finished`, `node_failed`, `node_skipped`, `checkpoint_saved`, `agent_event` (wraps a redacted `AgentEvent`), `workflow_event_overflow`. Sequences are monotonic; drain/order is deterministic by `(sequence, nodeId)`.
|
|
76
97
|
|
|
77
98
|
## Request/response example
|
|
78
99
|
|
|
@@ -111,6 +132,10 @@ import {
|
|
|
111
132
|
cancelWorkflowRun,
|
|
112
133
|
enqueueWorkflow,
|
|
113
134
|
createWorkflowCoordinator,
|
|
135
|
+
createWorkflowSchedules,
|
|
136
|
+
replayWorkflow,
|
|
137
|
+
workflowNode,
|
|
138
|
+
suspend,
|
|
114
139
|
} from "@arnilo/prism-workflows";
|
|
115
140
|
import { runRpcServer } from "@arnilo/prism";
|
|
116
141
|
import { createSqlitePersistence } from "@arnilo/prism-session-store-sqlite";
|
|
@@ -122,11 +147,20 @@ const research = agentNode({
|
|
|
122
147
|
const draft = functionNode({
|
|
123
148
|
execute: async (ctx) => `Draft from ${String(ctx.upstream.research)}`,
|
|
124
149
|
});
|
|
150
|
+
const publish = functionNode({
|
|
151
|
+
execute: async (ctx) => ctx.resume
|
|
152
|
+
? publishDraft(ctx.upstream.draft, ctx.resume.input)
|
|
153
|
+
: suspend({
|
|
154
|
+
reason: "publish",
|
|
155
|
+
data: { draft: ctx.upstream.draft },
|
|
156
|
+
resumeSchema: { type: "object", required: ["reviewer"] },
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
125
159
|
|
|
126
160
|
const workflow = defineWorkflow({
|
|
127
161
|
id: "research-draft",
|
|
128
|
-
nodes: { research, draft },
|
|
129
|
-
edges: [["research", "draft"]],
|
|
162
|
+
nodes: { research, draft, publish },
|
|
163
|
+
edges: [["research", "draft"], ["draft", "publish"]],
|
|
130
164
|
limits: { maxNodes: 256, maxFanOut: 32, maxConcurrency: 4 },
|
|
131
165
|
});
|
|
132
166
|
|
|
@@ -157,12 +191,20 @@ const result = await runWorkflow(workflow, { topic: "hooks" }, {
|
|
|
157
191
|
onEvent: (event) => sink.push(event),
|
|
158
192
|
});
|
|
159
193
|
|
|
160
|
-
// Durable resume after process restart
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
194
|
+
// Durable human resume after process restart. Use result.version shown to reviewer.
|
|
195
|
+
if (result.status === "suspended") {
|
|
196
|
+
await resumeWorkflow(workflow, { runId: result.runId }, {
|
|
197
|
+
checkpoints,
|
|
198
|
+
agentFactory: (name) => agents.resolve(name).createSession(),
|
|
199
|
+
ownership: { tenantId: "t1" },
|
|
200
|
+
resume: {
|
|
201
|
+
decision: "approve",
|
|
202
|
+
input: { reviewer: "Ada" },
|
|
203
|
+
expectedVersion: result.version,
|
|
204
|
+
},
|
|
205
|
+
validateResume: ({ value }) => validateResumePayload(value),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
166
208
|
|
|
167
209
|
await cancelWorkflowRun({
|
|
168
210
|
workflowId: workflow.id,
|
|
@@ -172,11 +214,34 @@ await cancelWorkflowRun({
|
|
|
172
214
|
});
|
|
173
215
|
|
|
174
216
|
// Optional host control via existing CLI/RPC CommandDefinition seam:
|
|
217
|
+
const schedules = createWorkflowSchedules({
|
|
218
|
+
store: persistence.checkpoints,
|
|
219
|
+
leases: persistence.leases,
|
|
220
|
+
checkpoints,
|
|
221
|
+
workflows: { [workflow.id]: workflow },
|
|
222
|
+
ownership: { tenantId: "t1", userId: "ops" },
|
|
223
|
+
ownerId: process.env.HOSTNAME ?? "scheduler-1",
|
|
224
|
+
});
|
|
225
|
+
await schedules.create({
|
|
226
|
+
id: "daily-research",
|
|
227
|
+
workflowId: workflow.id,
|
|
228
|
+
nextRunAt: "2026-07-17T00:00:00.000Z",
|
|
229
|
+
intervalMs: 86_400_000,
|
|
230
|
+
input: { topic: "hooks" },
|
|
231
|
+
});
|
|
232
|
+
// Host calls schedules.pollOnce() from an existing timer, or explicitly starts schedules.run({ signal }).
|
|
233
|
+
|
|
234
|
+
const replay = await replayWorkflow(workflow, {
|
|
235
|
+
sourceRunId: result.runId,
|
|
236
|
+
fromNodeId: "draft",
|
|
237
|
+
}, { checkpoints, ownership: { tenantId: "t1" }, agentFactory });
|
|
238
|
+
|
|
175
239
|
runRpcServer({
|
|
176
240
|
createSession,
|
|
177
241
|
commands: createWorkflowCommands({
|
|
178
242
|
workflows: { [workflow.id]: workflow },
|
|
179
243
|
checkpoints,
|
|
244
|
+
schedules,
|
|
180
245
|
runOptions: { ownership: { tenantId: "t1" }, agentFactory },
|
|
181
246
|
}),
|
|
182
247
|
});
|
|
@@ -187,7 +252,7 @@ runRpcServer({
|
|
|
187
252
|
- Workflow semantics stay in this optional package; generic checkpoint persistence and bounded event fan-in live in core.
|
|
188
253
|
- `ProductionPersistenceStore.checkpoints` and `.leases` are optional generic capabilities. First-party SQLite/PostgreSQL adapters own `prism_checkpoints` / `prism_leases`; workflows only adapt them.
|
|
189
254
|
- `createWorkflowEventBus()` delegates queueing, source fan-in, overflow, abort, and close behavior to core `createEventMultiplexer()`.
|
|
190
|
-
- `createWorkflowCommands()` is optional; hosts
|
|
255
|
+
- `createWorkflowCommands()` is optional; hosts can drive `workflow.start` / `enqueue` / `replay` / `status` / `list` / `cancel` / `resume`. The six `schedule.*` commands appear only when a scoped `schedules` service is supplied.
|
|
191
256
|
- Hosts may bridge `WorkflowEvent` into OpenTelemetry or custom sinks; there is no built-in TUI.
|
|
192
257
|
- Agent exclusivity is per session: one active `run()` at a time, same as core.
|
|
193
258
|
|
|
@@ -195,19 +260,28 @@ runRpcServer({
|
|
|
195
260
|
|
|
196
261
|
- Definitions fail closed on cycles, unknown edges, self-edges, and `maxNodes` overflow.
|
|
197
262
|
- Fan-out length is bounded by `maxFanOut`; concurrency by `maxConcurrency`.
|
|
198
|
-
- Node outputs and checkpoints are byte
|
|
263
|
+
- Node outputs, shared state/history, schedule input/records, and checkpoints are byte/count/depth bounded. Checkpoint size remains the final aggregate ceiling.
|
|
199
264
|
- Event buses use a bounded buffer (default 2048) with `close` / `drop_oldest` / `drop_newest` overflow.
|
|
200
|
-
- Checkpoints redact via `SecretRedactor` / `secrets` before save; resume rejects tenant, schema,
|
|
265
|
+
- Checkpoints redact suspension/resume payloads via `SecretRedactor` / `secrets` before save; resume rejects tenant, schema, definition-hash, and expected-version mismatch.
|
|
266
|
+
- Suspension requires a checkpoint adapter, consumes no worker/polling slot, and is ignored by distributed coordinators until explicit resume.
|
|
267
|
+
- Concurrent resumes race on checkpoint CAS before node execution; one wins and stale/duplicate reviewers fail closed. Approved tool nodes then re-run current `ExecutionPolicy`, so durable approval cannot grant stale permissions.
|
|
268
|
+
- `toolNode({ approval: { reason, data?, resumeSchema? } })` suspends before tool execution. Denial is terminal `denied`; no tool side effect occurs.
|
|
201
269
|
- `cancelWorkflowRun` aborts local runs immediately and writes a durable cancellation request for a remotely leased run; workers check it during lease renewal.
|
|
202
270
|
- Tool nodes attach `workflowId` / `nodeId` on `ExecutionAction.metadata` for approval/audit context.
|
|
203
|
-
-
|
|
271
|
+
- Nested workflows inherit host registries/policies and cannot inject broader tools, agents, ownership, or credentials. Nested depth is inherited; child suspension bubbles to the parent review cursor.
|
|
272
|
+
- Replay source ownership/hash/status/node eligibility are checked before a new checkpoint is created. Source records are immutable, lineage is bounded, and copied approval-bearing paths are rejected.
|
|
273
|
+
- Schedule services are ownership-scoped and explicitly started. Per-fire leases plus deterministic run IDs/CAS prevent duplicate enqueue across coordinators and crash retry. Host calculator IDs resolve only from the supplied map; no callback or cron expression is persisted.
|
|
274
|
+
- Scheduler stores O(nodes + active outputs + bounded state history); ready-node work uses indegree maps, not repeated full scans.
|
|
204
275
|
- Lease acquisition is atomic; opaque tokens protect renew/release; monotonically increasing fencing tokens plus checkpoint compare-and-swap prevent expired workers from committing after takeover. Node functions must honor `ctx.signal` for prompt cooperative cancellation.
|
|
205
276
|
|
|
277
|
+
Use workflows for known, durable, replayable graphs. Use optional supervisor delegation only when child selection must be dynamic at runtime; do not replace deterministic nodes with model routing without a concrete need.
|
|
278
|
+
|
|
206
279
|
## Related APIs
|
|
207
280
|
|
|
208
281
|
- Examples: `examples/workflow-research-and-review.ts`, `examples/workflow-parallel-research.ts`, `examples/workflow-tool-approval.ts`, `examples/workflow-multimodal-document.ts`, `examples/workflow-sqlite-resume.ts`, `examples/workflow-postgres-resume.ts`, `examples/workflow-event-sink.ts`, `examples/workflow-rpc-cancel.ts`, `examples/workflow-distributed-coordinator.ts` — offline runnable demos; PostgreSQL safely skips unless `PRISM_TEST_POSTGRES_URL` is set.
|
|
209
282
|
- [Workflow orchestration primitives](workflow-orchestration-primitives.md): Task 0–1 inventory and locked adapter contracts
|
|
210
|
-
- [Agent/session runtime](agent-session-runtime.md): `AgentSession.run()`, abort, subscribe
|
|
283
|
+
- [Agent/session runtime](agent-session-runtime.md): `AgentSession.run()`/`stream()`, abort, subscribe
|
|
284
|
+
- [Supervisor delegation](supervisors.md): bounded dynamic child selection.
|
|
211
285
|
- [Agent events](agent-events.md): core `AgentEvent` wrapped by `agent_event`
|
|
212
286
|
- [Session stores and branching](session-stores-and-branching.md): session `leafId` reuse on resume
|
|
213
287
|
- [CLI/RPC](cli-rpc.md): host control seam; wire `createWorkflowCommands()` into `runRpcServer`
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Working and semantic memory
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`@arnilo/prism-memory` is an optional package for schema/template-backed working memory and embedding-based semantic recall. It owns narrow `Embedder` and `VectorStore` contracts reused by `@arnilo/prism-rag`, plus an in-memory reference path and one PostgreSQL/pgvector production adapter.
|
|
6
|
+
|
|
7
|
+
## When to use it
|
|
8
|
+
|
|
9
|
+
Use it when a host needs durable per-tenant profile/state (working memory) or top-K semantic retrieval over prior thread entries. Do not use it as a replacement for observational memory compaction: observational memory compresses source-backed observations; semantic memory retrieves embeddings; working memory stores the current structured profile.
|
|
10
|
+
|
|
11
|
+
Ordinary Prism sessions do not require this package or any vector backend.
|
|
12
|
+
|
|
13
|
+
## Inputs / request
|
|
14
|
+
|
|
15
|
+
`createMemory(options)`:
|
|
16
|
+
|
|
17
|
+
| Field | Required | Meaning |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| `tenantId` | yes | Tenant isolation key |
|
|
20
|
+
| `resourceId` | yes | Resource/user isolation key |
|
|
21
|
+
| `threadId` | for semantic ops | Thread isolation; optional for resource-scoped working memory |
|
|
22
|
+
| `embedder` | yes | Host-owned or package hash embedder |
|
|
23
|
+
| `vectorStore` / `workingStore` | no | Defaults to in-memory adapters |
|
|
24
|
+
| `schema` / `validateWorkingMemory` | no | Working-memory shape checks (JSON Schema subset or host hook) |
|
|
25
|
+
| `workingMemoryTemplate` | no | `{{path}}` template for context injection |
|
|
26
|
+
| `limits` | no | top-K, adjacent range, batch, payload, injected-token caps |
|
|
27
|
+
| `redactor` / `secrets` | no | Redact text/metadata before persist/inject |
|
|
28
|
+
|
|
29
|
+
Semantic indexing:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
await memory.remember({ entries: [{ id, text, metadata?, sequence? }] }, { wait?: boolean })
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Semantic recall:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
await memory.recall(query, { topK?, messageRange?, signal? })
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Outputs / response / events
|
|
42
|
+
|
|
43
|
+
| API | Result |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `updateWorking` / `getWorking` | Versioned `WorkingMemoryRecord` |
|
|
46
|
+
| `remember` | `{ accepted, pending, done }` — default `wait: false` indexes asynchronously |
|
|
47
|
+
| `recall` | `{ hits, adjacent }` tenant/thread scoped |
|
|
48
|
+
| `createContextProvider()` | Inert `ContextProvider` blocks for working and/or semantic text |
|
|
49
|
+
| `createWorkingMemoryProcessor({ extract })` | Explicit host-invoked updater; never auto-runs |
|
|
50
|
+
|
|
51
|
+
No package-owned agent events are emitted. Injection uses existing context assembly only.
|
|
52
|
+
|
|
53
|
+
## Request/response example
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"tenantId": "t1",
|
|
58
|
+
"resourceId": "user-ada",
|
|
59
|
+
"threadId": "thread-1",
|
|
60
|
+
"working": { "name": "Ada", "preferences": { "format": "concise" } },
|
|
61
|
+
"recall": {
|
|
62
|
+
"query": "preferred response format",
|
|
63
|
+
"topK": 5,
|
|
64
|
+
"messageRange": 1
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Implementation example
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { createAgent, createMockProvider, providerDone, providerTextDelta } from "@arnilo/prism";
|
|
73
|
+
import { createHashEmbedder, createMemory } from "@arnilo/prism-memory";
|
|
74
|
+
|
|
75
|
+
const memory = createMemory({
|
|
76
|
+
tenantId: "t1",
|
|
77
|
+
resourceId: "user-ada",
|
|
78
|
+
threadId: "thread-1",
|
|
79
|
+
embedder: createHashEmbedder(),
|
|
80
|
+
workingMemoryTemplate: "Name: {{name}}; Format: {{preferences.format}}",
|
|
81
|
+
schema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
name: { type: "string" },
|
|
85
|
+
preferences: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: { format: { type: "string" } },
|
|
88
|
+
required: ["format"],
|
|
89
|
+
additionalProperties: false,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
required: ["name"],
|
|
93
|
+
additionalProperties: false,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await memory.updateWorking({ name: "Ada", preferences: { format: "concise" } });
|
|
98
|
+
await memory.remember({ entries: [{ id: "m1", text: "Prefers concise answers" }] });
|
|
99
|
+
|
|
100
|
+
const agent = createAgent({
|
|
101
|
+
model: { provider: "mock", model: "demo" },
|
|
102
|
+
provider: createMockProvider([providerTextDelta("Got it."), providerDone()]),
|
|
103
|
+
context: [memory.createContextProvider()],
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
PostgreSQL/pgvector:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { createPostgresMemoryStores, createMemory, createHashEmbedder } from "@arnilo/prism-memory";
|
|
111
|
+
|
|
112
|
+
const stores = await createPostgresMemoryStores({
|
|
113
|
+
connectionString: process.env.DATABASE_URL!,
|
|
114
|
+
schema: "prism_memory",
|
|
115
|
+
dimensions: 32,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const memory = createMemory({
|
|
119
|
+
tenantId: "t1",
|
|
120
|
+
resourceId: "user-ada",
|
|
121
|
+
threadId: "thread-1",
|
|
122
|
+
embedder: createHashEmbedder({ dimensions: 32 }),
|
|
123
|
+
workingStore: stores.workingStore,
|
|
124
|
+
vectorStore: stores.vectorStore,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Extension and configuration notes
|
|
129
|
+
|
|
130
|
+
- Hosts wire the context provider into `AgentConfig.context` or `resolveContextProviders()`.
|
|
131
|
+
- The working-memory processor is opt-in and host-invoked; middleware is not required.
|
|
132
|
+
- `createHashEmbedder()` is for tests/demos only; production hosts supply a real `Embedder`.
|
|
133
|
+
- Observational memory (`@arnilo/prism-compaction-observational-memory`) remains unchanged and composable.
|
|
134
|
+
- Profile bundles do not include this package yet.
|
|
135
|
+
|
|
136
|
+
Shared conformance:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { runMemoryConformance, createHashEmbedder, createMemoryVectorStore, createMemoryWorkingStore } from "@arnilo/prism-memory";
|
|
140
|
+
|
|
141
|
+
await runMemoryConformance(() => ({
|
|
142
|
+
embedder: createHashEmbedder(),
|
|
143
|
+
vectorStore: createMemoryVectorStore(),
|
|
144
|
+
workingStore: createMemoryWorkingStore(),
|
|
145
|
+
}));
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Security and performance notes
|
|
149
|
+
|
|
150
|
+
- Every write/query/delete requires `tenantId` + `resourceId`; semantic paths also require `threadId`.
|
|
151
|
+
- Cross-tenant and cross-thread access is denied.
|
|
152
|
+
- Configure `secrets` / `redactor` so memory text and metadata cannot persist or inject raw canaries.
|
|
153
|
+
- Injected context is inert text — it cannot grant tools or permissions.
|
|
154
|
+
- Hard caps: top-K ≤ 32, messageRange ≤ 4, embed batch ≤ 128, injected tokens ≤ 8000, payload/working-memory byte limits enforced.
|
|
155
|
+
- Default `remember()` does not block agent completion; pass `{ wait: true }` when indexing must finish first.
|
|
156
|
+
- PostgreSQL live suite is gated by `PRISM_TEST_POSTGRES_URL` and requires the `vector` extension.
|
|
157
|
+
|
|
158
|
+
## Delegated-agent isolation
|
|
159
|
+
|
|
160
|
+
Supervisor child factories receive unique derived `resourceId` and `threadId` values. Construct each child's `createMemory()` facade from those exact values; never reuse parent memory scope or let model-supplied IDs select another resource.
|
|
161
|
+
|
|
162
|
+
## Related APIs
|
|
163
|
+
|
|
164
|
+
- [Supervisor delegation](supervisors.md): package-derived child resource/thread scope.
|
|
165
|
+
- [Retrieval-augmented generation](rag.md): bounded document chunks reuse this package's embed/vector contracts.
|
|
166
|
+
- [Context and skills](context-and-skills.md): `ContextProvider` injection seam.
|
|
167
|
+
- [Observational memory compaction package](compaction-observational-memory.md): source-backed observation/reflection memory distinction.
|
|
168
|
+
- [PostgreSQL persistence](postgres-persistence.md): session/run persistence; memory vectors live in this optional package instead.
|
|
169
|
+
- [Middleware hooks](middleware-hooks.md): reuse existing `context` hook if hosts transform injected blocks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Agent harness for AI providers, agents, sessions, and tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
"types": "./dist/testing/run-ledger-conformance.d.ts",
|
|
55
55
|
"default": "./dist/testing/run-ledger-conformance.js"
|
|
56
56
|
},
|
|
57
|
+
"./testing/feedback": {
|
|
58
|
+
"types": "./dist/testing/feedback.d.ts",
|
|
59
|
+
"default": "./dist/testing/feedback.js"
|
|
60
|
+
},
|
|
57
61
|
"./node/config": {
|
|
58
62
|
"types": "./dist/node/config.d.ts",
|
|
59
63
|
"default": "./dist/node/config.js"
|
|
@@ -95,6 +99,7 @@
|
|
|
95
99
|
"!dist/__tests__",
|
|
96
100
|
"!dist/**/*.map",
|
|
97
101
|
"docs",
|
|
102
|
+
"templates",
|
|
98
103
|
"CHANGELOG.md"
|
|
99
104
|
],
|
|
100
105
|
"workspaces": [
|
|
@@ -108,6 +113,11 @@
|
|
|
108
113
|
"packages/coding-agent",
|
|
109
114
|
"packages/coding-security",
|
|
110
115
|
"packages/workflows",
|
|
116
|
+
"packages/evals",
|
|
117
|
+
"packages/memory",
|
|
118
|
+
"packages/rag",
|
|
119
|
+
"packages/server",
|
|
120
|
+
"packages/supervisor",
|
|
111
121
|
"packages/prism-*"
|
|
112
122
|
],
|
|
113
123
|
"scripts": {
|
|
@@ -116,7 +126,7 @@
|
|
|
116
126
|
"typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
|
|
117
127
|
"test": "npm run build && node --test dist/__tests__/*.test.js && npm run test --workspaces --if-present",
|
|
118
128
|
"pack:dry-run": "npm pack --dry-run && npm run pack:dry-run --workspaces --if-present",
|
|
119
|
-
"test:postgres": "npm run test:postgres --workspace @arnilo/prism-session-store-postgres",
|
|
129
|
+
"test:postgres": "npm run test:postgres --workspace @arnilo/prism-session-store-postgres && npm run test:postgres --workspace @arnilo/prism-memory",
|
|
120
130
|
"release:dry-run": "npm run sdk:ready",
|
|
121
131
|
"release:check": "node scripts/release.mjs check",
|
|
122
132
|
"release:publish": "node scripts/release.mjs publish",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
Minimal Prism agent scaffold generated by `prism init`.
|
|
4
|
+
|
|
5
|
+
__PROVIDER_README_NOTE__
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
npm test
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`npm test` always uses the built-in mock provider (no network, no credentials).
|
|
15
|
+
|
|
16
|
+
__NEXT_STEPS_LIVE__
|
|
17
|
+
|
|
18
|
+
## Layout
|
|
19
|
+
|
|
20
|
+
- `src/agent.ts` — creates the agent with the selected provider.
|
|
21
|
+
- `src/index.ts` — runs one prompt and prints `AgentRunResult.text`.
|
|
22
|
+
- `src/__tests__/agent.test.ts` — offline mock smoke test.
|
|
23
|
+
__OPTIONAL_DOCS__
|
|
24
|
+
## Notes
|
|
25
|
+
|
|
26
|
+
- Prism does not auto-load credentials, databases, telemetry, or tools.
|
|
27
|
+
- Keep real secrets out of git; `.gitignore` excludes `.env` and local stores.
|
|
28
|
+
- Docs: https://github.com/ashiqrniloy/prism
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__ENV_EXAMPLE__
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentRunResult } from "@arnilo/prism";
|
|
2
|
+
import { defineScorer, scoreRun } from "@arnilo/prism-evals";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic scorer example. Not wired into `npm start` — call after a run.
|
|
6
|
+
*/
|
|
7
|
+
export const greetsScorer = defineScorer({
|
|
8
|
+
id: "greets",
|
|
9
|
+
score: ({ result }) => ({
|
|
10
|
+
score: /\bhello\b/i.test(result.text) ? 1 : 0,
|
|
11
|
+
reason: "checks for a hello greeting",
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export async function scoreGreeting(result: AgentRunResult) {
|
|
16
|
+
return scoreRun({ result, scorers: [greetsScorer] });
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMemoryWorkflowCheckpoints,
|
|
3
|
+
defineWorkflow,
|
|
4
|
+
functionNode,
|
|
5
|
+
runWorkflow,
|
|
6
|
+
} from "@arnilo/prism-workflows";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tiny workflow example. Not wired into `npm start` — import and call from your host.
|
|
10
|
+
*/
|
|
11
|
+
export async function runHelloWorkflow(name: string) {
|
|
12
|
+
const workflow = defineWorkflow({
|
|
13
|
+
id: "hello",
|
|
14
|
+
nodes: {
|
|
15
|
+
greet: functionNode({
|
|
16
|
+
execute: async (ctx) => {
|
|
17
|
+
const input = ctx.workflowInput as { name?: string };
|
|
18
|
+
return { message: `Hello, ${input.name ?? name}` };
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return runWorkflow(workflow, { name }, {
|
|
25
|
+
checkpoints: createMemoryWorkflowCheckpoints(),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
9
|
+
"test": "npm run build && node --test dist/__tests__/agent.test.js",
|
|
10
|
+
"start": "npm run build && node dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
__DEPENDENCIES__
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^22.0.0",
|
|
17
|
+
"typescript": "^5.7.0"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
}
|
|
22
|
+
}
|