lite-agent 0.2.0__py3-none-any.whl → 0.4.0__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.
Potentially problematic release.
This version of lite-agent might be problematic. Click here for more details.
- lite_agent/__init__.py +2 -1
- lite_agent/agent.py +249 -58
- lite_agent/chat_display.py +779 -0
- lite_agent/client.py +69 -0
- lite_agent/message_transfers.py +9 -1
- lite_agent/processors/__init__.py +3 -2
- lite_agent/processors/completion_event_processor.py +306 -0
- lite_agent/processors/response_event_processor.py +205 -0
- lite_agent/runner.py +553 -225
- lite_agent/stream_handlers/__init__.py +3 -2
- lite_agent/stream_handlers/litellm.py +37 -68
- lite_agent/templates/handoffs_source_instructions.xml.j2 +10 -0
- lite_agent/templates/handoffs_target_instructions.xml.j2 +9 -0
- lite_agent/templates/wait_for_user_instructions.xml.j2 +6 -0
- lite_agent/types/__init__.py +97 -23
- lite_agent/types/events.py +119 -0
- lite_agent/types/messages.py +308 -33
- {lite_agent-0.2.0.dist-info → lite_agent-0.4.0.dist-info}/METADATA +2 -2
- lite_agent-0.4.0.dist-info/RECORD +23 -0
- lite_agent/processors/stream_chunk_processor.py +0 -106
- lite_agent/types/chunks.py +0 -89
- lite_agent-0.2.0.dist-info/RECORD +0 -17
- {lite_agent-0.2.0.dist-info → lite_agent-0.4.0.dist-info}/WHEEL +0 -0
lite_agent/types/messages.py
CHANGED
|
@@ -1,68 +1,343 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
|
-
from
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from typing import Any, Literal, NotRequired, TypedDict
|
|
3
4
|
|
|
4
|
-
from pydantic import BaseModel
|
|
5
|
-
from rich import Any
|
|
5
|
+
from pydantic import BaseModel, Field, model_validator
|
|
6
6
|
|
|
7
|
-
from .tool_calls import ToolCall
|
|
8
7
|
|
|
8
|
+
# Base metadata type
|
|
9
|
+
class MessageMeta(BaseModel):
|
|
10
|
+
"""Base metadata for all message types"""
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
id: str
|
|
12
|
-
index: int
|
|
13
|
-
role: Literal["assistant"] = "assistant"
|
|
14
|
-
content: str = ""
|
|
15
|
-
tool_calls: list[ToolCall] | None = None
|
|
12
|
+
sent_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
16
13
|
|
|
17
14
|
|
|
18
|
-
class
|
|
19
|
-
|
|
20
|
-
content: str
|
|
15
|
+
class BasicMessageMeta(MessageMeta):
|
|
16
|
+
"""Basic metadata for user messages and function calls"""
|
|
21
17
|
|
|
18
|
+
execution_time_ms: int | None = None
|
|
22
19
|
|
|
23
|
-
class UserMessageContentItemText(BaseModel):
|
|
24
|
-
type: Literal["text"]
|
|
25
|
-
text: str
|
|
26
20
|
|
|
21
|
+
class LLMResponseMeta(MessageMeta):
|
|
22
|
+
"""Metadata for LLM responses, includes performance metrics"""
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
latency_ms: int | None = None
|
|
25
|
+
output_time_ms: int | None = None
|
|
26
|
+
input_tokens: int | None = None
|
|
27
|
+
output_tokens: int | None = None
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
# New unified metadata types
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class MessageUsage(BaseModel):
|
|
34
|
+
"""Token usage statistics for messages"""
|
|
35
|
+
|
|
36
|
+
input_tokens: int | None = None
|
|
37
|
+
output_tokens: int | None = None
|
|
38
|
+
total_tokens: int | None = None
|
|
35
39
|
|
|
36
40
|
|
|
37
|
-
class
|
|
41
|
+
class AssistantMessageMeta(MessageMeta):
|
|
42
|
+
"""Enhanced metadata for assistant messages"""
|
|
43
|
+
|
|
44
|
+
model: str | None = None
|
|
45
|
+
usage: MessageUsage | None = None
|
|
46
|
+
total_time_ms: int | None = None
|
|
47
|
+
latency_ms: int | None = None
|
|
48
|
+
output_time_ms: int | None = None
|
|
49
|
+
input_tokens: int | None = None
|
|
50
|
+
output_tokens: int | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ResponseInputImageDict(TypedDict):
|
|
54
|
+
detail: NotRequired[Literal["low", "high", "auto"]]
|
|
55
|
+
type: Literal["input_image"]
|
|
56
|
+
file_id: str | None
|
|
57
|
+
image_url: str | None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ResponseInputTextDict(TypedDict):
|
|
61
|
+
text: str
|
|
62
|
+
type: Literal["input_text"]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# TypedDict definitions for better type hints
|
|
66
|
+
class UserMessageDict(TypedDict):
|
|
38
67
|
role: Literal["user"]
|
|
39
|
-
content: str | Sequence[
|
|
68
|
+
content: str | Sequence[ResponseInputTextDict | ResponseInputImageDict]
|
|
40
69
|
|
|
41
70
|
|
|
42
|
-
class
|
|
71
|
+
class AssistantMessageDict(TypedDict):
|
|
43
72
|
role: Literal["assistant"]
|
|
44
73
|
content: str
|
|
45
74
|
|
|
46
75
|
|
|
47
|
-
class
|
|
76
|
+
class SystemMessageDict(TypedDict):
|
|
48
77
|
role: Literal["system"]
|
|
49
78
|
content: str
|
|
50
79
|
|
|
51
80
|
|
|
52
|
-
class
|
|
53
|
-
arguments: str
|
|
81
|
+
class FunctionCallDict(TypedDict):
|
|
54
82
|
type: Literal["function_call"]
|
|
55
|
-
|
|
83
|
+
call_id: str
|
|
56
84
|
name: str
|
|
85
|
+
arguments: str
|
|
57
86
|
content: str
|
|
58
87
|
|
|
59
88
|
|
|
60
|
-
class
|
|
89
|
+
class FunctionCallOutputDict(TypedDict):
|
|
90
|
+
type: Literal["function_call_output"]
|
|
61
91
|
call_id: str
|
|
62
92
|
output: str
|
|
63
|
-
type: Literal["function_call_output"]
|
|
64
93
|
|
|
65
94
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
# Union type for all supported message dictionary formats
|
|
96
|
+
MessageDict = UserMessageDict | AssistantMessageDict | SystemMessageDict | FunctionCallDict | FunctionCallOutputDict
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# New structured message content types
|
|
100
|
+
class UserTextContent(BaseModel):
|
|
101
|
+
type: Literal["text"] = "text"
|
|
102
|
+
text: str
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class UserImageContent(BaseModel):
|
|
106
|
+
type: Literal["image"] = "image"
|
|
107
|
+
image_url: str | None = None
|
|
108
|
+
file_id: str | None = None
|
|
109
|
+
detail: Literal["low", "high", "auto"] = "auto"
|
|
110
|
+
|
|
111
|
+
@model_validator(mode="after")
|
|
112
|
+
def validate_image_source(self) -> "UserImageContent":
|
|
113
|
+
if not self.file_id and not self.image_url:
|
|
114
|
+
msg = "UserImageContent must have either file_id or image_url"
|
|
115
|
+
raise ValueError(msg)
|
|
116
|
+
return self
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class UserFileContent(BaseModel):
|
|
120
|
+
type: Literal["file"] = "file"
|
|
121
|
+
file_id: str
|
|
122
|
+
file_name: str | None = None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
UserMessageContent = UserTextContent | UserImageContent | UserFileContent
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class AssistantTextContent(BaseModel):
|
|
129
|
+
type: Literal["text"] = "text"
|
|
130
|
+
text: str
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class AssistantToolCall(BaseModel):
|
|
134
|
+
type: Literal["tool_call"] = "tool_call"
|
|
135
|
+
call_id: str
|
|
136
|
+
name: str
|
|
137
|
+
arguments: dict[str, Any] | str
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class AssistantToolCallResult(BaseModel):
|
|
141
|
+
type: Literal["tool_call_result"] = "tool_call_result"
|
|
142
|
+
call_id: str
|
|
143
|
+
output: str
|
|
144
|
+
execution_time_ms: int | None = None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
AssistantMessageContent = AssistantTextContent | AssistantToolCall | AssistantToolCallResult
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# New structured message types
|
|
151
|
+
class NewUserMessage(BaseModel):
|
|
152
|
+
"""User message with structured content support"""
|
|
153
|
+
|
|
154
|
+
role: Literal["user"] = "user"
|
|
155
|
+
content: list[UserMessageContent]
|
|
156
|
+
meta: MessageMeta = Field(default_factory=MessageMeta)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class NewSystemMessage(BaseModel):
|
|
160
|
+
"""System message"""
|
|
161
|
+
|
|
162
|
+
role: Literal["system"] = "system"
|
|
163
|
+
content: str
|
|
164
|
+
meta: MessageMeta = Field(default_factory=MessageMeta)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class NewAssistantMessage(BaseModel):
|
|
168
|
+
"""Assistant message with structured content and metadata"""
|
|
169
|
+
|
|
170
|
+
role: Literal["assistant"] = "assistant"
|
|
171
|
+
content: list[AssistantMessageContent]
|
|
172
|
+
meta: AssistantMessageMeta = Field(default_factory=AssistantMessageMeta)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# Union type for new structured messages
|
|
176
|
+
NewMessage = NewUserMessage | NewSystemMessage | NewAssistantMessage
|
|
177
|
+
NewMessages = Sequence[NewMessage]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# Response API format input types
|
|
181
|
+
class ResponseInputText(BaseModel):
|
|
182
|
+
type: Literal["input_text"] = "input_text"
|
|
183
|
+
text: str
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ResponseInputImage(BaseModel):
|
|
187
|
+
detail: Literal["low", "high", "auto"] = "auto"
|
|
188
|
+
type: Literal["input_image"] = "input_image"
|
|
189
|
+
file_id: str | None = None
|
|
190
|
+
image_url: str | None = None
|
|
191
|
+
|
|
192
|
+
@model_validator(mode="after")
|
|
193
|
+
def validate_image_source(self) -> "ResponseInputImage":
|
|
194
|
+
"""Ensure at least one of file_id or image_url is provided."""
|
|
195
|
+
if not self.file_id and not self.image_url:
|
|
196
|
+
msg = "ResponseInputImage must have either file_id or image_url"
|
|
197
|
+
raise ValueError(msg)
|
|
198
|
+
return self
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Compatibility types for old completion API format
|
|
202
|
+
class UserMessageContentItemText(BaseModel):
|
|
203
|
+
type: Literal["text"]
|
|
204
|
+
text: str
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class UserMessageContentItemImageURLImageURL(BaseModel):
|
|
208
|
+
url: str
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class UserMessageContentItemImageURL(BaseModel):
|
|
212
|
+
type: Literal["image_url"]
|
|
213
|
+
image_url: UserMessageContentItemImageURLImageURL
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# Legacy compatibility wrapper classes
|
|
217
|
+
class AgentUserMessage(NewUserMessage):
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
content: str | list[UserMessageContent] | None = None,
|
|
221
|
+
*,
|
|
222
|
+
role: Literal["user"] = "user",
|
|
223
|
+
meta: MessageMeta | None = None,
|
|
224
|
+
):
|
|
225
|
+
if isinstance(content, str):
|
|
226
|
+
content = [UserTextContent(text=content)]
|
|
227
|
+
elif content is None:
|
|
228
|
+
content = []
|
|
229
|
+
super().__init__(
|
|
230
|
+
role=role,
|
|
231
|
+
content=content,
|
|
232
|
+
meta=meta or MessageMeta(),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class AgentAssistantMessage(NewAssistantMessage):
|
|
237
|
+
def __init__(
|
|
238
|
+
self,
|
|
239
|
+
content: str | list[AssistantMessageContent] | None = None,
|
|
240
|
+
*,
|
|
241
|
+
role: Literal["assistant"] = "assistant",
|
|
242
|
+
meta: AssistantMessageMeta | None = None,
|
|
243
|
+
):
|
|
244
|
+
if isinstance(content, str):
|
|
245
|
+
content = [AssistantTextContent(text=content)]
|
|
246
|
+
elif content is None:
|
|
247
|
+
content = []
|
|
248
|
+
super().__init__(
|
|
249
|
+
role=role,
|
|
250
|
+
content=content,
|
|
251
|
+
meta=meta or AssistantMessageMeta(),
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
AgentSystemMessage = NewSystemMessage
|
|
256
|
+
RunnerMessage = NewMessage
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# Streaming processor types
|
|
260
|
+
class AssistantMessage(BaseModel):
|
|
261
|
+
"""
|
|
262
|
+
Temporary assistant message used during streaming processing.
|
|
263
|
+
|
|
264
|
+
This is a simplified message format used internally by completion event processors
|
|
265
|
+
to accumulate streaming content before converting to the final NewAssistantMessage format.
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
role: Literal["assistant"] = "assistant"
|
|
269
|
+
id: str = ""
|
|
270
|
+
index: int | None = None
|
|
271
|
+
content: str = ""
|
|
272
|
+
tool_calls: list[Any] | None = None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# Enhanced type definitions for better type hints
|
|
276
|
+
# Supports new message format, legacy messages, and dict (for backward compatibility)
|
|
277
|
+
FlexibleRunnerMessage = NewMessage | AgentUserMessage | AgentAssistantMessage | dict[str, Any]
|
|
278
|
+
RunnerMessages = Sequence[FlexibleRunnerMessage]
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# Type alias for user input - supports string, single message, or sequence of messages
|
|
282
|
+
UserInput = str | FlexibleRunnerMessage | RunnerMessages
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def user_message_to_llm_dict(message: NewUserMessage) -> dict[str, Any]:
|
|
286
|
+
"""Convert NewUserMessage to dict for LLM API"""
|
|
287
|
+
# Convert content to simplified format for LLM
|
|
288
|
+
content = message.content[0].text if len(message.content) == 1 and message.content[0].type == "text" else [item.model_dump() for item in message.content]
|
|
289
|
+
return {"role": message.role, "content": content}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def system_message_to_llm_dict(message: NewSystemMessage) -> dict[str, Any]:
|
|
293
|
+
"""Convert NewSystemMessage to dict for LLM API"""
|
|
294
|
+
return {"role": message.role, "content": message.content}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def assistant_message_to_llm_dict(message: NewAssistantMessage) -> dict[str, Any]:
|
|
298
|
+
"""Convert NewAssistantMessage to dict for LLM API"""
|
|
299
|
+
# Separate text content from tool calls
|
|
300
|
+
text_parts = []
|
|
301
|
+
tool_calls = []
|
|
302
|
+
|
|
303
|
+
for item in message.content:
|
|
304
|
+
if item.type == "text":
|
|
305
|
+
text_parts.append(item.text)
|
|
306
|
+
elif item.type == "tool_call":
|
|
307
|
+
tool_calls.append(
|
|
308
|
+
{
|
|
309
|
+
"id": item.call_id,
|
|
310
|
+
"type": "function",
|
|
311
|
+
"function": {
|
|
312
|
+
"name": item.name,
|
|
313
|
+
"arguments": item.arguments if isinstance(item.arguments, str) else str(item.arguments),
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
result = {
|
|
319
|
+
"role": message.role,
|
|
320
|
+
"content": " ".join(text_parts) if text_parts else None,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if tool_calls:
|
|
324
|
+
result["tool_calls"] = tool_calls
|
|
325
|
+
|
|
326
|
+
return result
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def message_to_llm_dict(message: NewMessage) -> dict[str, Any]:
|
|
330
|
+
"""Convert any NewMessage to dict for LLM API"""
|
|
331
|
+
if isinstance(message, NewUserMessage):
|
|
332
|
+
return user_message_to_llm_dict(message)
|
|
333
|
+
if isinstance(message, NewSystemMessage):
|
|
334
|
+
return system_message_to_llm_dict(message)
|
|
335
|
+
if isinstance(message, NewAssistantMessage):
|
|
336
|
+
return assistant_message_to_llm_dict(message)
|
|
337
|
+
# Fallback
|
|
338
|
+
return message.model_dump(exclude={"meta"})
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def messages_to_llm_format(messages: Sequence[NewMessage]) -> list[dict[str, Any]]:
|
|
342
|
+
"""Convert a sequence of NewMessage to LLM format, excluding meta data"""
|
|
343
|
+
return [message_to_llm_dict(message) for message in messages]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lite-agent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A lightweight, extensible framework for building AI agent.
|
|
5
5
|
Author-email: Jianqi Pan <jannchie@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -18,7 +18,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Requires-Dist: aiofiles>=24.1.0
|
|
21
|
-
Requires-Dist: funcall>=0.
|
|
21
|
+
Requires-Dist: funcall>=0.10.0
|
|
22
22
|
Requires-Dist: prompt-toolkit>=3.0.51
|
|
23
23
|
Requires-Dist: rich>=14.0.0
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
lite_agent/__init__.py,sha256=Swuefee0etSiaDnn30K2hBNV9UI3hIValW3A-pRE7e0,338
|
|
2
|
+
lite_agent/agent.py,sha256=7wM8nVXIaPvEirRiY2HV0rY0sQuYCj-_hQ6V369bB58,22897
|
|
3
|
+
lite_agent/chat_display.py,sha256=b0sUH3fkutc4e_KAKH7AtPu2msyLloNIAiWqCNavdds,30533
|
|
4
|
+
lite_agent/client.py,sha256=m2jfBPIsleMZ1QCczjyHND-PIF17kQh4RTuf5FaipGM,2571
|
|
5
|
+
lite_agent/loggers.py,sha256=XkNkdqwD_nQGfhQJ-bBWT7koci_mMkNw3aBpyMhOICw,57
|
|
6
|
+
lite_agent/message_transfers.py,sha256=9qucjc-uSIXvVfhcmVRC_0lp0Q8sWp99dV4ReCh6ZlI,4428
|
|
7
|
+
lite_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
lite_agent/runner.py,sha256=wi56i5cMYAJi3U9GBsBlzhGC6Do9ovMSOsA_Qqy2HtA,39642
|
|
9
|
+
lite_agent/processors/__init__.py,sha256=ybpAzpMBIE9v5I24wIBZRXeaOaPNTmoKH13aofgNI6Q,234
|
|
10
|
+
lite_agent/processors/completion_event_processor.py,sha256=8fQYRofgBd8t0V3oUakTOmZdv5Q9tCuzADGCGvVgy0k,13442
|
|
11
|
+
lite_agent/processors/response_event_processor.py,sha256=CElJMUzLs8mklVqJtoLiVu-NTq0Dz2NNd9YdAKpjgE0,8088
|
|
12
|
+
lite_agent/stream_handlers/__init__.py,sha256=a5s1GZr42uvndtcQqEhK2cnjGkK8ZFTAZCj3J61Bb5E,209
|
|
13
|
+
lite_agent/stream_handlers/litellm.py,sha256=lE2whfFG-txhjeIp58yZ4nqApXjVeSACUIk-3KYcnVg,2692
|
|
14
|
+
lite_agent/templates/handoffs_source_instructions.xml.j2,sha256=2XsXQlBzk38qbxGrfyt8y2b0KlZmsV_1xavLufcdkHc,428
|
|
15
|
+
lite_agent/templates/handoffs_target_instructions.xml.j2,sha256=gSbWVYYcovPKbGpFc0kqGSJ5Y5UC3fOHyUmZfcrDgSE,356
|
|
16
|
+
lite_agent/templates/wait_for_user_instructions.xml.j2,sha256=wXbcYD5Q1FaCGVBm3Hz_Cp7nnoK7KzloP0ao-jYMwPk,231
|
|
17
|
+
lite_agent/types/__init__.py,sha256=QKuhjFWRcpAlsBK9JYgoCABpoQExwhuyGudJoiiqQfs,3093
|
|
18
|
+
lite_agent/types/events.py,sha256=mFMqV55WWJbPDyb_P61nd3qMLpEnwZgVY6NTKFkINkg,2389
|
|
19
|
+
lite_agent/types/messages.py,sha256=c7nTIWqXNo562het_vaWcZvsoy-adkARwAYn4JNqm0c,9897
|
|
20
|
+
lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
|
|
21
|
+
lite_agent-0.4.0.dist-info/METADATA,sha256=biQoUoss9DcSuUX494mPj2yoXtE0H81Far_K3IpFB30,3456
|
|
22
|
+
lite_agent-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
+
lite_agent-0.4.0.dist-info/RECORD,,
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import litellm
|
|
2
|
-
from litellm.types.utils import ChatCompletionDeltaToolCall, ModelResponseStream, StreamingChoices
|
|
3
|
-
|
|
4
|
-
from lite_agent.loggers import logger
|
|
5
|
-
from lite_agent.types import AssistantMessage, ToolCall, ToolCallFunction
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class StreamChunkProcessor:
|
|
9
|
-
"""Processor for handling streaming responses"""
|
|
10
|
-
|
|
11
|
-
def __init__(self) -> None:
|
|
12
|
-
self._current_message: AssistantMessage | None = None
|
|
13
|
-
|
|
14
|
-
def initialize_message(self, chunk: ModelResponseStream, choice: StreamingChoices) -> None:
|
|
15
|
-
"""Initialize the message object"""
|
|
16
|
-
delta = choice.delta
|
|
17
|
-
if delta.role != "assistant":
|
|
18
|
-
logger.warning("Skipping chunk with role: %s", delta.role)
|
|
19
|
-
return
|
|
20
|
-
self._current_message = AssistantMessage(
|
|
21
|
-
id=chunk.id,
|
|
22
|
-
index=choice.index,
|
|
23
|
-
role=delta.role,
|
|
24
|
-
content="",
|
|
25
|
-
)
|
|
26
|
-
logger.debug('Initialized new message: "%s"', self._current_message.id)
|
|
27
|
-
|
|
28
|
-
def update_content(self, content: str) -> None:
|
|
29
|
-
"""Update message content"""
|
|
30
|
-
if self._current_message and content:
|
|
31
|
-
self._current_message.content += content
|
|
32
|
-
|
|
33
|
-
def _initialize_tool_calls(self, tool_calls: list[litellm.ChatCompletionMessageToolCall]) -> None:
|
|
34
|
-
"""Initialize tool calls"""
|
|
35
|
-
if not self._current_message:
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
self._current_message.tool_calls = []
|
|
39
|
-
for call in tool_calls:
|
|
40
|
-
logger.debug("Create new tool call: %s", call.id)
|
|
41
|
-
|
|
42
|
-
def _update_tool_calls(self, tool_calls: list[litellm.ChatCompletionMessageToolCall]) -> None:
|
|
43
|
-
"""Update existing tool calls"""
|
|
44
|
-
if not self._current_message:
|
|
45
|
-
return
|
|
46
|
-
if not hasattr(self._current_message, "tool_calls"):
|
|
47
|
-
self._current_message.tool_calls = []
|
|
48
|
-
if not self._current_message.tool_calls:
|
|
49
|
-
return
|
|
50
|
-
if not tool_calls:
|
|
51
|
-
return
|
|
52
|
-
for current_call, new_call in zip(self._current_message.tool_calls, tool_calls, strict=False):
|
|
53
|
-
if new_call.function.arguments and current_call.function.arguments:
|
|
54
|
-
current_call.function.arguments += new_call.function.arguments
|
|
55
|
-
if new_call.type and new_call.type == "function":
|
|
56
|
-
current_call.type = new_call.type
|
|
57
|
-
elif new_call.type:
|
|
58
|
-
logger.warning("Unexpected tool call type: %s", new_call.type)
|
|
59
|
-
|
|
60
|
-
def update_tool_calls(self, tool_calls: list[ChatCompletionDeltaToolCall]) -> None:
|
|
61
|
-
"""Handle tool call updates"""
|
|
62
|
-
if not tool_calls:
|
|
63
|
-
return
|
|
64
|
-
for call in tool_calls:
|
|
65
|
-
if call.id:
|
|
66
|
-
if call.type == "function":
|
|
67
|
-
new_tool_call = ToolCall(
|
|
68
|
-
id=call.id,
|
|
69
|
-
type=call.type,
|
|
70
|
-
function=ToolCallFunction(
|
|
71
|
-
name=call.function.name or "",
|
|
72
|
-
arguments=call.function.arguments,
|
|
73
|
-
),
|
|
74
|
-
index=call.index,
|
|
75
|
-
)
|
|
76
|
-
if self._current_message is not None:
|
|
77
|
-
if self._current_message.tool_calls is None:
|
|
78
|
-
self._current_message.tool_calls = []
|
|
79
|
-
self._current_message.tool_calls.append(new_tool_call)
|
|
80
|
-
else:
|
|
81
|
-
logger.warning("Unexpected tool call type: %s", call.type)
|
|
82
|
-
elif self._current_message is not None and self._current_message.tool_calls is not None and call.index is not None and 0 <= call.index < len(self._current_message.tool_calls):
|
|
83
|
-
existing_call = self._current_message.tool_calls[call.index]
|
|
84
|
-
if call.function.arguments:
|
|
85
|
-
if existing_call.function.arguments is None:
|
|
86
|
-
existing_call.function.arguments = ""
|
|
87
|
-
existing_call.function.arguments += call.function.arguments
|
|
88
|
-
else:
|
|
89
|
-
logger.warning("Cannot update tool call: current_message or tool_calls is None, or invalid index.")
|
|
90
|
-
|
|
91
|
-
def handle_usage_info(self, chunk: ModelResponseStream) -> litellm.Usage | None:
|
|
92
|
-
"""Handle usage info, return whether this chunk should be skipped"""
|
|
93
|
-
return getattr(chunk, "usage", None)
|
|
94
|
-
|
|
95
|
-
@property
|
|
96
|
-
def is_initialized(self) -> bool:
|
|
97
|
-
"""Check if the current message is initialized"""
|
|
98
|
-
return self._current_message is not None
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def current_message(self) -> AssistantMessage:
|
|
102
|
-
"""Get the current message being processed"""
|
|
103
|
-
if not self._current_message:
|
|
104
|
-
msg = "No current message initialized. Call initialize_message first."
|
|
105
|
-
raise ValueError(msg)
|
|
106
|
-
return self._current_message
|
lite_agent/types/chunks.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
from typing import Literal
|
|
2
|
-
|
|
3
|
-
from litellm import Usage
|
|
4
|
-
from litellm.types.utils import ModelResponseStream
|
|
5
|
-
from pydantic import BaseModel
|
|
6
|
-
|
|
7
|
-
from .messages import AssistantMessage
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class CompletionRawChunk(BaseModel):
|
|
11
|
-
"""
|
|
12
|
-
Define the type of chunk
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
type: Literal["completion_raw"]
|
|
16
|
-
raw: ModelResponseStream
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class UsageChunk(BaseModel):
|
|
20
|
-
"""
|
|
21
|
-
Define the type of usage info chunk
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
type: Literal["usage"]
|
|
25
|
-
usage: Usage
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class FinalMessageChunk(BaseModel):
|
|
29
|
-
"""
|
|
30
|
-
Define the type of final message chunk
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
type: Literal["final_message"]
|
|
34
|
-
message: AssistantMessage
|
|
35
|
-
finish_reason: str | None = None # Literal["stop", "tool_calls"]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class ToolCallChunk(BaseModel):
|
|
39
|
-
"""
|
|
40
|
-
Define the type of tool call chunk
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
type: Literal["tool_call"]
|
|
44
|
-
name: str
|
|
45
|
-
arguments: str
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class ToolCallResultChunk(BaseModel):
|
|
49
|
-
"""
|
|
50
|
-
Define the type of tool call result chunk
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
type: Literal["tool_call_result"]
|
|
54
|
-
tool_call_id: str
|
|
55
|
-
name: str
|
|
56
|
-
content: str
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class ContentDeltaChunk(BaseModel):
|
|
60
|
-
"""
|
|
61
|
-
Define the type of message chunk
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
type: Literal["content_delta"]
|
|
65
|
-
delta: str
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class ToolCallDeltaChunk(BaseModel):
|
|
69
|
-
"""
|
|
70
|
-
Define the type of tool call delta chunk
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
type: Literal["tool_call_delta"]
|
|
74
|
-
tool_call_id: str
|
|
75
|
-
name: str
|
|
76
|
-
arguments_delta: str
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
AgentChunk = CompletionRawChunk | UsageChunk | FinalMessageChunk | ToolCallChunk | ToolCallResultChunk | ContentDeltaChunk | ToolCallDeltaChunk
|
|
80
|
-
|
|
81
|
-
AgentChunkType = Literal[
|
|
82
|
-
"completion_raw",
|
|
83
|
-
"usage",
|
|
84
|
-
"final_message",
|
|
85
|
-
"tool_call",
|
|
86
|
-
"tool_call_result",
|
|
87
|
-
"content_delta",
|
|
88
|
-
"tool_call_delta",
|
|
89
|
-
]
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
lite_agent/__init__.py,sha256=T-jxY0aHwqPz5gs-ZzH1zvFgFdYVmOd15fnEc5A2H6U,229
|
|
2
|
-
lite_agent/agent.py,sha256=UE06H1Huk4gHGovbh9DuAJAH2zC0hqf1YXgrVa59_Os,13546
|
|
3
|
-
lite_agent/loggers.py,sha256=XkNkdqwD_nQGfhQJ-bBWT7koci_mMkNw3aBpyMhOICw,57
|
|
4
|
-
lite_agent/message_transfers.py,sha256=nT7-tID20RK2yoN-rDiEE6sSclluSlhYSkayCzmPwk8,3984
|
|
5
|
-
lite_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
lite_agent/runner.py,sha256=lO8Z5R2RxjjgYzDAeYQbO2niQeieXOEzqUEN484G7QU,21367
|
|
7
|
-
lite_agent/processors/__init__.py,sha256=X78GKL_IWwW2lg8w4DD6GOFWLzAR2wTfKxHlvOkcuUQ,114
|
|
8
|
-
lite_agent/processors/stream_chunk_processor.py,sha256=nMA_cW7FDpXwJvm4F8vFwBXmHHsSELQFcoNEjH3xvn8,4751
|
|
9
|
-
lite_agent/stream_handlers/__init__.py,sha256=2GSiG0VUgcQlFMl6JkGAqikXMII1a43Hr-J5NIct6dk,115
|
|
10
|
-
lite_agent/stream_handlers/litellm.py,sha256=NNMAl8Bvoc2xe-qWKtfqvJQA2yr3sz1IUU90rQ_9iBw,3976
|
|
11
|
-
lite_agent/types/__init__.py,sha256=sc2cdX1tPisfQwu2-apZtUa3u_Q6WDEqzNglfXhwCJo,1295
|
|
12
|
-
lite_agent/types/chunks.py,sha256=Ro5BtrrdsYGkKrEekIhs9vIrBM7HljtgOkHherH8B3k,1697
|
|
13
|
-
lite_agent/types/messages.py,sha256=cmMcj_r1_R9Pgu6ixmBIq2uwwqi5KzIllxGoxpcxF3w,1531
|
|
14
|
-
lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
|
|
15
|
-
lite_agent-0.2.0.dist-info/METADATA,sha256=egjWZCc9UgPAHMCJqZrjBXlXrG39f9LoW9k6DzntMas,3455
|
|
16
|
-
lite_agent-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
-
lite_agent-0.2.0.dist-info/RECORD,,
|
|
File without changes
|