Skip to main content
@stigg/agent-sdk-js adds gating, metering and budgets to the LLM calls your agents make. See AI agents for setup, and the source on GitHub.
npm also lists versions 1.0.0, 1.0.1, 1.1.0 and 2.0.0. Those are pre-release builds published before the package was re-versioned, and they aren’t supported. Install 0.1.0 or later.
2026-10-26
LangChain and LangGraph
  • Added: StiggLangChainCallbackHandler, from the new @stigg/agent-sdk-js/langchain entry point. Pass it in a run’s callbacks to govern a LangChain createAgent graph or a hand-built LangGraph StateGraph. Each model call and governed tool call is checked before it runs and billed after it succeeds, as the agent that made it. @langchain/core 1.x is an optional peer dependency.
  • Added: stigg.middleware({ stiggContext, tools, hooks, agents }), the framework-neutral logic behind the handler, for wiring other orchestrators.
  • Added: the run’s customer comes from metadata.stiggCustomerId, or from a default customerId in stiggContext. A run with neither is refused before its first step. Set stiggCustomerId on your server, because it wins over the default.
  • Added: per-tool governance in tools, keyed by tool name, with '*' for every tool not named:
    • An entitlement: checked, then billed one unit per call.
    • { entitlement, usage }: checked, then billed by a usage mapper over the call’s input and output.
    • { usage }: billed, never checked.
    • false: left ungoverned.
  • Added: agents, which gives each agent in the graph its own stiggContext and tools, laid over the shared ones. Point an agent’s agentId at an entity registered with stigg.register(), and its steps are checked and billed against that entity’s budget.
Other changes
  • Added: OpenTelemetry spans (stigg.check and stigg.ingest, with GenAI attribute names) from the middleware and the LangChain handler, so tracing tools such as Langfuse and LangSmith see Stigg’s decisions, including refusals. @opentelemetry/api is an optional peer dependency, and without it no spans are emitted. Wrapped clients emit no spans.
  • Changed: isAccessDenied finds an AccessDeniedError anywhere in an error’s cause chain or inside an AggregateError.
  • Added: HookContext carries the agent and tool a hook fired for.
2026-10-21
  • Added: defaultPlanId in stiggContext. A customer Stigg doesn’t know yet is created on that plan before their first check or report. An existing customer is left untouched.
    • Provisioning runs once per customer per process.
    • If Stigg is unreachable, the failure goes to onError and provisioning is retried on the next call. A check for a customer that couldn’t be provisioned follows checkErrorAction.
    • If Stigg refuses, for example because the plan doesn’t exist, the refusal is reported once and not retried.
2026-10-19
  • Fixed: the npm package links to the public stigg-agent-sdk-ts repository. It previously linked to a private one.
  • Fixed: the examples and .env.template use STIGG_SERVER_API_KEY, the variable the SDK reads. They previously used STIGG_API_KEY, which the SDK ignores. The examples still accept the old name.
2026-10-19
  • Fixed: a stream split with tee() is metered. Previously only for await was metered, so a teed Anthropic or OpenAI-compatible stream moved no budget.
  • ⚠️ Changed: wrap throws when stiggContext sets an idempotencyKey. One key shared by every call deduplicated them all down to the first, so later calls moved no budget. Set idempotencyKey per call instead.
  • ⚠️ Changed: a call throws when its customerId is empty or blank. It previously billed the client’s default customer. A call with no customerId still uses the default.
  • Fixed: apiKey is no longer enumerable on stigg.config, so logging or serializing the client no longer prints the key.
2026-10-19
  • Updated @stigg/node-server-sdk to 6.2.0. No change to the Agent SDK API.
2026-10-14
Databricks
  • Added: databricksRecipe, matched automatically on a Databricks workspace’s /serving-endpoints or /ai-gateway/mlflow/v1 URL. It covers both an OpenAI client pointed at the workspace and Databricks’ own @databricks/sdk-modelservingquery client, and emits databricks.chat.completions.create, databricks.responses.create and databricks.query.
  • Added: the model that answered is recorded as a dimension. On Databricks the model you send is a serving endpoint name, so the response is the only place the real model appears.
  • Added: databricksExternalRecipe for serving endpoints configured as external models, where the upstream provider charges you instead of Databricks. It emits databricks-external.* events. It’s opt-in, because the two routes look identical from the client: stigg.wrap(client, { recipe: databricksExternalRecipe() }).
  • Neither recipe reports a cost metric, because Databricks doesn’t state a price on any response. A workspace on a custom domain needs its base URL passed in: databricksRecipe({ baseUrl }).
Cloudflare
  • Added: cloudflareRecipe, matched automatically for both Workers AI (api.cloudflare.com/client/v4/accounts/<id>/ai/v1) and AI Gateway (gateway.ai.cloudflare.com). It covers an OpenAI client and the cloudflare package’s own ai.run, and emits cloudflare.chat.completions.create, cloudflare.responses.create, cloudflare.messages.create and cloudflare.ai.run.
  • Reports token counts only. Cloudflare doesn’t state a price or Neuron count on any response, so there’s no cost metric.
  • On AI Gateway, the model that served and the cf_aig_log_id are recorded as dimensions, and a cache hit isn’t metered because no one was charged for it.
  • Known limitation: a streamed ai.run call is gated but not metered, because Cloudflare returns raw SSE bytes for it.
2026-10-13
Initial release.Core
  • Added: StiggAgentSDK. Pass an API key, or one options object for the base URL, ingest mode and hooks.
  • Added: stigg.wrap(client, { stiggContext }), which returns a copy of a vendor client whose calls are checked and metered. The context names the customer, the agent the call is attributed to, and an optional entitlement. Naming an entitlement turns on gating. Without one, calls are metered but never refused. Any call can override the context in its own parameters, so one wrapped client can serve every customer.
  • Added: stigg.register() and stigg.deregister() to create an agent entity with a budget and a parent. Both are optional. Without them, checks and usage apply to the customer.
  • Added: a refused call throws AccessDeniedError. Pass it to stigg.denial(err) to get the decision, including which entity blocked the call and how to fix it.
  • Added: ingest: 'async' | 'sync'. Usage is reported as raw events by default. A metric named after a credit currency draws the credit balance directly. Metering failures go to the onError hook and never break the call.
  • Added: unitsPerTokens and weightedMetrics for pricing token counts in code. Stigg recommends reporting raw token counts and converting them in Stigg instead.
Providers
  • Added: Anthropic, OpenAI (Chat Completions and Responses), Google Gemini (models and chats), Groq, Mistral, Ollama and TypeSafe.
  • Added: any other OpenAI-compatible endpoint, metered under openai.* events.
Gateways
  • Added: OpenRouter, through an OpenAI client or OpenRouter’s own @openrouter/sdk. Reports cost and the model that served.
  • Added: LiteLLM. Reports cost from the response header and the model that served.
  • Added: Amazon Bedrock. Reports tokens only, because Bedrock doesn’t state a price.
  • Added: a gateway you operate yourself. The wrapped client sends attribution as x-stigg-* headers, and your gateway reports usage with stigg.ingestFromHeaders(...). This path meters but can’t refuse calls.