PROTRAILBLAZER

Jev gate guard · Agent
Tallyjev-latest · 1 call per turn
Turn
0
Intent conf
--
Latency
--
Tokens
--

How can an NPC judge what you say without an LLM writing its dialogue?

The guard has 40 scripted lines and a hidden suspicion meter. Every time you type something, the game sends your words plus the last six exchanges and the guard's memory as state, then asks typed questions: what are you trying to do, how plausible is it, are you contradicting yourself, did you say the password, and which of the 40 lines fits. The model picks from the designer's lines; it cannot invent a word.

The gatenight · gate shut
Guard Halt. Gate's shut for the night. State your business.
mood: wary
Say something120 characters, Enter to send
0 / 120suggestions change every turn, some are traps
12 coins in your purse
Transcriptlast 6 exchanges, sent with every call
  • Nothing said yet.
Jev inspectorsimulated · POST /v1/systemone
Simulated Jev responses A local mock. No request leaves this page.
Request in flightidle

Seven questions go out with every line you say: one choice over 12 intents, two score dials, three yes or no checks, and one choice over the guard's 40 lines. Say something to see the answers.

Input tokens this turn--
Input price$0.042 / M tokens, output free
This conversation so far$0.000000
A million conversations of 10 turns--
Last request not sent yet
{}
Last response mock, documented shape
{}
How it worksyour words in, typed judgments out, scripted lines only

Why history travels in the state on every call

A System One call is stateless. The model does not remember the last thing you said, so the game sends it again: your new line, the last six exchanges, and the guard's memory (suspicion, patience, coins offered, and every claim he has accepted). That is the only way a question like "does this contradict something they claimed earlier" can be answered at all. It also means the designer decides what the guard remembers. A claim only reaches claims_heard if code accepted it as believable, so a lie the guard already rejected cannot be used against you later.

on player_line(text):
    state = { player_line: text, transcript: last_6_exchanges,
              guard: { suspicion, patience, mood, claims_heard, coins_offered },
              world: { password_known_to_player, time: "night" } }
    a = jev(state, questions)                        // one call, seven questions

    if a.intent.confidence < 0.35:
        say(UNSURE_LINE); return                       // free turn, nothing changes

    suspicion += (1.5 - a.plausibility.score) * 12
    if a.respect.score < 0.5 or a.intent.choice in (insult, threat): patience -= 1
    if a.intent.choice == nonsense: patience -= 1

    if a.contradicts_claim.noul >= 0.7:  suspicion += 25; say(CAUGHT_YOU)
    elif a.password_said.noul >= 0.8 and password_known_to_player: open(PASSWORD_OK)
    elif a.password_said.noul >= 0.35 and not password_known_to_player:
        suspicion += 15; say(WHERE_DID_YOU_HEAR)
    elif a.intent.choice == bribe:
        n = first_number(text)                         // a regex, not the model
        if n >= 8 and n <= coins and suspicion < 70: open(BRIBE_OK)
        else: say(BRIBE_TOO_SMALL)
    elif warm and a.intent.choice == honest_request: open(GATE_OPENED)
    elif a.baron_critic.noul >= 0.7: baron_remarks += 1    // two warms the guard
    else: say(a.reaction.choice)                       // one of the 40 lines

    if a.plausibility.score >= 2 and is_claim(text): claims_heard.append(text)
    if patience == 0: end(CLOSED_FOR_GOOD)
    if suspicion >= 100: end(BACKUP)

Why the bribe number is parsed by code

The model is good at the fuzzy part: is this line an offer of money, said politely or as a threat, and does it hang together with what came before. It is the wrong tool for the exact part. "Here, take 10 coins" either contains a 10 or it does not, and a probability over that is a worse answer than a regular expression gives for free. So the intent question decides whether a bribe is happening, and a few lines of code read the number, check it against your purse, and compare it with the guard's price. The same split runs through the whole turn: the model returns judgments, and code owns every number that changes.

Why a 40 line table is a feature

The reaction question is a Choice over 40 options, and each option is a full line a writer wrote. The model can rank them, but it cannot add a 41st, so the guard can never say something off-brand, offensive, or plot-breaking, and no output filter is needed because there is no free text to filter. Localization is a table lookup, voice acting is 40 recordings, and QA can read every line the character will ever say. When the model is unsure, the game does not guess: a flat intent distribution maps to "Speak plainly, stranger", which is honest in character and costs the player nothing. Code also keeps the last word on the lines that matter: the caught-you, password, and bribe lines are overrides fired by thresholds, not suggestions.

Why a 1980s parser or a chat model could not do this

A classic text parser matches exact verbs and nouns. It would understand "GIVE COINS TO GUARD" and nothing else, so "here's a little something for your trouble" is a syntax error, and it has no way to notice that a farmer is now claiming to be a blacksmith. A chat model understands all of it, but it answers in free text that takes seconds to stream, it can say anything (including the password, or a line that breaks the story), and the game still has to parse its reply to decide whether the gate opens. A System One model sits between them: it reads loose language like the chat model, it answers in the closed shapes a parser would want, and it does it in 70 to 500 ms.

About this demo: every answer here comes from a local mock, and nothing on this page calls Jev, which is in early access. The 15 suggested lines have hand-set answers so they behave the same every time. Anything you type goes through a heuristic: keyword and pattern tables per intent, politeness and hostility markers for respect, first person claim patterns ("I am", "I work", "my brother") for plausibility, a subject match against claims_heard for the contradiction check, edit distance against the password, and a list of words that run the baron down. Those scores become logits and go through a softmax with jitter. Confidence is shown as 1 minus normalized entropy, an approximation of TypeSafe's unpublished formula. Latency is drawn uniformly from 70 to 500 ms, and token counts are the JSON length divided by 4. A real model would read far more than these tables do; the tables are only here so the page runs offline.