New:Socket for Asana Is Now Available.Learn more
Get Started

@sapiom/agent

Package Overview
Dependencies
Maintainers
4
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sapiom/agent

Versioned public contract for authoring Sapiom agents: types, directive constructors/guards, defineAgent, defineStep, InMemoryContextStore. Shared by customer agent definitions, the sandbox step-runner, and the engine.

Source
npmnpm
Version
0.9.5
Version published
Weekly downloads
5.2K
180.84%
Maintainers
4
Weekly downloads
 
Created
Source

@sapiom/agent

The versioned public contract for authoring Sapiom orchestrations.

A lean, dependency-light package (types + a small protocol runtime) shared by three consumers:

  • Customer orchestration definitions — authored against this package's types and compiled by the build.
  • The sandbox step-runner — reads a step's input, builds ctx, runs one step.
  • The engine — uses the directive guards + manifest schema; it never runs customer code, only validates the pure-data completion payload.

Install

npm install @sapiom/agent

Authoring surface

import {
  defineAgent,
  defineStep,
  goto,
  terminate,
} from "@sapiom/agent";

const start = defineStep({
  name: "start",
  next: ["finish"],
  async run(input, ctx) {
    return goto("finish", { greeting: `hello ${input.name}` });
  },
});

const finish = defineStep({
  name: "finish",
  next: [],
  terminal: true,
  async run() {
    return terminate({ done: true });
  },
});

export const hello = defineAgent({
  name: "hello",
  entry: "start",
  steps: { start, finish },
});

A step declares the transitions it may take (next / terminal / canFail / pause); the run return type is derived from those declarations, so an undeclared transition is a compile error. The build reads those same declarations to render the orchestration graph without executing anything.

The entry input contract

A step's inputSchema (a zod schema, imported from zod/v4) types and validates that step's input. The entry step's inputSchema is special — it is the agent's public API: the dashboard Run form, the trigger snippet, and the engine's pre-dispatch validation are all derived from it. Declare it on the entry step, with a .default() on each field so a zero-input run still validates:

import { defineStep, terminate } from "@sapiom/agent";
import { z } from "zod/v4";

const start = defineStep({
  name: "start",
  next: [],
  terminal: true,
  inputSchema: z.object({
    repo: z.string().default("sapiom/sapiom"),
  }),
  // `input` is inferred + validated from inputSchema: { repo: string }
  async run(input) {
    return terminate({ scanned: input.repo });
  },
});

inputSchema on a non-entry step types that step's inbound payload the same way — including a resumed step's signal payload, shown next.

Pausing on a long-running capability

Some ctx.sapiom capabilities are dispatched: you launch them, they run far past one step's budget, and they report back when they finish (a coding agent today; more below). A step can't inline-await one — it pauses, and a later step resumes with the result. pauseUntilSignal accepts the launch handle (or the launch promise itself) and reads everything it needs off it:

import { defineStep, pauseUntilSignal, terminate } from "@sapiom/agent";
import { CODING_RESULT_SIGNAL } from "@sapiom/tools";

const code = defineStep({
  name: "code",
  next: ["review"],
  // capability's exported signal constant so the decl can't drift from the handle.
  pause: { signal: CODING_RESULT_SIGNAL, resumeStep: "review" },
  async run(input, ctx) {
    // launch returns immediately; hand it straight to pauseUntilSignal. The run
    // parks at status='paused' and the dispatch loop exits.
    return pauseUntilSignal(
      ctx.sapiom.models.coding.launch({ task: input.task }),
      {
        resumeStep: "review",
      },
    );
  },
});

const review = defineStep({
  name: "review",
  next: [],
  terminal: true,
  // Give this step an `inputSchema` (a zod schema for the capability's result
  // shape) to type + validate what it receives.
  async run(result, ctx) {
    // Fires on success OR failure — branch on the terminal result.
    return terminate({ ok: result.status === "completed" });
  },
});

Things to know:

  • The pause is a real suspend across processes, so the launch and the resume are two steps — you can't fold them into one inline await.

  • The resumed step receives the capability's result as its input. Declare its inputSchema to type + validate it (each capability documents its result shape).

  • Pass the launch promise directly for the one-liner above, or await it first when you need the handle — to stash the run id in ctx.shared, or to try/catch a launch failure and route somewhere other than a retry. Awaiting doesn't lose the pause; the resolved handle still flows into pauseUntilSignal:

    async run(input, ctx) {
      const run = await ctx.sapiom.models.coding.launch({ task: input.task });
      ctx.shared.set("codingRunId", run.runId); // readable from the resumed step
      return pauseUntilSignal(run, { resumeStep: "review" });
    }
    
  • Outside an agent run nothing changesawait launch().wait() the capability as usual; the pause wiring only engages when a step pauses on the handle.

Compatible capabilities

Any capability whose launch returns a DispatchHandle (a dispatch member) is pausable; each ships a stable result-signal constant for the pause decl. This list grows as capabilities land:

CapabilityLaunchPause signal
Coding agentctx.sapiom.models.coding.launch(…)CODING_RESULT_SIGNAL (@sapiom/tools)

Keywords

sapiom

FAQs

Package last updated on 17 Aug 2026

Related posts