npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kortyx/hooks

v0.35.7

Published

Lifecycle hooks and extension points for Kortyx.

Readme

@kortyx/hooks

npm version CI License TypeScript

Node-level hooks for model calls, human-in-the-loop interrupts, structured stream data, runtime context, and durable node/workflow state.

Most application code should import these APIs from kortyx. Use @kortyx/hooks directly when you want the hook package without the full facade.

Install

pnpm add @kortyx/hooks
npm install @kortyx/hooks

Key APIs

  • useReason(...) for model calls, optional schema-constrained interrupt flow, and structured output.
  • useInterrupt(...) for explicit human-in-the-loop pauses.
  • useStructuredData(...) for UI-friendly structured stream events.
  • defineOutputContract(...) for reusable model-selected and application-authored structured values.
  • useRuntimeContext(...) for request context made available to node execution.
  • useNodeState(...) / useWorkflowState(...) for stateful node logic.

Define reusable model-driven human-input contracts with defineInterruptContract(...), then pass one or more through useReason({ interrupts: { contracts } }). Contract calls share the ordinary tool loop, so tools can run before and after a pause. Use mode: "optional" when the model may finish without asking, and maxRequests to bound sequential human turns.

Malformed model-authored requests return an isError tool result so the model can correct its arguments. They consume the existing model/loop allowance, but do not issue a human request or consume maxRequests. Required mode still requires a valid request. Human response validation and approval denial remain strict.

The singular useReason({ interrupt }) option and result.interruptResponse are deprecated and will be removed in the next major release. Migrate to interrupts.contracts and result.interruptHistory.

Pass output contracts through useReason({ outputs: { emit, return } }) to let the model emit values between text segments or choose a typed terminal result. Contracts with stream.fields start a separate streamed JSON pass and publish partial set, append, or text-delta updates before the validated final value. useStructuredData({ contract, data }) uses the same stream contract for application-authored values. The older outputSchema and structured options and result.output remain available during migration, but are deprecated and scheduled for removal in the next major release. TypeSafe Jev's provider-native decision schema is a temporary exception until a non-tool replacement ships.

Mixed tools, outputs, and interrupts

A model turn may request multiple domain tools, emit outputs, and interrupt contracts together. They run in the requested order, so an emitted card can appear before a question about it. Each interrupt pauses the remaining calls; resume reuses completed tool results, emissions, and human responses. Tool approval still applies, and interrupts.maxRequests and outputs.maxEmissions still bound their respective calls.

A terminal return runs after every other call in that turn, regardless of its position. When an output follows domain or interrupt results from the same turn, Kortyx generates its value in a separate schema-constrained model pass using those results, rather than publishing the original draft. Streamed contracts use their normal streamed generation pass; other contracts use a buffered pass. These passes, including failed attempts, consume toolExecution.maxSteps across resume. Budget exhaustion throws a ProviderRequestError with code REASON_OUTPUT_BUDGET_EXHAUSTED and guidance to increase maxSteps.

There is one terminal result.returned value. If the model requests multiple returns, each receives an error result asking the model to select one. Other calls proceed normally, and completed calls are not replayed for correction. Correction consumes the remaining maxSteps; exhaustion throws a typed REASON_OUTPUT_CONTRACT_CORRECTION_EXHAUSTED failure. Multiple emit outputs are supported without this restriction.

Runtime Resume Behavior

On resume, the node function is replayed from the top.

  • useReason resumes from its internal checkpoint.
  • Code before useReason will re-run unless guarded.

Workarounds:

  • Keep nodes minimal and call useReason first.
  • Guard pre-useReason side effects with useNodeState.

Documentation

License

Apache-2.0. See LICENSE.

Child workflows

Call a registered workflow from a node or custom hook and continue with its result:

const result = await useWorkflow({
  id: "research",
  workflow: researchWorkflow,
  input: { topic: "AI agents" },
});
return { data: { summary: result.data.summary } };

The child defines inputSchema and outputSchema on defineWorkflow. Inputs and returned data are inferred from those schemas and validated at runtime. The result is the child's accumulated data parsed by its output schema. Use createWorkflowHooks({ research: researchWorkflow }) for typed string ids. Register the same definitions with the agent.

Calls need stable ids. A child interrupt pauses the chain; resuming replays the enclosing node and reuses saved child results. Keep effects before calls idempotent. Fork/rollback retain nested checkpoints; use Redis for persistence across server restarts. Join concurrent children with parallel:

const [first, second] = await parallel([
  useWorkflow({ id: "first", workflow: researchWorkflow, input: { topic: "AI" } }),
  useWorkflow({ id: "second", workflow: researchWorkflow, input: { topic: "Robotics" } }),
]);

The tuple follows input order. The join preserves all siblings before pausing and presents waiting questions individually through the parent handle. Terminal group failures throw ParallelError, whose results exposes each settled outcome. Await groups sequentially within one node; children may contain nested groups. Native Promise.all calls and parallel graph edges remain unsupported.

See the execution and replay contract.

When a required outputs.return is missing, useReason raises the typed REASON_TERMINAL_OUTPUT_MISSING validation error. Optional toolExecution: { maxSteps: 4, missingReturnCorrections: 1 } allows an output-only correction within the existing step budget, without replaying business tools. The correction budget defaults to zero.

Output schema correction

useReason gives invalid emitted/returned contract payloads and ordinary outputSchema JSON one output-only repair pass by default. Set schemaCorrections: 0 to disable repair, or choose an integer from 1 to 10. This is separate from toolExecution.missingReturnCorrections, which only handles a missing terminal control call.

Correction receives the declared schema, invalid schema fields, the failed value, and completed tool/human results. Business tools and human-input tools are disabled during repair. A corrected emission continues the reason loop; a corrected return completes it. Invalid provisional streamed fields are invalidated before the validated final value is published.

Every repair consumes toolExecution.maxSteps and the root execution budget, adds provider usage/cost, and retains its attempt count in the reason checkpoint. Resume and explicit Continue retain completed effects and the remaining repair allowance. Exhaustion uses REASON_OUTPUT_SCHEMA_CORRECTION_EXHAUSTED, with the contract, attempts and terminal reason; disabling repair preserves the original validation failure. Cancellation, provider errors/refusals, and output truncation are not schema repair requests. Provider-native decision schemas and the deprecated singular no-tool interrupt path retain their existing behavior.

Keep side effects outside Kortyx tools idempotent: replaying node code still requires the application's existing guards. Never wrap the entire workflow in a retry just to repair a model-produced field.