lite-agent 0.3.0__py3-none-any.whl → 0.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -1,5 +1,6 @@
1
- from lite_agent.stream_handlers.litellm import litellm_stream_handler
1
+ from lite_agent.stream_handlers.litellm import litellm_completion_stream_handler, litellm_response_stream_handler
2
2
 
3
3
  __all__ = [
4
- "litellm_stream_handler",
4
+ "litellm_completion_stream_handler",
5
+ "litellm_response_stream_handler",
5
6
  ]
@@ -1,94 +1,47 @@
1
1
  from collections.abc import AsyncGenerator
2
2
  from pathlib import Path
3
+ from typing import TYPE_CHECKING
3
4
 
4
5
  import aiofiles
5
6
  import litellm
6
- from aiofiles.threadpool.text import AsyncTextIOWrapper
7
- from litellm.types.utils import Delta, ModelResponseStream, StreamingChoices
7
+ from litellm.types.llms.openai import ResponsesAPIStreamingResponse
8
+ from litellm.types.utils import ModelResponseStream
9
+ from pydantic import BaseModel
8
10
 
9
11
  from lite_agent.loggers import logger
10
- from lite_agent.processors import StreamChunkProcessor
11
- from lite_agent.types import AgentChunk, CompletionRawChunk, ContentDeltaChunk, FinalMessageChunk, ToolCallDeltaChunk, UsageChunk
12
+ from lite_agent.processors import CompletionEventProcessor, ResponseEventProcessor
13
+ from lite_agent.types import AgentChunk
12
14
 
15
+ if TYPE_CHECKING:
16
+ from aiofiles.threadpool.text import AsyncTextIOWrapper
13
17
 
14
- def ensure_record_file(record_to: Path | None) -> Path | None:
18
+
19
+ def ensure_record_file(record_to: Path | str | None) -> Path | None:
15
20
  if not record_to:
16
21
  return None
17
- if not record_to.parent.exists():
18
- logger.warning('Record directory "%s" does not exist, creating it.', record_to.parent)
19
- record_to.parent.mkdir(parents=True, exist_ok=True)
20
- return record_to
21
-
22
-
23
- async def process_chunk(
24
- processor: StreamChunkProcessor,
25
- chunk: ModelResponseStream,
26
- record_file: AsyncTextIOWrapper | None = None,
27
- ) -> AsyncGenerator[AgentChunk, None]:
28
- if record_file:
29
- await record_file.write(chunk.model_dump_json() + "\n")
30
- await record_file.flush()
31
- yield CompletionRawChunk(type="completion_raw", raw=chunk)
32
- usage_chunk = await handle_usage_chunk(processor, chunk)
33
- if usage_chunk:
34
- yield usage_chunk
35
- return
36
- if not chunk.choices:
37
- return
38
- choice = chunk.choices[0]
39
- delta = choice.delta
40
- for result in await handle_content_and_tool_calls(processor, chunk, choice, delta):
41
- yield result
42
- if choice.finish_reason:
43
- current_message = processor.current_message
44
- yield FinalMessageChunk(type="final_message", message=current_message, finish_reason=choice.finish_reason)
45
22
 
23
+ path = Path(record_to) if isinstance(record_to, str) else record_to
46
24
 
47
- async def handle_usage_chunk(processor: StreamChunkProcessor, chunk: ModelResponseStream) -> UsageChunk | None:
48
- usage = processor.handle_usage_info(chunk)
49
- if usage:
50
- return UsageChunk(type="usage", usage=usage)
51
- return None
25
+ # If the path is a directory, generate a filename
26
+ if path.is_dir():
27
+ path = path / "conversation.jsonl"
52
28
 
29
+ # Ensure parent directory exists
30
+ if not path.parent.exists():
31
+ logger.warning('Record directory "%s" does not exist, creating it.', path.parent)
32
+ path.parent.mkdir(parents=True, exist_ok=True)
53
33
 
54
- async def handle_content_and_tool_calls(
55
- processor: StreamChunkProcessor,
56
- chunk: ModelResponseStream,
57
- choice: StreamingChoices,
58
- delta: Delta,
59
- ) -> list[AgentChunk]:
60
- results: list[AgentChunk] = []
61
- if not processor.is_initialized:
62
- processor.initialize_message(chunk, choice)
63
- if delta.content:
64
- results.append(ContentDeltaChunk(type="content_delta", delta=delta.content))
65
- processor.update_content(delta.content)
66
- if delta.tool_calls is not None:
67
- processor.update_tool_calls(delta.tool_calls)
68
- if delta.tool_calls and processor.current_message.tool_calls:
69
- results.extend(
70
- [
71
- ToolCallDeltaChunk(
72
- type="tool_call_delta",
73
- tool_call_id=processor.current_message.tool_calls[-1].id,
74
- name=processor.current_message.tool_calls[-1].function.name,
75
- arguments_delta=tool_call.function.arguments or "",
76
- )
77
- for tool_call in delta.tool_calls
78
- if tool_call.function.arguments
79
- ],
80
- )
81
- return results
34
+ return path
82
35
 
83
36
 
84
- async def litellm_stream_handler(
37
+ async def litellm_completion_stream_handler(
85
38
  resp: litellm.CustomStreamWrapper,
86
- record_to: Path | None = None,
39
+ record_to: Path | str | None = None,
87
40
  ) -> AsyncGenerator[AgentChunk, None]:
88
41
  """
89
42
  Optimized chunk handler
90
43
  """
91
- processor = StreamChunkProcessor()
44
+ processor = CompletionEventProcessor()
92
45
  record_file: AsyncTextIOWrapper | None = None
93
46
  record_path = ensure_record_file(record_to)
94
47
  if record_path:
@@ -99,7 +52,32 @@ async def litellm_stream_handler(
99
52
  logger.warning("unexpected chunk type: %s", type(chunk))
100
53
  logger.warning("chunk content: %s", chunk)
101
54
  continue
102
- async for result in process_chunk(processor, chunk, record_file):
55
+ async for result in processor.process_chunk(chunk, record_file):
56
+ yield result
57
+ finally:
58
+ if record_file:
59
+ await record_file.close()
60
+
61
+
62
+ async def litellm_response_stream_handler(
63
+ resp: AsyncGenerator[ResponsesAPIStreamingResponse, None],
64
+ record_to: Path | str | None = None,
65
+ ) -> AsyncGenerator[AgentChunk, None]:
66
+ """
67
+ Response API stream handler for processing ResponsesAPIStreamingResponse chunks
68
+ """
69
+ processor = ResponseEventProcessor()
70
+ record_file: AsyncTextIOWrapper | None = None
71
+ record_path = ensure_record_file(record_to)
72
+ if record_path:
73
+ record_file = await aiofiles.open(record_path, "w", encoding="utf-8")
74
+ try:
75
+ async for chunk in resp:
76
+ if not isinstance(chunk, BaseModel):
77
+ logger.warning("unexpected chunk type: %s", type(chunk))
78
+ logger.warning("chunk content: %s", chunk)
79
+ continue
80
+ async for result in processor.process_chunk(chunk, record_file):
103
81
  yield result
104
82
  finally:
105
83
  if record_file:
@@ -1,39 +1,70 @@
1
1
  # Export all types from submodules
2
- from .chunks import (
2
+ from .events import (
3
3
  AgentChunk,
4
4
  AgentChunkType,
5
- CompletionRawChunk,
6
- ContentDeltaChunk,
7
- FinalMessageChunk,
8
- ToolCallChunk,
9
- ToolCallDeltaChunk,
10
- ToolCallResultChunk,
11
- UsageChunk,
5
+ AssistantMessageEvent,
6
+ CompletionRawEvent,
7
+ ContentDeltaEvent,
8
+ FunctionCallDeltaEvent,
9
+ FunctionCallEvent,
10
+ FunctionCallOutputEvent,
11
+ ResponseRawEvent,
12
+ Timing,
13
+ TimingEvent,
14
+ UsageEvent,
15
+ )
16
+ from .events import (
17
+ Usage as EventUsage,
12
18
  )
13
19
  from .messages import (
20
+ # Legacy compatibility aliases (temporary)
14
21
  AgentAssistantMessage,
15
- AgentFunctionCallOutput,
16
- AgentFunctionToolCallMessage,
17
- AgentMessage,
18
22
  AgentSystemMessage,
19
23
  AgentUserMessage,
20
24
  AssistantMessage,
25
+ # New types
26
+ AssistantMessageContent,
21
27
  AssistantMessageDict,
28
+ AssistantMessageMeta,
29
+ AssistantTextContent,
30
+ AssistantToolCall,
31
+ AssistantToolCallResult,
32
+ BasicMessageMeta,
22
33
  FlexibleRunnerMessage,
23
34
  FunctionCallDict,
24
35
  FunctionCallOutputDict,
25
- Message,
36
+ LLMResponseMeta,
26
37
  MessageDict,
38
+ # New metadata types
39
+ MessageMeta,
40
+ MessageUsage,
41
+ NewAssistantMessage,
42
+ NewMessage,
43
+ NewMessages,
44
+ NewSystemMessage,
45
+ # New structured message types
46
+ NewUserMessage,
27
47
  ResponseInputImage,
28
48
  ResponseInputText,
29
49
  RunnerMessage,
30
50
  RunnerMessages,
31
51
  SystemMessageDict,
52
+ UserFileContent,
53
+ UserImageContent,
32
54
  UserInput,
55
+ # New content types
56
+ UserMessageContent,
33
57
  UserMessageContentItemImageURL,
34
58
  UserMessageContentItemImageURLImageURL,
35
59
  UserMessageContentItemText,
36
60
  UserMessageDict,
61
+ UserTextContent,
62
+ # Utility functions
63
+ assistant_message_to_llm_dict,
64
+ message_to_llm_dict,
65
+ messages_to_llm_format,
66
+ system_message_to_llm_dict,
67
+ user_message_to_llm_dict,
37
68
  )
38
69
  from .tool_calls import ToolCall, ToolCallFunction
39
70
 
@@ -41,35 +72,58 @@ __all__ = [
41
72
  "AgentAssistantMessage",
42
73
  "AgentChunk",
43
74
  "AgentChunkType",
44
- "AgentFunctionCallOutput",
45
- "AgentFunctionToolCallMessage",
46
- "AgentMessage",
47
75
  "AgentSystemMessage",
48
76
  "AgentUserMessage",
49
77
  "AssistantMessage",
78
+ "AssistantMessageContent",
50
79
  "AssistantMessageDict",
51
- "CompletionRawChunk",
52
- "ContentDeltaChunk",
53
- "FinalMessageChunk",
80
+ "AssistantMessageEvent",
81
+ "AssistantMessageMeta",
82
+ "AssistantTextContent",
83
+ "AssistantToolCall",
84
+ "AssistantToolCallResult",
85
+ "BasicMessageMeta",
86
+ "CompletionRawEvent",
87
+ "ContentDeltaEvent",
88
+ "EventUsage",
54
89
  "FlexibleRunnerMessage",
90
+ "FunctionCallDeltaEvent",
55
91
  "FunctionCallDict",
92
+ "FunctionCallEvent",
56
93
  "FunctionCallOutputDict",
57
- "Message",
94
+ "FunctionCallOutputEvent",
95
+ "LLMResponseMeta",
58
96
  "MessageDict",
97
+ "MessageMeta",
98
+ "MessageUsage",
99
+ "NewAssistantMessage",
100
+ "NewMessage",
101
+ "NewMessages",
102
+ "NewSystemMessage",
103
+ "NewUserMessage",
59
104
  "ResponseInputImage",
60
105
  "ResponseInputText",
106
+ "ResponseRawEvent",
61
107
  "RunnerMessage",
62
108
  "RunnerMessages",
63
109
  "SystemMessageDict",
110
+ "Timing",
111
+ "TimingEvent",
64
112
  "ToolCall",
65
- "ToolCallChunk",
66
- "ToolCallDeltaChunk",
67
113
  "ToolCallFunction",
68
- "ToolCallResultChunk",
69
- "UsageChunk",
114
+ "UsageEvent",
115
+ "UserFileContent",
116
+ "UserImageContent",
70
117
  "UserInput",
118
+ "UserMessageContent",
71
119
  "UserMessageContentItemImageURL",
72
120
  "UserMessageContentItemImageURLImageURL",
73
121
  "UserMessageContentItemText",
74
122
  "UserMessageDict",
123
+ "UserTextContent",
124
+ "assistant_message_to_llm_dict",
125
+ "message_to_llm_dict",
126
+ "messages_to_llm_format",
127
+ "system_message_to_llm_dict",
128
+ "user_message_to_llm_dict",
75
129
  ]
@@ -0,0 +1,119 @@
1
+ from typing import Literal
2
+
3
+ from litellm.types.utils import ModelResponseStream
4
+ from pydantic import BaseModel
5
+
6
+ from .messages import NewAssistantMessage
7
+
8
+
9
+ class Usage(BaseModel):
10
+ input_tokens: int
11
+ output_tokens: int
12
+
13
+
14
+ class Timing(BaseModel):
15
+ latency_ms: int
16
+ output_time_ms: int
17
+
18
+
19
+ class CompletionRawEvent(BaseModel):
20
+ """
21
+ Define the type of chunk
22
+ """
23
+
24
+ type: Literal["completion_raw"] = "completion_raw"
25
+ raw: ModelResponseStream
26
+
27
+
28
+ class ResponseRawEvent(BaseModel):
29
+ """
30
+ Define the type of response raw chunk
31
+ """
32
+
33
+ type: Literal["response_raw"] = "response_raw"
34
+ raw: object
35
+
36
+
37
+ class UsageEvent(BaseModel):
38
+ """
39
+ Define the type of usage info chunk
40
+ """
41
+
42
+ type: Literal["usage"] = "usage"
43
+ usage: Usage
44
+
45
+
46
+ class TimingEvent(BaseModel):
47
+ """
48
+ Define the type of timing info chunk
49
+ """
50
+
51
+ type: Literal["timing"] = "timing"
52
+ timing: Timing
53
+
54
+
55
+ class AssistantMessageEvent(BaseModel):
56
+ """
57
+ Define the type of assistant message chunk
58
+ """
59
+
60
+ type: Literal["assistant_message"] = "assistant_message"
61
+ message: NewAssistantMessage
62
+
63
+
64
+ class FunctionCallEvent(BaseModel):
65
+ """
66
+ Define the type of tool call chunk
67
+ """
68
+
69
+ type: Literal["function_call"] = "function_call"
70
+ call_id: str
71
+ name: str
72
+ arguments: str
73
+
74
+
75
+ class FunctionCallOutputEvent(BaseModel):
76
+ """
77
+ Define the type of tool call result chunk
78
+ """
79
+
80
+ type: Literal["function_call_output"] = "function_call_output"
81
+ tool_call_id: str
82
+ name: str
83
+ content: str
84
+ execution_time_ms: int | None = None
85
+
86
+
87
+ class ContentDeltaEvent(BaseModel):
88
+ """
89
+ Define the type of message chunk
90
+ """
91
+
92
+ type: Literal["content_delta"] = "content_delta"
93
+ delta: str
94
+
95
+
96
+ class FunctionCallDeltaEvent(BaseModel):
97
+ """
98
+ Define the type of tool call delta chunk
99
+ """
100
+
101
+ type: Literal["function_call_delta"] = "function_call_delta"
102
+ tool_call_id: str
103
+ name: str
104
+ arguments_delta: str
105
+
106
+
107
+ AgentChunk = CompletionRawEvent | ResponseRawEvent | UsageEvent | TimingEvent | FunctionCallEvent | FunctionCallOutputEvent | ContentDeltaEvent | FunctionCallDeltaEvent | AssistantMessageEvent
108
+
109
+ AgentChunkType = Literal[
110
+ "completion_raw",
111
+ "response_raw",
112
+ "usage",
113
+ "timing",
114
+ "function_call",
115
+ "function_call_output",
116
+ "content_delta",
117
+ "function_call_delta",
118
+ "assistant_message",
119
+ ]