@kortyx/hooks 0.31.0 → 0.32.1

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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.32.1](https://github.com/kortyx-io/kortyx/compare/hooks-v0.32.0...hooks-v0.32.1) (2026-10-09)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * The following workspace dependencies were updated
9
+ * dependencies
10
+ * @kortyx/core bumped to 0.13.0
11
+ * @kortyx/providers bumped to 0.9.1
12
+
13
+ ## [0.32.0](https://github.com/kortyx-io/kortyx/compare/hooks-v0.31.0...hooks-v0.32.0) (2026-10-08)
14
+
15
+
16
+ ### Features
17
+
18
+ * **hooks:** support mixed tools outputs and interrupts ([#297](https://github.com/kortyx-io/kortyx/issues/297)) ([0aa4aa6](https://github.com/kortyx-io/kortyx/commit/0aa4aa6b08cd2ef44f603b8dbe8e35b30c54cbdc))
19
+
3
20
  ## [0.31.0](https://github.com/kortyx-io/kortyx/compare/hooks-v0.30.2...hooks-v0.31.0) (2026-10-08)
4
21
 
5
22
 
package/README.md CHANGED
@@ -49,6 +49,31 @@ and `result.output` remain available during migration, but are deprecated and
49
49
  scheduled for removal in the next major release. TypeSafe Jev's provider-native
50
50
  decision schema is a temporary exception until a non-tool replacement ships.
51
51
 
52
+ ## Mixed tools, outputs, and interrupts
53
+
54
+ A model turn may request multiple domain tools, `emit` outputs, and interrupt
55
+ contracts together. They run in the requested order, so an emitted card can
56
+ appear before a question about it. Each interrupt pauses the remaining calls;
57
+ resume reuses completed tool results, emissions, and human responses. Tool
58
+ approval still applies, and `interrupts.maxRequests` and `outputs.maxEmissions`
59
+ still bound their respective calls.
60
+
61
+ A terminal `return` runs after every other call in that turn, regardless of its
62
+ position. When an output follows domain or interrupt results from the same turn,
63
+ Kortyx generates its value in a separate schema-constrained model pass using
64
+ those results, rather than publishing the original draft. Streamed contracts use
65
+ their normal streamed generation pass; other contracts use a buffered pass.
66
+ These passes, including failed attempts, consume `toolExecution.maxSteps` across
67
+ resume. Budget exhaustion throws a `ProviderRequestError` with code
68
+ `REASON_OUTPUT_BUDGET_EXHAUSTED` and guidance to increase `maxSteps`.
69
+
70
+ There is one terminal `result.returned` value. If the model requests multiple
71
+ returns, each receives an error result asking the model to select one. Other
72
+ calls proceed normally, and completed calls are not replayed for correction.
73
+ Correction consumes the remaining `maxSteps`; exhaustion throws a typed
74
+ `REASON_OUTPUT_CONTRACT_CORRECTION_EXHAUSTED` failure. Multiple `emit` outputs
75
+ are supported without this restriction.
76
+
52
77
  ## Runtime Resume Behavior
53
78
 
54
79
  On resume, the node function is replayed from the top.
package/dist/index.d.ts CHANGED
@@ -96,6 +96,8 @@ type HookNodeRuntimeContext = {
96
96
  config: NodeConfig;
97
97
  emit: (event: string, payload: unknown) => void;
98
98
  awaitInterrupt: (args: InterruptInput) => InterruptResumeValue;
99
+ /** Consume an already-resolved engine interrupt when a durable hook skips it. */
100
+ replayInterrupt?: ((args: InterruptInput) => void) | undefined;
99
101
  callWorkflow?: WorkflowCallService;
100
102
  workflowCallTelemetry?: KortyxTelemetryConfig | undefined;
101
103
  };
@@ -258,6 +260,7 @@ type UseReasonInterruptConfig<TRequest extends InterruptInput = InterruptInput,
258
260
  schemaVersion?: string | undefined;
259
261
  };
260
262
  type UseReasonToolExecution = {
263
+ /** Model-pass budget, including output generation and correction across resume. */
261
264
  maxSteps?: number | undefined;
262
265
  approval?: boolean | Record<string, boolean> | undefined;
263
266
  emit?: boolean | Record<string, boolean> | undefined;