discussion_helper.session module
A conversation that outlives the call that started it.
Module summary
Discussion is a coroutine: you await it
and it hands back a finished conversation. That is the right shape for a
command line and the wrong one for everything else. A web page, an agent or a
“stop talking” button all need the same three things while the conversation is
still happening — to see it, to interrupt it, and to end it — and none
of them can hold the await.
So a Session is a running discussion plus the handle on it: a
background task, a floor you can read, an event stream you can follow, and an
interrupt that goes through the same barge-in path the microphone uses.
That last point is what keeps this from being a second implementation of the
loop. A button that stopped the audio some other way would stop it in some
other way — draining instead of discarding, or leaving the floor with the
agent — and the difference would only show in a room.
Why there is a registry
One process, several conversations: a server with two callers, a test that runs three at once, an agent that starts one and comes back later. The registry is what makes “come back later” possible, and it is deliberately in-memory — sessions do not survive a restart, because neither does the microphone they were listening to.
- class discussion_helper.session.Event(kind, at_s, data=<factory>)[source]
Bases:
objectSomething worth telling a watcher about, as it happens.
Deliberately coarse. A watcher wants to know that a turn landed, that the floor moved, that the agent was cut off — not every frame of audio. The audio has its own channel; this one is for what a transcript would show.
- Parameters:
- class discussion_helper.session.Session(listener, responder, voice, policy=None)[source]
Bases:
objectA discussion running in the background, with a handle on it.
- Parameters:
Notes
Subscribers get their own queue rather than sharing one. Two watchers reading from one queue each take half the events and neither knows it — the kind of bug that looks like a flaky network.
- async events()[source]
Follow the conversation as it happens.
Yields until the session ends. A subscriber that arrives late sees what happens next, not what it missed — the transcript is in
state, and duplicating it into the stream would make a reconnecting client replay the whole conversation.- Return type:
- async interrupt()[source]
Stop the agent now, as a person talking over it would.
Goes through
Voice.stop()— the same path the microphone’s barge-in takes — rather than cancelling the task. A button that stopped the audio some other way would stop it in some other way: draining instead of discarding, or leaving the floor with the agent. The difference would only ever show in a room.- Returns:
Whether there was anything to interrupt.
Falseis not a failure: it means the agent was not speaking, which is the common case for a button somebody pressed a moment too late.- Return type:
- start()[source]
Begin the conversation in the background and return immediately.
Must be called from the loop the conversation will run on — the tasks are scheduled here. Calling it from another thread binds them to a loop nobody is running, and the conversation simply never happens: no error, no turns, a session that reports running and does nothing.
- Return type:
- class discussion_helper.session.Sessions[source]
Bases:
objectEvery conversation this process is holding.
In-memory on purpose: a session is a microphone and an audio device as much as it is a transcript, and neither survives a restart. Persisting the text alone would hand a caller a session id that resolves to something that cannot speak.
- async aclose()[source]
Stop every session. Called when the server shuts down.
A microphone left open outlives the process that opened it on some platforms, which is the kind of thing a user discovers from a recording indicator that will not go away.
- Return type:
None
- async remove(session_id)[source]
Stop a session and forget it.
- Parameters:
session_id (str)
- Return type:
Conversation | None
- discussion_helper.session.utterance_of(speaker, text, at_s=0.0)[source]
Build an utterance from the wire, for callers that push text in.
speakeris the two-value Literal, notstr: this helper exists to accept values off the wire, and a wire value of"bot"would otherwise build an Utterance that claims to be one of two things and is neither.