1
+ """
2
+ Realtime agent module providing RealtimeAgent class with Pydantic validation.
3
+
4
+ This module implements realtime-specific agent functionality with strong type validation
5
+ and configuration management for voice-enabled agents.
6
+ """
7
+
1
8
from __future__ import annotations
2
9
3
- import dataclasses
4
10
import inspect
5
11
from collections .abc import Awaitable
6
- from dataclasses import dataclass , field
7
12
from typing import Any , Callable , Generic , cast
8
13
14
+ from pydantic import ConfigDict , Field
15
+
9
16
from ..agent import AgentBase
10
17
from ..handoffs import Handoff
11
18
from ..lifecycle import AgentHooksBase , RunHooksBase
20
27
"""Run hooks for `RealtimeAgent`s."""
21
28
22
29
23
- @dataclass
24
30
class RealtimeAgent (AgentBase , Generic [TContext ]):
25
- """A specialized agent instance that is meant to be used within a `RealtimeSession` to build
31
+ """
32
+ A specialized agent instance that is meant to be used within a `RealtimeSession` to build
26
33
voice agents. Due to the nature of this agent, some configuration options are not supported
27
- that are supported by regular `Agent` instances. For example:
28
- - `model` choice is not supported, as all RealtimeAgents will be handled by the same model
29
- within a `RealtimeSession`.
30
- - `modelSettings` is not supported, as all RealtimeAgents will be handled by the same model
31
- within a `RealtimeSession`.
32
- - `outputType` is not supported, as RealtimeAgents do not support structured outputs.
33
- - `toolUseBehavior` is not supported, as all RealtimeAgents will be handled by the same model
34
- within a `RealtimeSession`.
35
- - `voice` can be configured on an `Agent` level; however, it cannot be changed after the first
36
- agent within a `RealtimeSession` has spoken.
37
-
38
- See `AgentBase` for base parameters that are shared with `Agent`s.
34
+ that are supported by regular `Agent` instances.
35
+
36
+ Attributes:
37
+ instructions: Agent instructions/system prompt
38
+ handoffs: List of sub-agents for delegation
39
+ hooks: Lifecycle event callbacks
39
40
"""
40
41
42
+ model_config = ConfigDict (
43
+ arbitrary_types_allowed = True ,
44
+ validate_assignment = True ,
45
+ extra = "forbid" ,
46
+ frozen = True ,
47
+ defer_build = True ,
48
+ )
49
+
41
50
instructions : (
42
51
str
43
52
| Callable [
44
53
[RunContextWrapper [TContext ], RealtimeAgent [TContext ]],
45
54
MaybeAwaitable [str ],
46
55
]
47
56
| None
48
- ) = None
49
- """The instructions for the agent. Will be used as the "system prompt" when this agent is
50
- invoked. Describes what the agent should do, and how it responds.
51
-
52
- Can either be a string, or a function that dynamically generates instructions for the agent. If
53
- you provide a function, it will be called with the context and the agent instance. It must
54
- return a string.
55
- """
57
+ ) = Field (
58
+ default = None ,
59
+ description = "The instructions for the agent. Will be used as the 'system prompt' "
60
+ "when this agent is invoked." ,
61
+ )
56
62
57
- handoffs : list [RealtimeAgent [Any ] | Handoff [TContext , RealtimeAgent [Any ]]] = field (
58
- default_factory = list
63
+ handoffs : list [RealtimeAgent [Any ] | Handoff [TContext , RealtimeAgent [Any ]]] = Field (
64
+ default_factory = list , description = "Handoffs are sub-agents that the agent can delegate to."
59
65
)
60
- """Handoffs are sub-agents that the agent can delegate to. You can provide a list of handoffs,
61
- and the agent can choose to delegate to them if relevant. Allows for separation of concerns and
62
- modularity.
63
- """
64
66
65
- hooks : RealtimeAgentHooks | None = None
66
- """A class that receives callbacks on various lifecycle events for this agent.
67
- """
67
+ hooks : RealtimeAgentHooks | None = Field (
68
+ default = None ,
69
+ description = "A class that receives callbacks on various lifecycle events for this agent." ,
70
+ )
68
71
69
72
def clone (self , ** kwargs : Any ) -> RealtimeAgent [TContext ]:
70
- """Make a copy of the agent, with the given arguments changed. For example, you could do:
71
- ```
72
- new_agent = agent.clone(instructions="New instructions")
73
- ```
74
73
"""
75
- return dataclasses .replace (self , ** kwargs )
74
+ Make a copy of the agent, with the given arguments changed.
75
+
76
+ Args:
77
+ **kwargs: Fields to override in the new instance
78
+
79
+ Returns:
80
+ RealtimeAgent[TContext]: New agent instance with specified changes
81
+ """
82
+ return self .model_copy (update = kwargs )
76
83
77
84
async def get_system_prompt (self , run_context : RunContextWrapper [TContext ]) -> str | None :
78
- """Get the system prompt for the agent."""
85
+ """
86
+ Get the system prompt for the agent.
87
+
88
+ Args:
89
+ run_context: Current run context
90
+
91
+ Returns:
92
+ str | None: System prompt if available
93
+ """
79
94
if isinstance (self .instructions , str ):
80
95
return self .instructions
81
96
elif callable (self .instructions ):
@@ -87,3 +102,7 @@ async def get_system_prompt(self, run_context: RunContextWrapper[TContext]) -> s
87
102
logger .error (f"Instructions must be a string or a function, got { self .instructions } " )
88
103
89
104
return None
105
+
106
+
107
+ # Rebuild models after all definitions
108
+ RealtimeAgent .model_rebuild ()
0 commit comments