@@ -35,11 +35,14 @@ public struct Agent: Loggable {
3535
3636 public enum Error : LocalizedError {
3737 case timeout
38+ case left
3839
3940 public var errorDescription : String ? {
4041 switch self {
4142 case . timeout:
42- " Agent did not connect "
43+ " Agent did not connect to the room "
44+ case . left:
45+ " Agent left the room unexpectedly "
4346 }
4447 }
4548 }
@@ -90,50 +93,120 @@ public struct Agent: Loggable {
9093 log ( " Invalid transition from \( state) to connected " , . warning)
9194 }
9295 }
96+ }
97+
98+ // MARK: - Derived State
99+
100+ public extension Agent {
101+ /// A boolean value indicating whether the agent is connected to the client.
102+ ///
103+ /// Returns `true` when the agent is actively connected and in a conversational state
104+ /// (listening, thinking, or speaking).
105+ var isConnected : Bool {
106+ switch state {
107+ case let . connected( agentState, _, _) :
108+ switch agentState {
109+ case . listening, . thinking, . speaking:
110+ true
111+ default :
112+ false
113+ }
114+ default :
115+ false
116+ }
117+ }
118+
119+ /// A boolean value indicating whether the client could be listening for user speech.
120+ ///
121+ /// Returns `true` when the agent is in a state where it can receive user input,
122+ /// either through pre-connect buffering or active conversation states.
123+ ///
124+ /// - Note: This may not mean that the agent is actually connected. The audio pre-connect
125+ /// buffer could be active and recording user input before the agent actually connects.
126+ var canListen : Bool {
127+ switch state {
128+ case let . connecting( buffering) :
129+ buffering
130+ case let . connected( agentState, _, _) :
131+ switch agentState {
132+ case . listening, . thinking, . speaking:
133+ true
134+ default :
135+ false
136+ }
137+ default :
138+ false
139+ }
140+ }
93141
94- // MARK: - Public
142+ /// A boolean value indicating whether the agent is currently connecting or setting itself up.
143+ ///
144+ /// Returns `true` during the connection phase (before pre-connect buffering begins) or
145+ /// when the agent is initializing after connection.
146+ var isPending : Bool {
147+ switch state {
148+ case let . connecting( buffering) :
149+ !buffering
150+ case let . connected( agentState, _, _) :
151+ switch agentState {
152+ case . initializing, . idle:
153+ true
154+ default :
155+ false
156+ }
157+ default :
158+ false
159+ }
160+ }
95161
96- /// A boolean value indicating whether the agent is connected.
97- public var isConnected : Bool {
162+ /// A boolean value indicating whether the client has disconnected from the agent.
163+ ///
164+ /// Returns `true` when the agent session has ended, either for an expected or unexpected reason
165+ /// (including failures).
166+ var isFinished : Bool {
98167 switch state {
99- case . connected: true
100- default : false
168+ case . disconnected, . failed:
169+ true
170+ default :
171+ false
101172 }
102173 }
103174
104175 /// The current conversational state of the agent.
105- public var agentState : AgentState ? {
176+ var agentState : AgentState ? {
106177 switch state {
107178 case let . connected( agentState, _, _) : agentState
108179 default : nil
109180 }
110181 }
111182
112183 /// The agent's audio track.
113- public var audioTrack : ( any AudioTrack ) ? {
184+ var audioTrack : ( any AudioTrack ) ? {
114185 switch state {
115186 case let . connected( _, audioTrack, _) : audioTrack
116187 default : nil
117188 }
118189 }
119190
120191 /// The agent's avatar video track.
121- public var avatarVideoTrack : ( any VideoTrack ) ? {
192+ var avatarVideoTrack : ( any VideoTrack ) ? {
122193 switch state {
123194 case let . connected( _, _, avatarVideoTrack) : avatarVideoTrack
124195 default : nil
125196 }
126197 }
127198
128199 /// The last error that occurred.
129- public var error : Error ? {
200+ var error : Error ? {
130201 switch state {
131202 case let . failed( error) : error
132203 default : nil
133204 }
134205 }
135206}
136207
208+ // MARK: - Extension
209+
137210private extension Participant {
138211 var agentAudioTrack : ( any AudioTrack ) ? {
139212 audioTracks. first ( where: { $0. source == . microphone } ) ? . track as? AudioTrack
0 commit comments