Agents: read the raw Markdown of this page, or start at llms.txt.
Cookbook: Intelliprompter
TL;DR Send the full transcript so far as
stateand oneScorequestion per talking point not yet covered, all in one request. The SDK returns a 0–4 score (the probability-weighted level, so it can fall between levels); the cookbook adds 1 for a 1–5 display, and code marks a point covered at 2.5, keeps it covered and drops its question from later requests. Jev only scores; the order, the 2.5 rule and the one-way checklist live in your code.
Goal
A teleprompter tells a speaker what to say. Intelliprompter does the reverse: it listens to a talk given from bullet-point notes and, in near real time, ticks each planned point off once what the speaker has already said covers it (raw/docs/cookbooks__intelliprompter.md). The live app takes microphone audio through ElevenLabs speech-to-text and a local app; the cookbook skips that integration and replays six hard-coded transcript chunks to show only the TypeSafe part.
Upstream lists it under "Search and matching", level Beginner (raw/docs/cookbooks.md; Cookbooks overview). It is the first official cookbook that runs the same Score questions again and again over a growing text, with state kept in code between calls.
When to use it: you have a fixed list of things that should come up in a talk, meeting, call or lecture, and you want to know which have been covered, as the text grows. When not to: you need to know when or how well a point was made in one passage (each tick scores the whole transcript, not the latest line), or a point should be able to become uncovered again (this design never unchecks).
Inputs / state shape
The state is the whole transcript so far under one key, not just the latest line:
{"transcript": "Hello. This is Intelliprompter. It is a smart teleprompter. It listens while I present and marks points after I cover them."}
The checklist is three talking points with five criteria in all. Each criterion has short display text for the screen and a longer description that tells Jev what to look for, for example "The speaker said the name Intelliprompter." A talking point completes when all its criteria are covered. The six replayed chunks grow the transcript from 4 to 84 words.
Numbers below came from jev-1.13.0 on 2026-09-29 (the cookbook pins TYPESAFE_MODEL = "jev-1.13.0"; since the 2026-10-24 alias move the default jev-latest is jev-1.14.0, Models, aliases, pricing, rate limits, context). Every call is cached in json_cache.json in the typesafe-ai/typesafe-public-examples repo, so the published numbers can be replayed without a key.
Questions asked
One Score per unchecked criterion, keyed c_<point>_<criterion>, all in one request:
| Field | Value |
|---|---|
type |
score |
instructions |
How completely has the speaker covered this criterion in `transcript`: "<description>" |
criteria (ordered, levels 0–4) |
"Not mentioned at all"; "Briefly or indirectly mentioned"; "Mentioned directly"; "Mostly covered"; "Covered well and with useful detail" |
import os
from pathlib import Path
from cooksafe import JsonCache
from typesafe_sdk import Score, TypeSafeClient
TYPESAFE_MODEL = "jev-1.13.0"
COVERED_AT = 2.5 # the live app's default threshold on its 1–5 scale
client = TypeSafeClient(
api_key=os.environ.get("TYPESAFE_API_KEY", "cache-only"), # cached re-renders need no key
model=TYPESAFE_MODEL,
timeout=120.0,
)
json_cache = JsonCache(Path("json_cache.json"))
SCORE_LEVELS = [
"Not mentioned at all",
"Briefly or indirectly mentioned",
"Mentioned directly",
"Mostly covered",
"Covered well and with useful detail",
]
def score_question(description: str) -> Score:
return Score(
instructions=(
"How completely has the speaker covered this criterion in `transcript`: "
f'"{description}"'
),
criteria=SCORE_LEVELS,
)
@json_cache
def score_tick(transcript: str, pending: tuple[tuple[str, str], ...]) -> dict:
response = client.system_one(
state={"transcript": transcript},
questions={key: score_question(description) for key, description in pending},
)
return {
"answers": {
key: {"score": answer.score + 1} for key, answer in response.scores.items()
}
}
(Upstream verbatim except the display imports. Install: pip install ipython 'cooksafe>=0.2.0,<0.3.0', then set TYPESAFE_API_KEY.)
Combining logic in code
Jev returns scores and keeps no checklist state. The app keeps a set of covered keys. On each tick it appends the new chunk to the transcript, asks only about criteria not yet covered, and adds any key whose score reaches COVERED_AT. A covered key never leaves the set, so later requests omit it.
def pending_criteria(covered: set[str]) -> tuple[tuple[str, str], ...]:
return tuple(
(f"c_{point_index}_{criterion_index}", criterion["description"])
for point_index, point in enumerate(CHECKLIST)
for criterion_index, criterion in enumerate(point["criteria"])
if f"c_{point_index}_{criterion_index}" not in covered
)
def run_loop(chunks: list[str]) -> tuple[set[str], dict[str, dict]]:
transcript = ""
covered: set[str] = set()
latest: dict[str, dict] = {}
for chunk in chunks:
transcript = f"{transcript} {chunk}".strip()
pending = pending_criteria(covered)
if not pending:
break
for key, answer in score_tick(transcript, pending)["answers"].items():
latest[key] = answer
if answer["score"] >= COVERED_AT:
covered.add(key)
return covered, latest
(Condensed from upstream, which also records each tick's request for a playground link and prints a line per tick; CHECKLIST is the three-point list described above.)
The live app starts a new tick every half second when the transcript has changed and no request is in progress; the cookbook's loop uses the six chunks as its ticks. In the docs' words, 2.5 is "the demo's local coverage threshold, not a TypeSafe confidence value".
Results / what the cookbook reports
Scores on the 1–5 display scale, jev-1.13.0, 2026-09-29 (raw/docs/cookbooks__intelliprompter.md):
| Tick | Words | Scores sent back | New checks |
|---|---|---|---|
| 1 | 4 | c_0_0 = 3.02, c_0_1 = 1.11, c_1_0 = 1.00, c_1_1 = 1.00, c_2_0 = 1.00 | 1 |
| 2 | 21 | c_0_1 = 3.74, c_1_0 = 1.00, c_1_1 = 1.10, c_2_0 = 1.09 | 1 |
| 3 | 40 | c_1_0 = 3.76, c_1_1 = 1.15, c_2_0 = 1.06 | 1 |
| 4 | 60 | c_1_1 = 3.67, c_2_0 = 1.10 | 1 |
| 5 | 70 | c_2_0 = 2.06 | 0 |
| 6 | 84 | c_2_0 = 3.93 | 1 |
All five criteria end checked. Tick 5 shows progress without a check: after one use case ("on stage at an industry event") the "give at least two uses" criterion scored 2.06, below 2.5; the second and third uses in tick 6 took it to 3.93. Not-yet-mentioned criteria stayed near 1.00 throughout, and each request shrank as criteria were checked (five questions at tick 1, one at ticks 5 and 6).
Adapting it to a new domain
- Replace the replayed chunks with your transcription provider's accumulated text. Send the whole transcript each tick, not the newest line: a point may be made across several sentences.
- Write descriptions Jev can check against the text, as the cookbook does ("named at least two suitable uses, such as conference talks, lectures, or product demos"). A vague description ("explain the product") is hard to score.
- Keep the threshold in code and set it on your own transcripts; 2.5 is the demo's choice. Keep the one-way rule in code too, so a later, weaker paraphrase cannot uncheck a point.
- Other uses of the same loop (inferred): a sales-call or support-call script checklist, interview question coverage, meeting agenda tracking, a lecture's learning objectives.
- Long sessions: the transcript grows every tick and is sent in full, so it counts against the context limits on every request (Models, aliases, pricing, rate limits, context); for a long call, plan for that before the limit, for example by checking whether trimming earlier text changes your scores (inferred; the cookbook's transcript stays at 84 words).
Gotchas
- The score is a weighted level, not a probability. The SDK's Score answer is each level number times its probability, summed (0–4 here, so it can land between levels); the cookbook adds 1 for display (Score questions). Do not read 2.5 as 50%.
- Jev does not remember. Each tick is independent; the covered set, the order and the one-way rule are application state (System One Models).
- Cost and latency grow with the transcript. Each tick sends the whole transcript plus one question per unchecked point, so input tokens rise as the talk goes on while the question count falls (Models, aliases, pricing, rate limits, context).
- The cookbook pins
jev-1.13.0. Its numbers were recorded on 1.13; re-check the 2.5 cut if you run it on the default alias, which is now 1.14 (Running Jev in production: versioning, caching, retries, monitoring and fallbacks).
Related
- Score questions — Score questions, levels and the weighted score
- Speculative fan-out — all of a tick's questions in one request
- Cookbook: Knowledge graph entity alignment — another one-Score-per-item cookbook
- Cookbooks overview — the cookbook catalog
- Patterns: judging, search, documents, real-time and markets — community patterns for transcripts and real-time streams
Sources
- raw/docs/cookbooks__intelliprompter.md (https://docs.typesafe.ai/cookbooks/intelliprompter)
- raw/docs/cookbooks.md (https://docs.typesafe.ai/cookbooks) — section and level