lite-agent 0.13.0__tar.gz → 0.14.0__tar.gz

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.

Files changed (154) hide show
  1. {lite_agent-0.13.0 → lite_agent-0.14.0}/CHANGELOG.md +14 -0
  2. {lite_agent-0.13.0 → lite_agent-0.14.0}/PKG-INFO +1 -1
  3. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/basic.py +5 -2
  4. lite_agent-0.14.0/examples/context_modify.py +69 -0
  5. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/stop_before_functions.py +6 -3
  6. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/terminal.py +2 -2
  7. {lite_agent-0.13.0 → lite_agent-0.14.0}/pyproject.toml +1 -1
  8. lite_agent-0.14.0/src/lite_agent/__init__.py +8 -0
  9. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/chat_display.py +210 -35
  10. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/context.py +5 -2
  11. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/runner.py +22 -16
  12. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/integration/test_agent_with_mocks.py +2 -1
  13. lite_agent-0.14.0/tests/integration/test_context_modification.py +147 -0
  14. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_agent_additional.py +6 -4
  15. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_chat_display.py +1 -0
  16. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_chat_display_additional.py +1 -0
  17. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_message_builder.py +5 -1
  18. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_message_transfers.py +13 -9
  19. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_response_handlers.py +1 -0
  20. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_set_chat_history.py +1 -0
  21. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_utils_extended.py +0 -1
  22. {lite_agent-0.13.0 → lite_agent-0.14.0}/uv.lock +5 -5
  23. lite_agent-0.13.0/src/lite_agent/__init__.py +0 -8
  24. {lite_agent-0.13.0 → lite_agent-0.14.0}/.claude/settings.local.json +0 -0
  25. {lite_agent-0.13.0 → lite_agent-0.14.0}/.github/workflows/ci.yml +0 -0
  26. {lite_agent-0.13.0 → lite_agent-0.14.0}/.gitignore +0 -0
  27. {lite_agent-0.13.0 → lite_agent-0.14.0}/.python-version +0 -0
  28. {lite_agent-0.13.0 → lite_agent-0.14.0}/.vscode/launch.json +0 -0
  29. {lite_agent-0.13.0 → lite_agent-0.14.0}/CLAUDE.md +0 -0
  30. {lite_agent-0.13.0 → lite_agent-0.14.0}/README.md +0 -0
  31. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/basic_agent.py +0 -0
  32. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/basic_model.py +0 -0
  33. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/cancel_and_transfer_demo.py +0 -0
  34. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/channels/rich_channel.py +0 -0
  35. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/chat_display_demo.py +0 -0
  36. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/confirm_and_continue.py +0 -0
  37. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/consolidate_history.py +0 -0
  38. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/context.py +0 -0
  39. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/custom_termination.py +0 -0
  40. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/debug_non_streaming.py +0 -0
  41. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/debug_with_logging.py +0 -0
  42. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/handoffs.py +0 -0
  43. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/history_context_demo.py +0 -0
  44. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/image.py +0 -0
  45. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/knowledge/main.py +0 -0
  46. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/llm_config_demo.py +0 -0
  47. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/message_transfer_example.py +0 -0
  48. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/message_transfer_example_new.py +0 -0
  49. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/new_message_structure_demo.py +0 -0
  50. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/non_streaming.py +0 -0
  51. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/reasoning_example.py +0 -0
  52. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/response_api_example.py +0 -0
  53. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/responses.py +0 -0
  54. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/set_chat_history_example.py +0 -0
  55. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/simple_debug.py +0 -0
  56. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/simple_debug2.py +0 -0
  57. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/stop_with_tool_call.py +0 -0
  58. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/streaming_demo.py +0 -0
  59. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/translate/main.py +0 -0
  60. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/translate/prompts/translation_system.md.j2 +0 -0
  61. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/translate.py +0 -0
  62. {lite_agent-0.13.0 → lite_agent-0.14.0}/examples/type_system_example.py +0 -0
  63. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/.gitignore +0 -0
  64. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/class_index.html +0 -0
  65. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/coverage_html_cb_6fb7b396.js +0 -0
  66. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/favicon_32_cb_58284776.png +0 -0
  67. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/function_index.html +0 -0
  68. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/index.html +0 -0
  69. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  70. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/status.json +0 -0
  71. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/style_cb_6b508a39.css +0 -0
  72. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_02adcf90d0f2eeb1___init___py.html +0 -0
  73. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_02adcf90d0f2eeb1_events_py.html +0 -0
  74. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_02adcf90d0f2eeb1_messages_py.html +0 -0
  75. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_02adcf90d0f2eeb1_tool_calls_py.html +0 -0
  76. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_1d32cdd6b7b66bed___init___py.html +0 -0
  77. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_1d32cdd6b7b66bed_message_builder_py.html +0 -0
  78. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_1d32cdd6b7b66bed_metrics_py.html +0 -0
  79. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e___init___py.html +0 -0
  80. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_agent_py.html +0 -0
  81. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_chat_display_py.html +0 -0
  82. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_client_py.html +0 -0
  83. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_constants_py.html +0 -0
  84. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_loggers_py.html +0 -0
  85. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_message_transfers_py.html +0 -0
  86. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_40b804173f68aa9e_runner_py.html +0 -0
  87. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_71ac9935daa08879___init___py.html +0 -0
  88. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_71ac9935daa08879_base_py.html +0 -0
  89. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_71ac9935daa08879_completion_py.html +0 -0
  90. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_71ac9935daa08879_responses_py.html +0 -0
  91. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_c8357a9ef7e20b45___init___py.html +0 -0
  92. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_c8357a9ef7e20b45_litellm_py.html +0 -0
  93. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_f01690d2832086e5___init___py.html +0 -0
  94. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_f01690d2832086e5_completion_event_processor_py.html +0 -0
  95. {lite_agent-0.13.0 → lite_agent-0.14.0}/htmlcov/z_f01690d2832086e5_response_event_processor_py.html +0 -0
  96. {lite_agent-0.13.0 → lite_agent-0.14.0}/pyrightconfig.json +0 -0
  97. {lite_agent-0.13.0 → lite_agent-0.14.0}/scripts/record_chat_messages.py +0 -0
  98. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/agent.py +0 -0
  99. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/client.py +0 -0
  100. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/constants.py +0 -0
  101. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/loggers.py +0 -0
  102. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/message_transfers.py +0 -0
  103. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/processors/__init__.py +0 -0
  104. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/processors/completion_event_processor.py +0 -0
  105. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/processors/response_event_processor.py +0 -0
  106. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/py.typed +0 -0
  107. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/response_handlers/__init__.py +0 -0
  108. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/response_handlers/base.py +0 -0
  109. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/response_handlers/completion.py +0 -0
  110. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/response_handlers/responses.py +0 -0
  111. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/stream_handlers/__init__.py +0 -0
  112. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/stream_handlers/litellm.py +0 -0
  113. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/templates/handoffs_source_instructions.xml.j2 +0 -0
  114. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/templates/handoffs_target_instructions.xml.j2 +0 -0
  115. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/templates/wait_for_user_instructions.xml.j2 +0 -0
  116. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/types/__init__.py +0 -0
  117. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/types/events.py +0 -0
  118. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/types/messages.py +0 -0
  119. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/types/tool_calls.py +0 -0
  120. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/__init__.py +0 -0
  121. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/advanced_message_builder.py +0 -0
  122. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/message_builder.py +0 -0
  123. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/message_converter.py +0 -0
  124. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/message_state_manager.py +0 -0
  125. {lite_agent-0.13.0 → lite_agent-0.14.0}/src/lite_agent/utils/metrics.py +0 -0
  126. {lite_agent-0.13.0 → lite_agent-0.14.0}/temp/main.py +0 -0
  127. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/integration/test_basic.py +0 -0
  128. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/integration/test_mock_litellm.py +0 -0
  129. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/mocks/basic/1.jsonl +0 -0
  130. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/mocks/confirm_and_continue/1.jsonl +0 -0
  131. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/mocks/confirm_and_continue/2.jsonl +0 -0
  132. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/mocks/context/1.jsonl +0 -0
  133. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/mocks/handoffs/1.jsonl +0 -0
  134. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/performance/test_set_chat_history_performance.py +0 -0
  135. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/test_new_messages.py +0 -0
  136. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_agent.py +0 -0
  137. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_agent_handoffs.py +0 -0
  138. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_append_message.py +0 -0
  139. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_cancel_pending_tools.py +0 -0
  140. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_chat_display_simple.py +0 -0
  141. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_client.py +0 -0
  142. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_completion_condition.py +0 -0
  143. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_file_recording.py +0 -0
  144. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_litellm_stream_handler.py +0 -0
  145. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_message_transfer.py +0 -0
  146. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_message_transfers_additional.py +0 -0
  147. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_response_api_format.py +1 -1
  148. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_response_event_processor.py +0 -0
  149. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_runner.py +0 -0
  150. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_simple_stream_handlers.py +0 -0
  151. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_stream_chunk_processor.py +0 -0
  152. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_stream_handlers_additional.py +0 -0
  153. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/unit/test_streaming_config.py +0 -0
  154. {lite_agent-0.13.0 → lite_agent-0.14.0}/tests/utils/mock_litellm.py +0 -0
