Solutions/Use case

Jev is only as good as the state you send it.

Jev answers typed questions about a state object in a fraction of a second. Signals puts your customer's recent behavior in that object: compact, structured, current as of this click.

The real engine · no card · no sales call
The moment, as it happens
  1. 00:00
    Fourth price filter change, two failed searches

    This customer is struggling to decide.

  2. +<1s
    It is in checkout_session

    Current as of this click, not last night.

  3. +6ms
    One call, into the state object

    From your own code, inside the render budget.

  4. next render
    Jev picks the compare panel over the upsell

    A typed choice with a probability you can gate on.

Adaptive generative UI, in one render.Signals supplies the state, the model decides
Why it usually fails

The state is the bottleneck now, not the model.

TypeSafe's own docs say to filter state in code before the call, because accuracy falls as it fills with what the question does not need. Easy for a support ticket. A customer's session is thousands of raw events your code cannot reach from a render.

Raw clickstreamThousands of events a session. Storing, filtering and reading them fast enough is a project of its own.
Confidence over stale factsThe probability is calibrated against the state you sent. Send last night's and the model is confidently wrong.
State that costs more than the callThe answer takes a fraction of a second. A slow lookup in front of it spends the budget you adopted it for.
What you build with it

Four decisions that only work on live state.

Each is a typed question asked on every render. The model does not change the answer. Whether the state describes this visit or last night's does.

Adaptive generative UI

The page composes itself around the job in hand. Give the model what this customer compared, abandoned and came back to, and it picks the components that fit them, not the average visitor.

engagement rate · conversion rate

Real-time decisioning

Which offer, flow or message, chosen against what is happening now instead of a segment computed overnight. A rule over the same activity fires the moment the condition is met.

offer acceptance · revenue per session

In-session ranking

Results and recommendations reorder against three price filter changes and two failed searches in this visit, not what this customer wanted last week.

click-through · add to cart · search exit rate

Routing and triage

Which flow the customer belongs in, when to escalate, and whether the question needs a frontier model at all. The cheapest decision is the one the live state already answers.

escalation rate · cost per conversation
What you build

Behavioral context, ready for a typed decision.

01 · Collect

Add a Snowplow SDK

Web, mobile or server. Events flow in, validated against your schemas.

02 · Shape

Say what belongs in the context

Pick the activity the decision needs, as JSON for a state object or a narrative for a prompt.

03 · Read

One call, into the state

Named and typed, ready for Jev.

The code

Signals on the left of the call, the model on the right.

The Node SDK reads the context, the TypeSafe SDK decides. Nothing between them but the object you were already sending.

First, give your agent the Signals skills
npx plugins add snowplow/skills
Write it yourself
import { Signals } from "@snowplow/signals-node";
import { choice, noul, TypeSafeClient } from "@typesafe-ai/sdk";

const signals = new Signals({
  baseUrl, apiKey, apiKeyId, organizationId,
});
const typesafe = new TypeSafeClient();

// Already shaped for a model, so it goes in as state without a mapping step.
const session = await signals.getAgenticContext({
  name: "checkout_session",
  identifier: sessionId,
  format: "json",
});

const { answers } = await typesafe.systemOne({
  state: { session },
  questions: {
    panel: choice("Which panel should this page lead with?", {
      compare: "They are weighing two products against each other",
      reassure: "They are hesitating on price or delivery",
      resume: "They are returning to an unfinished basket",
    }),
    stalled: noul("This customer has stalled and would take help"),
  },
});

if (answers.stalled.noul > 0.8) render(answers.panel.choice);
Or hand your agent this prompt
Add Snowplow Signals to this app so the typed call runs on live behavior. Find where we already ask the model a typed question. Add the Node SDK, define an agentic context named for the surface that decision drives, read it with getAgenticContext in json format and pass it as the state on that call. Leave the questions unchanged, so the only thing that moves is what the model can see.

The JSON form returns the named log: its events, when the session started, and an optional prompt. Ask for narrative and the same call returns a string.

What changes

The decision runs on the moment.

6ms

Read the context, p50 in-region

<1s

Event in to attribute updated

2 shapes

JSON for the state object, narrative for the prompt

any key

user · session · basket · listing · store

Questions

Before you wire it up

Does Signals decide anything?

No. Signals hands over what the customer is doing. Which panel renders, which offer fires and which flow runs is your model's call, in your code.

Does this only work with Jev?

No. Agentic context comes back as JSON over the REST API, the Node.js or Python SDK, or the MCP server, and as a string in narrative form. Anything that takes a state object or a prompt can read it, System One models included.

Why not send the raw event history instead?

Accuracy. TypeSafe's documentation says accuracy falls as state fills with material the question does not need, and to retrieve and filter in code first. A named context is that filter, applied before the call.

Can I not read this from my own database?

You can read what the customer bought. A current, model-shaped view of what they are doing right now is the part you would build: a stream processor, a store, windowing, late events, hot keys, and someone on call. That is what Signals is.

Do I need an event stream already?

No. Collection is part of Signals. Add a Snowplow SDK and events start flowing. If you already run Snowplow, Signals reads the pipeline you have.

Where does it run?

Managed SaaS, or a private deployment in your own AWS or GCP account. Same architecture either way.

Sources

Start with one attribute.

Define it, read it in your own product, and see it change while you click around. The free tier runs on the real engine: no card, no sales call.

Signals, about you
connecting...