lite-agent 0.6.0__py3-none-any.whl → 0.9.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.

@@ -30,6 +30,7 @@ from .messages import (
30
30
  AssistantToolCall,
31
31
  AssistantToolCallResult,
32
32
  BasicMessageMeta,
33
+ FlexibleInputMessage,
33
34
  FlexibleRunnerMessage,
34
35
  FunctionCallDict,
35
36
  FunctionCallOutputDict,
@@ -86,6 +87,7 @@ __all__ = [
86
87
  "CompletionRawEvent",
87
88
  "ContentDeltaEvent",
88
89
  "EventUsage",
90
+ "FlexibleInputMessage",
89
91
  "FlexibleRunnerMessage",
90
92
  "FunctionCallDeltaEvent",
91
93
  "FunctionCallDict",
@@ -46,8 +46,6 @@ class AssistantMessageMeta(MessageMeta):
46
46
  total_time_ms: int | None = None
47
47
  latency_ms: int | None = None
48
48
  output_time_ms: int | None = None
49
- input_tokens: int | None = None
50
- output_tokens: int | None = None
51
49
 
52
50
 
53
51
  class ResponseInputImageDict(TypedDict):
@@ -273,13 +271,16 @@ class AssistantMessage(BaseModel):
273
271
 
274
272
 
275
273
  # 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]
274
+ # FlexibleRunnerMessage for internal storage - only NewMessage types
275
+ FlexibleRunnerMessage = NewMessage
278
276
  RunnerMessages = Sequence[FlexibleRunnerMessage]
279
277
 
278
+ # Input types that can be converted - includes dict for backward compatibility
279
+ FlexibleInputMessage = NewMessage | dict[str, Any]
280
+ InputMessages = Sequence[FlexibleInputMessage]
280
281
 
281
282
  # Type alias for user input - supports string, single message, or sequence of messages
282
- UserInput = str | FlexibleRunnerMessage | RunnerMessages
283
+ UserInput = str | FlexibleInputMessage | InputMessages
283
284
 
284
285
 
285
286
  def user_message_to_llm_dict(message: NewUserMessage) -> dict[str, Any]:
File without changes
@@ -0,0 +1,213 @@
1
+ import json
2
+ from typing import Any
3
+
4
+ from lite_agent.types import (
5
+ AssistantMessageContent,
6
+ AssistantMessageMeta,
7
+ AssistantTextContent,
8
+ AssistantToolCall,
9
+ AssistantToolCallResult,
10
+ MessageMeta,
11
+ NewAssistantMessage,
12
+ NewSystemMessage,
13
+ NewUserMessage,
14
+ UserImageContent,
15
+ UserMessageContent,
16
+ UserTextContent,
17
+ )
18
+
19
+
20
+ class MessageBuilder:
21
+ """Utility class for building and converting messages from various formats."""
22
+
23
+ @staticmethod
24
+ def build_user_message_from_dict(message: dict[str, Any]) -> NewUserMessage:
25
+ """Build a NewUserMessage from a dictionary.
26
+
27
+ Args:
28
+ message: Dictionary containing user message data
29
+
30
+ Returns:
31
+ NewUserMessage instance
32
+ """
33
+ content = message.get("content", "")
34
+
35
+ # Preserve meta information if present
36
+ meta_data = message.get("meta", {})
37
+ meta = MessageMeta(**meta_data) if meta_data else MessageMeta()
38
+
39
+ if isinstance(content, str):
40
+ return NewUserMessage(content=[UserTextContent(text=content)], meta=meta)
41
+
42
+ if isinstance(content, list):
43
+ return NewUserMessage(content=MessageBuilder._build_user_content_items(content), meta=meta)
44
+
45
+ # Handle non-string, non-list content
46
+ return NewUserMessage(content=[UserTextContent(text=str(content))], meta=meta)
47
+
48
+ @staticmethod
49
+ def _build_user_content_items(content_list: list[Any]) -> list[UserMessageContent]:
50
+ """Build user content items from a list of content data.
51
+
52
+ Args:
53
+ content_list: List of content items (dicts or objects)
54
+
55
+ Returns:
56
+ List of UserMessageContent items
57
+ """
58
+ user_content_items: list[UserMessageContent] = []
59
+
60
+ for item in content_list:
61
+ if isinstance(item, dict):
62
+ user_content_items.append(MessageBuilder._build_user_content_from_dict(item))
63
+ elif hasattr(item, "type"):
64
+ user_content_items.append(MessageBuilder._build_user_content_from_object(item))
65
+ else:
66
+ # Fallback: convert to text
67
+ user_content_items.append(UserTextContent(text=str(item)))
68
+
69
+ return user_content_items
70
+
71
+ @staticmethod
72
+ def _build_user_content_from_dict(item: dict[str, Any]) -> UserMessageContent:
73
+ """Build user content from a dictionary item.
74
+
75
+ Args:
76
+ item: Dictionary containing content item data
77
+
78
+ Returns:
79
+ UserMessageContent instance
80
+ """
81
+ item_type = item.get("type")
82
+
83
+ if item_type in {"input_text", "text"}:
84
+ return UserTextContent(text=item.get("text", ""))
85
+
86
+ if item_type in {"input_image", "image_url"}:
87
+ if item_type == "image_url":
88
+ # Handle completion API format
89
+ image_url_data = item.get("image_url", {})
90
+ url = image_url_data.get("url", "") if isinstance(image_url_data, dict) else str(image_url_data)
91
+ return UserImageContent(image_url=url)
92
+
93
+ # Handle response API format
94
+ return UserImageContent(
95
+ image_url=item.get("image_url"),
96
+ file_id=item.get("file_id"),
97
+ detail=item.get("detail", "auto"),
98
+ )
99
+
100
+ # Fallback: treat as text
101
+ return UserTextContent(text=str(item.get("text", item)))
102
+
103
+ @staticmethod
104
+ def _build_user_content_from_object(item: Any) -> UserMessageContent: # noqa: ANN401
105
+ """Build user content from an object with attributes.
106
+
107
+ Args:
108
+ item: Object with type attribute and other properties
109
+
110
+ Returns:
111
+ UserMessageContent instance
112
+ """
113
+ if item.type == "input_text":
114
+ return UserTextContent(text=item.text)
115
+
116
+ if item.type == "input_image":
117
+ return UserImageContent(
118
+ image_url=getattr(item, "image_url", None),
119
+ file_id=getattr(item, "file_id", None),
120
+ detail=getattr(item, "detail", "auto"),
121
+ )
122
+
123
+ # Fallback: convert to text
124
+ return UserTextContent(text=str(item))
125
+
126
+ @staticmethod
127
+ def build_system_message_from_dict(message: dict[str, Any]) -> NewSystemMessage:
128
+ """Build a NewSystemMessage from a dictionary.
129
+
130
+ Args:
131
+ message: Dictionary containing system message data
132
+
133
+ Returns:
134
+ NewSystemMessage instance
135
+ """
136
+ content = message.get("content", "")
137
+
138
+ # Preserve meta information if present
139
+ meta_data = message.get("meta", {})
140
+ meta = MessageMeta(**meta_data) if meta_data else MessageMeta()
141
+
142
+ return NewSystemMessage(content=str(content), meta=meta)
143
+
144
+ @staticmethod
145
+ def build_assistant_message_from_dict(message: dict[str, Any]) -> NewAssistantMessage:
146
+ """Build a NewAssistantMessage from a dictionary.
147
+
148
+ Args:
149
+ message: Dictionary containing assistant message data
150
+
151
+ Returns:
152
+ NewAssistantMessage instance
153
+ """
154
+ content = message.get("content", "")
155
+ assistant_content_items: list[AssistantMessageContent] = []
156
+
157
+ if content:
158
+ if isinstance(content, str):
159
+ assistant_content_items = [AssistantTextContent(text=content)]
160
+ elif isinstance(content, list):
161
+ # Handle array content (from new format messages)
162
+ for item in content:
163
+ if isinstance(item, dict):
164
+ item_type = item.get("type")
165
+ if item_type == "text":
166
+ assistant_content_items.append(AssistantTextContent(text=item.get("text", "")))
167
+ elif item_type == "tool_call":
168
+ assistant_content_items.append(
169
+ AssistantToolCall(
170
+ call_id=item.get("call_id", ""),
171
+ name=item.get("name", ""),
172
+ arguments=item.get("arguments", "{}"),
173
+ ),
174
+ )
175
+ elif item_type == "tool_call_result":
176
+ assistant_content_items.append(
177
+ AssistantToolCallResult(
178
+ call_id=item.get("call_id", ""),
179
+ output=item.get("output", ""),
180
+ execution_time_ms=item.get("execution_time_ms"),
181
+ ),
182
+ )
183
+ else:
184
+ # Unknown dict type - convert to text
185
+ assistant_content_items.append(AssistantTextContent(text=str(item)))
186
+ else:
187
+ # Fallback for unknown item format
188
+ assistant_content_items.append(AssistantTextContent(text=str(item)))
189
+ else:
190
+ # Fallback for other content types
191
+ assistant_content_items = [AssistantTextContent(text=str(content))]
192
+
193
+ # Handle tool calls if present (legacy format)
194
+ if "tool_calls" in message:
195
+ for tool_call in message.get("tool_calls", []):
196
+ try:
197
+ arguments = json.loads(tool_call["function"]["arguments"]) if isinstance(tool_call["function"]["arguments"], str) else tool_call["function"]["arguments"]
198
+ except (json.JSONDecodeError, TypeError):
199
+ arguments = tool_call["function"]["arguments"]
200
+
201
+ assistant_content_items.append(
202
+ AssistantToolCall(
203
+ call_id=tool_call["id"],
204
+ name=tool_call["function"]["name"],
205
+ arguments=arguments,
206
+ ),
207
+ )
208
+
209
+ # Preserve meta information if present
210
+ meta_data = message.get("meta", {})
211
+ meta = AssistantMessageMeta(**meta_data) if meta_data else AssistantMessageMeta()
212
+
213
+ return NewAssistantMessage(content=assistant_content_items, meta=meta)
@@ -0,0 +1,50 @@
1
+ from datetime import datetime
2
+
3
+
4
+ class TimingMetrics:
5
+ """Utility class for calculating timing metrics in LLM responses."""
6
+
7
+ @staticmethod
8
+ def calculate_latency_ms(start_time: datetime | None, first_output_time: datetime | None) -> int | None:
9
+ """Calculate latency from start to first output.
10
+
11
+ Args:
12
+ start_time: When the request started
13
+ first_output_time: When the first output was received
14
+
15
+ Returns:
16
+ Latency in milliseconds, or None if either time is missing
17
+ """
18
+ if start_time is None or first_output_time is None:
19
+ return None
20
+ return int((first_output_time - start_time).total_seconds() * 1000)
21
+
22
+ @staticmethod
23
+ def calculate_output_time_ms(first_output_time: datetime | None, output_complete_time: datetime | None) -> int | None:
24
+ """Calculate time from first output to completion.
25
+
26
+ Args:
27
+ first_output_time: When the first output was received
28
+ output_complete_time: When output was completed
29
+
30
+ Returns:
31
+ Output time in milliseconds, or None if either time is missing
32
+ """
33
+ if first_output_time is None or output_complete_time is None:
34
+ return None
35
+ return int((output_complete_time - first_output_time).total_seconds() * 1000)
36
+
37
+ @staticmethod
38
+ def calculate_total_time_ms(start_time: datetime | None, output_complete_time: datetime | None) -> int | None:
39
+ """Calculate total time from start to completion.
40
+
41
+ Args:
42
+ start_time: When the request started
43
+ output_complete_time: When output was completed
44
+
45
+ Returns:
46
+ Total time in milliseconds, or None if either time is missing
47
+ """
48
+ if start_time is None or output_complete_time is None:
49
+ return None
50
+ return int((output_complete_time - start_time).total_seconds() * 1000)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lite-agent
3
- Version: 0.6.0
3
+ Version: 0.9.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,8 @@ 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.10.0
21
+ Requires-Dist: funcall>=0.11.0
22
+ Requires-Dist: openai<=1.99.5
22
23
  Requires-Dist: prompt-toolkit>=3.0.51
23
24
  Requires-Dist: rich>=14.0.0
24
25
  Description-Content-Type: text/markdown
@@ -0,0 +1,31 @@
1
+ lite_agent/__init__.py,sha256=Swuefee0etSiaDnn30K2hBNV9UI3hIValW3A-pRE7e0,338
2
+ lite_agent/agent.py,sha256=Jls9fwGgMLpFunT8Tr3Cp8P9AyeuvrHklWyFD3mhvtM,32061
3
+ lite_agent/chat_display.py,sha256=IG2oM3FtpcfcduG7b6yt2mLFpG-Z6zHxXUN_J1XNVp8,40563
4
+ lite_agent/client.py,sha256=PTsic12TVYklUKJzb9gk8-FWl2yhNkSYRS_Cs5dosEU,8677
5
+ lite_agent/constants.py,sha256=_xIDdQwaJrWk8N_62o-KYEo3jj1waPJ0ZOd3hHybKNo,718
6
+ lite_agent/loggers.py,sha256=XkNkdqwD_nQGfhQJ-bBWT7koci_mMkNw3aBpyMhOICw,57
7
+ lite_agent/message_transfers.py,sha256=N9ViK7Gxqqa1sd3V_hkNuQ9fUipg7M95l-sVBBG2Id4,5357
8
+ lite_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ lite_agent/runner.py,sha256=iv4xqRJKH9PXyg7goQIBd6IfNODUo5GfjBdlZdxv3kw,45150
10
+ lite_agent/processors/__init__.py,sha256=ybpAzpMBIE9v5I24wIBZRXeaOaPNTmoKH13aofgNI6Q,234
11
+ lite_agent/processors/completion_event_processor.py,sha256=zoWvs8dfrIkCSITGtS-4Hpve3WFCA0UUsMvYifL2fw0,13010
12
+ lite_agent/processors/response_event_processor.py,sha256=Jr3cj1ItJ8aq9UBhEEjDwWDnPNOZ2ZXjWJ3-g4ghkhM,8514
13
+ lite_agent/response_handlers/__init__.py,sha256=za1pV3DwYhiX4lqo4TafpKlZSBGz81TViWsYebo6Qo4,386
14
+ lite_agent/response_handlers/base.py,sha256=rSs3ImmInBG7aaGv47pYnfHblEs3DIKkT58y7nCUgOc,1682
15
+ lite_agent/response_handlers/completion.py,sha256=e14etxhunRo-T68HgWOE-9JcmMXi5TPvPzyVwE8H7_s,3230
16
+ lite_agent/response_handlers/responses.py,sha256=_Mb2s6RWLYynEncfPis_jRM5WDDEJik8npJvqG6qq9o,3170
17
+ lite_agent/stream_handlers/__init__.py,sha256=a5s1GZr42uvndtcQqEhK2cnjGkK8ZFTAZCj3J61Bb5E,209
18
+ lite_agent/stream_handlers/litellm.py,sha256=3D0u7R2ADA8kDwpFImZlw20o-CsmFXVLvq4nvwwD0Rk,2922
19
+ lite_agent/templates/handoffs_source_instructions.xml.j2,sha256=2XsXQlBzk38qbxGrfyt8y2b0KlZmsV_1xavLufcdkHc,428
20
+ lite_agent/templates/handoffs_target_instructions.xml.j2,sha256=gSbWVYYcovPKbGpFc0kqGSJ5Y5UC3fOHyUmZfcrDgSE,356
21
+ lite_agent/templates/wait_for_user_instructions.xml.j2,sha256=wXbcYD5Q1FaCGVBm3Hz_Cp7nnoK7KzloP0ao-jYMwPk,231
22
+ lite_agent/types/__init__.py,sha256=Zk7Uf1ScOJ5IGfeiJ3PM2FzPD4wmiq-9jzQzLpPpecI,3147
23
+ lite_agent/types/events.py,sha256=mFMqV55WWJbPDyb_P61nd3qMLpEnwZgVY6NTKFkINkg,2389
24
+ lite_agent/types/messages.py,sha256=QjWL2McEWckVy7AIogl2HQkUy-XXdNAAcB0oCNnojbg,9922
25
+ lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
26
+ lite_agent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ lite_agent/utils/message_builder.py,sha256=L15e4-qSlCYUNNtJ1zB-EPviuoxH9bTEVNlkvaH0q3U,8142
28
+ lite_agent/utils/metrics.py,sha256=RzOEhCWxbLmmIEkzaxOJ6tAdthI8dv2Foc98Lq8afOQ,1915
29
+ lite_agent-0.9.0.dist-info/METADATA,sha256=e1eaVu37mmGYrHI_KofiLTOHCerY6fXY5BPZoIXbTO4,3486
30
+ lite_agent-0.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ lite_agent-0.9.0.dist-info/RECORD,,
@@ -1,27 +0,0 @@
1
- lite_agent/__init__.py,sha256=Swuefee0etSiaDnn30K2hBNV9UI3hIValW3A-pRE7e0,338
2
- lite_agent/agent.py,sha256=9stxur0iqdG9NUDXdk1ElxenjYsRsurt36hGhZcz_-c,23323
3
- lite_agent/chat_display.py,sha256=Pfg6ZgTeIuzRZMVxOUzlwZU18rfOLD9-8I1lqUd_fXc,30516
4
- lite_agent/client.py,sha256=QhtZZGX54ha9-HKHcbx0qUsaAUi4-TAO-YckCH_itQY,8633
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=B0KYE0Wfta4X85kPm_hMMGrLz8o1-TmGUnOG1cUZeBM,40985
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/response_handlers/__init__.py,sha256=2xe8YngMpjdp1B5tE8C3IiimYI30TnqQHj9KTtg6wCI,385
13
- lite_agent/response_handlers/base.py,sha256=amQSnhUdoMyaacL7BlGfIUJDYDgqH6seYlfOl6loy-w,1566
14
- lite_agent/response_handlers/completion.py,sha256=X-sBM-ZBxodppcCXAwoN8Lslda5QYSoK7DdKEdgaYnM,2026
15
- lite_agent/response_handlers/responses.py,sha256=KEKnnsel8HLiF2Ob8TzVSXuRjudCpvyZ_GMrg3ME2g0,1915
16
- lite_agent/stream_handlers/__init__.py,sha256=a5s1GZr42uvndtcQqEhK2cnjGkK8ZFTAZCj3J61Bb5E,209
17
- lite_agent/stream_handlers/litellm.py,sha256=3D0u7R2ADA8kDwpFImZlw20o-CsmFXVLvq4nvwwD0Rk,2922
18
- lite_agent/templates/handoffs_source_instructions.xml.j2,sha256=2XsXQlBzk38qbxGrfyt8y2b0KlZmsV_1xavLufcdkHc,428
19
- lite_agent/templates/handoffs_target_instructions.xml.j2,sha256=gSbWVYYcovPKbGpFc0kqGSJ5Y5UC3fOHyUmZfcrDgSE,356
20
- lite_agent/templates/wait_for_user_instructions.xml.j2,sha256=wXbcYD5Q1FaCGVBm3Hz_Cp7nnoK7KzloP0ao-jYMwPk,231
21
- lite_agent/types/__init__.py,sha256=QKuhjFWRcpAlsBK9JYgoCABpoQExwhuyGudJoiiqQfs,3093
22
- lite_agent/types/events.py,sha256=mFMqV55WWJbPDyb_P61nd3qMLpEnwZgVY6NTKFkINkg,2389
23
- lite_agent/types/messages.py,sha256=c7nTIWqXNo562het_vaWcZvsoy-adkARwAYn4JNqm0c,9897
24
- lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
25
- lite_agent-0.6.0.dist-info/METADATA,sha256=_gfjiwA85XKoQdB9TCJx3BI2D21gNkw-C5pL3CaiZz8,3456
26
- lite_agent-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- lite_agent-0.6.0.dist-info/RECORD,,