@@ -1,3 +1,17 @@
1
+ ## v0.14.0
2
+
3
+ [v0.13.0...v0.14.0](https://github.com/Jannchie/lite-agent/compare/v0.13.0...v0.14.0)
4
+
5
+ ### :sparkles: Features
6
+
7
+ - **chat-display**: improve compact message table layout and add flexible string output functions - By [Jannchie](mailto:jannchie@gmail.com) in [454fe91](https://github.com/Jannchie/lite-agent/commit/454fe91)
8
+ - **chat-display**: add messages_to_string and chat_summary_to_string - By [Jannchie](mailto:jannchie@gmail.com) in [887cdf0](https://github.com/Jannchie/lite-agent/commit/887cdf0)
9
+ - **context**: add context modification example and tests - By [Jannchie](mailto:jannchie@gmail.com) in [3e32ac1](https://github.com/Jannchie/lite-agent/commit/3e32ac1)
10
+
11
+ ### :art: Refactors
12
+
13
+ - **chat-display**: use keyword arguments and typing hints - By [Jannchie](mailto:jannchie@gmail.com) in [3e7a6cd](https://github.com/Jannchie/lite-agent/commit/3e7a6cd)
14
+
1
15
  ## v0.13.0
2
16
 
3
17
  [v0.12.0...v0.13.0](https://github.com/Jannchie/lite-agent/compare/v0.12.0...v0.13.0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lite-agent
3
- Version: 0.13.0
3
+ Version: 0.14.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
@@ -6,7 +6,7 @@ from openai import BaseModel
6
6
  from rich.logging import RichHandler
7
7
 
8
8
  from lite_agent.agent import Agent
9
- from lite_agent.chat_display import display_messages
9
+ from lite_agent.chat_display import chat_summary_to_string, messages_to_string
10
10
  from lite_agent.client import LiteLLMClient
11
11
  from lite_agent.runner import Runner
12
12
 
@@ -49,7 +49,10 @@ async def main():
49
49
  includes=["usage", "assistant_message", "function_call", "function_call_output", "timing"],
50
50
  context=ctx,
51
51
  )
52
- display_messages(runner.messages)
52
+ messages = messages_to_string(runner.messages)
53
+ summary = chat_summary_to_string(runner.messages)
54
+ print(messages)
55
+ print(summary)
53
56
 
54
57
 
55
58
  if __name__ == "__main__":
@@ -0,0 +1,69 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from funcall import Context
5
+ from pydantic import BaseModel
6
+ from rich.logging import RichHandler
7
+
8
+ from lite_agent.agent import Agent
9
+ from lite_agent.chat_display import display_messages
10
+ from lite_agent.context import HistoryContext
11
+ from lite_agent.runner import Runner
12
+
13
+
14
+ class UserCtx(BaseModel):
15
+ name: str
16
+
17
+
18
+ logging.basicConfig(
19
+ level=logging.WARNING,
20
+ format="%(message)s",
21
+ datefmt="[%X]",
22
+ handlers=[RichHandler(rich_tracebacks=True)],
23
+ )
24
+
25
+ logger = logging.getLogger("lite_agent")
26
+ logger.setLevel(logging.DEBUG)
27
+
28
+
29
+ async def get_user_name(context: Context[HistoryContext[UserCtx]]) -> str:
30
+ """Get the user name from the context."""
31
+ if not context.value.data:
32
+ msg = "User name must be specified in the context."
33
+ raise ValueError(msg)
34
+ return context.value.data.name
35
+
36
+
37
+ async def set_user_name(context: Context[HistoryContext[UserCtx]], new_user_name: str) -> str:
38
+ """Set the user name in the context."""
39
+ if not context.value.data:
40
+ msg = "User name must be specified in the context."
41
+ raise ValueError(msg)
42
+
43
+ context.value.data.name = new_user_name
44
+ return f"User name set to: {new_user_name}"
45
+
46
+
47
+ agent = Agent(
48
+ model="gpt-4.1-nano",
49
+ name="User Name Assistant",
50
+ instructions="You can get and set the user name.",
51
+ tools=[get_user_name, set_user_name],
52
+ )
53
+
54
+
55
+ async def main():
56
+ runner = Runner(agent)
57
+ user_ctx = Context(UserCtx(name="ATC"))
58
+ resp = runner.run(
59
+ "Set User name to TXA.",
60
+ context=user_ctx,
61
+ )
62
+ async for chunk in resp:
63
+ logger.info(chunk)
64
+ await runner.run_until_complete("get the user's name", context=user_ctx)
65
+ display_messages(runner.messages)
66
+
67
+
68
+ if __name__ == "__main__":
69
+ asyncio.run(main())
@@ -60,7 +60,8 @@ async def main():
60
60
  print(f"\nHas require confirm tools: {await runner.has_require_confirm_tools()}")
61
61
 
62
62
  # Continue execution
63
- resp = runner.run(None,
63
+ resp = runner.run(
64
+ None,
64
65
  includes=["usage", "assistant_message", "function_call", "function_call_output"],
65
66
  )
66
67
  async for chunk in resp:
@@ -82,7 +83,8 @@ async def main():
82
83
  print(f"\nHas require confirm tools: {await runner2.has_require_confirm_tools()}")
83
84
 
84
85
  # Continue execution
85
- resp = runner2.run(None,
86
+ resp = runner2.run(
87
+ None,
86
88
  includes=["usage", "assistant_message", "function_call", "function_call_output"],
87
89
  )
88
90
  async for chunk in resp:
@@ -103,7 +105,8 @@ async def main():
103
105
  print(f"\nHas require confirm tools (decorator): {await runner3.has_require_confirm_tools()}")
104
106
 
105
107
  # Continue execution
106
- resp = runner3.run(None,
108
+ resp = runner3.run(
109
+ None,
107
110
  includes=["usage", "assistant_message", "function_call", "function_call_output"],
108
111
  )
109
112
  async for chunk in resp:
@@ -60,11 +60,11 @@ async def main():
60
60
  validate_while_typing=False,
61
61
  )
62
62
  if user_input.lower() in {"y", "yes"}:
63
- response = runner.run(None )
63
+ response = runner.run(None)
64
64
  async for chunk in response:
65
65
  await rich_channel.handle(chunk)
66
66
  else:
67
- response = runner.run(None )
67
+ response = runner.run(None)
68
68
  rich_channel.new_turn()
69
69
  except (EOFError, KeyboardInterrupt):
70
70
  break
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lite-agent"
3
- version = "0.13.0"
3
+ version = "0.14.0"
4
4
  description = "A lightweight, extensible framework for building AI agent."
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Jianqi Pan", email = "jannchie@gmail.com" }]
@@ -0,0 +1,8 @@
1
+ """Lite Agent - A lightweight AI agent framework."""
2
+
3
+ from .agent import Agent
4
+ from .chat_display import chat_summary_to_string, display_chat_summary, display_messages, messages_to_string
5
+ from .message_transfers import consolidate_history_transfer
6
+ from .runner import Runner
7
+
8
+ __all__ = ["Agent", "Runner", "chat_summary_to_string", "consolidate_history_transfer", "display_chat_summary", "display_messages", "messages_to_string"]
@@ -10,6 +10,7 @@ import json
10
10
  import time
11
11
  from collections.abc import Callable
12
12
  from datetime import datetime, timedelta, timezone
13
+ from io import StringIO
13
14
 
14
15
  try:
15
16
  from zoneinfo import ZoneInfo
@@ -46,6 +47,7 @@ class DisplayConfig:
46
47
  console: Console | None = None
47
48
  show_indices: bool = True
48
49
  show_timestamps: bool = True
50
+ show_metadata: bool = True
49
51
  max_content_length: int = 1000
50
52
  local_timezone: timezone | str | None = None
51
53
 
@@ -57,6 +59,7 @@ class MessageContext:
57
59
  console: Console
58
60
  index_str: str
59
61
  timestamp_str: str
62
+ show_metadata: bool
60
63
  max_content_length: int
61
64
  truncate_content: Callable[[str, int], str]
62
65
 
@@ -441,6 +444,7 @@ def display_messages(
441
444
  console=console,
442
445
  max_content_length=config.max_content_length,
443
446
  show_timestamp=config.show_timestamps,
447
+ show_metadata=config.show_metadata,
444
448
  local_timezone=local_timezone,
445
449
  )
446
450
 
@@ -452,6 +456,7 @@ def _display_single_message_compact(
452
456
  console: Console,
453
457
  max_content_length: int = 100,
454
458
  show_timestamp: bool = False,
459
+ show_metadata: bool = True,
455
460
  local_timezone: timezone | None = None,
456
461
  ) -> None:
457
462
  """以列式格式打印单个消息,类似 rich log。"""
@@ -469,7 +474,7 @@ def _display_single_message_compact(
469
474
  timestamp = _format_timestamp(message_time, local_timezone=local_timezone)
470
475
 
471
476
  # 创建列式显示
472
- _display_message_in_columns(message, console, index, timestamp, max_content_length, truncate_content)
477
+ _display_message_in_columns(message, console, index, timestamp, show_metadata=show_metadata, max_content_length=max_content_length, truncate_content=truncate_content)
473
478
 
474
479
 
475
480
  def _display_message_in_columns(
@@ -477,6 +482,8 @@ def _display_message_in_columns(
477
482
  console: Console,
478
483
  index: int | None,
479
484
  timestamp: str | None,
485
+ *,
486
+ show_metadata: bool,
480
487
  max_content_length: int,
481
488
  truncate_content: Callable[[str, int], str],
482
489
  ) -> None:
@@ -490,12 +497,9 @@ def _display_message_in_columns(
490
497
  if isinstance(message, NewUserMessage):
491
498
  _display_user_message_with_columns(message, console, time_str, index_str, max_content_length, truncate_content)
492
499
  elif isinstance(message, NewAssistantMessage):
493
- _display_assistant_message_with_columns(message, console, time_str, index_str, max_content_length, truncate_content)
500
+ _display_assistant_message_with_columns(message, console, time_str, index_str, show_metadata=show_metadata, max_content_length=max_content_length, truncate_content=truncate_content)
494
501
  elif isinstance(message, NewSystemMessage):
495
502
  _display_system_message_with_columns(message, console, time_str, index_str, max_content_length, truncate_content)
496
- else:
497
- # 处理旧格式消息
498
- _display_legacy_message_with_columns(message, console, time_str, index_str, max_content_length, truncate_content)
499
503
 
500
504
 
501
505
  def _display_user_message_with_columns(
@@ -523,27 +527,48 @@ def _display_user_message_with_columns(
523
527
  content = " ".join(content_parts)
524
528
  content = truncate_content(content, max_content_length)
525
529
 
526
- # 创建表格来确保对齐
530
+ # 创建表格来确保对齐,根据配置动态调整列宽
527
531
  table = Table.grid(padding=0)
528
- table.add_column(width=8, justify="left") # 时间列
529
- table.add_column(width=4, justify="left") # 序号列
532
+
533
+ # 只有在显示时间戳时才添加时间列
534
+ time_width = 8 if time_str.strip() else 0
535
+ if time_width > 0:
536
+ table.add_column(width=time_width, justify="left") # 时间列
537
+
538
+ # 只有在显示序号时才添加序号列
539
+ index_width = 4 if index_str.strip() else 0
540
+ if index_width > 0:
541
+ table.add_column(width=index_width, justify="left") # 序号列
542
+
530
543
  table.add_column(min_width=0) # 内容列
531
544
 
545
+ # 辅助函数:根据列数构建行
546
+ def build_table_row(*content_parts: str) -> tuple[str, ...]:
547
+ row_parts = []
548
+ if time_width > 0:
549
+ row_parts.append(content_parts[0] if len(content_parts) > 0 else "")
550
+ if index_width > 0:
551
+ row_parts.append(content_parts[1] if len(content_parts) > 1 else "")
552
+ row_parts.append(content_parts[-1] if content_parts else "") # 内容列总是最后一个
553
+ return tuple(row_parts)
554
+
532
555
  lines = content.split("\n")
533
556
  for i, line in enumerate(lines):
534
557
  if i == 0:
535
558
  # 第一行显示 User: 标签
536
559
  table.add_row(
537
- f"[dim]{time_str:8}[/dim]",
538
- f"[dim]{index_str:4}[/dim]",
539
- "[blue]User:[/blue]",
560
+ *build_table_row(
561
+ f"[dim]{time_str:8}[/dim]",
562
+ f"[dim]{index_str:4}[/dim]",
563
+ "[blue]User:[/blue]",
564
+ ),
540
565
  )
541
566
  # 如果有内容,添加内容行
542
567
  if line:
543
- table.add_row("", "", line)
568
+ table.add_row(*build_table_row("", "", line))
544
569
  else:
545
570
  # 续行只在内容列显示
546
- table.add_row("", "", line)
571
+ table.add_row(*build_table_row("", "", line))
547
572
 
548
573
  console.print(table)
549
574
 
@@ -559,24 +584,45 @@ def _display_system_message_with_columns(
559
584
  """使用列布局显示系统消息。"""
560
585
  content = truncate_content(message.content, max_content_length)
561
586
 
562
- # 创建表格来确保对齐
587
+ # 创建表格来确保对齐,根据配置动态调整列宽
563
588
  table = Table.grid(padding=0)
564
- table.add_column(width=8, justify="left") # 时间列
565
- table.add_column(width=4, justify="left") # 序号列
589
+
590
+ # 只有在显示时间戳时才添加时间列
591
+ time_width = 8 if time_str.strip() else 0
592
+ if time_width > 0:
593
+ table.add_column(width=time_width, justify="left") # 时间列
594
+
595
+ # 只有在显示序号时才添加序号列
596
+ index_width = 4 if index_str.strip() else 0
597
+ if index_width > 0:
598
+ table.add_column(width=index_width, justify="left") # 序号列
599
+
566
600
  table.add_column(min_width=0) # 内容列
567
601
 
602
+ # 辅助函数:根据列数构建行
603
+ def build_table_row(*content_parts: str) -> tuple[str, ...]:
604
+ row_parts = []
605
+ if time_width > 0:
606
+ row_parts.append(content_parts[0] if len(content_parts) > 0 else "")
607
+ if index_width > 0:
608
+ row_parts.append(content_parts[1] if len(content_parts) > 1 else "")
609
+ row_parts.append(content_parts[-1] if content_parts else "") # 内容列总是最后一个
610
+ return tuple(row_parts)
611
+
568
612
  lines = content.split("\n")
569
613
  for i, line in enumerate(lines):
570
614
  if i == 0:
571
615
  # 第一行显示完整信息
572
616
  table.add_row(
573
- f"[dim]{time_str:8}[/dim]",
574
- f"[dim]{index_str:4}[/dim]",
575
- f"[yellow]System:[/yellow] {line}",
617
+ *build_table_row(
618
+ f"[dim]{time_str:8}[/dim]",
619
+ f"[dim]{index_str:4}[/dim]",
620
+ f"[yellow]System:[/yellow] {line}",
621
+ ),
576
622
  )
577
623
  else:
578
624
  # 续行只在内容列显示
579
- table.add_row("", "", line)
625
+ table.add_row(*build_table_row("", "", line))
580
626
 
581
627
  console.print(table)
582
628
 
@@ -586,6 +632,8 @@ def _display_assistant_message_with_columns(
586
632
  console: Console,
587
633
  time_str: str,
588
634
  index_str: str,
635
+ *,
636
+ show_metadata: bool,
589
637
  max_content_length: int,
590
638
  truncate_content: Callable[[str, int], str],
591
639
  ) -> None:
@@ -605,7 +653,7 @@ def _display_assistant_message_with_columns(
605
653
 
606
654
  # 构建元信息
607
655
  meta_info = ""
608
- if message.meta:
656
+ if show_metadata and message.meta:
609
657
  meta_parts = []
610
658
  if message.meta.model is not None:
611
659
  meta_parts.append(f"Model:{message.meta.model}")
@@ -620,12 +668,31 @@ def _display_assistant_message_with_columns(
620
668
  if meta_parts:
621
669
  meta_info = f" [dim]({' | '.join(meta_parts)})[/dim]"
622
670
 
623
- # 创建表格来确保对齐
671
+ # 创建表格来确保对齐,根据配置动态调整列宽
624
672
  table = Table.grid(padding=0)
625
- table.add_column(width=8, justify="left") # 时间列
626
- table.add_column(width=4, justify="left") # 序号列
673
+
674
+ # 只有在显示时间戳时才添加时间列
675
+ time_width = 8 if time_str.strip() else 0
676
+ if time_width > 0:
677
+ table.add_column(width=time_width, justify="left") # 时间列
678
+
679
+ # 只有在显示序号时才添加序号列
680
+ index_width = 4 if index_str.strip() else 0
681
+ if index_width > 0:
682
+ table.add_column(width=index_width, justify="left") # 序号列
683
+
627
684
  table.add_column(min_width=0) # 内容列
628
685
 
686
+ # 辅助函数:根据列数构建行
687
+ def build_table_row(*content_parts: str) -> tuple[str, ...]:
688
+ row_parts = []
689
+ if time_width > 0:
690
+ row_parts.append(content_parts[0] if len(content_parts) > 0 else "")
691
+ if index_width > 0:
692
+ row_parts.append(content_parts[1] if len(content_parts) > 1 else "")
693
+ row_parts.append(content_parts[-1] if content_parts else "") # 内容列总是最后一个
694
+ return tuple(row_parts)
695
+
629
696
  # 处理文本内容
630
697
  first_row_added = False
631
698
  if text_parts:
@@ -636,24 +703,28 @@ def _display_assistant_message_with_columns(
636
703
  if i == 0:
637
704
  # 第一行显示 Assistant: 标签
638
705
  table.add_row(
639
- f"[dim]{time_str:8}[/dim]",
640
- f"[dim]{index_str:4}[/dim]",
641
- f"[green]Assistant:[/green]{meta_info}",
706
+ *build_table_row(
707
+ f"[dim]{time_str:8}[/dim]",
708
+ f"[dim]{index_str:4}[/dim]",
709
+ f"[green]Assistant:[/green]{meta_info}",
710
+ ),
642
711
  )
643
712
  # 如果有内容,添加内容行
644
713
  if line:
645
- table.add_row("", "", line)
714
+ table.add_row(*build_table_row("", "", line))
646
715
  first_row_added = True
647
716
  else:
648
717
  # 续行只在内容列显示
649
- table.add_row("", "", line)
718
+ table.add_row(*build_table_row("", "", line))
650
719
 
651
720
  # 如果没有文本内容,只显示助手消息头
652
721
  if not first_row_added:
653
722
  table.add_row(
654
- f"[dim]{time_str:8}[/dim]",
655
- f"[dim]{index_str:4}[/dim]",
656
- f"[green]Assistant:[/green]{meta_info}",
723
+ *build_table_row(
724
+ f"[dim]{time_str:8}[/dim]",
725
+ f"[dim]{index_str:4}[/dim]",
726
+ f"[green]Assistant:[/green]{meta_info}",
727
+ ),
657
728
  )
658
729
 
659
730
  # 添加工具调用
@@ -667,7 +738,7 @@ def _display_assistant_message_with_columns(
667
738
  args_str = f" {tool_call.arguments}"
668
739
 
669
740
  args_display = truncate_content(args_str, max_content_length - len(tool_call.name) - 10)
670
- table.add_row("", "", f"[magenta]Call:[/magenta] {tool_call.name}{args_display}")
741
+ table.add_row(*build_table_row("", "", f"[magenta]Call:[/magenta] {tool_call.name}{args_display}"))
671
742
 
672
743
  # 添加工具结果
673
744
  for tool_result in tool_results:
@@ -676,10 +747,10 @@ def _display_assistant_message_with_columns(
676
747
  if tool_result.execution_time_ms is not None:
677
748
  time_info = f" [dim]({tool_result.execution_time_ms}ms)[/dim]"
678
749
 
679
- table.add_row("", "", f"[cyan]Output:[/cyan]{time_info}")
750
+ table.add_row(*build_table_row("", "", f"[cyan]Output:[/cyan]{time_info}"))
680
751
  lines = output.split("\n")
681
752
  for line in lines:
682
- table.add_row("", "", line)
753
+ table.add_row(*build_table_row("", "", line))
683
754
 
684
755
  console.print(table)
685
756
 
@@ -689,6 +760,8 @@ def _display_legacy_message_with_columns(
689
760
  console: Console,
690
761
  time_str: str,
691
762
  index_str: str,
763
+ *,
764
+ show_metadata: bool, # noqa: ARG001
692
765
  max_content_length: int,
693
766
  truncate_content: Callable[[str, int], str],
694
767
  ) -> None:
@@ -735,6 +808,7 @@ def _create_message_context(context_config: dict[str, FlexibleRunnerMessage | Co
735
808
  max_content_length = max_content_length_val
736
809
  truncate_content = context_config["truncate_content"]
737
810
  show_timestamp = context_config.get("show_timestamp", False)
811
+ show_metadata = bool(context_config.get("show_metadata", True))
738
812
  local_timezone = context_config.get("local_timezone")
739
813
 
740
814
  # 类型检查
@@ -773,6 +847,7 @@ def _create_message_context(context_config: dict[str, FlexibleRunnerMessage | Co
773
847
  console=console,
774
848
  index_str=index_str,
775
849
  timestamp_str=timestamp_str,
850
+ show_metadata=show_metadata,
776
851
  max_content_length=max_content_length,
777
852
  truncate_content=truncate_content, # type: ignore[arg-type]
778
853
  )
@@ -1048,3 +1123,103 @@ def _display_new_assistant_message_compact(message: NewAssistantMessage, context
1048
1123
  # Always use indented format for better hierarchy
1049
1124
  context.console.print(f" [cyan]Output:[/cyan]{time_info}")
1050
1125
  context.console.print(f" {output}")
1126
+
1127
+
1128
+ def messages_to_string(
1129
+ messages: RunnerMessages,
1130
+ *,
1131
+ show_indices: bool = False,
1132
+ show_timestamps: bool = False,
1133
+ show_metadata: bool = False,
1134
+ max_content_length: int = 1000,
1135
+ local_timezone: timezone | str | None = None,
1136
+ ) -> str:
1137
+ """
1138
+ 将消息列表转换为纯文本字符串,默认简洁格式(不显示时间、序号、元数据)。
1139
+
1140
+ Args:
1141
+ messages: 要转换的消息列表
1142
+ show_indices: 是否显示消息序号(默认False)
1143
+ show_timestamps: 是否显示时间戳(默认False)
1144
+ show_metadata: 是否显示元数据(如模型、延迟、token使用等,默认False)
1145
+ max_content_length: 内容最大长度限制(默认1000)
1146
+ local_timezone: 本地时区设置(可选)
1147
+
1148
+ Returns:
1149
+ 包含所有消息的纯文本字符串
1150
+ """
1151
+ # 创建一个没有颜色的 Console 来捕获输出
1152
+ string_buffer = StringIO()
1153
+ plain_console = Console(file=string_buffer, force_terminal=False, no_color=True, width=120)
1154
+
1155
+ # 使用配置
1156
+ config = DisplayConfig(
1157
+ console=plain_console,
1158
+ show_indices=show_indices,
1159
+ show_timestamps=show_timestamps,
1160
+ show_metadata=show_metadata,
1161
+ max_content_length=max_content_length,
1162
+ local_timezone=local_timezone,
1163
+ )
1164
+
1165
+ # 调用现有的 display_messages 函数,但输出到字符串缓冲区
1166
+ display_messages(messages, config=config)
1167
+
1168
+ # 获取结果并清理尾随空格
1169
+ result = string_buffer.getvalue()
1170
+ string_buffer.close()
1171
+
1172
+ # 清理每行的尾随空格
1173
+ lines = result.split("\n")
1174
+ cleaned_lines = [line.rstrip() for line in lines]
1175
+ return "\n".join(cleaned_lines)
1176
+
1177
+
1178
+ def chat_summary_to_string(messages: RunnerMessages, *, include_performance: bool = False) -> str:
1179
+ """
1180
+ 将聊天摘要转换为纯文本字符串,默认只显示基本统计信息。
1181
+
1182
+ Args:
1183
+ messages: 要分析的消息列表
1184
+ include_performance: 是否包含性能统计信息(默认False)
1185
+
1186
+ Returns:
1187
+ 包含聊天摘要的纯文本字符串
1188
+ """
1189
+ string_buffer = StringIO()
1190
+ plain_console = Console(file=string_buffer, force_terminal=False, no_color=True, width=120)
1191
+
1192
+ if include_performance:
1193
+ # 调用现有的 display_chat_summary 函数,包含所有信息
1194
+ display_chat_summary(messages, console=plain_console)
1195
+ else:
1196
+ # 只显示基本的消息统计信息
1197
+ _display_basic_message_stats(messages, plain_console)
1198
+
1199
+ # 获取结果并清理
1200
+ result = string_buffer.getvalue()
1201
+ string_buffer.close()
1202
+
1203
+ return result
1204
+
1205
+
1206
+ def _display_basic_message_stats(messages: RunnerMessages, console: Console) -> None:
1207
+ """显示基本的消息统计信息,不包含性能数据。"""
1208
+ message_counts, _ = _analyze_messages(messages)
1209
+
1210
+ # 创建简化的统计表格
1211
+ table = Table(title="Message Summary", show_header=True, header_style="bold blue")
1212
+ table.add_column("Message Type", justify="left")
1213
+ table.add_column("Count", justify="right")
1214
+
1215
+ # 添加消息类型统计
1216
+ for msg_type, count in message_counts.items():
1217
+ if msg_type != "Total": # 跳过总计,单独处理
1218
+ table.add_row(msg_type, str(count))
1219
+
1220
+ # 添加总计行
1221
+ if "Total" in message_counts:
1222
+ table.add_row("", "") # 空行分隔
1223
+ table.add_row("[bold]Total[/bold]", f"[bold]{message_counts['Total']}[/bold]")
1224
+
1225
+ console.print(table)
@@ -2,10 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Generic, TypeVar
5
+ from typing import TYPE_CHECKING, Generic, TypeVar
6
6
 
7
7
  from pydantic import BaseModel
8
8
 
9
+ if TYPE_CHECKING:
10
+ from lite_agent.types import NewMessage
11
+
9
12
  T = TypeVar("T")
10
13
 
11
14
 
@@ -33,5 +36,5 @@ class HistoryContext(BaseModel, Generic[T]):
33
36
  ... return f"用户 {user_id} 有 {len(messages)} 条消息"
34
37
  """
35
38
 
36
- history_messages: list[Any]
39
+ history_messages: list[NewMessage]
37
40
  data: T | None = None