@codemation/node-example 0.0.38 → 0.0.40

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @codemation/node-example
2
2
 
3
+ ## 0.0.40
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`3044474`](https://github.com/MadeRelevant/codemation/commit/3044474495525490735510ff74500b53761284b6)]:
8
+ - @codemation/core@0.12.0
9
+
10
+ ## 0.0.39
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [[`e0933eb`](https://github.com/MadeRelevant/codemation/commit/e0933ebc51806a9593f94758860c591b8346a7a5)]:
15
+ - @codemation/core@0.11.1
16
+
3
17
  ## 0.0.38
4
18
 
5
19
  ### Patch Changes
package/LICENSE CHANGED
@@ -1 +1,37 @@
1
- ../../LICENSE
1
+ Codemation Pre-Stable License
2
+
3
+ Copyright (c) Made Relevant B.V. All rights reserved.
4
+
5
+ 1. Definitions
6
+
7
+ "Software" means the Codemation source code, documentation, and artifacts in this repository and any published npm packages in the Codemation monorepo.
8
+
9
+ "Stable Version" means the first published release of the package `@codemation/core` on the public npm registry with version 1.0.0 or higher.
10
+
11
+ 2. Permitted use (before Stable Version)
12
+
13
+ Until a Stable Version exists, you may use, copy, modify, and distribute the Software only for non-commercial purposes, including personal learning, research, evaluation, and internal use within your organization that does not charge third parties for access to the Software or a product or service whose primary value is the Software.
14
+
15
+ 3. Restrictions (before Stable Version)
16
+
17
+ Until a Stable Version exists, you must not:
18
+
19
+ a) Sell, rent, lease, or sublicense the Software or a derivative work for a fee;
20
+
21
+ b) Offer the Software or a derivative work as part of a paid product or service (including hosting, support, or consulting) where the Software is a material part of the offering;
22
+
23
+ c) Use the Software or a derivative work primarily to generate revenue or commercial advantage for you or others.
24
+
25
+ These restrictions apply to all versions published before a Stable Version, even if a later Stable Version is released under different terms.
26
+
27
+ 4. After Stable Version
28
+
29
+ The maintainers may publish a Stable Version under different license terms. If they do, those terms apply only to that Stable Version and subsequent releases they designate; they do not automatically apply to earlier pre-stable versions.
30
+
31
+ 5. No warranty
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34
+
35
+ 6. Third-party components
36
+
37
+ The Software may include third-party components under their own licenses. Those licenses govern those components.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { ReadableStream } from "node:stream/web";
2
1
  import { ZodType } from "zod";
3
2
  import { InjectionToken as TypeToken } from "tsyringe";
3
+ import { ReadableStream } from "node:stream/web";
4
4
 
5
5
  //#region ../core/src/contracts/baseTypes.d.ts
