lite-agent 0.6.0__tar.gz → 0.8.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.
- {lite_agent-0.6.0 → lite_agent-0.8.0}/.claude/settings.local.json +4 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/CHANGELOG.md +30 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/PKG-INFO +2 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/basic.py +3 -7
- lite_agent-0.8.0/examples/cancel_and_transfer_demo.py +299 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/confirm_and_continue.py +1 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/debug_non_streaming.py +1 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/debug_with_logging.py +1 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/handoffs.py +1 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/llm_config_demo.py +1 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/non_streaming.py +2 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/reasoning_example.py +2 -2
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/response_api_example.py +3 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/simple_debug.py +2 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/simple_debug2.py +1 -0
- lite_agent-0.8.0/examples/stop_before_functions.py +114 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/streaming_demo.py +1 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/pyproject.toml +3 -1
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/agent.py +177 -42
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/chat_display.py +21 -13
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/client.py +4 -0
- lite_agent-0.8.0/src/lite_agent/constants.py +30 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/message_transfers.py +3 -3
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/processors/completion_event_processor.py +14 -20
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/processors/response_event_processor.py +21 -15
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/response_handlers/__init__.py +1 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/response_handlers/base.py +17 -9
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/response_handlers/completion.py +35 -7
- lite_agent-0.8.0/src/lite_agent/response_handlers/responses.py +76 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/runner.py +302 -246
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/types/__init__.py +2 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/types/messages.py +6 -5
- lite_agent-0.8.0/src/lite_agent/utils/__init__.py +0 -0
- lite_agent-0.8.0/src/lite_agent/utils/message_builder.py +211 -0
- lite_agent-0.8.0/src/lite_agent/utils/metrics.py +50 -0
- lite_agent-0.8.0/temp/main.py +36 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/mocks/confirm_and_continue/1.jsonl +21 -21
- lite_agent-0.8.0/tests/mocks/confirm_and_continue/2.jsonl +48 -0
- lite_agent-0.8.0/tests/performance/test_set_chat_history_performance.py +142 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_agent.py +1 -5
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_agent_handoffs.py +17 -4
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_append_message.py +18 -51
- lite_agent-0.8.0/tests/unit/test_cancel_pending_tools.py +233 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_message_transfers.py +19 -10
- lite_agent-0.8.0/tests/unit/test_response_api_format.py +130 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_runner.py +5 -5
- lite_agent-0.8.0/tests/unit/test_set_chat_history.py +198 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_stream_handlers_additional.py +1 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_streaming_config.py +9 -4
- {lite_agent-0.6.0 → lite_agent-0.8.0}/uv.lock +133 -130
- lite_agent-0.6.0/src/lite_agent/response_handlers/responses.py +0 -42
- lite_agent-0.6.0/tests/mocks/confirm_and_continue/2.jsonl +0 -37
- lite_agent-0.6.0/tests/performance/test_set_chat_history_performance.py +0 -130
- lite_agent-0.6.0/tests/unit/test_response_api_format.py +0 -290
- lite_agent-0.6.0/tests/unit/test_set_chat_history.py +0 -354
- {lite_agent-0.6.0 → lite_agent-0.8.0}/.github/workflows/ci.yml +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/.gitignore +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/.python-version +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/.vscode/launch.json +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/CLAUDE.md +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/README.md +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/basic_agent.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/basic_model.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/channels/rich_channel.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/chat_display_demo.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/consolidate_history.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/context.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/image.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/message_transfer_example.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/message_transfer_example_new.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/new_message_structure_demo.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/responses.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/set_chat_history_example.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/stop_with_tool_call.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/terminal.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/translate/main.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/translate/prompts/translation_system.md.j2 +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/translate.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/examples/type_system_example.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/scripts/record_chat_messages.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/__init__.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/loggers.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/processors/__init__.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/py.typed +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/stream_handlers/__init__.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/stream_handlers/litellm.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/templates/handoffs_source_instructions.xml.j2 +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/templates/handoffs_target_instructions.xml.j2 +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/templates/wait_for_user_instructions.xml.j2 +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/types/events.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/src/lite_agent/types/tool_calls.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/integration/test_agent_with_mocks.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/integration/test_basic.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/integration/test_mock_litellm.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/mocks/basic/1.jsonl +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/mocks/context/1.jsonl +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/mocks/handoffs/1.jsonl +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/test_new_messages.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_agent_additional.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_chat_display.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_chat_display_additional.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_completion_condition.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_file_recording.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_litellm_stream_handler.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_message_transfer.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_message_transfers_additional.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_response_event_processor.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_simple_stream_handlers.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/unit/test_stream_chunk_processor.py +0 -0
- {lite_agent-0.6.0 → lite_agent-0.8.0}/tests/utils/mock_litellm.py +0 -0
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## v0.8.0
|
|
2
|
+
|
|
3
|
+
[v0.7.0...v0.8.0](https://github.com/Jannchie/lite-agent/compare/v0.7.0...v0.8.0)
|
|
4
|
+
|
|
5
|
+
### :rocket: Breaking Changes
|
|
6
|
+
|
|
7
|
+
- **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)
|
|
8
|
+
|
|
9
|
+
### :sparkles: Features
|
|
10
|
+
|
|
11
|
+
- **agent**: add dynamic stop-before-functions support - By [Jannchie](mailto:jannchie@gmail.com) in [e7de181](https://github.com/Jannchie/lite-agent/commit/e7de181)
|
|
12
|
+
- **agent**: improve tool call extraction and meta preservation - By [Jannchie](mailto:jannchie@gmail.com) in [1b10296](https://github.com/Jannchie/lite-agent/commit/1b10296)
|
|
13
|
+
- **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)
|
|
14
|
+
- **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)
|
|
15
|
+
|
|
16
|
+
## v0.7.0
|
|
17
|
+
|
|
18
|
+
[v0.6.0...v0.7.0](https://github.com/Jannchie/lite-agent/compare/v0.6.0...v0.7.0)
|
|
19
|
+
|
|
20
|
+
### :sparkles: Features
|
|
21
|
+
|
|
22
|
+
- **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)
|
|
23
|
+
- **message-builder**: support array content in assistant messages - By [Jannchie](mailto:jannchie@gmail.com) in [1b7a790](https://github.com/Jannchie/lite-agent/commit/1b7a790)
|
|
24
|
+
- **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)
|
|
25
|
+
|
|
26
|
+
### :art: Refactors
|
|
27
|
+
|
|
28
|
+
- **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)
|
|
29
|
+
- **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)
|
|
30
|
+
|
|
1
31
|
## v0.6.0
|
|
2
32
|
|
|
3
33
|
[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.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -19,6 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Requires-Dist: aiofiles>=24.1.0
|
|
21
21
|
Requires-Dist: funcall>=0.10.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.
|
|
34
|
+
runner = Runner(agent, streaming=False, api="completion")
|
|
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
|
-
|
|
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__":
|
|
@@ -0,0 +1,299 @@
|
|
|
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 logging
|
|
10
|
+
|
|
11
|
+
from funcall.decorators import tool
|
|
12
|
+
from rich.logging import RichHandler
|
|
13
|
+
|
|
14
|
+
from lite_agent.agent import Agent
|
|
15
|
+
from lite_agent.runner import Runner
|
|
16
|
+
from lite_agent.types import AssistantTextContent, AssistantToolCall, NewAssistantMessage
|
|
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
|
+
@tool
|
|
30
|
+
async def get_weather(city: str) -> str:
|
|
31
|
+
"""Get the weather for a city."""
|
|
32
|
+
await asyncio.sleep(2) # Simulate long operation
|
|
33
|
+
return f"The weather in {city} is sunny with a few clouds."
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@tool
|
|
37
|
+
async def get_temperature(city: str) -> str:
|
|
38
|
+
"""Get the temperature for a city."""
|
|
39
|
+
await asyncio.sleep(2) # Simulate long operation
|
|
40
|
+
return f"The temperature in {city} is 25°C."
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@tool
|
|
44
|
+
async def book_flight(destination: str, date: str) -> str:
|
|
45
|
+
"""Book a flight to a destination."""
|
|
46
|
+
await asyncio.sleep(3) # Simulate very long operation
|
|
47
|
+
return f"Flight booked to {destination} on {date}"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def demo_1_cancel_pending_tools():
|
|
51
|
+
"""Demo 1: Cancellation of pending tool calls"""
|
|
52
|
+
print("=== Demo 1: Cancellation of Pending Tool Calls ===\n")
|
|
53
|
+
|
|
54
|
+
agent = Agent(
|
|
55
|
+
model="gpt-4.1-nano",
|
|
56
|
+
name="WeatherBot",
|
|
57
|
+
instructions="You are a helpful weather assistant.",
|
|
58
|
+
tools=[get_weather, get_temperature, book_flight],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
runner = Runner(agent)
|
|
62
|
+
|
|
63
|
+
# Simulate a scenario where the agent made tool calls but user interrupts
|
|
64
|
+
print("1. Simulating assistant making tool calls...")
|
|
65
|
+
assistant_message = NewAssistantMessage(
|
|
66
|
+
content=[
|
|
67
|
+
AssistantTextContent(text="I'll check the weather and temperature for you, and also help you book that flight."),
|
|
68
|
+
AssistantToolCall(
|
|
69
|
+
call_id="weather_call",
|
|
70
|
+
name="get_weather",
|
|
71
|
+
arguments='{"city": "Tokyo"}',
|
|
72
|
+
),
|
|
73
|
+
AssistantToolCall(
|
|
74
|
+
call_id="temp_call",
|
|
75
|
+
name="get_temperature",
|
|
76
|
+
arguments='{"city": "Tokyo"}',
|
|
77
|
+
),
|
|
78
|
+
AssistantToolCall(
|
|
79
|
+
call_id="flight_call",
|
|
80
|
+
name="book_flight",
|
|
81
|
+
arguments='{"destination": "Paris", "date": "2024-12-25"}',
|
|
82
|
+
),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
runner.messages.append(assistant_message)
|
|
87
|
+
|
|
88
|
+
# Check pending calls
|
|
89
|
+
pending_calls = runner._find_pending_tool_calls()
|
|
90
|
+
print(f"Pending tool calls: {len(pending_calls)}")
|
|
91
|
+
for call in pending_calls:
|
|
92
|
+
print(f" - {call.name} (call_id: {call.call_id})")
|
|
93
|
+
|
|
94
|
+
print(f"Total messages before cancellation: {len(runner.messages)}")
|
|
95
|
+
print(f"Content items in assistant message: {len(assistant_message.content)}")
|
|
96
|
+
|
|
97
|
+
# User provides new input - this should cancel pending calls and generate events
|
|
98
|
+
print("\n2. User provides new input: 'Actually, never mind about the weather. What's the capital of Japan?'")
|
|
99
|
+
|
|
100
|
+
print("\n2a. Testing via run() method (integrated flow with event yielding):")
|
|
101
|
+
# Test the integrated flow - collect cancellation events from run()
|
|
102
|
+
# This will automatically call _cancel_pending_tool_calls() and yield events
|
|
103
|
+
chunks = []
|
|
104
|
+
try:
|
|
105
|
+
async for chunk in runner.run("What's the capital of Japan?", includes=["function_call_output"]):
|
|
106
|
+
chunks.append(chunk)
|
|
107
|
+
if len(chunks) >= 3: # Stop after getting cancellation events
|
|
108
|
+
break
|
|
109
|
+
except Exception:
|
|
110
|
+
# Expected - no real LLM configured
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
print(f"Events from run() method: {len(chunks)}")
|
|
114
|
+
for i, chunk in enumerate(chunks):
|
|
115
|
+
if chunk.type == "function_call_output":
|
|
116
|
+
print(f" - Chunk {i + 1}: {chunk.type} for {chunk.tool_call_id}")
|
|
117
|
+
print(f" Tool: {chunk.name}")
|
|
118
|
+
print(f" Content: {chunk.content}")
|
|
119
|
+
|
|
120
|
+
# Now demonstrate the direct method on fresh data
|
|
121
|
+
print("\n2b. Testing direct cancellation method (returns events):")
|
|
122
|
+
# Create a new runner with fresh pending calls
|
|
123
|
+
runner2 = Runner(agent)
|
|
124
|
+
runner2.messages.append(
|
|
125
|
+
NewAssistantMessage(
|
|
126
|
+
content=[
|
|
127
|
+
AssistantTextContent(text="Let me help with a different task."),
|
|
128
|
+
AssistantToolCall(
|
|
129
|
+
call_id="new_call_1",
|
|
130
|
+
name="get_weather",
|
|
131
|
+
arguments='{"city": "London"}',
|
|
132
|
+
),
|
|
133
|
+
AssistantToolCall(
|
|
134
|
+
call_id="new_call_2",
|
|
135
|
+
name="get_temperature",
|
|
136
|
+
arguments='{"city": "London"}',
|
|
137
|
+
),
|
|
138
|
+
],
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
cancellation_events = runner2._cancel_pending_tool_calls()
|
|
143
|
+
print(f"Cancellation events generated: {len(cancellation_events)}")
|
|
144
|
+
for event in cancellation_events:
|
|
145
|
+
print(f" - Event: {event.type} for {event.tool_call_id} ({event.name})")
|
|
146
|
+
print(f" Content: {event.content}")
|
|
147
|
+
print(f" Execution time: {event.execution_time_ms}ms")
|
|
148
|
+
|
|
149
|
+
print("\n3. After cancellation:")
|
|
150
|
+
pending_calls_after = runner._find_pending_tool_calls()
|
|
151
|
+
print(f"Pending tool calls: {len(pending_calls_after)}")
|
|
152
|
+
|
|
153
|
+
print(f"Total messages after cancellation: {len(runner.messages)}")
|
|
154
|
+
if runner.messages:
|
|
155
|
+
assistant_msg = runner.messages[0]
|
|
156
|
+
print(f"Content items in assistant message: {len(assistant_msg.content)}")
|
|
157
|
+
|
|
158
|
+
# Show the cancellation results
|
|
159
|
+
cancellation_results = [item for item in assistant_msg.content if item.type == "tool_call_result"]
|
|
160
|
+
print(f"Cancellation results added: {len(cancellation_results)}")
|
|
161
|
+
for result in cancellation_results:
|
|
162
|
+
print(f" - {result.call_id}: {result.output}")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def demo_2_transfer_events():
|
|
166
|
+
"""Demo 2: function_call_output events for agent transfers"""
|
|
167
|
+
print("\n\n=== Demo 2: Transfer Events ===\n")
|
|
168
|
+
|
|
169
|
+
# Create agents with handoff relationships
|
|
170
|
+
weather_agent = Agent(
|
|
171
|
+
model="gpt-4",
|
|
172
|
+
name="WeatherAgent",
|
|
173
|
+
instructions="You specialize in weather information.",
|
|
174
|
+
tools=[get_weather, get_temperature],
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
travel_agent = Agent(
|
|
178
|
+
model="gpt-4",
|
|
179
|
+
name="TravelAgent",
|
|
180
|
+
instructions="You specialize in travel bookings.",
|
|
181
|
+
tools=[book_flight],
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
main_agent = Agent(
|
|
185
|
+
model="gpt-4",
|
|
186
|
+
name="MainAgent",
|
|
187
|
+
instructions="You are the main agent that coordinates with specialists.",
|
|
188
|
+
handoffs=[weather_agent, travel_agent],
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
runner = Runner(main_agent)
|
|
192
|
+
|
|
193
|
+
print("1. Testing transfer_to_agent with function_call_output events:")
|
|
194
|
+
print(f"Current agent: {runner.agent.name}")
|
|
195
|
+
|
|
196
|
+
# Simulate transfer_to_agent call
|
|
197
|
+
import json
|
|
198
|
+
|
|
199
|
+
from lite_agent.types import ToolCall, ToolCallFunction
|
|
200
|
+
|
|
201
|
+
transfer_call = ToolCall(
|
|
202
|
+
type="function",
|
|
203
|
+
id="transfer_001",
|
|
204
|
+
function=ToolCallFunction(
|
|
205
|
+
name="transfer_to_agent",
|
|
206
|
+
arguments=json.dumps({"name": "WeatherAgent"}),
|
|
207
|
+
),
|
|
208
|
+
index=0,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# Handle transfer and collect events
|
|
212
|
+
chunks = []
|
|
213
|
+
async for chunk in runner._handle_tool_calls([transfer_call], ["function_call_output"]):
|
|
214
|
+
chunks.append(chunk)
|
|
215
|
+
|
|
216
|
+
print(f"Events generated: {len(chunks)}")
|
|
217
|
+
for i, chunk in enumerate(chunks):
|
|
218
|
+
print(f" Event {i + 1}: {chunk.type} - {chunk.content}")
|
|
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 = []
|
|
236
|
+
async for chunk in runner._handle_tool_calls([parent_transfer_call], ["function_call_output"]):
|
|
237
|
+
chunks.append(chunk)
|
|
238
|
+
|
|
239
|
+
print(f"Events generated: {len(chunks)}")
|
|
240
|
+
for i, chunk in enumerate(chunks):
|
|
241
|
+
print(f" Event {i + 1}: {chunk.type} - {chunk.content}")
|
|
242
|
+
|
|
243
|
+
print(f"Agent after parent transfer: {runner.agent.name}")
|
|
244
|
+
|
|
245
|
+
print("\n3. Testing multiple transfers (only first executes):")
|
|
246
|
+
|
|
247
|
+
# Multiple transfer calls
|
|
248
|
+
transfer_call_1 = ToolCall(
|
|
249
|
+
type="function",
|
|
250
|
+
id="multi_001",
|
|
251
|
+
function=ToolCallFunction(
|
|
252
|
+
name="transfer_to_agent",
|
|
253
|
+
arguments=json.dumps({"name": "TravelAgent"}),
|
|
254
|
+
),
|
|
255
|
+
index=0,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
transfer_call_2 = ToolCall(
|
|
259
|
+
type="function",
|
|
260
|
+
id="multi_002",
|
|
261
|
+
function=ToolCallFunction(
|
|
262
|
+
name="transfer_to_agent",
|
|
263
|
+
arguments=json.dumps({"name": "WeatherAgent"}),
|
|
264
|
+
),
|
|
265
|
+
index=1,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
chunks = []
|
|
269
|
+
async for chunk in runner._handle_tool_calls([transfer_call_1, transfer_call_2], ["function_call_output"]):
|
|
270
|
+
chunks.append(chunk)
|
|
271
|
+
|
|
272
|
+
print(f"Events generated: {len(chunks)}")
|
|
273
|
+
for i, chunk in enumerate(chunks):
|
|
274
|
+
print(f" Event {i + 1}: {chunk.content}")
|
|
275
|
+
|
|
276
|
+
print(f"Final agent: {runner.agent.name}")
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
async def main():
|
|
280
|
+
"""Run both demos"""
|
|
281
|
+
print("🚀 Demo: New LiteAgent Features\n")
|
|
282
|
+
|
|
283
|
+
# Demo 1: Cancellation of pending tools
|
|
284
|
+
await demo_1_cancel_pending_tools()
|
|
285
|
+
|
|
286
|
+
# Demo 2: Transfer events
|
|
287
|
+
await demo_2_transfer_events()
|
|
288
|
+
|
|
289
|
+
print("\n✅ All demos completed!")
|
|
290
|
+
print("\nKey takeaways:")
|
|
291
|
+
print("1. Pending tool calls are automatically cancelled when user provides new input")
|
|
292
|
+
print("2. Cancellation now generates function_call_output events (not just history records)")
|
|
293
|
+
print("3. Transfer operations generate function_call_output events like regular tools")
|
|
294
|
+
print("4. Multiple transfers in one call: only the first executes, others get 'already executed' message")
|
|
295
|
+
print("5. Both cancellation and transfer events are yielded through the run() method")
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
if __name__ == "__main__":
|
|
299
|
+
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.
|
|
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
|
)
|
|
@@ -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,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Simple example demonstrating non-streaming mode in LiteAgent.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import asyncio
|
|
5
6
|
|
|
6
7
|
from lite_agent import Agent, Runner
|
|
@@ -33,6 +34,7 @@ async def main():
|
|
|
33
34
|
def get_time() -> str:
|
|
34
35
|
"""Get the current time."""
|
|
35
36
|
from datetime import datetime
|
|
37
|
+
|
|
36
38
|
return f"Current time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
|
37
39
|
|
|
38
40
|
agent_with_tools = Agent(
|
|
@@ -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
|
|
|
@@ -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
|
|
101
|
+
if isinstance(message, BaseModel):
|
|
100
102
|
print(f" {message.model_dump()}")
|
|
101
103
|
else:
|
|
102
104
|
print(f" {message}")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Simple debug to check non-streaming response.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import asyncio
|
|
5
6
|
|
|
6
7
|
from lite_agent import Agent, Runner
|
|
@@ -29,6 +30,7 @@ async def main():
|
|
|
29
30
|
except Exception as e:
|
|
30
31
|
print(f"Error: {e}")
|
|
31
32
|
import traceback
|
|
33
|
+
|
|
32
34
|
traceback.print_exc()
|
|
33
35
|
|
|
34
36
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from funcall.decorators import tool
|
|
5
|
+
from rich.logging import RichHandler
|
|
6
|
+
|
|
7
|
+
from lite_agent.agent import Agent
|
|
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
|
+
async def get_weather(city: str) -> str:
|
|
22
|
+
"""Get the weather for a city."""
|
|
23
|
+
await asyncio.sleep(1)
|
|
24
|
+
return f"The weather in {city} is sunny with a few clouds."
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def get_temperature(city: str) -> str:
|
|
28
|
+
"""Get the temperature for a city."""
|
|
29
|
+
await asyncio.sleep(1)
|
|
30
|
+
return f"The temperature in {city} is 25°C."
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@tool(require_confirmation=True)
|
|
34
|
+
async def send_email(to: str, subject: str) -> str:
|
|
35
|
+
"""Send an email (decorated with require_confirmation=True)."""
|
|
36
|
+
await asyncio.sleep(1)
|
|
37
|
+
return f"Email sent to {to} with subject: {subject}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
async def main():
|
|
41
|
+
# Create agent with stop_before_functions parameter (using callable)
|
|
42
|
+
agent = Agent(
|
|
43
|
+
model="gpt-4.1-nano",
|
|
44
|
+
name="Weather Assistant",
|
|
45
|
+
instructions="You are a helpful weather assistant. Provide friendly and informative responses.",
|
|
46
|
+
tools=[get_weather, get_temperature, send_email],
|
|
47
|
+
stop_before_tools=[get_temperature], # Stop before calling get_temperature (using callable)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
runner = Runner(agent)
|
|
51
|
+
|
|
52
|
+
print("=== Test 1: stop_before_functions in constructor ===")
|
|
53
|
+
resp = runner.run(
|
|
54
|
+
"What is the weather in New York? And what is the temperature there?",
|
|
55
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
56
|
+
)
|
|
57
|
+
async for chunk in resp:
|
|
58
|
+
logger.info(chunk)
|
|
59
|
+
|
|
60
|
+
print(f"\nHas require confirm tools: {await runner.has_require_confirm_tools()}")
|
|
61
|
+
|
|
62
|
+
# Continue execution
|
|
63
|
+
resp = runner.run_continue_stream(
|
|
64
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
65
|
+
)
|
|
66
|
+
async for chunk in resp:
|
|
67
|
+
logger.info(chunk)
|
|
68
|
+
|
|
69
|
+
print("\n=== Test 2: Dynamic function addition (using callable) ===")
|
|
70
|
+
# Add another function dynamically using callable
|
|
71
|
+
agent.add_stop_before_function(get_weather)
|
|
72
|
+
print(f"Stop before functions: {agent.get_stop_before_functions()}")
|
|
73
|
+
|
|
74
|
+
runner2 = Runner(agent)
|
|
75
|
+
resp = runner2.run(
|
|
76
|
+
"What is the weather in Tokyo?",
|
|
77
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
78
|
+
)
|
|
79
|
+
async for chunk in resp:
|
|
80
|
+
logger.info(chunk)
|
|
81
|
+
|
|
82
|
+
print(f"\nHas require confirm tools: {await runner2.has_require_confirm_tools()}")
|
|
83
|
+
|
|
84
|
+
# Continue execution
|
|
85
|
+
resp = runner2.run_continue_stream(
|
|
86
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
87
|
+
)
|
|
88
|
+
async for chunk in resp:
|
|
89
|
+
logger.info(chunk)
|
|
90
|
+
|
|
91
|
+
print("\n=== Test 3: Decorator-based require_confirmation still works ===")
|
|
92
|
+
agent.clear_stop_before_functions()
|
|
93
|
+
print(f"Stop before functions cleared: {agent.get_stop_before_functions()}")
|
|
94
|
+
|
|
95
|
+
runner3 = Runner(agent)
|
|
96
|
+
resp = runner3.run(
|
|
97
|
+
"Send an email to john@example.com with subject 'Weather Update'",
|
|
98
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
99
|
+
)
|
|
100
|
+
async for chunk in resp:
|
|
101
|
+
logger.info(chunk)
|
|
102
|
+
|
|
103
|
+
print(f"\nHas require confirm tools (decorator): {await runner3.has_require_confirm_tools()}")
|
|
104
|
+
|
|
105
|
+
# Continue execution
|
|
106
|
+
resp = runner3.run_continue_stream(
|
|
107
|
+
includes=["usage", "assistant_message", "function_call", "function_call_output"],
|
|
108
|
+
)
|
|
109
|
+
async for chunk in resp:
|
|
110
|
+
logger.info(chunk)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lite-agent"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.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" }]
|
|
@@ -10,6 +10,7 @@ dependencies = [
|
|
|
10
10
|
"funcall>=0.10.0",
|
|
11
11
|
"prompt-toolkit>=3.0.51",
|
|
12
12
|
"rich>=14.0.0",
|
|
13
|
+
"openai<=1.99.5",
|
|
13
14
|
]
|
|
14
15
|
keywords = [
|
|
15
16
|
"function call",
|
|
@@ -89,6 +90,7 @@ ignore = [
|
|
|
89
90
|
"ARG002",
|
|
90
91
|
]
|
|
91
92
|
|
|
93
|
+
|
|
92
94
|
[tool.uv]
|
|
93
95
|
upgrade = true
|
|
94
96
|
package = true
|