> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gloo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# System One Examples

> Short System One patterns to adapt: moderation with a review band, intent routing, yes-or-no policy checks, and choosing a next step. Each shows the questions to send and the code that acts on the answers.

These are short patterns for [System One](https://docs.gloo.com/api-guides/system-one.md). Each one shows what the app needs to decide, the `state` and `questions` it sends, and the code that acts on the answers. For a full build with every step explained, follow the [System One tutorial](https://docs.gloo.com/tutorials/system-one.md), which triages support tickets.

The thresholds below are starting points, not recommendations. Before you let an app act on its own, choose them from your own labelled examples, as described in [Best Practices: System One](https://docs.gloo.com/best-practices/system-one.md#choose-thresholds-from-your-own-data).

## Setup

Every example calls one helper, `ask`, that sends `state` and `questions` and returns the parsed response. It needs your API key from the [API Keys page](https://docs.gloo.com/studio/manage-api-credentials.md) in `GLOO_API_KEY`.

```python Python theme={null}
import os
import requests

SYSTEM_ONE_URL = "https://platform.ai.gloo.com/ai/v2/systemone"

def ask(state, questions: dict) -> dict:
    resp = requests.post(
        SYSTEM_ONE_URL,
        headers={"Authorization": f"Bearer {os.environ['GLOO_API_KEY']}"},
        json={"state": state, "questions": questions},
        timeout=30,
    )
    if not resp.ok:
        raise RuntimeError(f"System One returned {resp.status_code}: {resp.text}")
    return resp.json()
```

```typescript TypeScript theme={null}
const SYSTEM_ONE_URL = "https://platform.ai.gloo.com/ai/v2/systemone";

async function ask(state: unknown, questions: Record<string, unknown>): Promise<any> {
  const resp = await fetch(SYSTEM_ONE_URL, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GLOO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ state, questions }),
  });
  if (!resp.ok) {
    throw new Error(`System One returned ${resp.status}: ${await resp.text()}`);
  }
  return resp.json();
}
```

Which errors to retry, and how, is in [Handle errors and retries](https://docs.gloo.com/best-practices/system-one.md#handle-errors-and-retries).

## Moderate posts with a review band

**The decision:** a community app checks each new post before it appears. Clear posts are published, clear violations are hidden, and everything in between goes to a moderator.

One `choice` question covers every outcome. `ok` is the option for posts that follow the rules, and `other_issue` catches problems the named options don't cover. Gloo applies no [guardrails](https://docs.gloo.com/ai-learning-center/gloo-ai-101/application-patterns.md#guardrails) to System One, so your rules live in `criteria`.

```json Request body theme={null}
{
  "state": {
    "community": "A neighbourhood forum for parents. No selling, no personal attacks.",
    "post": "Anyone know a good pediatric dentist near Elm Street? Ours just retired."
  },
  "questions": {
    "policy": {
      "type": "choice",
      "instructions": "Does this post follow the community rules, and if not, which rule does it break?",
      "criteria": {
        "ok": "The post follows the community rules.",
        "selling": "The post advertises or sells a product or service.",
        "attack": "The post insults, threatens, or mocks a person.",
        "personal_info": "The post shares someone else's phone number, address, or other private details.",
        "other_issue": "The post breaks the community rules in a way none of the other options describe."
      }
    }
  }
}
```

Act on the probability of `ok`, not on the top pick. A post is published only when `ok` is very likely, hidden only when it is very unlikely, and sent to a moderator otherwise:

```python Python theme={null}
PUBLISH_AT = 0.95  # p(ok) at or above this: publish
HIDE_AT = 0.05     # p(ok) at or below this: hide

def moderate(state: dict, questions: dict) -> dict:
    result = ask(state, questions)
    p_ok = result["answers"]["policy"]["probabilities"].get("ok")
    if p_ok is None:
        return {"action": "moderator"}
    if p_ok >= PUBLISH_AT:
        return {"action": "publish"}
    if p_ok <= HIDE_AT:
        return {"action": "hide", "reason": result["answers"]["policy"]["choice"]}
    return {"action": "moderator"}
```

```typescript TypeScript theme={null}
const PUBLISH_AT = 0.95; // p(ok) at or above this: publish
const HIDE_AT = 0.05; // p(ok) at or below this: hide

async function moderate(state: unknown, questions: Record<string, unknown>) {
  const result = await ask(state, questions);
  const pOk: number | null = result.answers.policy.probabilities.ok ?? null;
  if (pOk === null) return { action: "moderator" };
  if (pOk >= PUBLISH_AT) return { action: "publish" };
  if (pOk <= HIDE_AT) return { action: "hide", reason: result.answers.policy.choice as string };
  return { action: "moderator" };
}
```

When a post is hidden, `moderate` returns the top violation (`answers.policy.choice`) as `reason`. Keep it with the post so the author and your moderators can see why. Widen the band if your moderators overturn too many automatic decisions; narrow it if they agree with nearly all of them.

## Route a chat message by intent

**The decision:** a chat assistant decides which handler should answer each message: a help article search, an order lookup, a booking flow, or a person.

Put the latest message and a little recent context in `state`, so short replies such as "yes, that one" can be understood. Include `other` so a message that fits no handler isn't forced into one.

```json Request body theme={null}
{
  "state": {
    "recent_messages": [
      { "role": "assistant", "text": "Your order #4821 shipped on Monday." },
      { "role": "user", "text": "It still hasn't arrived and I need it by Friday." }
    ]
  },
  "questions": {
    "intent": {
      "type": "choice",
      "instructions": "What does the user want from their most recent message?",
      "criteria": {
        "help_article": "A how-to or general question that a help article can answer.",
        "order_status": "Where an order is, when it will arrive, or a problem with its delivery.",
        "booking": "To book, move, or cancel an appointment.",
        "talk_to_person": "To speak with a member of staff.",
        "other": "Anything the other options don't describe."
      }
    }
  }
}
```

When the top intent is likely enough, hand the message to its handler, and send a confident `other` to a person. When it isn't, ask the user to choose between the two most likely named intents instead of guessing:

```python Python theme={null}
ROUTE_AT = 0.8

def route(state: dict, questions: dict) -> dict:
    answer = ask(state, questions)["answers"]["intent"]
    ranked = sorted(answer["probabilities"].items(), key=lambda kv: kv[1], reverse=True)
    top, p_top = ranked[0]
    if p_top >= ROUTE_AT:
        return {"handler": "talk_to_person" if top == "other" else top}
    return {"clarify": [name for name, _ in ranked if name != "other"][:2]}
```

```typescript TypeScript theme={null}
const ROUTE_AT = 0.8;

async function route(state: unknown, questions: Record<string, unknown>) {
  const answer = (await ask(state, questions)).answers.intent;
  const ranked = Object.entries(answer.probabilities as Record<string, number>).sort(
    (a, b) => b[1] - a[1],
  );
  const [top, pTop] = ranked[0];
  if (pTop >= ROUTE_AT) return { handler: top === "other" ? "talk_to_person" : top };
  return { clarify: ranked.map(([name]) => name).filter((name) => name !== "other").slice(0, 2) };
}
```

Your app turns the `clarify` list into a question, such as "Do you want to check your order or talk to someone?", and routes on the reply.

## Check a request against a policy

**The decision:** a care team's request form must not give medical advice, and urgent requests must reach a person quickly. The app checks every request against both rules before it is answered.

Each rule is its own `noul` question, written as a statement that is either true or false of the request. Asking both in one request sends the `state` once.

```json Request body theme={null}
{
  "state": {
    "request": "My dad was prescribed a new blood pressure pill. Is it safe to take it with his usual painkillers?"
  },
  "questions": {
    "medical_advice": {
      "type": "noul",
      "instructions": "The person is asking for a diagnosis, a treatment, or advice about medication."
    },
    "urgent": {
      "type": "noul",
      "instructions": "The person describes a situation where someone may need help today."
    }
  }
}
```

The two checks have different costs when they're wrong. Missing an urgent request is worse than reviewing one that wasn't, so `urgent` uses a very low threshold. Adding a "see a professional" note costs little, so `medical_advice` uses a low one too. If a probability is missing from the response, the code takes the action anyway rather than skipping it.

```python Python theme={null}
def check(state: dict, questions: dict) -> list[str]:
    answers = ask(state, questions).get("answers", {})
    urgent = answers.get("urgent", {}).get("noul")
    medical_advice = answers.get("medical_advice", {}).get("noul")
    actions = []
    # A missing probability triggers the action, so a gap never skips a safety step.
    if urgent is None or urgent >= 0.2:
        actions.append("notify_on_call_person")
    if medical_advice is None or medical_advice >= 0.3:
        actions.append("reply_with_see_a_professional_note")
    return actions or ["answer_normally"]
```

```typescript TypeScript theme={null}
async function check(state: unknown, questions: Record<string, unknown>) {
  const answers = (await ask(state, questions)).answers ?? {};
  const urgent: number | undefined = answers.urgent?.noul;
  const medicalAdvice: number | undefined = answers.medical_advice?.noul;
  const actions: string[] = [];
  // A missing probability triggers the action, so a gap never skips a safety step.
  if (typeof urgent !== "number" || urgent >= 0.2) actions.push("notify_on_call_person");
  if (typeof medicalAdvice !== "number" || medicalAdvice >= 0.3) {
    actions.push("reply_with_see_a_professional_note");
  }
  return actions.length ? actions : ["answer_normally"];
}
```

A `noul` is a probability, so set each threshold from what a miss costs, not at 0.5 by default.

A check like `urgent` can miss a request at any threshold, so don't make it your only safeguard. Show how to get urgent help (for example, your local emergency number) on the form itself, and keep every request in a queue a person reads, whatever the answer.

## Choose the next step

**The decision:** when someone fills in a sign-up card, the app picks one follow-up for them. If the model isn't sure, the app sends a standard welcome and leaves the card for a staff member.

Put the card's fields in `state` as an object, so each fact stays separate. Give every follow-up an option, plus `none` for cards that need nothing.

```json Request body theme={null}
{
  "state": {
    "first_visit": true,
    "interests": ["kids programs"],
    "note": "We just moved here with two kids, 6 and 9. Looking for something for them midweek."
  },
  "questions": {
    "next_step": {
      "type": "choice",
      "instructions": "Which single follow-up best fits this person's card?",
      "criteria": {
        "kids_program_intro": "They ask about activities or programs for their children.",
        "small_group_invite": "They want to meet people or join a regular group.",
        "personal_call": "They ask for a conversation, or describe a hard situation.",
        "volunteer_info": "They offer to help or ask how to get involved.",
        "none": "The card asks for nothing and fits none of the other follow-ups."
      }
    }
  }
}
```

If cards can describe a crisis, ask about it as its own `noul`, with a low threshold, as in the [policy check](#check-a-request-against-a-policy), rather than relying on one option of a `choice`.

```python Python theme={null}
ACT_AT = 0.7

def next_step(state: dict, questions: dict) -> dict:
    result = ask(state, questions)
    answer = result["answers"]["next_step"]
    step = answer["choice"]
    if answer["probabilities"][step] >= ACT_AT:
        return {"send": step, "model": result["model"]}
    return {"send": "standard_welcome", "review": True, "model": result["model"]}
```

```typescript TypeScript theme={null}
const ACT_AT = 0.7;

async function nextStep(state: unknown, questions: Record<string, unknown>) {
  const result = await ask(state, questions);
  const answer = result.answers.next_step;
  const step: string = answer.choice;
  if (answer.probabilities[step] >= ACT_AT) return { send: step, model: result.model };
  return { send: "standard_welcome", review: true, model: result.model };
}
```

Keeping `model` with each decision lets you tell which model version made it when you review the cards later.

## Next steps

> [card] [Tutorial: Triage Tickets with System One](https://docs.gloo.com/tutorials/system-one.md)
>
> Build a support-ticket triage step from start to finish, in Python and TypeScript.

> [card] [Best Practices: System One](https://docs.gloo.com/best-practices/system-one.md)
>
> Write clear options, choose thresholds from your own data, log decisions and control cost.

> [card] [System One Guide](https://docs.gloo.com/api-guides/system-one.md)
>
> What System One is, when to use it, the model it runs on, and pricing.

> [card] [API Reference: System One Decisions](https://docs.gloo.com/api-reference/system-one/v2.md)
>
> Every request and response field, and every error status.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.