literun 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
literun/__init__.py CHANGED
@@ -30,4 +30,4 @@ __all__ = [
30
30
  "RunResultStreaming",
31
31
  ]
32
32
 
33
- __version__ = "0.1.0"
33
+ __version__ = "0.1.1"
literun/agent.py CHANGED
@@ -2,81 +2,79 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import json
6
- from typing import Any, Dict, Iterable, Optional, Iterator, List, Union
5
+ from typing import Any, Iterator
6
+ from pydantic import BaseModel, PrivateAttr, model_validator
7
7
 
8
8
  from .tool import Tool
9
9
  from .llm import ChatOpenAI
10
10
  from .prompt_template import PromptTemplate
11
11
  from .results import RunResult, RunResultStreaming
12
- from .items import (
13
- RunItem,
14
- MessageOutputItem,
15
- ToolCallItem,
16
- ToolCallOutputItem,
17
- ReasoningItem,
18
- ResponseFunctionToolCallOutput,
19
- )
20
- from .events import (
21
- StreamEvent,
22
- ResponseFunctionCallOutputItemAddedEvent,
23
- ResponseFunctionCallOutputItemDoneEvent,
12
+ from .runner import Runner
13
+ from .constants import (
14
+ ToolChoice,
15
+ DEFAULT_MAX_TOOL_CALLS_LIMIT,
16
+ DEFAULT_MAX_ITERATIONS_LIMIT,
24
17
  )
25
18
 
26
19
 
27
- class Agent:
28
- """A minimal agent runtime built on OpenAI Responses API."""
20
+ class Agent(BaseModel):
21
+ """A minimal agent runtime built on OpenAI Responses API.
29
22
 
30
- def __init__(
31
- self,
32
- *,
33
- llm: ChatOpenAI,
34
- system_prompt: Optional[str] = None,
35
- tools: Optional[List[Tool]] = None,
36
- tool_choice: str = "auto", # "auto", "none", "required"
37
- parallel_tool_calls: bool = True,
38
- max_iterations: int = 10,
39
- ) -> None:
40
- """Initialize the Agent.
23
+ This class holds the configuration and state of the agent.
24
+ Execution logic is delegated to the `Runner` class.
41
25
 
42
- Args:
43
- llm: The OpenAI language model instance to use.
44
- system_prompt: The system instructions for the agent.
45
- tools: An optional list of Tool instances to register.
46
- tool_choice: Strategy for selecting tools during execution.
47
- One of "auto", "none", or "required".
48
- parallel_tool_calls: Whether to call tools in parallel.
49
- max_iterations: Maximum number of iterations for the agent loop. Must be >= 1.
26
+ Args:
27
+ llm: The OpenAI language model instance to use.
28
+ system_prompt: The system instructions for the agent.
29
+ tools: An optional list of Tool instances to register.
30
+ tool_choice: Strategy for selecting tools during execution.
31
+ Options: "auto", "none", "required".
32
+ parallel_tool_calls: Whether to call tools in parallel.
33
+ max_iterations: Maximum number of iterations for the agent loop. Must be >= 1.
50
34
 
51
- Raises:
52
- ValueError: If max_iterations is less than 1.
53
- """
54
- if max_iterations < 1:
35
+ Raises:
36
+ ValueError: If max_iterations is less than 1.
37
+ """
38
+
39
+ llm: ChatOpenAI
40
+ system_prompt: str | None = None
41
+ tools: list[Tool] | None = None
42
+ tool_choice: ToolChoice = "auto"
43
+ parallel_tool_calls: bool = True
44
+ max_tool_calls: int = DEFAULT_MAX_TOOL_CALLS_LIMIT
45
+ max_iterations: int = DEFAULT_MAX_ITERATIONS_LIMIT
46
+
47
+ _tools: dict[str, Tool] = PrivateAttr(default_factory=dict)
48
+
49
+ @model_validator(mode="after")
50
+ def _validate_config(self) -> Agent:
51
+ """Validate configuration and initialize tools."""
52
+ if self.max_iterations < 1:
55
53
  raise ValueError("max_iterations must be >= 1")
54
+ return self
56
55
 
57
- self.llm = llm
58
- self.system_prompt = system_prompt
59
- self.tool_choice = tool_choice
60
- self.parallel_tool_calls = parallel_tool_calls
61
- self.max_iterations = max_iterations
62
- self.tools: Dict[str, Tool] = self.add_tools(tools)
56
+ @model_validator(mode="after")
57
+ def _initialize_tools(self) -> Agent:
58
+ self._tools = self.add_tools(self.tools)
59
+ # Convert a list of tools to internal dictionary
60
+ return self
63
61
 
64
62
  def add_tools(
65
63
  self,
66
- tools: Optional[Iterable[Tool]],
67
- ) -> Dict[str, Tool]:
64
+ tools: list[Tool] | None,
65
+ ) -> dict[str, Tool]:
68
66
  """Register a set of tools for the agent.
69
67
 
70
68
  Args:
71
69
  tools: An optional list of Tool instances to register.
72
70
 
73
71
  Returns:
74
- Dict[str, Tool]: A mapping from tool names to their Tool instances.
72
+ dict[str, Tool]: A mapping from tool names to their Tool instances.
75
73
 
76
74
  Raises:
77
75
  ValueError: If there are duplicate tool names.
78
76
  """
