@kortyx/hooks 0.28.1 → 0.30.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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.30.0](https://github.com/kortyx-io/kortyx/compare/hooks-v0.29.0...hooks-v0.30.0) (2026-09-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * **hooks:** add realtime model-selected output contracts ([#249](https://github.com/kortyx-io/kortyx/issues/249)) ([ac52b47](https://github.com/kortyx-io/kortyx/commit/ac52b47151b64ce5be6ce6c7fd42d34a0fa8a76d))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @kortyx/telemetry-contracts bumped to 0.12.0
16
+
17
+ ## [0.29.0](https://github.com/kortyx-io/kortyx/compare/hooks-v0.28.1...hooks-v0.29.0) (2026-09-22)
18
+
19
+
20
+ ### Features
21
+
22
+ * **providers:** add OpenRouter and Jev support ([#230](https://github.com/kortyx-io/kortyx/issues/230)) ([7a6ac2c](https://github.com/kortyx-io/kortyx/commit/7a6ac2c2171850fa89f041e66c980521409e6819))
23
+
24
+
25
+ ### Dependencies
26
+
27
+ * The following workspace dependencies were updated
28
+ * dependencies
29
+ * @kortyx/core bumped to 0.11.0
30
+ * @kortyx/providers bumped to 0.8.3
31
+
3
32
  ## [0.28.1](https://github.com/kortyx-io/kortyx/compare/hooks-v0.28.0...hooks-v0.28.1) (2026-09-21)
4
33
 
5
34
 
package/README.md CHANGED
@@ -24,6 +24,7 @@ npm install @kortyx/hooks
24
24
  - `useReason(...)` for model calls, optional schema-constrained interrupt flow, and structured output.
25
25
  - `useInterrupt(...)` for explicit human-in-the-loop pauses.
26
26
  - `useStructuredData(...)` for UI-friendly structured stream events.
27
+ - `defineOutputContract(...)` for reusable model-selected and application-authored structured values.
27
28
  - `useRuntimeContext(...)` for request context made available to node execution.
28
29
  - `useNodeState(...)` / `useWorkflowState(...)` for stateful node logic.
29
30
 
@@ -38,6 +39,16 @@ The singular `useReason({ interrupt })` option and `result.interruptResponse`
38
39
  are deprecated and will be removed in the next major release. Migrate to
39
40
  `interrupts.contracts` and `result.interruptHistory`.
40
41
 
42
+ Pass output contracts through `useReason({ outputs: { emit, return } })` to let
43
+ the model emit values between text segments or choose a typed terminal result.
44
+ Contracts with `stream.fields` start a separate streamed JSON pass and publish
45
+ partial `set`, `append`, or `text-delta` updates before the validated `final`
46
+ value. `useStructuredData({ contract, data })` uses the same stream contract for
47
+ application-authored values. The older `outputSchema` and `structured` options
48
+ and `result.output` remain available during migration, but are deprecated and
49
+ scheduled for removal in the next major release. TypeSafe Jev's provider-native
50
+ decision schema is a temporary exception until a non-tool replacement ships.
51
+
41
52
  ## Runtime Resume Behavior
42
53
 
43
54
  On resume, the node function is replayed from the top.
package/dist/index.d.ts CHANGED
@@ -110,6 +110,10 @@ declare function runWithHookContext<T>(ctx: HookRuntimeContext, fn: () => Promis
110
110
  }>;
111
111
 
112
112
  type SchemaLike<T> = {
113
+ /** Provider helpers can opt out of prompt-appended output instructions. */
114
+ readonly "~kortyx"?: {
115
+ readonly nativeOutput?: boolean | undefined;
116
+ } | undefined;
113
117
  safeParse: (value: unknown) => {
114
118
  success: true;
115
119
  data: T;
@@ -131,6 +135,28 @@ type InterruptContract<TRequest = unknown, TResponse = unknown> = {
131
135
  schemaVersion: string;
132
136
  };
133
137
  type InterruptContractMap = Record<string, InterruptContract<unknown, unknown>>;
138
+ type OutputContract<TData = unknown> = {
139
+ description: string;
140
+ schema: SchemaLike<TData>;
141
+ schemaId: string;
142
+ schemaVersion: string;
143
+ /** Paths the model may update before emitting the validated final value. */
144
+ stream?: {
145
+ fields: UseReasonStructuredFields;
146
+ } | undefined;
147
+ };
148
+ type OutputContractMap = Record<string, OutputContract<unknown>>;
149
+ type UseReasonOutputsConfig<TEmit extends OutputContractMap = OutputContractMap, TReturn extends OutputContractMap = OutputContractMap> = {
150
+ emit?: TEmit | undefined;
151
+ return?: TReturn | undefined;
152
+ maxEmissions?: number | undefined;
153
+ };
154
+ type OutputContractEntry<TContracts extends OutputContractMap> = {
155
+ [TName in Extract<keyof TContracts, string>]: TContracts[TName] extends OutputContract<infer TData> ? {
156
+ contract: TName;
157
+ data: TData;
158
+ } : never;
159
+ }[Extract<keyof TContracts, string>];
134
160
  type UseReasonInterruptsConfig<TContracts extends InterruptContractMap = InterruptContractMap> = {
135
161
  mode?: "required" | "optional" | undefined;
136
162
  /** Maximum number of model-requested human interactions for this operation. */
@@ -155,6 +181,31 @@ type UseStructuredDataBaseArgs = {
155
181
  id?: string | undefined;
156
182
  streamId?: string | undefined;
157
183
  };
184
+ type UseContractStructuredDataArgs<TData> = {
185
+ contract: OutputContract<TData>;
186
+ id?: string | undefined;
187
+ } & ({
188
+ kind?: "final" | undefined;
189
+ data: TData;
190
+ streamId?: string | undefined;
191
+ } | {
192
+ kind: "set";
193
+ path: string;
194
+ value: unknown;
195
+ valueSchema?: SchemaLike<unknown> | undefined;
196
+ streamId: string;
197
+ } | {
198
+ kind: "append";
199
+ path: string;
200
+ items: unknown[];
201
+ itemSchema?: SchemaLike<unknown> | undefined;
202
+ streamId: string;
203
+ } | {
204
+ kind: "text-delta";
205
+ path: string;
206
+ delta: string;
207
+ streamId: string;
208
+ });
158
209
  type UseStructuredDataFinalArgs<TData = unknown> = UseStructuredDataBaseArgs & {
159
210
  kind?: "final" | undefined;
160
211
  data: TData;
@@ -211,7 +262,7 @@ type UseReasonToolExecution = {
211
262
  approval?: boolean | Record<string, boolean> | undefined;
212
263
  emit?: boolean | Record<string, boolean> | undefined;
213
264
  };
214
- type UseReasonArgs<TOutput = unknown, TRequest extends InterruptInput = InterruptInput, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap> = {
265
+ type UseReasonArgs<TOutput = unknown, TRequest extends InterruptInput = InterruptInput, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap, TEmit extends OutputContractMap = OutputContractMap, TReturn extends OutputContractMap = OutputContractMap> = {
215
266
  model: ProviderModelRef;
216
267
  input: string;
217
268
  system?: string | undefined;
@@ -226,8 +277,11 @@ type UseReasonArgs<TOutput = unknown, TRequest extends InterruptInput = Interrup
226
277
  stream?: boolean | undefined;
227
278
  id?: string | undefined;
228
279
  telemetry?: KortyxTraceMetadata | undefined;
280
+ /** @deprecated Removed in the next major. Use `outputs.return` with `defineOutputContract`. */
229
281
  outputSchema?: SchemaLike<TOutput> | undefined;
282
+ /** @deprecated Removed in the next major. Use output contracts for model-selected structured emissions. */
230
283
  structured?: UseReasonStructuredConfig | undefined;
284
+ outputs?: UseReasonOutputsConfig<TEmit, TReturn> | undefined;
231
285
  /** @deprecated Use `interrupts`. Removed in the next major release. */
232
286
  interrupt?: UseReasonInterruptConfig<TRequest, TResponse> | undefined;
233
287
  interrupts?: UseReasonInterruptsConfig<TContracts> | undefined;
@@ -235,6 +289,7 @@ type UseReasonArgs<TOutput = unknown, TRequest extends InterruptInput = Interrup
235
289
  toolExecution?: UseReasonToolExecution | undefined;
236
290
  };
237
291
  type UseReasonStep = {
292
+ kind?: "output" | undefined;
238
293
  toolObservations?: _kortyx_providers.ToolObservation[];
239
294
  stepIndex: number;
240
295
  text: string;
@@ -245,7 +300,7 @@ type UseReasonStep = {
245
300
  providerMetadata?: KortyxProviderMetadata | undefined;
246
301
  warnings?: KortyxWarning[] | undefined;
247
302
  };
248
- type UseReasonResult<TOutput = unknown, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap> = {
303
+ type UseReasonResult<TOutput = unknown, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap, TEmit extends OutputContractMap = OutputContractMap, TReturn extends OutputContractMap = OutputContractMap> = {
249
304
  id?: string;
250
305
  opId: string;
251
306
  text: string;
@@ -254,7 +309,10 @@ type UseReasonResult<TOutput = unknown, TResponse = InterruptResult, TContracts
254
309
  finishReason?: KortyxFinishReason;
255
310
  providerMetadata?: KortyxProviderMetadata;
256
311
  warnings?: KortyxWarning[];
312
+ /** @deprecated Removed in the next major. Use `returned` from an output contract. */
257
313
  output?: TOutput;
314
+ emissions?: OutputContractEntry<TEmit>[];
315
+ returned?: OutputContractEntry<TReturn>;
258
316
  /** @deprecated Use `interruptHistory`. Removed in the next major release. */
259
317
  interruptResponse?: TResponse;
260
318
  interruptHistory?: InterruptHistoryEntry<TContracts>[];
@@ -280,9 +338,12 @@ type UseContractInterruptArgs<TRequest, TResponse> = {
280
338
 
281
339
  declare const defineInterruptContract: <TRequest, TResponse>(contract: InterruptContract<TRequest, TResponse>) => InterruptContract<TRequest, TResponse>;
282
340
 
341
+ declare const defineOutputContract: <TData>(contract: OutputContract<TData>) => OutputContract<TData>;
342
+
283
343
  type StateSetter<T> = (next: T | ((prev: T) => T)) => void;
344
+ declare function useStructuredData<TData>(args: UseContractStructuredDataArgs<TData>): void;
284
345
  declare function useStructuredData<TData = unknown>(args: UseStructuredDataArgs<TData>): void;
285
- declare function useReason<TOutput = unknown, TRequest extends InterruptInput = InterruptInput, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap>(args: UseReasonArgs<TOutput, TRequest, TResponse, TContracts>): Promise<UseReasonResult<TOutput, TResponse, TContracts>>;
346
+ declare function useReason<TOutput = unknown, TRequest extends InterruptInput = InterruptInput, TResponse = InterruptResult, TContracts extends InterruptContractMap = InterruptContractMap, TEmit extends OutputContractMap = OutputContractMap, TReturn extends OutputContractMap = OutputContractMap>(args: UseReasonArgs<TOutput, TRequest, TResponse, TContracts, TEmit, TReturn>): Promise<UseReasonResult<TOutput, TResponse, TContracts, TEmit, TReturn>>;
286
347
  declare function useInterrupt<TRequest, TResponse>(args: UseContractInterruptArgs<TRequest, TResponse>): Promise<TResponse>;
287
348
  declare function useInterrupt<TRequest extends InterruptInput = InterruptInput, TResponse = InterruptResult>(args: UseInterruptArgs<TRequest, TResponse>): Promise<TResponse>;
288
349
  /** Live execution signal for cooperative I/O. Never store it in workflow state. */
@@ -305,4 +366,4 @@ declare function useTool<T extends KortyxExecutableTool>(args: UseToolArgs<T>):
305
366
  /** Best effort lifecycle facts. Engine snapshots and interrupt tokens never leave the runtime. */
306
367
  declare function emitWorkflowCall(telemetry: KortyxTelemetryConfig | undefined, type: KortyxTelemetryEventType, payload: Record<string, unknown>): void;
307
368
 
308
- export { type CompleteResponseOptions, type HookRuntimeContext, type InterruptContract, type InterruptContractMap, type InterruptHistoryEntry, KortyxTelemetryConfig, KortyxTelemetryEventType, KortyxTraceMetadata, ParallelError, ReasonTraceAdapter, ReportErrorOptions, type UseContractInterruptArgs, type UseInterruptArgs, type UseReasonArgs, type UseReasonInterruptConfig, type UseReasonInterruptsConfig, type UseReasonResult, type UseReasonStep, type UseReasonToolExecution, type UseStructuredDataArgs, type UseToolArgs, WorkflowCallError, type WorkflowCallOutcome, type WorkflowCallService, completeResponse, createWorkflowHooks, defineInterruptContract, emitWorkflowCall, parallel, reportError, runWithHookContext, useAbortSignal, useInterrupt, useNodeState, useReason, useRuntimeContext, useStructuredData, useTool, useWorkflow, useWorkflowState, workflowCallFingerprint };
369
+ export { type CompleteResponseOptions, type HookRuntimeContext, type InterruptContract, type InterruptContractMap, type InterruptHistoryEntry, KortyxTelemetryConfig, KortyxTelemetryEventType, KortyxTraceMetadata, type OutputContract, type OutputContractEntry, type OutputContractMap, ParallelError, ReasonTraceAdapter, ReportErrorOptions, type UseContractInterruptArgs, type UseContractStructuredDataArgs, type UseInterruptArgs, type UseReasonArgs, type UseReasonInterruptConfig, type UseReasonInterruptsConfig, type UseReasonOutputsConfig, type UseReasonResult, type UseReasonStep, type UseReasonToolExecution, type UseStructuredDataArgs, type UseToolArgs, WorkflowCallError, type WorkflowCallOutcome, type WorkflowCallService, completeResponse, createWorkflowHooks, defineInterruptContract, defineOutputContract, emitWorkflowCall, parallel, reportError, runWithHookContext, useAbortSignal, useInterrupt, useNodeState, useReason, useRuntimeContext, useStructuredData, useTool, useWorkflow, useWorkflowState, workflowCallFingerprint };