6
6
  /**
@@ -13,6 +13,137 @@ type NodeId = string;
13
13
  type OutputPortKey = string;
14
14
  type InputPortKey = string;
15
15
  //#endregion
16
+ //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
17
+ type CostTrackingComponent = "chat" | "ocr" | "rag";
18
+ interface CostTrackingUsageRecord {
19
+ readonly component: CostTrackingComponent;
20
+ readonly provider: string;
21
+ readonly operation: string;
22
+ readonly pricingKey: string;
23
+ readonly usageUnit: string;
24
+ readonly quantity: number;
25
+ readonly modelName?: string;
26
+ readonly attributes?: TelemetryAttributes;
27
+ }
28
+ interface CostTrackingPriceQuote {
29
+ readonly currency: string;
30
+ readonly currencyScale: number;
31
+ readonly estimatedAmountMinor: number;
32
+ readonly estimateKind: "catalog";
33
+ }
34
+ interface CostTrackingTelemetry {
35
+ captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
36
+ forScope(scope: TelemetryScope): CostTrackingTelemetry;
37
+ }
38
+ //#endregion
39
+ //#region ../core/src/contracts/telemetryTypes.d.ts
40
+ type TelemetryAttributePrimitive = string | number | boolean | null;
41
+ interface TelemetryAttributes {
42
+ readonly [key: string]: TelemetryAttributePrimitive | undefined;
43
+ }
44
+ interface TelemetryMetricRecord {
45
+ readonly name: string;
46
+ readonly value: number;
47
+ readonly unit?: string;
48
+ readonly attributes?: TelemetryAttributes;
49
+ }
50
+ interface TelemetrySpanEventRecord {
51
+ readonly name: string;
52
+ readonly occurredAt?: Date;
53
+ readonly attributes?: TelemetryAttributes;
54
+ }
55
+ interface TelemetryArtifactAttachment {
56
+ readonly kind: string;
57
+ readonly contentType: string;
58
+ readonly previewText?: string;
59
+ readonly previewJson?: JsonValue;
60
+ readonly payloadText?: string;
61
+ readonly payloadJson?: JsonValue;
62
+ readonly bytes?: number;
63
+ readonly truncated?: boolean;
64
+ readonly expiresAt?: Date;
65
+ }
66
+ interface TelemetryArtifactReference {
67
+ readonly artifactId: string;
68
+ readonly traceId?: string;
69
+ readonly spanId?: string;
70
+ }
71
+ interface TelemetrySpanEnd {
72
+ readonly status?: "ok" | "error";
73
+ readonly statusMessage?: string;
74
+ readonly endedAt?: Date;
75
+ readonly attributes?: TelemetryAttributes;
76
+ }
77
+ interface TelemetryChildSpanStart {
78
+ readonly name: string;
79
+ readonly kind?: "internal" | "client";
80
+ readonly startedAt?: Date;
81
+ readonly attributes?: TelemetryAttributes;
82
+ }
83
+ interface TelemetryScope {
84
+ readonly traceId?: string;
85
+ readonly spanId?: string;
86
+ readonly costTracking?: CostTrackingTelemetry;
87
+ addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
88
+ recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
89
+ attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
90
+ }
91
+ interface TelemetrySpanScope extends TelemetryScope {
92
+ readonly traceId: string;
93
+ readonly spanId: string;
94
+ end(args?: TelemetrySpanEnd): Promise<void> | void;
95
+ /**
96
+ * Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
97
+ * Children created via the returned telemetry's `startChildSpan` get this span as their parent.
98
+ *
99
+ * Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
100
+ * span instead of the orchestrator's node-level span.
101
+ */
102
+ asNodeTelemetry(args: Readonly<{
103
+ nodeId: NodeId;
104
+ activationId: NodeActivationId;
105
+ }>): NodeExecutionTelemetry;
106
+ }
107
+ interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
108
+ startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
109
+ }
110
+ interface ExecutionTelemetry extends TelemetryScope {
111
+ readonly traceId: string;
112
+ readonly spanId: string;
113
+ forNode(args: Readonly<{
114
+ nodeId: NodeId;
115
+ activationId: NodeActivationId;
116
+ }>): NodeExecutionTelemetry;
117
+ }
118
+ //#endregion
119
+ //#region ../core/src/contracts/retryPolicySpec.types.d.ts
120
+ /**
121
+ * In-process retry policy for runnable nodes. Serialized configs use the same
122
+ * `kind` discriminator (`JSON.stringify` / persisted workflows).
123
+ *
124
+ * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
125
+ */
126
+ type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
127
+ interface NoneRetryPolicySpec {
128
+ readonly kind: "none";
129
+ }
130
+ interface FixedRetryPolicySpec {
131
+ readonly kind: "fixed";
132
+ /** Total attempts including the first execution. Must be >= 1. */
133
+ readonly maxAttempts: number;
134
+ readonly delayMs: number;
135
+ }
136
+ interface ExponentialRetryPolicySpec {
137
+ readonly kind: "exponential";
138
+ /** Total attempts including the first execution. Must be >= 1. */
139
+ readonly maxAttempts: number;
140
+ readonly initialDelayMs: number;
141
+ readonly multiplier: number;
142
+ readonly maxDelayMs?: number;
143
+ /** When true, each delay is multiplied by a random factor in [1, 1.2). */
144
+ readonly jitter?: boolean;
145
+ }
146
+ //#endregion
16
147
  //#region ../core/src/contracts/credentialTypes.d.ts
17
148
  type CredentialTypeId = string;
