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 +1 -1
- literun/agent.py +78 -331
- literun/args_schema.py +18 -24
- literun/constants.py +18 -13
- literun/events.py +35 -35
- literun/items.py +12 -17
- literun/llm.py +160 -68
- literun/prompt_message.py +35 -48
- literun/prompt_template.py +14 -17
- literun/results.py +3 -5
- literun/runner.py +342 -0
- literun/tool.py +29 -41
- literun-0.1.1.dist-info/METADATA +187 -0
- literun-0.1.1.dist-info/RECORD +17 -0
- {literun-0.1.0.dist-info → literun-0.1.1.dist-info}/WHEEL +1 -2
- literun-0.1.0.dist-info/METADATA +0 -242
- literun-0.1.0.dist-info/RECORD +0 -17
- literun-0.1.0.dist-info/top_level.txt +0 -1
- {literun-0.1.0.dist-info → literun-0.1.1.dist-info}/licenses/LICENSE +0 -0
literun/__init__.py
CHANGED
literun/agent.py
CHANGED
|
@@ -2,81 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
from
|
|
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 .
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
self.
|
|
60
|
-
|
|
61
|
-
self
|
|
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:
|
|
67
|
-
) ->
|
|
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
|
-
|
|
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:
|
|
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
|
|
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.
|
|
96
|
+
if tool.name in self._tools:
|
|
98
97
|
raise ValueError(f"Tool '{tool.name}' already registered")
|
|
99
|
-
self.
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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:
|
|
170
|
-
runtime_context:
|
|
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
|
-
|
|
175
|
-
|
|
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``:
|
|
186
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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:
|
|
299
|
-
runtime_context:
|
|
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
|
-
|
|
304
|
-
|
|
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``:
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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) ->
|
|
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
|
-
|
|
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
|
|
5
|
+
from typing import Literal
|
|
6
6
|
|
|
7
|
+
Role = Literal["system", "user", "assistant", "developer", "tool"]
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
107
|
-
TResponseStreamEvent
|
|
108
|
-
ResponseFunctionCallOutputItemAddedEvent
|
|
109
|
-
ResponseFunctionCallOutputItemDoneEvent
|
|
110
|
-
|
|
106
|
+
StreamEvent: TypeAlias = (
|
|
107
|
+
TResponseStreamEvent
|
|
108
|
+
| ResponseFunctionCallOutputItemAddedEvent
|
|
109
|
+
| ResponseFunctionCallOutputItemDoneEvent
|
|
110
|
+
)
|