79
- tool_map: Dict[str, Tool] = {}
77
+ tool_map: dict[str, Tool] = {}
80
78
  for tool in tools or []:
81
79
  if tool.name in tool_map:
82
80
  raise ValueError(f"Duplicate tool name: {tool.name}")
@@ -86,7 +84,8 @@ class Agent:
86
84
  def add_tool(self, tool: Tool) -> None:
87
85
  """Add a single tool at runtime.
88
86
 
89
- This method MUTATES agent state. Intended for advanced/dynamic use cases.
87
+ This method mutates agent state (internal tool registry).
88
+ Intended for advanced/dynamic use cases.
90
89
 
91
90
  Args:
92
91
  tool: The tool instance to register.
@@ -94,87 +93,26 @@ class Agent:
94
93
  Raises:
95
94
  ValueError: If a tool with the same name is already registered.
96
95
  """
97
- if tool.name in self.tools:
96
+ if tool.name in self._tools:
98
97
  raise ValueError(f"Tool '{tool.name}' already registered")
99
- self.tools[tool.name] = tool
100
-
101
- def _convert_to_openai_tools(self) -> List[Dict[str, Any]]:
102
- """Convert all registered tools to the OpenAI tool schema format.
103
-
104
- Returns:
105
- List[Dict[str, Any]]: A list of tools in OpenAI-compatible dictionary format.
106
- """
107
- return [tool.to_openai_tool() for tool in self.tools.values()]
108
-
109
- def _execute_tool(
110
- self,
111
- name: str,
112
- arguments: Union[str, Dict[str, Any]],
113
- runtime_context: Optional[Dict[str, Any]] = None,
114
- ) -> str:
115
- """Execute a registered tool safely with provided arguments.
98
+ self._tools[tool.name] = tool
116
99
 
117
- Handles parsing of arguments (from JSON string or dict) and catches execution errors.
118
-
119
- Args:
120
- name: The name of the tool to execute.
121
- arguments: Arguments to pass to the tool, either as a JSON string or dict.
122
- runtime_context: Optional runtime context to pass to tool arguments of type ``ToolRuntime``.
123
-
124
- Returns:
125
- str: The output of the tool execution, or an error message if execution fails.
126
- """
127
- tool = self.tools.get(name)
128
- if not tool:
129
- return f"Error: Tool '{name}' not found"
130
-
131
- try:
132
- if isinstance(arguments, str):
133
- args = json.loads(arguments)
134
- else:
135
- args = arguments
136
-
137
- result = tool.execute(args, runtime_context)
138
- return str(result)
139
- except Exception as e:
140
- return f"Error executing tool '{name}': {e}"
141
-
142
- def _build_prompt(
143
- self, user_input: str, prompt_template: Optional[PromptTemplate] = None
144
- ) -> PromptTemplate:
145
- """Construct the conversation state for a new agent turn.
146
-
147
- Args:
148
- user_input: The user's input text.
149
- prompt_template: Optional template to initialize the conversation history.
150
- If None, a new ``PromptTemplate`` is created, and the system prompt is added if available.
151
-
152
- Returns:
153
- ``PromptTemplate``: The fully constructed prompt containing system, user, and previous messages.
154
- """
155
- if prompt_template is not None:
156
- prompt = prompt_template.copy()
157
- else:
158
- prompt = PromptTemplate()
159
- if self.system_prompt:
160
- prompt.add_system(self.system_prompt)
161
-
162
- prompt.add_user(user_input)
163
- return prompt
100
+ # Keep public list in sync for Runner/LLM usage
101
+ if self.tools is None:
102
+ self.tools = []
103
+ self.tools.append(tool)
164
104
 
165
105
  def invoke(
166
106
  self,
167
107
  *,
168
108
  user_input: str,
169
- prompt_template: Optional[PromptTemplate] = None,
170
- runtime_context: Optional[Dict[str, Any]] = None,
109
+ prompt_template: PromptTemplate | None = None,
110
+ runtime_context: dict[str, Any] | None = None,
171
111
  ) -> RunResult:
172
112
  """Run the agent synchronously.
173
113
 
174
- This method executes the agent loop, calling the language model and any
175
- registered tools until a final output is produced or the maximum number
176
- of iterations is reached. Each step in the execution is recorded in
177
- the returned ``RunResult``.
114
+ Executes the agent loop, calling the language model and tools until
115
+ a final response is generated.
178
116
 
179
117
  Args:
180
118
  user_input: The input text from the user.
@@ -182,127 +120,27 @@ class Agent:
182
120
  runtime_context: Optional runtime context dictionary to pass to tools.
183
121
 
184
122
  Returns:
185
- ``RunResult``: Contains the original input, all items generated
186
- during execution (messages, tool calls, reasoning), and the final output.
187
-
188
- Raises:
189
- ValueError: If `user_input` is empty.
190
- RuntimeError: If the agent exceeds `max_iterations` without completing.
123
+ ``RunResult``: The result of the agent run, including user input,
124
+ internal items (messages, tool calls), and the final output text.
191
125
  """
192
- if not user_input:
193
- raise ValueError("user_input cannot be empty")
194
-
195
- prompt = self._build_prompt(user_input, prompt_template)
196
- all_items: List[RunItem] = []
197
-
198
- for _ in range(self.max_iterations):
199
- response = self.llm.chat(
200
- messages=prompt.to_openai_input(),
201
- stream=False,
202
- tools=self._convert_to_openai_tools() if self.tools else None,
203
- tool_choice=self.tool_choice,
204
- parallel_tool_calls=self.parallel_tool_calls,
205
- )
206
-
207
- tool_calls: Dict[str, Dict[str, Any]] = {}
208
- final_output_text: str = ""
209
-
210
- # Process each output item from OpenAI response
211
- for item in response.output:
212
- if item.type == "reasoning":
213
- all_items.append(
214
- ReasoningItem(
215
- role="assistant",
216
- content=item.content,
217
- raw_item=item,
218
- type="reasoning_item",
219
- )
220
- )
221
-
222
- elif item.type == "function_call":
223
- tool_calls[item.id] = {
224
- "call_id": item.call_id,
225
- "name": item.name,
226
- "arguments": item.arguments,
227
- }
228
- all_items.append(
229
- ToolCallItem(
230
- role="assistant",
231
- content="",
232
- raw_item=item,
233
- type="tool_call_item",
234
- )
235
- )
236
-
237
- elif item.type == "message":
238
- text_parts = [
239
- c.text for c in item.content if c.type == "output_text"
240
- ]
241
- final_output_text = "".join(text_parts)
242
- all_items.append(
243
- MessageOutputItem(
244
- role="assistant",
245
- content=final_output_text,
246
- raw_item=item,
247
- type="message_output_item",
248
- )
249
- )
250
-
251
- if not tool_calls:
252
- return RunResult(
253
- input=user_input,
254
- new_items=all_items,
255
- final_output=final_output_text,
256
- )
257
-
258
- # Update history with assistant's text (Critical for context)
259
- if final_output_text:
260
- prompt.add_assistant(final_output_text)
261
-
262
- for tc in tool_calls.values():
263
- call_id = tc["call_id"]
264
- name = tc["name"]
265
- arguments_str = tc["arguments"]
266
-
267
- prompt.add_tool_call(
268
- name=name,
269
- arguments=arguments_str,
270
- call_id=call_id,
271
- )
272
-
273
- tool_output = self._execute_tool(name, arguments_str, runtime_context)
274
-
275
- prompt.add_tool_output(call_id=call_id, output=tool_output)
276
-
277
- all_items.append(
278
- ToolCallOutputItem(
279
- role="tool",
280
- content=tool_output,
281
- raw_item=ResponseFunctionToolCallOutput(
282
- call_id=call_id,
283
- output=tool_output,
284
- name=name,
285
- type="function_call_output",
286
- status="completed",
287
- ),
288
- type="tool_call_output_item",
289
- )
290
- )
291
-
292
- raise RuntimeError(f"Agent exceeded max iterations ({self.max_iterations})")
126
+ return Runner.run(
127
+ agent=self,
128
+ user_input=user_input,
129
+ prompt_template=prompt_template,
130
+ runtime_context=runtime_context,
131
+ )
293
132
 
294
133
  def stream(
295
134
  self,
296
135
  *,
297
136
  user_input: str,
298
- prompt_template: Optional[PromptTemplate] = None,
299
- runtime_context: Optional[Dict[str, Any]] = None,
137
+ prompt_template: PromptTemplate | None = None,
138
+ runtime_context: dict[str, Any] | None = None,
300
139
  ) -> Iterator[RunResultStreaming]:
301
140
  """Run the agent with streaming output.
302
141
 
303
- This method streams response events from the agent as they occur,
304
- including messages, tool calls, and tool outputs. It allows
305
- real-time processing of the agent's reasoning and tool execution.
142
+ Streams events as they happen (tokens, tool calls, tool results).
143
+ Useful for real-time UIs.
306
144
 
307
145
  Args:
308
146
  user_input: The input text from the user.
@@ -310,102 +148,11 @@ class Agent:
310
148
  runtime_context: Optional runtime context dictionary to pass to tools.
311
149
 
312
150
  Yields:
313
- ``RunResultStreaming``: Streaming events containing the current input,
314
- the event from the LLM or tool, and the accumulated final output.
315
-
316
- Raises:
317
- ValueError: If `user_input` is empty.
318
- RuntimeError: If the agent exceeds `max_iterations`.
151
+ ``RunResultStreaming``: Iteration of events from the agent execution.
319
152
  """
320
- if not user_input:
321
- raise ValueError("user_input cannot be empty")
322
-
323
- prompt = self._build_prompt(user_input, prompt_template)
324
-
325
- for _ in range(self.max_iterations):
326
- response_stream = self.llm.chat(
327
- messages=prompt.to_openai_input(),
328
- stream=True,
329
- tools=self._convert_to_openai_tools() if self.tools else None,
330
- tool_choice=self.tool_choice,
331
- parallel_tool_calls=self.parallel_tool_calls,
332
- )
333
-
334
- tool_calls: Dict[str, Dict[str, Any]] = {}
335
- final_output_text: str = ""
336
-
337
- for event in response_stream:
338
- yield RunResultStreaming(
339
- input=user_input,
340
- event=event,
341
- final_output=final_output_text,
342
- )
343
-
344
- if event.type == "response.output_item.done":
345
- if event.item.type == "message":
346
- for content_part in event.item.content:
347
- if content_part.type == "output_text":
348
- final_output_text += content_part.text
349
-
350
- elif event.item.type == "function_call":
351
- tool_calls[event.item.id] = {
352
- "call_id": event.item.call_id,
353
- "name": event.item.name,
354
- "arguments": event.item.arguments,
355
- }
356
-
357
- if not tool_calls:
358
- return
359
-
360
- # Update history with assistant's text (Critical for context)
361
- if final_output_text:
362
- prompt.add_assistant(final_output_text)
363
-
364
- for tc in tool_calls.values():
365
- call_id = tc["call_id"]
366
- name = tc["name"]
367
- arguments_str = tc["arguments"]
368
-
369
- prompt.add_tool_call(
370
- name=name, arguments=arguments_str, call_id=call_id
371
- )
372
-
373
- yield RunResultStreaming(
374
- input=user_input,
375
- event=ResponseFunctionCallOutputItemAddedEvent(
376
- type="response.function_call_output_item.added",
377
- item=ResponseFunctionToolCallOutput(
378
- call_id=call_id,
379
- output="",
380
- name=name,
381
- type="function_call_output",
382
- status="in_progress",
383
- ),
384
- output_index=None,
385
- sequence_number=None,
386
- ),
387
- final_output=final_output_text,
388
- )
389
-
390
- tool_output = self._execute_tool(name, arguments_str, runtime_context)
391
-
392
- prompt.add_tool_output(call_id=call_id, output=tool_output)
393
-
394
- yield RunResultStreaming(
395
- input=user_input,
396
- event=ResponseFunctionCallOutputItemDoneEvent(
397
- type="response.function_call_output_item.done",
398
- item=ResponseFunctionToolCallOutput(
399
- call_id=call_id,
400
- output=tool_output,
401
- name=name,
402
- type="function_call_output",
403
- status="completed",
404
- ),
405
- output_index=None,
406
- sequence_number=None,
407
- ),
408
- final_output=final_output_text,
409
- )
410
-
411
- raise RuntimeError(f"Agent exceeded max iterations ({self.max_iterations})")
153
+ return Runner.run_streamed(
154
+ agent=self,
155
+ user_input=user_input,
156
+ prompt_template=prompt_template,
157
+ runtime_context=runtime_context,
158
+ )
literun/args_schema.py CHANGED
@@ -2,39 +2,33 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, List, Optional, Type, Dict
5
+ from typing import Any
6
+ from pydantic import BaseModel, ConfigDict, Field
6
7
 
