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

Potentially problematic release.


This version of lite-agent might be problematic. Click here for more details.

@@ -1,503 +0,0 @@
1
- """
2
- Rich chat history renderer for lite-agent.
3
-
4
- This module provides utilities to beautifully render chat history using the rich library.
5
- It supports all message types including user messages, assistant messages, function calls,
6
- and function call outputs.
7
- """
8
-
9
- import json
10
- from datetime import datetime, timezone
11
-
12
- from rich.console import Console
13
- from rich.panel import Panel
14
- from rich.syntax import Syntax
15
- from rich.table import Table
16
-
17
- from lite_agent.types import (
18
- AgentAssistantMessage,
19
- AgentFunctionCallOutput,
20
- AgentFunctionToolCallMessage,
21
- AgentSystemMessage,
22
- AgentUserMessage,
23
- RunnerMessages,
24
- )
25
-
26
-
27
- def print_chat_history(
28
- messages: RunnerMessages,
29
- *,
30
- console: Console | None = None,
31
- show_timestamps: bool = True,
32
- show_indices: bool = True,
33
- chat_width: int = 80,
34
- ) -> None:
35
- """
36
- 使用 rich 库美观地渲染聊天记录。
37
-
38
- Args:
39
- messages: 要渲染的消息列表
40
- console: Rich Console 实例,如果为 None 则创建新的
41
- show_timestamps: 是否显示时间戳
42
- show_indices: 是否显示消息索引
43
- chat_width: 聊天气泡的最大宽度
44
-
45
- Example:
46
- >>> from lite_agent.runner import Runner
47
- >>> from lite_agent.rich_helpers import render_chat_history
48
- >>>
49
- >>> runner = Runner(agent=my_agent)
50
- >>> # ... add some messages ...
51
- >>> render_chat_history(runner.messages)
52
- """
53
- if console is None:
54
- console = Console()
55
-
56
- if not messages:
57
- console.print("[dim]No messages to display[/dim]")
58
- return
59
-
60
- console.print(f"\n[bold blue]Chat History[/bold blue] ([dim]{len(messages)} messages[/dim])\n")
61
-
62
- for i, message in enumerate(messages):
63
- _render_single_message(
64
- message,
65
- index=i if show_indices else None,
66
- console=console,
67
- show_timestamp=show_timestamps,
68
- chat_width=chat_width,
69
- )
70
-
71
-
72
- def _render_single_message(
73
- message: object,
74
- *,
75
- index: int | None = None,
76
- console: Console,
77
- show_timestamp: bool = True,
78
- chat_width: int = 80,
79
- ) -> None:
80
- """渲染单个消息。"""
81
- timestamp = datetime.now(timezone.utc).strftime("%H:%M:%S") if show_timestamp else None
82
-
83
- # 处理不同类型的消息
84
- if isinstance(message, AgentUserMessage):
85
- _render_user_message(message, index, console, timestamp, chat_width)
86
- elif isinstance(message, AgentAssistantMessage):
87
- _render_assistant_message(message, index, console, timestamp, chat_width)
88
- elif isinstance(message, AgentSystemMessage):
89
- _render_system_message(message, index, console, timestamp, chat_width)
90
- elif isinstance(message, AgentFunctionToolCallMessage):
91
- _render_function_call_message(message, index, console, timestamp, chat_width)
92
- elif isinstance(message, AgentFunctionCallOutput):
93
- _render_function_output_message(message, index, console, timestamp, chat_width)
94
- elif isinstance(message, dict):
95
- _render_dict_message(message, index, console, timestamp, chat_width)
96
- else:
97
- _render_unknown_message(message, index, console, timestamp, chat_width)
98
-
99
-
100
- def _render_user_message(
101
- message: AgentUserMessage,
102
- index: int | None,
103
- console: Console,
104
- timestamp: str | None,
105
- chat_width: int,
106
- ) -> None:
107
- """渲染用户消息 - 靠右显示的蓝色气泡。"""
108
- content = str(message.content) # 显示完整内容,不截断
109
-
110
- title_parts = ["👤 User"]
111
- if index is not None:
112
- title_parts.append(f"#{index}")
113
- if timestamp:
114
- title_parts.append(f"[dim]{timestamp}[/dim]")
115
-
116
- title = " ".join(title_parts)
117
-
118
- # 计算内容的实际宽度,用于气泡大小
119
- content_width = min(len(content) + 4, chat_width) # +4 for padding
120
- bubble_width = max(content_width, 20) # 最小宽度
121
-
122
- # 创建用户消息气泡 - 靠右
123
- panel = Panel(
124
- content,
125
- title=title,
126
- title_align="left",
127
- border_style="blue",
128
- padding=(0, 1),
129
- width=bubble_width,
130
- )
131
-
132
- # 用户消息靠右
133
- console.print(panel, justify="right")
134
-
135
-
136
- def _render_assistant_message(
137
- message: AgentAssistantMessage,
138
- index: int | None,
139
- console: Console,
140
- timestamp: str | None,
141
- chat_width: int,
142
- ) -> None:
143
- """渲染助手消息 - 靠左显示的绿色气泡。"""
144
- content = message.content # 显示完整内容,不截断
145
-
146
- title_parts = ["🤖 Assistant"]
147
- if index is not None:
148
- title_parts.append(f"#{index}")
149
- if timestamp:
150
- title_parts.append(f"[dim]{timestamp}[/dim]")
151
-
152
- title = " ".join(title_parts)
153
-
154
- # 计算内容的实际宽度,用于气泡大小
155
- content_width = min(len(content) + 4, chat_width) # +4 for padding
156
- bubble_width = max(content_width, 20) # 最小宽度
157
-
158
- # 创建助手消息气泡 - 靠左
159
- panel = Panel(
160
- content,
161
- title=title,
162
- title_align="left",
163
- border_style="green",
164
- padding=(0, 1),
165
- width=bubble_width,
166
- )
167
-
168
- # 助手消息靠左
169
- console.print(panel)
170
-
171
-
172
- def _render_system_message(
173
- message: AgentSystemMessage,
174
- index: int | None,
175
- console: Console,
176
- timestamp: str | None,
177
- chat_width: int,
178
- ) -> None:
179
- """渲染系统消息 - 居中显示的黄色气泡。"""
180
- content = message.content # 显示完整内容,不截断
181
-
182
- title_parts = ["⚙️ System"]
183
- if index is not None:
184
- title_parts.append(f"#{index}")
185
- if timestamp:
186
- title_parts.append(f"[dim]{timestamp}[/dim]")
187
-
188
- title = " ".join(title_parts)
189
-
190
- # 系统消息居中显示,使用较小的宽度
191
- console.print(
192
- Panel(
193
- content,
194
- title=title,
195
- title_align="center",
196
- border_style="yellow",
197
- padding=(0, 1),
198
- width=min(len(content) + 10, chat_width),
199
- ),
200
- justify="center",
201
- )
202
-
203
-
204
- def _render_function_call_message(
205
- message: AgentFunctionToolCallMessage,
206
- index: int | None,
207
- console: Console,
208
- timestamp: str | None,
209
- chat_width: int,
210
- ) -> None:
211
- """渲染函数调用消息 - 靠左显示的紫色气泡。"""
212
- title_parts = ["🛠️ Function Call"]
213
- if index is not None:
214
- title_parts.append(f"#{index}")
215
- if timestamp:
216
- title_parts.append(f"[dim]{timestamp}[/dim]")
217
-
218
- title = " ".join(title_parts)
219
-
220
- # 创建表格显示函数调用详情
221
- table = Table(show_header=False, box=None, padding=0)
222
- table.add_column("Field", style="cyan", width=12)
223
- table.add_column("Value", style="white")
224
-
225
- table.add_row("Name:", f"[bold]{message.name}[/bold]")
226
- table.add_row("Call ID:", f"[dim]{message.function_call_id}[/dim]")
227
-
228
- if message.arguments:
229
- # 尝试格式化 JSON 参数 - 显示完整内容
230
- try:
231
- parsed_args = json.loads(message.arguments)
232
- formatted_args = json.dumps(parsed_args, indent=2, ensure_ascii=False)
233
- syntax = Syntax(formatted_args, "json", theme="monokai", line_numbers=False)
234
- table.add_row("Arguments:", syntax)
235
- except (json.JSONDecodeError, TypeError):
236
- table.add_row("Arguments:", message.arguments)
237
-
238
- # 函数调用消息靠左
239
- console.print(
240
- Panel(
241
- table,
242
- title=title,
243
- title_align="left",
244
- border_style="magenta",
245
- padding=(0, 1),
246
- width=min(chat_width, 100),
247
- ),
248
- )
249
-
250
-
251
- def _render_function_output_message(
252
- message: AgentFunctionCallOutput,
253
- index: int | None,
254
- console: Console,
255
- timestamp: str | None,
256
- chat_width: int,
257
- ) -> None:
258
- """渲染函数输出消息 - 靠左显示的青色气泡。"""
259
- title_parts = ["📤 Function Output"]
260
- if index is not None:
261
- title_parts.append(f"#{index}")
262
- if timestamp:
263
- title_parts.append(f"[dim]{timestamp}[/dim]")
264
-
265
- title = " ".join(title_parts)
266
-
267
- output_content = message.output # 显示完整内容,不截断
268
-
269
- # 创建表格显示函数输出详情
270
- table = Table(show_header=False, box=None, padding=0)
271
- table.add_column("Field", style="cyan", width=12)
272
- table.add_column("Value", style="white")
273
-
274
- table.add_row("Call ID:", f"[dim]{message.call_id}[/dim]")
275
- table.add_row("Output:", output_content)
276
-
277
- # 函数输出消息靠左
278
- console.print(
279
- Panel(
280
- table,
281
- title=title,
282
- title_align="left",
283
- border_style="cyan",
284
- padding=(0, 1),
285
- width=min(chat_width, 100),
286
- ),
287
- )
288
-
289
-
290
- def _render_role_based_dict_message( # noqa: PLR0913
291
- *,
292
- message: dict[str, object],
293
- role: str,
294
- index: int | None,
295
- console: Console,
296
- timestamp: str | None,
297
- chat_width: int,
298
- ) -> None:
299
- """渲染基于角色的字典消息。"""
300
- content = str(message.get("content", "")) # 显示完整内容,不截断
301
-
302
- title_parts = []
303
- if role == "user":
304
- title_parts = ["👤 User"]
305
- border_style = "blue"
306
- # 用户消息靠右
307
- content_width = min(len(content) + 4, chat_width)
308
- bubble_width = max(content_width, 20)
309
- if index is not None:
310
- title_parts.append(f"#{index}")
311
- if timestamp:
312
- title_parts.append(f"[dim]{timestamp}[/dim]")
313
-
314
- panel = Panel(
315
- content,
316
- title=" ".join(title_parts),
317
- title_align="left",
318
- border_style=border_style,
319
- padding=(0, 1),
320
- width=bubble_width,
321
- )
322
- console.print(panel, justify="right")
323
- elif role == "assistant":
324
- title_parts = ["🤖 Assistant"]
325
- border_style = "green"
326
- # 助手消息靠左
327
- content_width = min(len(content) + 4, chat_width)
328
- bubble_width = max(content_width, 20)
329
- if index is not None:
330
- title_parts.append(f"#{index}")
331
- if timestamp:
332
- title_parts.append(f"[dim]{timestamp}[/dim]")
333
-
334
- panel = Panel(
335
- content,
336
- title=" ".join(title_parts),
337
- title_align="left",
338
- border_style=border_style,
339
- padding=(0, 1),
340
- width=bubble_width,
341
- )
342
- # 助手消息靠左
343
- console.print(panel)
344
- else: # system
345
- title_parts = ["⚙️ System"]
346
- border_style = "yellow"
347
- if index is not None:
348
- title_parts.append(f"#{index}")
349
- if timestamp:
350
- title_parts.append(f"[dim]{timestamp}[/dim]")
351
-
352
- # 系统消息居中
353
- console.print(
354
- Panel(
355
- content,
356
- title=" ".join(title_parts),
357
- title_align="center",
358
- border_style=border_style,
359
- padding=(0, 1),
360
- width=min(len(content) + 10, chat_width),
361
- ),
362
- justify="center",
363
- )
364
-
365
-
366
- def _render_dict_message(
367
- message: dict[str, object],
368
- index: int | None,
369
- console: Console,
370
- timestamp: str | None,
371
- chat_width: int,
372
- ) -> None:
373
- """渲染字典格式的消息。"""
374
- message_type = message.get("type")
375
- role = message.get("role")
376
-
377
- if message_type == "function_call":
378
- # 创建临时 AgentFunctionToolCallMessage 对象进行渲染
379
- temp_message = AgentFunctionToolCallMessage(
380
- type="function_call",
381
- function_call_id=str(message.get("function_call_id", "")),
382
- name=str(message.get("name", "unknown")),
383
- arguments=str(message.get("arguments", "")),
384
- content=str(message.get("content", "")),
385
- )
386
- _render_function_call_message(temp_message, index, console, timestamp, chat_width)
387
- elif message_type == "function_call_output":
388
- # 创建临时 AgentFunctionCallOutput 对象进行渲染
389
- temp_message = AgentFunctionCallOutput(
390
- type="function_call_output",
391
- call_id=str(message.get("call_id", "")),
392
- output=str(message.get("output", "")),
393
- )
394
- _render_function_output_message(temp_message, index, console, timestamp, chat_width)
395
- elif role in ["user", "assistant", "system"]:
396
- _render_role_based_dict_message(
397
- message=message,
398
- role=str(role),
399
- index=index,
400
- console=console,
401
- timestamp=timestamp,
402
- chat_width=chat_width,
403
- )
404
- else:
405
- _render_unknown_message(message, index, console, timestamp, chat_width)
406
-
407
-
408
- def _render_unknown_message(
409
- message: object,
410
- index: int | None,
411
- console: Console,
412
- timestamp: str | None,
413
- chat_width: int,
414
- ) -> None:
415
- """渲染未知类型的消息 - 居中显示的红色气泡。"""
416
- title_parts = ["❓ Unknown"]
417
- if index is not None:
418
- title_parts.append(f"#{index}")
419
- if timestamp:
420
- title_parts.append(f"[dim]{timestamp}[/dim]")
421
-
422
- title = " ".join(title_parts)
423
-
424
- # 尝试将消息转换为可读格式 - 显示完整内容
425
- try:
426
- content = str(message.model_dump()) if hasattr(message, "model_dump") else str(message) # type: ignore[attr-defined]
427
- except Exception:
428
- content = str(message)
429
-
430
- console.print(
431
- Panel(
432
- content,
433
- title=title,
434
- title_align="center",
435
- border_style="red",
436
- padding=(0, 1),
437
- width=min(len(content) + 10, chat_width),
438
- ),
439
- justify="center",
440
- )
441
-
442
-
443
- def create_chat_summary_table(messages: RunnerMessages) -> Table:
444
- """
445
- 创建聊天记录摘要表格。
446
-
447
- Args:
448
- messages: 要汇总的消息列表
449
-
450
- Returns:
451
- Rich Table 对象,包含消息统计信息
452
- """
453
- table = Table(title="Chat Summary")
454
- table.add_column("Message Type", style="cyan")
455
- table.add_column("Count", justify="right", style="green")
456
-
457
- # 统计各种消息类型
458
- counts = {
459
- "User": 0,
460
- "Assistant": 0,
461
- "System": 0,
462
- "Function Call": 0,
463
- "Function Output": 0,
464
- "Unknown": 0,
465
- }
466
-
467
- for message in messages:
468
- if isinstance(message, AgentUserMessage) or (isinstance(message, dict) and message.get("role") == "user"):
469
- counts["User"] += 1
470
- elif isinstance(message, AgentAssistantMessage) or (isinstance(message, dict) and message.get("role") == "assistant"):
471
- counts["Assistant"] += 1
472
- elif isinstance(message, AgentSystemMessage) or (isinstance(message, dict) and message.get("role") == "system"):
473
- counts["System"] += 1
474
- elif isinstance(message, AgentFunctionToolCallMessage) or (isinstance(message, dict) and message.get("type") == "function_call"):
475
- counts["Function Call"] += 1
476
- elif isinstance(message, AgentFunctionCallOutput) or (isinstance(message, dict) and message.get("type") == "function_call_output"):
477
- counts["Function Output"] += 1
478
- else:
479
- counts["Unknown"] += 1
480
-
481
- # 只显示计数大于0的类型
482
- for msg_type, count in counts.items():
483
- if count > 0:
484
- table.add_row(msg_type, str(count))
485
-
486
- table.add_row("[bold]Total[/bold]", f"[bold]{len(messages)}[/bold]")
487
-
488
- return table
489
-
490
-
491
- def print_chat_summary(messages: RunnerMessages, *, console: Console | None = None) -> None:
492
- """
493
- 打印聊天记录摘要。
494
-
495
- Args:
496
- messages: 要汇总的消息列表
497
- console: Rich Console 实例,如果为 None 则创建新的
498
- """
499
- if console is None:
500
- console = Console()
501
-
502
- summary_table = create_chat_summary_table(messages)
503
- console.print(summary_table)
@@ -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,22 +0,0 @@
1
- lite_agent/__init__.py,sha256=Xaex4kVGxZzg_hhO17b8_tVXf63xFbSzBOlVdhRf-Ng,338
2
- lite_agent/agent.py,sha256=MsdAnM2pqh9RLTGOFuynowkS52QXUb7vHaMHQyiOpoQ,17627
3
- lite_agent/client.py,sha256=e_BsXo6KUgleRFkSPSESUoIPvyLXWyJ9E1AzExYXXsk,1236
4
- lite_agent/loggers.py,sha256=XkNkdqwD_nQGfhQJ-bBWT7koci_mMkNw3aBpyMhOICw,57
5
- lite_agent/message_transfers.py,sha256=nT7-tID20RK2yoN-rDiEE6sSclluSlhYSkayCzmPwk8,3984
6
- lite_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- lite_agent/rich_helpers.py,sha256=6HdjMwR2U7P5ieZ5KHQNUsQbW-apG67GzQ_nvJm774E,15583
8
- lite_agent/runner.py,sha256=LWhtmxrYxL4sFi3ZKeWWRymK3tGCvWfIh1-EcWf8P0g,27822
9
- lite_agent/processors/__init__.py,sha256=X78GKL_IWwW2lg8w4DD6GOFWLzAR2wTfKxHlvOkcuUQ,114
10
- lite_agent/processors/stream_chunk_processor.py,sha256=nMA_cW7FDpXwJvm4F8vFwBXmHHsSELQFcoNEjH3xvn8,4751
11
- lite_agent/stream_handlers/__init__.py,sha256=2GSiG0VUgcQlFMl6JkGAqikXMII1a43Hr-J5NIct6dk,115
12
- lite_agent/stream_handlers/litellm.py,sha256=NNMAl8Bvoc2xe-qWKtfqvJQA2yr3sz1IUU90rQ_9iBw,3976
13
- lite_agent/templates/handoffs_source_instructions.xml.j2,sha256=2XsXQlBzk38qbxGrfyt8y2b0KlZmsV_1xavLufcdkHc,428
14
- lite_agent/templates/handoffs_target_instructions.xml.j2,sha256=gSbWVYYcovPKbGpFc0kqGSJ5Y5UC3fOHyUmZfcrDgSE,356
15
- lite_agent/templates/wait_for_user_instructions.xml.j2,sha256=wXbcYD5Q1FaCGVBm3Hz_Cp7nnoK7KzloP0ao-jYMwPk,231
16
- lite_agent/types/__init__.py,sha256=8l2RL-55sRHQW-sTmtKkKzCQGLrENaJT7Cgy5iA5xCo,1767
17
- lite_agent/types/chunks.py,sha256=Ro5BtrrdsYGkKrEekIhs9vIrBM7HljtgOkHherH8B3k,1697
18
- lite_agent/types/messages.py,sha256=A66YVl2IYMMTlnEdGlbCXqMztSSMSjS9F2yyebBlKR0,3364
19
- lite_agent/types/tool_calls.py,sha256=Xnut8-2-Ld9vgA2GKJY6BbFlBaAv_n4W7vo7Jx21A-E,260
20
- lite_agent-0.3.0.dist-info/METADATA,sha256=l4SLUuFQlcrlr-CHOIaWqQ3WOyYnPVIsHjjxKjR_g4E,3455
21
- lite_agent-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- lite_agent-0.3.0.dist-info/RECORD,,