lite-agent 0.10.0__py3-none-any.whl → 0.11.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/client.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import abc
2
2
  import os
3
- from typing import Any, Literal
3
+ from typing import Any, Literal, NotRequired, TypedDict
4
4
 
5
5
  import litellm
6
6
  from openai.types.chat import ChatCompletionToolParam
@@ -8,12 +8,28 @@ from openai.types.responses import FunctionToolParam
8
8
  from pydantic import BaseModel
9
9
 
10
10
  ReasoningEffort = Literal["minimal", "low", "medium", "high"]
11
- ThinkingConfig = dict[str, Any] | None
11
+
12
+
13
+ class ThinkingConfigDict(TypedDict):
14
+ """Thinking configuration for reasoning models like Claude."""
15
+
16
+ type: Literal["enabled"] # 启用推理
17
+ budget_tokens: NotRequired[int] # 推理令牌预算,可选
18
+
19
+
20
+ class ReasoningEffortDict(TypedDict):
21
+ """Reasoning effort configuration."""
22
+
23
+ effort: ReasoningEffort
24
+
25
+
26
+ ThinkingConfig = ThinkingConfigDict | None
12
27
 
13
28
  # 统一的推理配置类型
14
29
  ReasoningConfig = (
15
- str
16
- | dict[str, Any] # {"type": "enabled", "budget_tokens": 2048} 或其他配置
30
+ ReasoningEffort # "minimal", "low", "medium", "high"
31
+ | ReasoningEffortDict # {"effort": "minimal"}
32
+ | ThinkingConfigDict # {"type": "enabled", "budget_tokens": 2048}
17
33
  | bool # True/False 简单开关
18
34
  | None # 不启用推理
19
35
  )