7
8
 
8
- class ArgsSchema:
9
- """Represents an argument for a tool."""
9
+ class ArgsSchema(BaseModel):
10
+ """Represents an argument for a tool.
10
11
 
11
- def __init__(
12
- self,
13
- *,
14
- name: str,
15
- type: Type,
16
- description: str,
17
- enum: Optional[List[Any]] = None,
18
- ):
19
- """Initialize an ArgsSchema.
12
+ Args:
13
+ name: The name of the argument.
14
+ type: The Python type of the argument (e.g., str, int, float, bool).
15
+ description: A description of the argument for documentation purposes.
16
+ enum: Optional list of allowed values for the argument.
17
+ """
20
18
 
21
- Args:
22
- name: The name of the argument.
23
- type: The Python type of the argument (e.g., str, int, float, bool).
24
- description: A description of the argument for documentation purposes.
25
- enum: Optional list of allowed values for the argument.
26
- """
27
- self.name = name
28
- self.type_ = type
29
- self.description = description
30
- self.enum = enum
19
+ model_config = ConfigDict(populate_by_name=True)
20
+
21
+ name: str
22
+ type_: type[Any] = Field(alias="type")
23
+ description: str = ""
24
+ enum: list[Any] | None = None
31
25
 
32
26
  # JSON schema representation
33
- def to_json_schema(self) -> Dict[str, Any]:
27
+ def to_json_schema(self) -> dict[str, Any]:
34
28
  """Convert the argument to a JSON Schema representation.
35
29
 
36
30
  Returns:
37
- Dict[str, Any]: A dictionary representing the argument in JSON Schema format.
31
+ dict[str, Any]: A dictionary representing the argument in JSON Schema format.
38
32
  """
