teff.assistant¶
teff.assistant
¶
Durable conversation turns against a compiled graph.
:class:Assistant is the app-facing service object for one durable
conversation: it holds the compiled :class:~teff.graph.Graph, its tools,
the :class:~teff.checkpoint.Checkpointer, and the conversation state shape
(reducers, fresh-session seed, transient keys, messages key), then exposes a
single interrupt-aware entry point:
- :meth:
Assistant.run— one turn, returns a :class:TurnResult(a pause is folded intowaiting=Trueinstead of raised). - :meth:
Assistant.stream— the streaming equivalent, yielding :class:~teff.stream.StreamEventobjects.
Both auto-detect a paused session from durable state and either resume it
with the message (the operator's answer) or start/continue the conversation.
The turn machinery itself lives on :class:~teff.graph.Graph
(run(message=...) / stream(message=...)); :class:Assistant just
binds the settings so apps call one object.
Classes:
| Name | Description |
|---|---|
Assistant |
Runs durable conversation turns against a compiled graph. |
Assistant
¶
Runs durable conversation turns against a compiled graph.
Methods:
| Name | Description |
|---|---|
get_state |
Return the durable conversation state for session_id. |
last_reply |
Return the latest assistant reply for session_id ( |
pending |
Return the interrupt this session is paused on, or |
run |
Run one turn, resuming a paused session transparently. |
stream |
Stream one turn, resuming a paused session transparently. |
update_state |
Edit the durable state of a session and persist it. |
Source code in teff/assistant.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |
get_state
async
¶
get_state(session_id, *, owner=DEFAULT_OWNER)
Return the durable conversation state for session_id.
Reads the latest checkpoint (paused or completed). The internal
__interrupt__ bookkeeping key is stripped — use
:meth:pending to inspect a paused run's interrupt.
Source code in teff/assistant.py
165 166 167 168 169 170 171 172 173 174 175 176 | |
last_reply
async
¶
last_reply(session_id, *, owner=DEFAULT_OWNER)
Return the latest assistant reply for session_id ("" if none).
Reads the durable checkpoint, so it works even for agents that do
not stream tokens (e.g. tool-using agents): the CLI prints this at
the end of a turn instead of relying on token events alone.
Source code in teff/assistant.py
136 137 138 139 140 141 142 143 144 145 146 147 148 | |
pending
async
¶
pending(session_id, *, owner=DEFAULT_OWNER)
Return the interrupt this session is paused on, or None.
The interrupt bookkeeping lives in durable state: when graph.run
pauses on an :class:~teff.node.Interrupt it writes a __interrupt__
entry into the saved checkpoint. This reads it back so the caller —
without a try/except or an in-memory pending map — can tell whether
the next message is a fresh turn or the operator's answer to resume.
Source code in teff/assistant.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | |
run
async
¶
run(
session_id,
message,
*,
owner=DEFAULT_OWNER,
max_iterations=None,
tracer=None,
on_llm_payload=None,
)
Run one turn, resuming a paused session transparently.
This is the single entry point apps call::
result = await assistant.run(session_id, message)
if result.waiting:
# surface result.prompt to the operator, await their answer
... # and call run() again with it
else:
print(result.reply)
- If the session is paused on an interrupt (:meth:
pending), message is the operator's answer and the run resumes from the checkpoint. - Otherwise message starts (or continues) the conversation.
- A pause is not raised to the caller: it is folded into the
returned :class:
TurnResult(waiting=Truewith the prompt and key), so the loop above keeps working across an arbitrary number of interrupts (e.g. a "rework" branch that re-asks).
Source code in teff/assistant.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
stream
async
¶
stream(
session_id,
message,
*,
owner=DEFAULT_OWNER,
max_iterations=None,
tracer=None,
on_llm_payload=None,
)
Stream one turn, resuming a paused session transparently.
The streaming equivalent of :meth:run. Relays the underlying
graph.stream(message=...) events verbatim; a paused session
auto-resumes with the message, and a re-work pause surfaces an
interrupt event (with key/prompt in its data) where
the stream ends — call this again with the operator's answer to
continue.
Source code in teff/assistant.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |
update_state
async
¶
update_state(session_id, values, *, owner=DEFAULT_OWNER, as_node=None)
Edit the durable state of a session and persist it.
The HITL "fix the data then resume" primitive: override the given
keys, save the checkpoint, then the next :meth:run continues
from where the session paused with the edited state.
Source code in teff/assistant.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |