lite-agent 0.6.0__tar.gz → 0.9.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 (151) hide show
  1. {lite_agent-0.6.0 → lite_agent-0.9.0}/.claude/settings.local.json +4 -1
  2. {lite_agent-0.6.0 → lite_agent-0.9.0}/CHANGELOG.md +48 -0
  3. {lite_agent-0.6.0 → lite_agent-0.9.0}/PKG-INFO +3 -2
  4. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/basic.py +3 -7
  5. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/basic_agent.py +4 -4
  6. lite_agent-0.9.0/examples/cancel_and_transfer_demo.py +301 -0
  7. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/confirm_and_continue.py +1 -1
  8. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/debug_non_streaming.py +1 -0
  9. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/debug_with_logging.py +1 -0
  10. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/handoffs.py +1 -1
  11. lite_agent-0.9.0/examples/knowledge/main.py +67 -0
  12. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/llm_config_demo.py +1 -1
  13. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/non_streaming.py +3 -2
  14. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/reasoning_example.py +2 -2
  15. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/response_api_example.py +5 -3
  16. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/simple_debug.py +2 -1
  17. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/simple_debug2.py +1 -0
  18. lite_agent-0.9.0/examples/stop_before_functions.py +114 -0
  19. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/streaming_demo.py +1 -0
  20. lite_agent-0.9.0/htmlcov/.gitignore +2 -0
  21. lite_agent-0.9.0/htmlcov/class_index.html +771 -0
  22. lite_agent-0.9.0/htmlcov/coverage_html_cb_6fb7b396.js +733 -0
  23. lite_agent-0.9.0/htmlcov/favicon_32_cb_58284776.png +0 -0
  24. lite_agent-0.9.0/htmlcov/function_index.html +1475 -0
  25. lite_agent-0.9.0/htmlcov/index.html +272 -0
  26. lite_agent-0.9.0/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  27. lite_agent-0.9.0/htmlcov/status.json +1 -0
  28. lite_agent-0.9.0/htmlcov/style_cb_6b508a39.css +377 -0
  29. lite_agent-0.9.0/htmlcov/z_02adcf90d0f2eeb1___init___py.html +228 -0
  30. lite_agent-0.9.0/htmlcov/z_02adcf90d0f2eeb1_events_py.html +216 -0
  31. lite_agent-0.9.0/htmlcov/z_02adcf90d0f2eeb1_messages_py.html +441 -0
  32. lite_agent-0.9.0/htmlcov/z_02adcf90d0f2eeb1_tool_calls_py.html +112 -0
  33. lite_agent-0.9.0/htmlcov/z_1d32cdd6b7b66bed___init___py.html +97 -0
  34. lite_agent-0.9.0/htmlcov/z_1d32cdd6b7b66bed_message_builder_py.html +308 -0
  35. lite_agent-0.9.0/htmlcov/z_1d32cdd6b7b66bed_metrics_py.html +147 -0
  36. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e___init___py.html +105 -0
  37. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_agent_py.html +777 -0
  38. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_chat_display_py.html +884 -0
  39. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_client_py.html +337 -0
  40. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_constants_py.html +127 -0
  41. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_loggers_py.html +100 -0
  42. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_message_transfers_py.html +216 -0
  43. lite_agent-0.9.0/htmlcov/z_40b804173f68aa9e_runner_py.html +993 -0
  44. lite_agent-0.9.0/htmlcov/z_71ac9935daa08879___init___py.html +108 -0
  45. lite_agent-0.9.0/htmlcov/z_71ac9935daa08879_base_py.html +151 -0
  46. lite_agent-0.9.0/htmlcov/z_71ac9935daa08879_completion_py.html +175 -0
  47. lite_agent-0.9.0/htmlcov/z_71ac9935daa08879_responses_py.html +173 -0
  48. lite_agent-0.9.0/htmlcov/z_c8357a9ef7e20b45___init___py.html +103 -0
  49. lite_agent-0.9.0/htmlcov/z_c8357a9ef7e20b45_litellm_py.html +181 -0
  50. lite_agent-0.9.0/htmlcov/z_f01690d2832086e5___init___py.html +101 -0
  51. lite_agent-0.9.0/htmlcov/z_f01690d2832086e5_completion_event_processor_py.html +397 -0
  52. lite_agent-0.9.0/htmlcov/z_f01690d2832086e5_response_event_processor_py.html +310 -0
  53. {lite_agent-0.6.0 → lite_agent-0.9.0}/pyproject.toml +9 -2
  54. lite_agent-0.9.0/pyrightconfig.json +12 -0
  55. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/agent.py +233 -47
  56. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/chat_display.py +319 -54
  57. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/client.py +4 -0
  58. lite_agent-0.9.0/src/lite_agent/constants.py +30 -0
  59. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/message_transfers.py +24 -5
  60. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/processors/completion_event_processor.py +14 -20
  61. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/processors/response_event_processor.py +23 -15
  62. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/response_handlers/__init__.py +1 -0
  63. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/response_handlers/base.py +17 -9
  64. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/response_handlers/completion.py +35 -7
  65. lite_agent-0.9.0/src/lite_agent/response_handlers/responses.py +76 -0
  66. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/runner.py +336 -249
  67. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/types/__init__.py +2 -0
  68. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/types/messages.py +6 -5
  69. lite_agent-0.9.0/src/lite_agent/utils/__init__.py +0 -0
  70. lite_agent-0.9.0/src/lite_agent/utils/message_builder.py +213 -0
  71. lite_agent-0.9.0/src/lite_agent/utils/metrics.py +50 -0
  72. lite_agent-0.9.0/temp/main.py +36 -0
  73. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/mocks/confirm_and_continue/1.jsonl +21 -21
  74. lite_agent-0.9.0/tests/mocks/confirm_and_continue/2.jsonl +48 -0
  75. lite_agent-0.9.0/tests/performance/test_set_chat_history_performance.py +142 -0
  76. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_agent.py +1 -5
  77. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_agent_additional.py +6 -12
  78. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_agent_handoffs.py +17 -4
  79. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_append_message.py +18 -51
  80. lite_agent-0.9.0/tests/unit/test_cancel_pending_tools.py +233 -0
  81. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_chat_display_additional.py +2 -3
  82. lite_agent-0.9.0/tests/unit/test_chat_display_simple.py +155 -0
  83. lite_agent-0.9.0/tests/unit/test_client.py +326 -0
  84. lite_agent-0.9.0/tests/unit/test_message_builder.py +422 -0
  85. lite_agent-0.9.0/tests/unit/test_message_transfers.py +90 -0
  86. lite_agent-0.9.0/tests/unit/test_response_api_format.py +130 -0
  87. lite_agent-0.9.0/tests/unit/test_response_handlers.py +270 -0
  88. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_runner.py +5 -5
  89. lite_agent-0.9.0/tests/unit/test_set_chat_history.py +198 -0
  90. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_stream_handlers_additional.py +1 -0
  91. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_streaming_config.py +9 -4
  92. lite_agent-0.9.0/tests/unit/test_utils_extended.py +97 -0
  93. {lite_agent-0.6.0 → lite_agent-0.9.0}/uv.lock +290 -287
  94. lite_agent-0.6.0/src/lite_agent/response_handlers/responses.py +0 -42
  95. lite_agent-0.6.0/tests/mocks/confirm_and_continue/2.jsonl +0 -37
  96. lite_agent-0.6.0/tests/performance/test_set_chat_history_performance.py +0 -130
  97. lite_agent-0.6.0/tests/unit/test_message_transfers.py +0 -74
  98. lite_agent-0.6.0/tests/unit/test_response_api_format.py +0 -290
  99. lite_agent-0.6.0/tests/unit/test_set_chat_history.py +0 -354
  100. {lite_agent-0.6.0 → lite_agent-0.9.0}/.github/workflows/ci.yml +0 -0
  101. {lite_agent-0.6.0 → lite_agent-0.9.0}/.gitignore +0 -0
  102. {lite_agent-0.6.0 → lite_agent-0.9.0}/.python-version +0 -0
  103. {lite_agent-0.6.0 → lite_agent-0.9.0}/.vscode/launch.json +0 -0
  104. {lite_agent-0.6.0 → lite_agent-0.9.0}/CLAUDE.md +0 -0
  105. {lite_agent-0.6.0 → lite_agent-0.9.0}/README.md +0 -0
  106. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/basic_model.py +0 -0
  107. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/channels/rich_channel.py +0 -0
  108. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/chat_display_demo.py +0 -0
  109. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/consolidate_history.py +0 -0
  110. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/context.py +0 -0
  111. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/image.py +0 -0
  112. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/message_transfer_example.py +0 -0
  113. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/message_transfer_example_new.py +0 -0
  114. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/new_message_structure_demo.py +0 -0
  115. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/responses.py +0 -0
  116. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/set_chat_history_example.py +0 -0
  117. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/stop_with_tool_call.py +0 -0
  118. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/terminal.py +0 -0
  119. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/translate/main.py +0 -0
  120. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/translate/prompts/translation_system.md.j2 +0 -0
  121. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/translate.py +0 -0
  122. {lite_agent-0.6.0 → lite_agent-0.9.0}/examples/type_system_example.py +0 -0
  123. {lite_agent-0.6.0 → lite_agent-0.9.0}/scripts/record_chat_messages.py +0 -0
  124. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/__init__.py +0 -0
  125. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/loggers.py +0 -0
  126. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/processors/__init__.py +0 -0
  127. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/py.typed +0 -0
  128. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/stream_handlers/__init__.py +0 -0
  129. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/stream_handlers/litellm.py +0 -0
  130. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/templates/handoffs_source_instructions.xml.j2 +0 -0
  131. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/templates/handoffs_target_instructions.xml.j2 +0 -0
  132. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/templates/wait_for_user_instructions.xml.j2 +0 -0
  133. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/types/events.py +0 -0
  134. {lite_agent-0.6.0 → lite_agent-0.9.0}/src/lite_agent/types/tool_calls.py +0 -0
  135. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/integration/test_agent_with_mocks.py +0 -0
  136. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/integration/test_basic.py +0 -0
  137. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/integration/test_mock_litellm.py +0 -0
  138. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/mocks/basic/1.jsonl +0 -0
  139. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/mocks/context/1.jsonl +0 -0
  140. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/mocks/handoffs/1.jsonl +0 -0
  141. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/test_new_messages.py +0 -0
  142. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_chat_display.py +0 -0
  143. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_completion_condition.py +0 -0
  144. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_file_recording.py +0 -0
  145. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_litellm_stream_handler.py +0 -0
  146. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_message_transfer.py +0 -0
  147. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_message_transfers_additional.py +0 -0
  148. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_response_event_processor.py +0 -0
  149. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_simple_stream_handlers.py +0 -0
  150. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/unit/test_stream_chunk_processor.py +0 -0
  151. {lite_agent-0.6.0 → lite_agent-0.9.0}/tests/utils/mock_litellm.py +0 -0
@@ -15,7 +15,10 @@
15
15
  "Bash(timeout:*)",
16
16
  "Bash(pyright:*)",
17
17
  "Bash(rg:*)",
18
- "Bash(uv run:*)"
18
+ "Bash(uv run:*)",
19
+ "Bash(mkdir:*)",
20
+ "Bash(sed:*)",
21
+ "Bash(mv:*)"
19
22
  ],
20
23
  "deny": []
21
24
  }
@@ -1,3 +1,51 @@
1
+ ## v0.9.0
2
+
3
+ [v0.8.0...v0.9.0](https://github.com/Jannchie/lite-agent/compare/v0.8.0...v0.9.0)
4
+
5
+ ### :sparkles: Features
6
+
7
+ - **agent**: improve assistant message tool_call handling - By [Jannchie](mailto:jannchie@gmail.com) in [45e6de8](https://github.com/Jannchie/lite-agent/commit/45e6de8)
8
+ - **chat-display**: add column-style message display and show model info - By [Jannchie](mailto:jannchie@gmail.com) in [3559137](https://github.com/Jannchie/lite-agent/commit/3559137)
9
+ - **tests**: add tests for client message_builder and response handlers - By [Jannchie](mailto:jannchie@gmail.com) in [ceec7d7](https://github.com/Jannchie/lite-agent/commit/ceec7d7)
10
+
11
+ ### :art: Refactors
12
+
13
+ - **examples**: update examples to use new message and content types - By [Jannchie](mailto:jannchie@gmail.com) in [59b4618](https://github.com/Jannchie/lite-agent/commit/59b4618)
14
+
15
+ ### :wrench: Chores
16
+
17
+ - **deps**: bump funcall to 0.11.0 - By [Jannchie](mailto:jannchie@gmail.com) in [eb5e7ae](https://github.com/Jannchie/lite-agent/commit/eb5e7ae)
18
+
19
+ ## v0.8.0
20
+
21
+ [v0.7.0...v0.8.0](https://github.com/Jannchie/lite-agent/compare/v0.7.0...v0.8.0)
22
+
23
+ ### :rocket: Breaking Changes
24
+
25
+ - **runner**: remove dict-format and legacy support from message history and enforce newmessage format - By [Jannchie](mailto:jannchie@gmail.com) in [44b435c](https://github.com/Jannchie/lite-agent/commit/44b435c)
26
+
27
+ ### :sparkles: Features
28
+
29
+ - **agent**: add dynamic stop-before-functions support - By [Jannchie](mailto:jannchie@gmail.com) in [e7de181](https://github.com/Jannchie/lite-agent/commit/e7de181)
30
+ - **agent**: improve tool call extraction and meta preservation - By [Jannchie](mailto:jannchie@gmail.com) in [1b10296](https://github.com/Jannchie/lite-agent/commit/1b10296)
31
+ - **runner**: add cancellation events for pending tool calls and implement function_call_output for agent transfers - By [Jannchie](mailto:jannchie@gmail.com) in [4c298b7](https://github.com/Jannchie/lite-agent/commit/4c298b7)
32
+ - **runner**: preserve original dict message structure in chat history - By [Jannchie](mailto:jannchie@gmail.com) in [da4ad59](https://github.com/Jannchie/lite-agent/commit/da4ad59)
33
+
34
+ ## v0.7.0
35
+
36
+ [v0.6.0...v0.7.0](https://github.com/Jannchie/lite-agent/compare/v0.6.0...v0.7.0)
37
+
38
+ ### :sparkles: Features
39
+
40
+ - **assistant-meta**: add model and usage support to assistant message meta and refactor token accounting - By [Jannchie](mailto:jannchie@gmail.com) in [b50ed0e](https://github.com/Jannchie/lite-agent/commit/b50ed0e)
41
+ - **message-builder**: support array content in assistant messages - By [Jannchie](mailto:jannchie@gmail.com) in [1b7a790](https://github.com/Jannchie/lite-agent/commit/1b7a790)
42
+ - **runner**: add tool call handling and usage events for completion and responses api - By [Jannchie](mailto:jannchie@gmail.com) in [1a82a18](https://github.com/Jannchie/lite-agent/commit/1a82a18)
43
+
44
+ ### :art: Refactors
45
+
46
+ - **messages**: replace type checks with isinstance for assistant content - By [Jannchie](mailto:jannchie@gmail.com) in [ec506a8](https://github.com/Jannchie/lite-agent/commit/ec506a8)
47
+ - **utils**: extract constants and message utilities && centralize timing metrics - By [Jannchie](mailto:jannchie@gmail.com) in [d928637](https://github.com/Jannchie/lite-agent/commit/d928637)
48
+
1
49
  ## v0.6.0
2
50
 
3
51
  [v0.5.0...v0.6.0](https://github.com/Jannchie/lite-agent/compare/v0.5.0...v0.6.0)
@@ -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
@@ -4,7 +4,6 @@ import logging
4
4
  from rich.logging import RichHandler
5
5
 
6
6
  from lite_agent.agent import Agent
7
- from lite_agent.chat_display import display_messages
8
7
  from lite_agent.runner import Runner
9
8
 
10
9
  logging.basicConfig(
@@ -32,15 +31,12 @@ agent = Agent(
32
31
 
33
32
 
34
33
  async def main():
35
- runner = Runner(agent)
36
- resp = runner.run(
34
+ runner = Runner(agent, streaming=True, api="responses")
35
+ resp = await runner.run_until_complete(
37
36
  "What is the temperature in New York?",
38
37
  includes=["usage", "assistant_message", "function_call", "function_call_output", "timing"],
39
38
  )
40
- async for chunk in resp:
41
- logger.info(chunk)
42
- display_messages(runner.messages)
43
- print(runner.messages)
39
+ print(resp[0])
44
40
 
45
41
 
46
42
  if __name__ == "__main__":
@@ -4,6 +4,7 @@ import logging
4
4
  from rich.logging import RichHandler
5
5
 
6
6
  from lite_agent.agent import Agent
7
+ from lite_agent.types import NewUserMessage, UserTextContent
7
8
 
8
9
  logging.basicConfig(
9
10
  level=logging.WARNING,
@@ -39,10 +40,9 @@ agent = Agent(
39
40
  async def main():
40
41
  resp = await agent.completion(
41
42
  [
42
- {
43
- "role": "user",
44
- "content": "What is the temperature and whether in New York?",
45
- },
43
+ NewUserMessage(
44
+ content=[UserTextContent(text="What is the temperature and whether in New York?")],
45
+ ),
46
46
  ],
47
47
  )
48
48
  async for chunk in resp:
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Demo showing two new features:
4
+ 1. Cancellation of pending tool calls when user provides new input
5
+ 2. function_call_output events for transfer_to_agent and transfer_to_parent
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ import logging
11
+
12
+ from funcall.decorators import tool
13
+ from rich.logging import RichHandler
14
+
15
+ from lite_agent.agent import Agent
16
+ from lite_agent.runner import Runner
17
+ from lite_agent.types import AssistantTextContent, AssistantToolCall, AssistantToolCallResult, NewAssistantMessage, ToolCall, ToolCallFunction
18
+ from lite_agent.types.events import FunctionCallOutputEvent
19
+
20
+ logging.basicConfig(
21
+ level=logging.WARNING,
22
+ format="%(message)s",
23
+ datefmt="[%X]",
24
+ handlers=[RichHandler(rich_tracebacks=True)],
25
+ )
26
+
27
+ logger = logging.getLogger("lite_agent")
28
+ logger.setLevel(logging.DEBUG)
29
+
30
+
31
+ @tool
32
+ async def get_weather(city: str) -> str:
33
+ """Get the weather for a city."""
34
+ await asyncio.sleep(2) # Simulate long operation
35
+ return f"The weather in {city} is sunny with a few clouds."
36
+
37
+
38
+ @tool
39
+ async def get_temperature(city: str) -> str:
40
+ """Get the temperature for a city."""
41
+ await asyncio.sleep(2) # Simulate long operation
42
+ return f"The temperature in {city} is 25°C."
43
+
44
+
45
+ @tool
46
+ async def book_flight(destination: str, date: str) -> str:
47
+ """Book a flight to a destination."""
48
+ await asyncio.sleep(3) # Simulate very long operation
49
+ return f"Flight booked to {destination} on {date}"
50
+
51
+
52
+ async def demo_1_cancel_pending_tools():
53
+ """Demo 1: Cancellation of pending tool calls"""
54
+ print("=== Demo 1: Cancellation of Pending Tool Calls ===\n")
55
+
56
+ agent = Agent(
57
+ model="gpt-4.1-nano",
58
+ name="WeatherBot",
59
+ instructions="You are a helpful weather assistant.",
60
+ tools=[get_weather, get_temperature, book_flight],
61
+ )
62
+
63
+ runner = Runner(agent)
64
+
65
+ # Simulate a scenario where the agent made tool calls but user interrupts
66
+ print("1. Simulating assistant making tool calls...")
67
+ assistant_message = NewAssistantMessage(
68
+ content=[
69
+ AssistantTextContent(text="I'll check the weather and temperature for you, and also help you book that flight."),
70
+ AssistantToolCall(
71
+ call_id="weather_call",
72
+ name="get_weather",
73
+ arguments='{"city": "Tokyo"}',
74
+ ),
75
+ AssistantToolCall(
76
+ call_id="temp_call",
77
+ name="get_temperature",
78
+ arguments='{"city": "Tokyo"}',
79
+ ),
80
+ AssistantToolCall(
81
+ call_id="flight_call",
82
+ name="book_flight",
83
+ arguments='{"destination": "Paris", "date": "2024-12-25"}',
84
+ ),
85
+ ],
86
+ )
87
+
88
+ runner.messages.append(assistant_message)
89
+
90
+ # Check pending calls
91
+ pending_calls = runner._find_pending_tool_calls()
92
+ print(f"Pending tool calls: {len(pending_calls)}")
93
+ for call in pending_calls:
94
+ print(f" - {call.name} (call_id: {call.call_id})")
95
+
96
+ print(f"Total messages before cancellation: {len(runner.messages)}")
97
+ print(f"Content items in assistant message: {len(assistant_message.content)}")
98
+
99
+ # User provides new input - this should cancel pending calls and generate events
100
+ print("\n2. User provides new input: 'Actually, never mind about the weather. What's the capital of Japan?'")
101
+
102
+ print("\n2a. Testing via run() method (integrated flow with event yielding):")
103
+ # Test the integrated flow - collect cancellation events from run()
104
+ # This will automatically call _cancel_pending_tool_calls() and yield events
105
+ chunks = []
106
+ try:
107
+ async for chunk in runner.run("What's the capital of Japan?", includes=["function_call_output"]):
108
+ chunks.append(chunk)
109
+ if len(chunks) >= 3: # Stop after getting cancellation events
110
+ break
111
+ except Exception as e:
112
+ # Expected - no real LLM configured
113
+ logger.debug("Expected exception in demo: %s", e)
114
+
115
+ print(f"Events from run() method: {len(chunks)}")
116
+ for i, chunk in enumerate(chunks):
117
+ if chunk.type == "function_call_output":
118
+ print(f" - Chunk {i + 1}: {chunk.type} for {chunk.tool_call_id}")
119
+ print(f" Tool: {chunk.name}")
120
+ print(f" Content: {chunk.content}")
121
+
122
+ # Now demonstrate the direct method on fresh data
123
+ print("\n2b. Testing direct cancellation method (returns events):")
124
+ # Create a new runner with fresh pending calls
125
+ runner2 = Runner(agent)
126
+ runner2.messages.append(
127
+ NewAssistantMessage(
128
+ content=[
129
+ AssistantTextContent(text="Let me help with a different task."),
130
+ AssistantToolCall(
131
+ call_id="new_call_1",
132
+ name="get_weather",
133
+ arguments='{"city": "London"}',
134
+ ),
135
+ AssistantToolCall(
136
+ call_id="new_call_2",
137
+ name="get_temperature",
138
+ arguments='{"city": "London"}',
139
+ ),
140
+ ],
141
+ ),
142
+ )
143
+
144
+ cancellation_events = runner2._cancel_pending_tool_calls()
145
+ print(f"Cancellation events generated: {len(cancellation_events)}")
146
+ for event in cancellation_events:
147
+ print(f" - Event: {event.type} for {event.tool_call_id} ({event.name})")
148
+ print(f" Content: {event.content}")
149
+ print(f" Execution time: {event.execution_time_ms}ms")
150
+
151
+ print("\n3. After cancellation:")
152
+ pending_calls_after = runner._find_pending_tool_calls()
153
+ print(f"Pending tool calls: {len(pending_calls_after)}")
154
+
155
+ print(f"Total messages after cancellation: {len(runner.messages)}")
156
+ if runner.messages:
157
+ assistant_msg = runner.messages[0]
158
+ print(f"Content items in assistant message: {len(assistant_msg.content)}")
159
+
160
+ # Show the cancellation results
161
+ cancellation_results = [item for item in assistant_msg.content if isinstance(item, AssistantToolCallResult)]
162
+ print(f"Cancellation results added: {len(cancellation_results)}")
163
+ for result in cancellation_results:
164
+ print(f" - {result.call_id}: {result.output}")
165
+
166
+
167
+ async def demo_2_transfer_events():
168
+ """Demo 2: function_call_output events for agent transfers"""
169
+ print("\n\n=== Demo 2: Transfer Events ===\n")
170
+
171
+ # Create agents with handoff relationships
172
+ weather_agent = Agent(
173
+ model="gpt-4",
174
+ name="WeatherAgent",
175
+ instructions="You specialize in weather information.",
176
+ tools=[get_weather, get_temperature],
177
+ )
178
+
179
+ travel_agent = Agent(
180
+ model="gpt-4",
181
+ name="TravelAgent",
182
+ instructions="You specialize in travel bookings.",
183
+ tools=[book_flight],
184
+ )
185
+
186
+ main_agent = Agent(
187
+ model="gpt-4",
188
+ name="MainAgent",
189
+ instructions="You are the main agent that coordinates with specialists.",
190
+ handoffs=[weather_agent, travel_agent],
191
+ )
192
+
193
+ runner = Runner(main_agent)
194
+
195
+ print("1. Testing transfer_to_agent with function_call_output events:")
196
+ print(f"Current agent: {runner.agent.name}")
197
+
198
+ # Simulate transfer_to_agent call
199
+
200
+ transfer_call = ToolCall(
201
+ type="function",
202
+ id="transfer_001",
203
+ function=ToolCallFunction(
204
+ name="transfer_to_agent",
205
+ arguments=json.dumps({"name": "WeatherAgent"}),
206
+ ),
207
+ index=0,
208
+ )
209
+
210
+ # Handle transfer and collect events
211
+ chunks = [chunk async for chunk in runner._handle_tool_calls([transfer_call], ["function_call_output"])]
212
+
213
+ print(f"Events generated: {len(chunks)}")
214
+ for i, chunk in enumerate(chunks):
215
+ if isinstance(chunk, FunctionCallOutputEvent):
216
+ print(f" Event {i + 1}: {chunk.type} - {chunk.content}")
217
+ else:
218
+ print(f" Event {i + 1}: {chunk.type}")
219
+
220
+ print(f"Agent after transfer: {runner.agent.name}")
221
+
222
+ print("\n2. Testing transfer_to_parent with function_call_output events:")
223
+
224
+ parent_transfer_call = ToolCall(
225
+ type="function",
226
+ id="transfer_002",
227
+ function=ToolCallFunction(
228
+ name="transfer_to_parent",
229
+ arguments="{}",
230
+ ),
231
+ index=0,
232
+ )
233
+
234
+ # Handle parent transfer and collect events
235
+ chunks = [chunk async for chunk in runner._handle_tool_calls([parent_transfer_call], ["function_call_output"])]
236
+
237
+ print(f"Events generated: {len(chunks)}")
238
+ for i, chunk in enumerate(chunks):
239
+ if isinstance(chunk, FunctionCallOutputEvent):
240
+ print(f" Event {i + 1}: {chunk.type} - {chunk.content}")
241
+ else:
242
+ print(f" Event {i + 1}: {chunk.type}")
243
+
244
+ print(f"Agent after parent transfer: {runner.agent.name}")
245
+
246
+ print("\n3. Testing multiple transfers (only first executes):")
247
+
248
+ # Multiple transfer calls
249
+ transfer_call_1 = ToolCall(
250
+ type="function",
251
+ id="multi_001",
252
+ function=ToolCallFunction(
253
+ name="transfer_to_agent",
254
+ arguments=json.dumps({"name": "TravelAgent"}),
255
+ ),
256
+ index=0,
257
+ )
258
+
259
+ transfer_call_2 = ToolCall(
260
+ type="function",
261
+ id="multi_002",
262
+ function=ToolCallFunction(
263
+ name="transfer_to_agent",
264
+ arguments=json.dumps({"name": "WeatherAgent"}),
265
+ ),
266
+ index=1,
267
+ )
268
+
269
+ chunks = [chunk async for chunk in runner._handle_tool_calls([transfer_call_1, transfer_call_2], ["function_call_output"])]
270
+
271
+ print(f"Events generated: {len(chunks)}")
272
+ for i, chunk in enumerate(chunks):
273
+ if isinstance(chunk, FunctionCallOutputEvent):
274
+ print(f" Event {i + 1}: {chunk.content}")
275
+ else:
276
+ print(f" Event {i + 1}: {chunk.type}")
277
+
278
+ print(f"Final agent: {runner.agent.name}")
279
+
280
+
281
+ async def main():
282
+ """Run both demos"""
283
+ print("🚀 Demo: New LiteAgent Features\n")
284
+
285
+ # Demo 1: Cancellation of pending tools
286
+ await demo_1_cancel_pending_tools()
287
+
288
+ # Demo 2: Transfer events
289
+ await demo_2_transfer_events()
290
+
291
+ print("\n✅ All demos completed!")
292
+ print("\nKey takeaways:")
293
+ print("1. Pending tool calls are automatically cancelled when user provides new input")
294
+ print("2. Cancellation now generates function_call_output events (not just history records)")
295
+ print("3. Transfer operations generate function_call_output events like regular tools")
296
+ print("4. Multiple transfers in one call: only the first executes, others get 'already executed' message")
297
+ print("5. Both cancellation and transfer events are yielded through the run() method")
298
+
299
+
300
+ if __name__ == "__main__":
301
+ asyncio.run(main())
@@ -48,7 +48,7 @@ async def main():
48
48
  )
49
49
  async for chunk in resp:
50
50
  logger.info(chunk)
51
- resp = runner.run_continue_stream(
51
+ resp = runner.run(
52
52
  includes=["usage", "assistant_message", "function_call", "function_call_output"],
53
53
  record_to="tests/mocks/confirm_and_continue/2.jsonl",
54
54
  )
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Debug example to investigate non-streaming mode issues.
3
3
  """
4
+
4
5
  import asyncio
5
6
  import logging
6
7
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Debug with full logging enabled.
3
3
  """
4
+
4
5
  import asyncio
5
6
  import logging
6
7
 
@@ -70,7 +70,7 @@ async def main():
70
70
  )
71
71
  async for message in resp:
72
72
  logger.info(message)
73
- print(f"{runner.get_messages_dict()}")
73
+ print(f"{runner.get_messages()}")
74
74
  logger.info(runner.agent.name)
75
75
 
76
76
 
@@ -0,0 +1,67 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from rich.logging import RichHandler
5
+
6
+ from lite_agent.agent import Agent
7
+ from lite_agent.chat_display import display_messages
8
+ from lite_agent.runner import Runner
9
+
10
+ logging.basicConfig(
11
+ level=logging.WARNING,
12
+ format="%(message)s",
13
+ datefmt="[%X]",
14
+ handlers=[RichHandler(rich_tracebacks=True)],
15
+ )
16
+
17
+ logger = logging.getLogger("lite_agent")
18
+ logger.setLevel(logging.DEBUG)
19
+
20
+
21
+ def list_knowledges() -> list[str]:
22
+ """
23
+ 列出系统中存在的知识,返回的是知识的标题
24
+ """
25
+ return ["苹果的价格的计算方法", "香蕉的价格", "茄子的价格", "芒果的价格", "其他水果蔬菜的价格"]
26
+
27
+
28
+ def read_knowledge(knowledge: str) -> str:
29
+ """
30
+ 通过知识的标题获取其内容
31
+ """
32
+ match knowledge:
33
+ case "苹果的价格的计算方法":
34
+ return "苹果的价格是两倍的香蕉的价格减去茄子的价格"
35
+ case "香蕉的价格":
36
+ return "香蕉的价格为3元"
37
+ case "其他水果蔬菜的价格":
38
+ return "茄子的价格为5元"
39
+ case "茄子的价格":
40
+ return "茄子的价格请参阅其他知识库"
41
+ case "芒果的价格":
42
+ return "芒果的价格为7元"
43
+ case _:
44
+ return "不存在的知识"
45
+
46
+
47
+ agent = Agent(
48
+ model="gpt-5-mini",
49
+ name="Assistant",
50
+ instructions="你是一个有帮助的助手。",
51
+ tools=[list_knowledges, read_knowledge],
52
+ reasoning={"effort": "minimal"},
53
+ )
54
+
55
+
56
+ async def main():
57
+ runner = Runner(agent, streaming=True)
58
+ await runner.run_until_complete(
59
+ "苹果的价格是多少?查询知识库告诉我答案。",
60
+ includes=["usage", "assistant_message", "function_call", "function_call_output", "timing"],
61
+ )
62
+
63
+ display_messages(runner.messages)
64
+
65
+
66
+ if __name__ == "__main__":
67
+ asyncio.run(main())
@@ -72,7 +72,7 @@ async def main():
72
72
  logger.info(chunk)
73
73
  display_messages(runner1.messages)
74
74
 
75
- print("\n" + "="*50 + "\n")
75
+ print("\n" + "=" * 50 + "\n")
76
76
 
77
77
  # Test agent with creative settings (high temperature, longer responses)
78
78
  print("=== Testing Agent 2 (Creative Settings) ===")
@@ -1,7 +1,9 @@
1
1
  """
2
2
  Simple example demonstrating non-streaming mode in LiteAgent.
3
3
  """
4
+
4
5
  import asyncio
6
+ from datetime import datetime, timezone
5
7
 
6
8
  from lite_agent import Agent, Runner
7
9
 
@@ -32,8 +34,7 @@ async def main():
32
34
  # Example with a simple tool
33
35
  def get_time() -> str:
34
36
  """Get the current time."""
35
- from datetime import datetime
36
- return f"Current time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
37
+ return f"Current time: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}"
37
38
 
38
39
  agent_with_tools = Agent(
39
40
  name="TimeAgent",
@@ -75,9 +75,9 @@ async def main():
75
75
  """主演示函数。"""
76
76
  await demo_reasoning_configurations()
77
77
 
78
- print("\n" + "="*60)
78
+ print("\n" + "=" * 60)
79
79
  print("推理配置使用说明:")
80
- print("="*60)
80
+ print("=" * 60)
81
81
  print("""
82
82
  1. reasoning_effort 参数 (OpenAI兼容):
83
83
  - "minimal": 最小推理,快速响应
@@ -9,6 +9,8 @@ to the legacy Completion API format when making actual LLM calls.
9
9
 
10
10
  import asyncio
11
11
 
12
+ from pydantic import BaseModel
13
+
12
14
  from lite_agent import Agent, Runner
13
15
  from lite_agent.types import ResponseInputImage, ResponseInputText
14
16
 
@@ -84,7 +86,7 @@ async def main():
84
86
  )
85
87
 
86
88
  # This will raise an error when trying to convert
87
- converted_messages = agent._convert_responses_to_completions_format(runner.messages) # noqa: SLF001
89
+ converted_messages = agent._convert_responses_to_completions_format(runner.messages)
88
90
  print("❌ This should not be reached!")
89
91
 
90
92
  except ValueError as e:
@@ -96,7 +98,7 @@ async def main():
96
98
  print("\n=== Internal message representation ===")
97
99
  for i, message in enumerate(runner.messages):
98
100
  print(f"Message {i + 1}:")
99
- if hasattr(message, "model_dump"):
101
+ if isinstance(message, BaseModel):
100
102
  print(f" {message.model_dump()}")
101
103
  else:
102
104
  print(f" {message}")
@@ -106,7 +108,7 @@ async def main():
106
108
  print("\n=== Converted messages for LLM API ===")
107
109
  # Note: In a real application, this conversion happens automatically
108
110
  # We're accessing the private method here just for demonstration
109
- converted_messages = agent._convert_responses_to_completions_format(runner.messages) # noqa: SLF001
111
+ converted_messages = agent._convert_responses_to_completions_format(runner.messages)
110
112
  for i, message in enumerate(converted_messages):
111
113
  print(f"Converted Message {i + 1}:")
112
114
  print(f" {message}")
@@ -1,7 +1,9 @@
1
1
  """
2
2
  Simple debug to check non-streaming response.
3
3
  """
4
+
4
5
  import asyncio
6
+ import traceback
5
7
 
6
8
  from lite_agent import Agent, Runner
7
9
 
@@ -28,7 +30,6 @@ async def main():
28
30
  print(f"First chunk: {chunks[0]}")
29
31
  except Exception as e:
30
32
  print(f"Error: {e}")
31
- import traceback
32
33
  traceback.print_exc()
33
34
 
34
35
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Simple debug to check which API is being used.
3
3
  """
4
+
4
5
  import asyncio
5
6
 
6
7
  from lite_agent import Agent, Runner