39
33
  schema = {
40
34
  "type": self._json_type(),
literun/constants.py CHANGED
@@ -2,20 +2,25 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from enum import Enum
5
+ from typing import Literal
6
6
 
7
+ Role = Literal["system", "user", "assistant", "developer", "tool"]
7
8
 
8
- class Role(str, Enum):
9
- SYSTEM = "system"
10
- USER = "user"
11
- ASSISTANT = "assistant"
12
- DEVELOPER = "developer"
13
- TOOL = "tool"
9
+ ContentType = Literal[
10
+ "input_text",
11
+ "output_text",
12
+ "message",
13
+ "function_call",
14
+ "function_call_output",
15
+ ]
14
16
 
17
+ ToolChoice = Literal["auto", "none", "required"]
18
+ ReasoningEffort = Literal["none", "low", "medium", "high"]
19
+ Verbosity = Literal["low", "medium", "high"]
20
+ TextFormat = Literal["text", "json_object", "json_schema"]
15
21
 
16
- class ContentType(str, Enum):
17
- INPUT_TEXT = "input_text"
18
- OUTPUT_TEXT = "output_text"
19
- MESSAGE = "message"
20
- FUNCTION_CALL = "function_call"
21
- FUNCTION_CALL_OUTPUT = "function_call_output"
22
+ DEFAULT_OPENAI_MODEL = "gpt-4.1-mini"
23
+ DEFAULT_MAX_RETRIES = 3
24
+ DEFAULT_TIMEOUT = 60.0 # seconds
25
+ DEFAULT_MAX_TOOL_CALLS_LIMIT = 10
26
+ DEFAULT_MAX_ITERATIONS_LIMIT = 20
literun/events.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Union, Literal, TypeAlias
5
+ from typing import Literal, TypeAlias
6
6
  from pydantic import BaseModel
7
7
 
8
8
  from .items import ResponseFunctionToolCallOutput
@@ -37,35 +37,35 @@ from openai.types.responses import (
37
37
  )
38
38
 
39
39
 
40
- ResponseStreamEvent: TypeAlias = Union[
41
- ResponseCompletedEvent,
42
- ResponseContentPartAddedEvent,
43
- ResponseContentPartDoneEvent,
44
- ResponseCreatedEvent,
45
- ResponseErrorEvent,
46
- ResponseFunctionCallArgumentsDeltaEvent,
47
- ResponseFunctionCallArgumentsDoneEvent,
48
- ResponseInProgressEvent,
49
- ResponseFailedEvent,
50
- ResponseIncompleteEvent,
51
- ResponseOutputItemAddedEvent,
52
- ResponseOutputItemDoneEvent,
53
- ResponseReasoningSummaryPartAddedEvent,
54
- ResponseReasoningSummaryPartDoneEvent,
55
- ResponseReasoningSummaryTextDeltaEvent,
56
- ResponseReasoningSummaryTextDoneEvent,
57
- ResponseReasoningTextDeltaEvent,
58
- ResponseReasoningTextDoneEvent,
59
- ResponseRefusalDeltaEvent,
60
- ResponseRefusalDoneEvent,
61
- ResponseTextDeltaEvent,
62
- ResponseTextDoneEvent,
63
- ResponseWebSearchCallCompletedEvent,
64
- ResponseWebSearchCallInProgressEvent,
65
- ResponseWebSearchCallSearchingEvent,
66
- ResponseOutputTextAnnotationAddedEvent,
67
- ResponseQueuedEvent,
68
- ]
40
+ ResponseStreamEvent: TypeAlias = (
41
+ ResponseCompletedEvent
42
+ | ResponseContentPartAddedEvent
43
+ | ResponseContentPartDoneEvent
44
+ | ResponseCreatedEvent
45
+ | ResponseErrorEvent
46
+ | ResponseFunctionCallArgumentsDeltaEvent
47
+ | ResponseFunctionCallArgumentsDoneEvent
48
+ | ResponseInProgressEvent
49
+ | ResponseFailedEvent
50
+ | ResponseIncompleteEvent
51
+ | ResponseOutputItemAddedEvent
52
+ | ResponseOutputItemDoneEvent
53
+ | ResponseReasoningSummaryPartAddedEvent
54
+ | ResponseReasoningSummaryPartDoneEvent
55
+ | ResponseReasoningSummaryTextDeltaEvent
56
+ | ResponseReasoningSummaryTextDoneEvent
57
+ | ResponseReasoningTextDeltaEvent
58
+ | ResponseReasoningTextDoneEvent
59
+ | ResponseRefusalDeltaEvent
60
+ | ResponseRefusalDoneEvent
61
+ | ResponseTextDeltaEvent
62
+ | ResponseTextDoneEvent
63
+ | ResponseWebSearchCallCompletedEvent
64
+ | ResponseWebSearchCallInProgressEvent
65
+ | ResponseWebSearchCallSearchingEvent
66
+ | ResponseOutputTextAnnotationAddedEvent
67
+ | ResponseQueuedEvent
68
+ )
69
69
 
70
70
 
71
71
  # Custom internal events
@@ -103,8 +103,8 @@ class ResponseFunctionCallOutputItemDoneEvent(BaseModel):
103
103
 
104
104
  TResponseStreamEvent = ResponseStreamEvent
105
105
 
106
- StreamEvent: TypeAlias = Union[
107
- TResponseStreamEvent,
108
- ResponseFunctionCallOutputItemAddedEvent,
109
- ResponseFunctionCallOutputItemDoneEvent,
110
- ]
106
+ StreamEvent: TypeAlias = (
107
+ TResponseStreamEvent
108
+ | ResponseFunctionCallOutputItemAddedEvent
109
+ | ResponseFunctionCallOutputItemDoneEvent
110
+ )