18
149
  type CredentialRequirement = Readonly<{
@@ -24,6 +155,71 @@ type CredentialRequirement = Readonly<{
24
155
  helpUrl?: string;
25
156
  }>;
26
157
  //#endregion
158
+ //#region ../core/src/contracts/collectionTypes.d.ts
159
+ /**
160
+ * Represents a typed store for a single collection.
161
+ * All rows include auto-managed id, created_at, and updated_at fields.
162
+ */
163
+ interface CollectionStore<TRow extends Record<string, unknown> = Record<string, unknown>> {
164
+ /**
165
+ * Insert a new row. id, created_at, and updated_at are auto-populated.
166
+ */
167
+ insert(row: TRow): Promise<TRow & {
168
+ id: string;
169
+ created_at: Date;
170
+ updated_at: Date;
171
+ }>;
172
+ /**
173
+ * Get a single row by id.
174
+ */
175
+ get(id: string): Promise<(TRow & {
176
+ id: string;
177
+ created_at: Date;
178
+ updated_at: Date;
179
+ }) | null>;
180
+ /**
181
+ * Find a single row matching the provided filter.
182
+ */
183
+ findOne(filter: Partial<TRow>): Promise<(TRow & {
184
+ id: string;
185
+ created_at: Date;
186
+ updated_at: Date;
187
+ }) | null>;
188
+ /**
189
+ * List rows with optional pagination and filtering.
190
+ */
191
+ list(opts?: {
192
+ limit?: number;
193
+ offset?: number;
194
+ where?: Partial<TRow>;
195
+ }): Promise<{
196
+ rows: ReadonlyArray<TRow & {
197
+ id: string;
198
+ created_at: Date;
199
+ updated_at: Date;
200
+ }>;
201
+ total: number;
202
+ }>;
203
+ /**
204
+ * Update a row by id with partial data.
205
+ */
206
+ update(id: string, patch: Partial<TRow>): Promise<TRow & {
207
+ id: string;
208
+ created_at: Date;
209
+ updated_at: Date;
210
+ }>;
211
+ /**
212
+ * Delete a row by id. Hard delete only (no soft delete).
213
+ */
214
+ delete(id: string): Promise<{
215
+ deleted: boolean;
216
+ }>;
217
+ }
218
+ /**
219
+ * Runtime collections context: keyed by collection name.
220
+ */
221
+ type CollectionsContext = Readonly<Record<string, CollectionStore>>;
222
+ //#endregion
27
223
  //#region ../core/src/contracts/runTypes.d.ts
28
224
  /**
29
225
  * Test-suite linkage for a run. When set, this run was started by a TestSuiteOrchestrator
@@ -42,7 +238,7 @@ interface RunTestContext {
42
238
  readonly testCaseLabel?: string;
43
239
  }
44
240
  type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
45
- type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
241
+ type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped" | "hitl-approved" | "hitl-rejected" | "hitl-timeout" | "hitl-auto-accepted" | "hitl-cancelled";
46
242
  interface NodeExecutionError {
47
243
  message: string;
48
244
  name?: string;
@@ -71,34 +267,6 @@ type ConnectionInvocationAppendArgs = Readonly<{
71
267
  parentInvocationId?: ConnectionInvocationId;
72
268
  }>;
73
269
  //#endregion
74
- //#region ../core/src/contracts/retryPolicySpec.types.d.ts
75
- /**
76
- * In-process retry policy for runnable nodes. Serialized configs use the same
77
- * `kind` discriminator (`JSON.stringify` / persisted workflows).
78
- *
79
- * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
80
- */
81
- type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
82
- interface NoneRetryPolicySpec {
83
- readonly kind: "none";
84
- }
85
- interface FixedRetryPolicySpec {
86
- readonly kind: "fixed";
87
- /** Total attempts including the first execution. Must be >= 1. */
88
- readonly maxAttempts: number;
89
- readonly delayMs: number;
90
- }
91
- interface ExponentialRetryPolicySpec {
92
- readonly kind: "exponential";
93
- /** Total attempts including the first execution. Must be >= 1. */
94
- readonly maxAttempts: number;
95
- readonly initialDelayMs: number;
96
- readonly multiplier: number;
97
- readonly maxDelayMs?: number;
98
- /** When true, each delay is multiplied by a random factor in [1, 1.2). */
99
- readonly jitter?: boolean;
100
- }
101
- //#endregion
102
270
  //#region ../core/src/contracts/workflowTypes.d.ts
103
271
  type NodeIdRef<TJson = unknown> = NodeId & Readonly<{
104
272
  __codemationNodeJson?: TJson;
@@ -260,175 +428,53 @@ interface NodeErrorHandler {
260
428
  }
261
429
  type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandler;
262
430
  //#endregion
263
- //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
264
- type CostTrackingComponent = "chat" | "ocr" | "rag";
265
- interface CostTrackingUsageRecord {
266
- readonly component: CostTrackingComponent;
267
- readonly provider: string;
268
- readonly operation: string;
269
- readonly pricingKey: string;
270
- readonly usageUnit: string;
271
- readonly quantity: number;
272
- readonly modelName?: string;
273
- readonly attributes?: TelemetryAttributes;
274
- }
275
- interface CostTrackingPriceQuote {
276
- readonly currency: string;
277
- readonly currencyScale: number;
278
- readonly estimatedAmountMinor: number;
279
- readonly estimateKind: "catalog";
280
- }
281
- interface CostTrackingTelemetry {
282
- captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
283
- forScope(scope: TelemetryScope): CostTrackingTelemetry;
284
- }
285
- //#endregion
286
- //#region ../core/src/contracts/telemetryTypes.d.ts
287
- type TelemetryAttributePrimitive = string | number | boolean | null;
288
- interface TelemetryAttributes {
289
- readonly [key: string]: TelemetryAttributePrimitive | undefined;
290
- }
291
- interface TelemetryMetricRecord {
292
- readonly name: string;
293
- readonly value: number;
294
- readonly unit?: string;
295
- readonly attributes?: TelemetryAttributes;
296
- }
297
- interface TelemetrySpanEventRecord {
298
- readonly name: string;
299
- readonly occurredAt?: Date;
300
- readonly attributes?: TelemetryAttributes;
301
- }
302
- interface TelemetryArtifactAttachment {
303
- readonly kind: string;
304
- readonly contentType: string;
305
- readonly previewText?: string;
306
- readonly previewJson?: JsonValue;
307
- readonly payloadText?: string;
308
- readonly payloadJson?: JsonValue;
309
- readonly bytes?: number;
310
- readonly truncated?: boolean;
311
- readonly expiresAt?: Date;
312
- }
313
- interface TelemetryArtifactReference {
314
- readonly artifactId: string;
315
- readonly traceId?: string;
316
- readonly spanId?: string;
317
- }
318
- interface TelemetrySpanEnd {
319
- readonly status?: "ok" | "error";
320
- readonly statusMessage?: string;
321
- readonly endedAt?: Date;
322
- readonly attributes?: TelemetryAttributes;
323
- }
324
- interface TelemetryChildSpanStart {
325
- readonly name: string;
326
- readonly kind?: "internal" | "client";
327
- readonly startedAt?: Date;
328
- readonly attributes?: TelemetryAttributes;
329
- }
330
- interface TelemetryScope {
331
- readonly traceId?: string;
332
- readonly spanId?: string;
333
- readonly costTracking?: CostTrackingTelemetry;
334
- addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
335
- recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
336
- attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
337
- }
338
- interface TelemetrySpanScope extends TelemetryScope {
339
- readonly traceId: string;
340
- readonly spanId: string;
341
- end(args?: TelemetrySpanEnd): Promise<void> | void;
431
+ //#region ../core/src/contracts/runtimeTypes.d.ts
432
+ /** Opaque unique identifier for a single HumanTask instance. */
433
+ type HumanTaskId = string;
434
+ /**
435
+ * Minimal handle handed to the `deliver` callback so it can route to the correct
436
+ * inbox channel.
437
+ */
438
+ interface HumanTaskHandle {
439
+ readonly taskId: HumanTaskId;
440
+ readonly runId: string;
441
+ readonly nodeId: string;
442
+ readonly expiresAt: Date;
443
+ /** TODO: real signed URL; placeholder empty string for now. */
444
+ readonly resumeUrl: string;
342
445
  /**
343
- * Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
344
- * Children created via the returned telemetry's `startChildSpan` get this span as their parent.
345
- *
346
- * Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
347
- * span instead of the orchestrator's node-level span.
446
+ * Arbitrary JSON metadata copied from `SuspensionRequest.request.metadata` at suspension time.
447
+ * Used by the agent runtime to round-trip the `agentCheckpoint` back to the
448
+ * resumed node via `ctx.resumeContext.task.metadata`.
348
449
  */
349
- asNodeTelemetry(args: Readonly<{
350
- nodeId: NodeId;
351
- activationId: NodeActivationId;
352
- }>): NodeExecutionTelemetry;
450
+ readonly metadata?: Readonly<Record<string, JsonValue>>;
353
451
  }
354
- interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
355
- startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
452
+ /** Identity of the person who made a decision on the task. */
453
+ interface HumanTaskActor {
454
+ readonly actorId: string;
455
+ readonly displayName?: string;
356
456
  }
357
- interface ExecutionTelemetry extends TelemetryScope {
358
- readonly traceId: string;
359
- readonly spanId: string;
360
- forNode(args: Readonly<{
361
- nodeId: NodeId;
362
- activationId: NodeActivationId;
363
- }>): NodeExecutionTelemetry;
364
- }
365
- //#endregion
366
- //#region ../core/src/contracts/collectionTypes.d.ts
367
457
  /**
368
- * Represents a typed store for a single collection.
369
- * All rows include auto-managed id, created_at, and updated_at fields.
458
+ * Resume context injected into `NodeExecutionContext` when the engine re-activates
459
+ * a previously suspended node. `defineHumanApprovalNode` wraps this with parsed
460
+ * `TDecision`; at the engine layer `decision.value` is `unknown`.
370
461
  */
371
- interface CollectionStore<TRow extends Record<string, unknown> = Record<string, unknown>> {
372
- /**
373
- * Insert a new row. id, created_at, and updated_at are auto-populated.
374
- */
375
- insert(row: TRow): Promise<TRow & {
376
- id: string;
377
- created_at: Date;
378
- updated_at: Date;
379
- }>;
380
- /**
381
- * Get a single row by id.
382
- */
383
- get(id: string): Promise<(TRow & {
384
- id: string;
385
- created_at: Date;
386
- updated_at: Date;
387
- }) | null>;
388
- /**
389
- * Find a single row matching the provided filter.
390
- */
391
- findOne(filter: Partial<TRow>): Promise<(TRow & {
392
- id: string;
393
- created_at: Date;
394
- updated_at: Date;
395
- }) | null>;
396
- /**
397
- * List rows with optional pagination and filtering.
398
- */
399
- list(opts?: {
400
- limit?: number;
401
- offset?: number;
402
- where?: Partial<TRow>;
403
- }): Promise<{
404
- rows: ReadonlyArray<TRow & {
405
- id: string;
406
- created_at: Date;
407
- updated_at: Date;
408
- }>;
409
- total: number;
410
- }>;
411
- /**
412
- * Update a row by id with partial data.
413
- */
414
- update(id: string, patch: Partial<TRow>): Promise<TRow & {
415
- id: string;
416
- created_at: Date;
417
- updated_at: Date;
418
- }>;
419
- /**
420
- * Delete a row by id. Hard delete only (no soft delete).
421
- */
422
- delete(id: string): Promise<{
423
- deleted: boolean;
462
+ interface ResumeContext {
463
+ readonly decision: Readonly<{
464
+ kind: "decided";
465
+ value: unknown;
466
+ actor: HumanTaskActor;
467
+ decidedAt: Date;
468
+ }> | Readonly<{
469
+ kind: "timed_out";
470
+ at: Date;
471
+ }> | Readonly<{
472
+ kind: "auto_accepted";
473
+ at: Date;
424
474
  }>;
475
+ readonly delivery: JsonValue;
476
+ readonly task: HumanTaskHandle;
425
477
  }
426
- /**
427
- * Runtime collections context: keyed by collection name.
428
- */
429
- type CollectionsContext = Readonly<Record<string, CollectionStore>>;
430
- //#endregion
431
- //#region ../core/src/contracts/runtimeTypes.d.ts
432
478
  interface NodeExecutionStatePublisher {
433
479
  markQueued(args: {
434
480
  nodeId: NodeId;
@@ -517,6 +563,14 @@ interface ExecutionContext {
517
563
  * Collections registered in the codemation config, keyed by collection name.
518
564
  */
519
565
  readonly collections?: CollectionsContext;
566
+ /**
567
+ * Resolve a DI token from the host container.
568
+ * Allows nodes to reach host-side services (e.g. `InboxChannelResolverToken`)
569
+ * without importing host code. Wired by `DefaultExecutionContextFactory`; throws
570
+ * a clear error when no resolver is configured (e.g. in unit tests that don't
571
+ * set up the full container).
572
+ */
573
+ resolve<T>(token: TypeToken<T>): T;
520
574
  }
521
575
  interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
522
576
  nodeId: NodeId;
@@ -524,6 +578,11 @@ interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase>
524
578
  config: TConfig;
525
579
  telemetry: NodeExecutionTelemetry;
526
580
  binary: NodeBinaryAttachmentService;
581
+ /**
582
+ * Present when this node activation is a HITL resume.
583
+ * The node checks `ctx.resumeContext !== undefined` and takes the resume branch.
584
+ */
585
+ resumeContext?: ResumeContext;
527
586
  }
528
587
  /**
529
588
  * Per-item runnable node: return JSON, an array to fan-out on `main`, an explicit `Item`, or {@link emitPorts}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { ReadableStream } from "node:stream/web";
2
1
  import { ZodType } from "zod";
3
2
  import { InjectionToken as TypeToken } from "tsyringe";
3
+ import { ReadableStream } from "node:stream/web";
4
4
 
5
5
  //#region ../core/src/contracts/baseTypes.d.ts
6
6
  /**
@@ -13,6 +13,137 @@ type NodeId = string;
13
13
  type OutputPortKey = string;
14
14
  type InputPortKey = string;
15
15
  //#endregion
16
+ //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
17
+ type CostTrackingComponent = "chat" | "ocr" | "rag";
18
+ interface CostTrackingUsageRecord {
19
+ readonly component: CostTrackingComponent;
20
+ readonly provider: string;
21
+ readonly operation: string;
22
+ readonly pricingKey: string;
23
+ readonly usageUnit: string;
24
+ readonly quantity: number;
25
+ readonly modelName?: string;
26
+ readonly attributes?: TelemetryAttributes;
27
+ }
28
+ interface CostTrackingPriceQuote {
29
+ readonly currency: string;
30
+ readonly currencyScale: number;
31
+ readonly estimatedAmountMinor: number;
32
+ readonly estimateKind: "catalog";
33
+ }
34
+ interface CostTrackingTelemetry {
35
+ captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
36
+ forScope(scope: TelemetryScope): CostTrackingTelemetry;
37
+ }
38
+ //#endregion
39
+ //#region ../core/src/contracts/telemetryTypes.d.ts
40
+ type TelemetryAttributePrimitive = string | number | boolean | null;
41
+ interface TelemetryAttributes {
42
+ readonly [key: string]: TelemetryAttributePrimitive | undefined;
43
+ }
44
+ interface TelemetryMetricRecord {
45
+ readonly name: string;
46
+ readonly value: number;
47
+ readonly unit?: string;
48
+ readonly attributes?: TelemetryAttributes;
49
+ }
50
+ interface TelemetrySpanEventRecord {
51
+ readonly name: string;
52
+ readonly occurredAt?: Date;
53
+ readonly attributes?: TelemetryAttributes;
54
+ }
55
+ interface TelemetryArtifactAttachment {
56
+ readonly kind: string;
57
+ readonly contentType: string;
58
+ readonly previewText?: string;
59
+ readonly previewJson?: JsonValue;
60
+ readonly payloadText?: string;
61
+ readonly payloadJson?: JsonValue;
62
+ readonly bytes?: number;
63
+ readonly truncated?: boolean;
64
+ readonly expiresAt?: Date;
65
+ }
66
+ interface TelemetryArtifactReference {
67
+ readonly artifactId: string;
68
+ readonly traceId?: string;
69
+ readonly spanId?: string;
70
+ }
71
+ interface TelemetrySpanEnd {
72
+ readonly status?: "ok" | "error";
73
+ readonly statusMessage?: string;
74
+ readonly endedAt?: Date;
75
+ readonly attributes?: TelemetryAttributes;
76
+ }
77
+ interface TelemetryChildSpanStart {
78
+ readonly name: string;
79
+ readonly kind?: "internal" | "client";
80
+ readonly startedAt?: Date;
81
+ readonly attributes?: TelemetryAttributes;
82
+ }
83
+ interface TelemetryScope {
84
+ readonly traceId?: string;
85
+ readonly spanId?: string;
86
+ readonly costTracking?: CostTrackingTelemetry;
87
+ addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
88
+ recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
89
+ attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
90
+ }
91
+ interface TelemetrySpanScope extends TelemetryScope {
92
+ readonly traceId: string;
93
+ readonly spanId: string;
94
+ end(args?: TelemetrySpanEnd): Promise<void> | void;
95
+ /**
96
+ * Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
97
+ * Children created via the returned telemetry's `startChildSpan` get this span as their parent.
98
+ *
99
+ * Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
100
+ * span instead of the orchestrator's node-level span.
101
+ */
102
+ asNodeTelemetry(args: Readonly<{
103
+ nodeId: NodeId;
104
+ activationId: NodeActivationId;
105
+ }>): NodeExecutionTelemetry;
106
+ }
107
+ interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
108
+ startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
109
+ }
110
+ interface ExecutionTelemetry extends TelemetryScope {
111
+ readonly traceId: string;
112
+ readonly spanId: string;
113
+ forNode(args: Readonly<{
114
+ nodeId: NodeId;
115
+ activationId: NodeActivationId;
116
+ }>): NodeExecutionTelemetry;
117
+ }
118
+ //#endregion
119
+ //#region ../core/src/contracts/retryPolicySpec.types.d.ts
120
+ /**
121
+ * In-process retry policy for runnable nodes. Serialized configs use the same
122
+ * `kind` discriminator (`JSON.stringify` / persisted workflows).
123
+ *
124
+ * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
125
+ */
126
+ type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
127
+ interface NoneRetryPolicySpec {
128
+ readonly kind: "none";
129
+ }
130
+ interface FixedRetryPolicySpec {
131
+ readonly kind: "fixed";
132
+ /** Total attempts including the first execution. Must be >= 1. */
133
+ readonly maxAttempts: number;
134
+ readonly delayMs: number;
135
+ }
136
+ interface ExponentialRetryPolicySpec {
137
+ readonly kind: "exponential";
138
+ /** Total attempts including the first execution. Must be >= 1. */
139
+ readonly maxAttempts: number;
140
+ readonly initialDelayMs: number;
141
+ readonly multiplier: number;
142
+ readonly maxDelayMs?: number;
143
+ /** When true, each delay is multiplied by a random factor in [1, 1.2). */
144
+ readonly jitter?: boolean;
145
+ }
146
+ //#endregion
16
147
  //#region ../core/src/contracts/credentialTypes.d.ts
17
148
  type CredentialTypeId = string;
18
149
  type CredentialRequirement = Readonly<{
@@ -24,6 +155,71 @@ type CredentialRequirement = Readonly<{
24
155
  helpUrl?: string;
25
156
  }>;
26
157
  //#endregion
158
+ //#region ../core/src/contracts/collectionTypes.d.ts
159
+ /**
160
+ * Represents a typed store for a single collection.
161
+ * All rows include auto-managed id, created_at, and updated_at fields.
162
+ */
163
+ interface CollectionStore<TRow extends Record<string, unknown> = Record<string, unknown>> {
164
+ /**
165
+ * Insert a new row. id, created_at, and updated_at are auto-populated.
166
+ */
167
+ insert(row: TRow): Promise<TRow & {
168
+ id: string;
169
+ created_at: Date;
170
+ updated_at: Date;
171
+ }>;
172
+ /**
173
+ * Get a single row by id.
174
+ */
175
+ get(id: string): Promise<(TRow & {
176
+ id: string;
177
+ created_at: Date;
178
+ updated_at: Date;
179
+ }) | null>;
180
+ /**
181
+ * Find a single row matching the provided filter.
182
+ */
183
+ findOne(filter: Partial<TRow>): Promise<(TRow & {
184
+ id: string;
185
+ created_at: Date;
186
+ updated_at: Date;
187
+ }) | null>;
188
+ /**
189
+ * List rows with optional pagination and filtering.
190
+ */
191
+ list(opts?: {
192
+ limit?: number;
193
+ offset?: number;
194
+ where?: Partial<TRow>;
195
+ }): Promise<{
196
+ rows: ReadonlyArray<TRow & {
197
+ id: string;
198
+ created_at: Date;
199
+ updated_at: Date;
200
+ }>;
201
+ total: number;
202
+ }>;
203
+ /**
204
+ * Update a row by id with partial data.
205
+ */
206
+ update(id: string, patch: Partial<TRow>): Promise<TRow & {
207
+ id: string;
208
+ created_at: Date;
209
+ updated_at: Date;
210
+ }>;
211
+ /**
212
+ * Delete a row by id. Hard delete only (no soft delete).
213
+ */
214
+ delete(id: string): Promise<{
215
+ deleted: boolean;
216
+ }>;
217
+ }
218
+ /**
219
+ * Runtime collections context: keyed by collection name.
220
+ */
221
+ type CollectionsContext = Readonly<Record<string, CollectionStore>>;
222
+ //#endregion
27
223
  //#region ../core/src/contracts/runTypes.d.ts
28
224
  /**
29
225
  * Test-suite linkage for a run. When set, this run was started by a TestSuiteOrchestrator
@@ -42,7 +238,7 @@ interface RunTestContext {
42
238
  readonly testCaseLabel?: string;
43
239
  }
44
240
  type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
45
- type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
241
+ type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped" | "hitl-approved" | "hitl-rejected" | "hitl-timeout" | "hitl-auto-accepted" | "hitl-cancelled";
46
242
  interface NodeExecutionError {
47
243
  message: string;
48
244
  name?: string;
@@ -71,34 +267,6 @@ type ConnectionInvocationAppendArgs = Readonly<{
71
267
  parentInvocationId?: ConnectionInvocationId;
72
268
  }>;
73
269
  //#endregion
74
- //#region ../core/src/contracts/retryPolicySpec.types.d.ts
75
- /**
76
- * In-process retry policy for runnable nodes. Serialized configs use the same
77
- * `kind` discriminator (`JSON.stringify` / persisted workflows).
78
- *
79
- * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
80
- */
81
- type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
82
- interface NoneRetryPolicySpec {
83
- readonly kind: "none";
84
- }
85
- interface FixedRetryPolicySpec {
86
- readonly kind: "fixed";
87
- /** Total attempts including the first execution. Must be >= 1. */
88
- readonly maxAttempts: number;
89
- readonly delayMs: number;
90
- }
91
- interface ExponentialRetryPolicySpec {
92
- readonly kind: "exponential";
93
- /** Total attempts including the first execution. Must be >= 1. */
94
- readonly maxAttempts: number;
95
- readonly initialDelayMs: number;
96
- readonly multiplier: number;
97
- readonly maxDelayMs?: number;
98
- /** When true, each delay is multiplied by a random factor in [1, 1.2). */
99
- readonly jitter?: boolean;
100
- }
101
- //#endregion
102
270
  //#region ../core/src/contracts/workflowTypes.d.ts
103
271
  type NodeIdRef<TJson = unknown> = NodeId & Readonly<{
104
272
  __codemationNodeJson?: TJson;
@@ -260,175 +428,53 @@ interface NodeErrorHandler {
260
428
  }
261
429
  type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandler;
262
430
  //#endregion
263
- //#region ../core/src/contracts/CostTrackingTelemetryContract.d.ts
264
- type CostTrackingComponent = "chat" | "ocr" | "rag";
265
- interface CostTrackingUsageRecord {
266
- readonly component: CostTrackingComponent;
267
- readonly provider: string;
268
- readonly operation: string;
269
- readonly pricingKey: string;
270
- readonly usageUnit: string;
271
- readonly quantity: number;
272
- readonly modelName?: string;
273
- readonly attributes?: TelemetryAttributes;
274
- }
275
- interface CostTrackingPriceQuote {
276
- readonly currency: string;
277
- readonly currencyScale: number;
278
- readonly estimatedAmountMinor: number;
279
- readonly estimateKind: "catalog";
280
- }
281
- interface CostTrackingTelemetry {
282
- captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined>;
283
- forScope(scope: TelemetryScope): CostTrackingTelemetry;
284
- }
285
- //#endregion
286
- //#region ../core/src/contracts/telemetryTypes.d.ts
287
- type TelemetryAttributePrimitive = string | number | boolean | null;
288
- interface TelemetryAttributes {
289
- readonly [key: string]: TelemetryAttributePrimitive | undefined;
290
- }
291
- interface TelemetryMetricRecord {
292
- readonly name: string;
293
- readonly value: number;
294
- readonly unit?: string;
295
- readonly attributes?: TelemetryAttributes;
296
- }
297
- interface TelemetrySpanEventRecord {
298
- readonly name: string;
299
- readonly occurredAt?: Date;
300
- readonly attributes?: TelemetryAttributes;
301
- }
302
- interface TelemetryArtifactAttachment {
303
- readonly kind: string;
304
- readonly contentType: string;
305
- readonly previewText?: string;
306
- readonly previewJson?: JsonValue;
307
- readonly payloadText?: string;
308
- readonly payloadJson?: JsonValue;
309
- readonly bytes?: number;
310
- readonly truncated?: boolean;
311
- readonly expiresAt?: Date;
312
- }
313
- interface TelemetryArtifactReference {
314
- readonly artifactId: string;
315
- readonly traceId?: string;
316
- readonly spanId?: string;
317
- }
318
- interface TelemetrySpanEnd {
319
- readonly status?: "ok" | "error";
320
- readonly statusMessage?: string;
321
- readonly endedAt?: Date;
322
- readonly attributes?: TelemetryAttributes;
323
- }
324
- interface TelemetryChildSpanStart {
325
- readonly name: string;
326
- readonly kind?: "internal" | "client";
327
- readonly startedAt?: Date;
328
- readonly attributes?: TelemetryAttributes;
329
- }
330
- interface TelemetryScope {
331
- readonly traceId?: string;
332
- readonly spanId?: string;
333
- readonly costTracking?: CostTrackingTelemetry;
334
- addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
335
- recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
336
- attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
337
- }
338
- interface TelemetrySpanScope extends TelemetryScope {
339
- readonly traceId: string;
340
- readonly spanId: string;
341
- end(args?: TelemetrySpanEnd): Promise<void> | void;
431
+ //#region ../core/src/contracts/runtimeTypes.d.ts
432
+ /** Opaque unique identifier for a single HumanTask instance. */
433
+ type HumanTaskId = string;
434
+ /**
435
+ * Minimal handle handed to the `deliver` callback so it can route to the correct
436
+ * inbox channel.
437
+ */
438
+ interface HumanTaskHandle {
439
+ readonly taskId: HumanTaskId;
440
+ readonly runId: string;
441
+ readonly nodeId: string;
442
+ readonly expiresAt: Date;
443
+ /** TODO: real signed URL; placeholder empty string for now. */
444
+ readonly resumeUrl: string;
342
445
  /**
343
- * Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
344
- * Children created via the returned telemetry's `startChildSpan` get this span as their parent.
345
- *
346
- * Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
347
- * span instead of the orchestrator's node-level span.
446
+ * Arbitrary JSON metadata copied from `SuspensionRequest.request.metadata` at suspension time.
447
+ * Used by the agent runtime to round-trip the `agentCheckpoint` back to the
448
+ * resumed node via `ctx.resumeContext.task.metadata`.
348
449
  */
349
- asNodeTelemetry(args: Readonly<{
350
- nodeId: NodeId;
351
- activationId: NodeActivationId;
352
- }>): NodeExecutionTelemetry;
450
+ readonly metadata?: Readonly<Record<string, JsonValue>>;
353
451
  }
354
- interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
355
- startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
452
+ /** Identity of the person who made a decision on the task. */
453
+ interface HumanTaskActor {
454
+ readonly actorId: string;
455
+ readonly displayName?: string;
356
456
  }
357
- interface ExecutionTelemetry extends TelemetryScope {
358
- readonly traceId: string;
359
- readonly spanId: string;
360
- forNode(args: Readonly<{
361
- nodeId: NodeId;
362
- activationId: NodeActivationId;
363
- }>): NodeExecutionTelemetry;
364
- }
365
- //#endregion
366
- //#region ../core/src/contracts/collectionTypes.d.ts
367
457
  /**
368
- * Represents a typed store for a single collection.
369
- * All rows include auto-managed id, created_at, and updated_at fields.
458
+ * Resume context injected into `NodeExecutionContext` when the engine re-activates
459
+ * a previously suspended node. `defineHumanApprovalNode` wraps this with parsed
460
+ * `TDecision`; at the engine layer `decision.value` is `unknown`.
370
461
  */
371
- interface CollectionStore<TRow extends Record<string, unknown> = Record<string, unknown>> {
372
- /**
373
- * Insert a new row. id, created_at, and updated_at are auto-populated.
374
- */
375
- insert(row: TRow): Promise<TRow & {
376
- id: string;
377
- created_at: Date;
378
- updated_at: Date;
379
- }>;
380
- /**
381
- * Get a single row by id.
382
- */
383
- get(id: string): Promise<(TRow & {
384
- id: string;
385
- created_at: Date;
386
- updated_at: Date;
387
- }) | null>;
388
- /**
389
- * Find a single row matching the provided filter.
390
- */
391
- findOne(filter: Partial<TRow>): Promise<(TRow & {
392
- id: string;
393
- created_at: Date;
394
- updated_at: Date;
395
- }) | null>;
396
- /**
397
- * List rows with optional pagination and filtering.
398
- */
399
- list(opts?: {
400
- limit?: number;
401
- offset?: number;
402
- where?: Partial<TRow>;
403
- }): Promise<{
404
- rows: ReadonlyArray<TRow & {
405
- id: string;
406
- created_at: Date;
407
- updated_at: Date;
408
- }>;
409
- total: number;
410
- }>;
411
- /**
412
- * Update a row by id with partial data.
413
- */
414
- update(id: string, patch: Partial<TRow>): Promise<TRow & {
415
- id: string;
416
- created_at: Date;
417
- updated_at: Date;
418
- }>;
419
- /**
420
- * Delete a row by id. Hard delete only (no soft delete).
421
- */
422
- delete(id: string): Promise<{
423
- deleted: boolean;
462
+ interface ResumeContext {
463
+ readonly decision: Readonly<{
464
+ kind: "decided";
465
+ value: unknown;
466
+ actor: HumanTaskActor;
467
+ decidedAt: Date;
468
+ }> | Readonly<{
469
+ kind: "timed_out";
470
+ at: Date;
471
+ }> | Readonly<{
472
+ kind: "auto_accepted";
473
+ at: Date;
424
474
  }>;
475
+ readonly delivery: JsonValue;
476
+ readonly task: HumanTaskHandle;
425
477
  }
426
- /**
427
- * Runtime collections context: keyed by collection name.
428
- */
429
- type CollectionsContext = Readonly<Record<string, CollectionStore>>;
430
- //#endregion
431
- //#region ../core/src/contracts/runtimeTypes.d.ts
432
478
  interface NodeExecutionStatePublisher {
433
479
  markQueued(args: {
434
480
  nodeId: NodeId;
@@ -517,6 +563,14 @@ interface ExecutionContext {
517
563
  * Collections registered in the codemation config, keyed by collection name.
518
564
  */
519
565
  readonly collections?: CollectionsContext;
566
+ /**
567
+ * Resolve a DI token from the host container.
568
+ * Allows nodes to reach host-side services (e.g. `InboxChannelResolverToken`)
569
+ * without importing host code. Wired by `DefaultExecutionContextFactory`; throws
570
+ * a clear error when no resolver is configured (e.g. in unit tests that don't
571
+ * set up the full container).
572
+ */
573
+ resolve<T>(token: TypeToken<T>): T;
520
574
  }
521
575
  interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
522
576
  nodeId: NodeId;
@@ -524,6 +578,11 @@ interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase>
524
578
  config: TConfig;
525
579
  telemetry: NodeExecutionTelemetry;
526
580
  binary: NodeBinaryAttachmentService;
581
+ /**
582
+ * Present when this node activation is a HITL resume.
583
+ * The node checks `ctx.resumeContext !== undefined` and takes the resume branch.
584
+ */
585
+ resumeContext?: ResumeContext;
527
586
  }
528
587
  /**
529
588
  * Per-item runnable node: return JSON, an array to fan-out on `main`, an explicit `Item`, or {@link emitPorts}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemation/node-example",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -28,7 +28,7 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@codemation/core": "0.11.0"
31
+ "@codemation/core": "0.12.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^25.3.5",