@@ -36,8 +52,9 @@ def parse_reasoning_config(reasoning: ReasoningConfig) -> tuple[ReasoningEffort
36
52
 
37
53
  Args:
38
54
  reasoning: 统一的推理配置
39
- - str: "minimal", "low", "medium", "high" -> reasoning_effort
40
- - dict: {"effort": "minimal"} -> reasoning_effort, 其他格式 -> thinking_config
55
+ - ReasoningEffort: "minimal", "low", "medium", "high" -> reasoning_effort
56
+ - ReasoningEffortDict: {"effort": "minimal"} -> reasoning_effort
57
+ - ThinkingConfigDict: {"type": "enabled", "budget_tokens": 2048} -> thinking_config
41
58
  - bool: True -> "medium", False -> None
42
59
  - None: 不启用推理
43
60
 
@@ -47,28 +64,38 @@ def parse_reasoning_config(reasoning: ReasoningConfig) -> tuple[ReasoningEffort
47
64
  if reasoning is None:
48
65
  return None, None
49
66
 
50
- if isinstance(reasoning, str):
51
- # 字符串类型,使用 reasoning_effort
52
- # 确保字符串是有效的 ReasoningEffort 值
53
- if reasoning in ("minimal", "low", "medium", "high"):
54
- return reasoning, None # type: ignore[return-value]
55
- elif isinstance(reasoning, dict):
56
- # 检查是否为 {"effort": "value"} 格式
57
- if "effort" in reasoning and len(reasoning) == 1:
58
- effort = reasoning["effort"]
59
- if isinstance(effort, str) and effort in ("minimal", "low", "medium", "high"):
60
- return effort, None # type: ignore[return-value]
61
- else:
62
- # 其他字典格式,作为 thinking_config
63
- return None, reasoning
64
- elif isinstance(reasoning, bool):
65
- # 布尔类型,True 使用默认的 medium,False 不启用
67
+ if isinstance(reasoning, str) and reasoning in ("minimal", "low", "medium", "high"):
68
+ return reasoning, None # type: ignore[return-value]
69
+
70
+ if isinstance(reasoning, bool):
66
71
  return ("medium", None) if reasoning else (None, None)
67
72
 
73
+ if isinstance(reasoning, dict):
74
+ return _parse_dict_reasoning_config(reasoning)
75
+
68
76
  # 其他类型或无效格式,默认不启用
69
77
  return None, None
70
78
 
71
79
 
80
+ def _parse_dict_reasoning_config(reasoning: ReasoningEffortDict | ThinkingConfigDict | dict[str, Any]) -> tuple[ReasoningEffort | None, ThinkingConfig]:
81
+ """解析字典格式的推理配置。"""
82
+ # 检查是否为 {"effort": "value"} 格式 (ReasoningEffortDict)
83
+ if "effort" in reasoning and len(reasoning) == 1:
84
+ effort = reasoning["effort"]
85
+ if isinstance(effort, str) and effort in ("minimal", "low", "medium", "high"):
86
+ return effort, None # type: ignore[return-value]
87
+
88
+ # 检查是否为 ThinkingConfigDict 格式
89
+ if "type" in reasoning and reasoning.get("type") == "enabled":
90
+ # 验证 ThinkingConfigDict 的结构
91
+ valid_keys = {"type", "budget_tokens"}
92
+ if all(key in valid_keys for key in reasoning):
93
+ return None, reasoning # type: ignore[return-value]
94
+
95
+ # 其他未知字典格式,仍尝试作为 thinking_config
96
+ return None, reasoning # type: ignore[return-value]
97
+
98
+
72
99
  class BaseLLMClient(abc.ABC):
73
100
  """Base class for LLM clients."""
74
101
 
@@ -240,8 +267,7 @@ class LiteLLMClient(BaseLLMClient):
240
267
 
241
268
  # Add reasoning parameters if specified
242
269
  if final_reasoning_effort is not None:
243
- response_params["reasoning_effort"] = final_reasoning_effort
270
+ response_params["reasoning"] = {"effort": final_reasoning_effort}
244
271
  if final_thinking_config is not None:
245
272
  response_params["thinking"] = final_thinking_config
246
-
247
273
  return await litellm.aresponses(**response_params) # type: ignore[return-value]
@@ -1,7 +1,7 @@
1
1
  """Advanced message builder with fluent interface for complex message construction."""
2
2
 
3
3
  from datetime import datetime, timezone
4
- from typing import Any
4
+ from typing import Any, Literal
5
5
 
6
6
  from lite_agent.loggers import logger
7
7
  from lite_agent.types import (
@@ -71,7 +71,7 @@ class FluentMessageBuilder:
71
71
  logger.debug(f"Added text content (length: {len(text)})")
72
72
  return self
73
73
 
74
- def add_image(self, image_url: str | None = None, file_id: str | None = None, detail: str = "auto") -> "FluentMessageBuilder":
74
+ def add_image(self, image_url: str | None = None, file_id: str | None = None, detail: Literal["auto", "low", "high"] = "auto") -> "FluentMessageBuilder":
75
75
  """Add image content to user message."""
76
76
  if self._message_type != "user":
77
77
  msg = "Images can only be added to user messages"
@@ -121,10 +121,9 @@ class FluentMessageBuilder:
121
121
  msg = "Message type not set. Call user_message(), assistant_message(), or system_message() first."
122
122
  raise ValueError(msg)
123
123
 
124
- if not hasattr(self._meta, "usage"):
125
- self._meta.usage = MessageUsage()
126
-
127
- if self._meta.usage is not None:
124
+ if isinstance(self._meta, AssistantMessageMeta):
125
+ if self._meta.usage is None:
126
+ self._meta.usage = MessageUsage()
128
127
  if input_tokens is not None:
129
128
  self._meta.usage.input_tokens = input_tokens
130
129
  if output_tokens is not None:
@@ -144,20 +143,30 @@ class FluentMessageBuilder:
144
143
  msg = "Message type not set. Call user_message(), assistant_message(), or system_message() first."
145
144
  raise ValueError(msg)
146
145
 
147
- if latency_ms is not None:
148
- self._meta.latency_ms = latency_ms # type: ignore[attr-defined]
149
- if total_time_ms is not None:
150
- self._meta.total_time_ms = total_time_ms # type: ignore[attr-defined]
146
+ if isinstance(self._meta, AssistantMessageMeta):
147
+ if latency_ms is not None:
148
+ self._meta.latency_ms = latency_ms
149
+ if total_time_ms is not None:
150
+ self._meta.total_time_ms = total_time_ms
151
151
 
152
152
  return self
153
153
 
154
154
  def build(self) -> NewUserMessage | NewAssistantMessage | NewSystemMessage:
155
155
  """Build the final message."""
156
156
  if self._message_type == "user":
157
+ if not isinstance(self._meta, MessageMeta):
158
+ msg = "Invalid meta type for user message"
159
+ raise TypeError(msg)
157
160
  message = NewUserMessage(content=self._content_items, meta=self._meta)
158
161
  elif self._message_type == "assistant":
162
+ if not isinstance(self._meta, AssistantMessageMeta):
163
+ msg = "Invalid meta type for assistant message"
164
+ raise TypeError(msg)
159
165
  message = NewAssistantMessage(content=self._content_items, meta=self._meta)
160
166
  elif self._message_type == "system":
167
+ if not isinstance(self._meta, MessageMeta):
168
+ msg = "Invalid meta type for system message"
169
+ raise TypeError(msg)
161
170
  message = NewSystemMessage(content=self._content, meta=self._meta)
162
171
  else:
163
172
  msg = "Message type not set"
@@ -173,29 +182,53 @@ class MessageBuilderFactory:
173
182
  @staticmethod
174
183
  def create_simple_user_message(text: str) -> NewUserMessage:
175
184
  """Create a simple user text message."""
176
- return FluentMessageBuilder().user_message().add_text(text).build()
185
+ result = FluentMessageBuilder().user_message().add_text(text).build()
186
+ if not isinstance(result, NewUserMessage):
187
+ msg = "Expected NewUserMessage"
188
+ raise TypeError(msg)
189
+ return result
177
190
 
178
191
  @staticmethod
179
192
  def create_simple_assistant_message(text: str, model: str | None = None) -> NewAssistantMessage:
180
193
  """Create a simple assistant text message."""
181
- return FluentMessageBuilder().assistant_message(model).add_text(text).build()
194
+ result = FluentMessageBuilder().assistant_message(model).add_text(text).build()
195
+ if not isinstance(result, NewAssistantMessage):
196
+ msg = "Expected NewAssistantMessage"
197
+ raise TypeError(msg)
198
+ return result
182
199
 
183
200
  @staticmethod
184
201
  def create_system_message(text: str) -> NewSystemMessage:
185
202
  """Create a system message."""
186
- return FluentMessageBuilder().system_message().add_text(text).build()
203
+ result = FluentMessageBuilder().system_message().add_text(text).build()
204
+ if not isinstance(result, NewSystemMessage):
205
+ msg = "Expected NewSystemMessage"
206
+ raise TypeError(msg)
207
+ return result
187
208
 
188
209
  @staticmethod
189
210
  def create_user_message_with_image(text: str, image_url: str) -> NewUserMessage:
190
211
  """Create a user message with text and image."""
191
- return FluentMessageBuilder().user_message().add_text(text).add_image(image_url=image_url).build()
212
+ result = FluentMessageBuilder().user_message().add_text(text).add_image(image_url=image_url).build()
213
+ if not isinstance(result, NewUserMessage):
214
+ msg = "Expected NewUserMessage"
215
+ raise TypeError(msg)
216
+ return result
192
217
 
193
218
  @staticmethod
194
219
  def create_assistant_with_tool_call(text: str, call_id: str, tool_name: str, arguments: dict[str, Any], model: str | None = None) -> NewAssistantMessage:
195
220
  """Create an assistant message with text and a tool call."""
196
- return FluentMessageBuilder().assistant_message(model).add_text(text).add_tool_call(call_id, tool_name, arguments).build()
221
+ result = FluentMessageBuilder().assistant_message(model).add_text(text).add_tool_call(call_id, tool_name, arguments).build()
222
+ if not isinstance(result, NewAssistantMessage):
223
+ msg = "Expected NewAssistantMessage"
224
+ raise TypeError(msg)
225
+ return result
197
226
 
198
227
  @staticmethod
199
228
  def create_assistant_with_tool_result(call_id: str, result: str, execution_time_ms: int | None = None, model: str | None = None) -> NewAssistantMessage:
200
229
  """Create an assistant message with just a tool result."""
201
- return FluentMessageBuilder().assistant_message(model).add_tool_result(call_id, result, execution_time_ms).build()
230
+ build_result = FluentMessageBuilder().assistant_message(model).add_tool_result(call_id, result, execution_time_ms).build()
231
+ if not isinstance(build_result, NewAssistantMessage):
232
+ msg = "Expected NewAssistantMessage"
233
+ raise TypeError(msg)
234
+ return build_result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lite-agent
3
- Version: 0.10.0
3
+ Version: 0.11.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
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
16
17
  Classifier: Topic :: Communications :: Chat
17
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -1,7 +1,7 @@
1
1
  lite_agent/__init__.py,sha256=Swuefee0etSiaDnn30K2hBNV9UI3hIValW3A-pRE7e0,338
2
2
  lite_agent/agent.py,sha256=UXmQY8vhi_2DIPcWkji0B_pCGlBvZLfx6YoNaUJO6Wc,18028
3
3
  lite_agent/chat_display.py,sha256=6gPgutMj7hCUOH6QBcC2f4Bhc93Gdq4vBa_1y6QKt2g,40793
4
- lite_agent/client.py,sha256=8PQeyMZ9eu7FXSP9ovLCIyuqUOfXPPN3kiUU1qn_NSk,9035
4
+ lite_agent/client.py,sha256=-9BXLhAp3bGJsdKJ02lLpPJeHQKyHKQwhebZ6WCYh_k,9988
5
5
  lite_agent/constants.py,sha256=_xIDdQwaJrWk8N_62o-KYEo3jj1waPJ0ZOd3hHybKNo,718
6
6
  lite_agent/loggers.py,sha256=XkNkdqwD_nQGfhQJ-bBWT7koci_mMkNw3aBpyMhOICw,57
7
7
  lite_agent/message_transfers.py,sha256=N9ViK7Gxqqa1sd3V_hkNuQ9fUipg7M95l-sVBBG2Id4,5357
@@ -24,11 +24,11 @@ lite_agent/types/events.py,sha256=mFMqV55WWJbPDyb_P61nd3qMLpEnwZgVY6NTKFkINkg,23
24
24
  lite_agent/types/messages.py,sha256=aq36BOLktd6rwxknqVXOLK7pLlwYktaBFn0Sp71l6nw,9993
25
25
  lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
26
26
  lite_agent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- lite_agent/utils/advanced_message_builder.py,sha256=qKM2cm1nQrDJ8RxbUfvi31mIqXIw1LQ-igAp_CB0uz4,8696
27
+ lite_agent/utils/advanced_message_builder.py,sha256=3U1PQrbdYQuIkv3j83TggDu3TmFN57TPZU32GTyPe4E,10196
28
28
  lite_agent/utils/message_builder.py,sha256=J-yycL9pXSO9MbgC5NEGqvoP1LC2Nxe9r2YRWXoaIAQ,8126
29
29
  lite_agent/utils/message_converter.py,sha256=5HmNncTl71TD2M_6Ezz1Tnfavzna8DQYb4-D47Du7mA,9165
30
30
  lite_agent/utils/message_state_manager.py,sha256=rFUyqyd_7NdJRtyqsAWGcfwrDIlD6gK2dBDSDx1eGBs,5766
31
31
  lite_agent/utils/metrics.py,sha256=RzOEhCWxbLmmIEkzaxOJ6tAdthI8dv2Foc98Lq8afOQ,1915
32
- lite_agent-0.10.0.dist-info/METADATA,sha256=Ju9w3WAg6AvOqyFocCPMTfkSv-AepicdWkgQVonFKAM,3487
33
- lite_agent-0.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- lite_agent-0.10.0.dist-info/RECORD,,
32
+ lite_agent-0.11.0.dist-info/METADATA,sha256=WRwZ5xKujQt0pJdWvIBvhYQsnedrsW9WUqOseXQiVhU,3538
33
+ lite_agent-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
+ lite_agent-0.11.0.dist-info/RECORD,,