agentex-sdk 0.4.6__py3-none-any.whl → 0.4.8__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.
agentex/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "agentex"
4
- __version__ = "0.4.6" # x-release-please-version
4
+ __version__ = "0.4.8" # x-release-please-version
@@ -2,7 +2,7 @@ from typing import AsyncGenerator, Union
2
2
  from agentex.lib.sdk.fastacp.fastacp import FastACP
3
3
  from agentex.lib.types.acp import SendMessageParams
4
4
 
5
- from agentex.lib.types.task_message_updates import TaskMessageUpdate
5
+ from agentex.types.task_message_update import TaskMessageUpdate
6
6
  from agentex.types.task_message_content import TaskMessageContent
7
7
  from agentex.types.text_content import TextContent
8
8
  from agentex.lib.utils.logging import make_logger
@@ -1,4 +1,4 @@
1
- from typing import Any, cast
1
+ from typing import Any, List, cast
2
2
 
3
3
  from agentex import AsyncAgentex
4
4
  from agentex.lib.core.tracing.tracer import AsyncTracer
@@ -78,7 +78,7 @@ class ACPService:
78
78
  task_name: str | None = None,
79
79
  trace_id: str | None = None,
80
80
  parent_span_id: str | None = None,
81
- ) -> TaskMessage:
81
+ ) -> List[TaskMessage]:
82
82
  trace = self._tracer.trace(trace_id=trace_id)
83
83
  async with trace.span(
84
84
  parent_id=parent_span_id,
@@ -115,10 +115,17 @@ class ACPService:
115
115
  else:
116
116
  raise ValueError("Either agent_name or agent_id must be provided")
117
117
 
118
- task_message = TaskMessage.model_validate(json_rpc_response.result)
118
+ task_messages: List[TaskMessage] = []
119
+ if isinstance(json_rpc_response.result, list):
120
+ for message in json_rpc_response.result:
121
+ task_message = TaskMessage.model_validate(message)
122
+ task_messages.append(task_message)
123
+ else:
124
+ task_messages = [TaskMessage.model_validate(json_rpc_response.result)]
125
+
119
126
  if span:
120
- span.output = task_message.model_dump()
121
- return task_message
127
+ span.output = [task_message.model_dump() for task_message in task_messages]
128
+ return task_messages
122
129
 
123
130
  async def event_send(
124
131
  self,
@@ -4,7 +4,7 @@ from typing import Any, Coroutine, cast
4
4
  from agentex import AsyncAgentex
5
5
  from agentex.lib.core.services.adk.streaming import StreamingService
6
6
  from agentex.lib.core.tracing.tracer import AsyncTracer
7
- from agentex.lib.types.task_message_updates import StreamTaskMessageFull, TaskMessageUpdate
7
+ from agentex.types.task_message_update import StreamTaskMessageFull, TaskMessageUpdate
8
8
  from agentex.types.task_message import TaskMessage, TaskMessageContent
9
9
  from agentex.lib.utils.logging import make_logger
10
10
  from agentex.lib.utils.temporal import heartbeat_if_in_workflow
@@ -8,11 +8,11 @@ from agentex.lib.types.llm_messages import (
8
8
  Completion,
9
9
  LLMConfig,
10
10
  )
11
- from agentex.lib.types.task_message_updates import (
11
+ from agentex.types.task_message_update import (
12
12
  StreamTaskMessageDelta,
13
13
  StreamTaskMessageFull,
14
- TextDelta,
15
14
  )
15
+ from agentex.types.task_message_delta import TextDelta
16
16
  from agentex.types.task_message import TaskMessage
17
17
  from agentex.types.task_message_content import TextContent
18
18
  from agentex.lib.utils import logging
@@ -112,6 +112,7 @@ class LiteLLMService:
112
112
  update=StreamTaskMessageFull(
113
113
  parent_task_message=streaming_context.task_message,
114
114
  content=final_content,
115
+ type="full",
115
116
  ),
116
117
  )
117
118
  else:
@@ -221,7 +222,8 @@ class LiteLLMService:
221
222
  await streaming_context.stream_update(
222
223
  update=StreamTaskMessageDelta(
223
224
  parent_task_message=streaming_context.task_message,
224
- delta=TextDelta(text_delta=delta),
225
+ delta=TextDelta(text_delta=delta, type="text"),
226
+ type="delta",
225
227
  ),
226
228
  )
227
229
  heartbeat_if_in_workflow("content chunk streamed")
@@ -244,6 +246,7 @@ class LiteLLMService:
244
246
  update=StreamTaskMessageFull(
245
247
  parent_task_message=streaming_context.task_message,
246
248
  content=final_content,
249
+ type="full",
247
250
  ),
248
251
  )
249
252
 
@@ -11,7 +11,12 @@ from openai.types.responses import (
11
11
  ResponseCompletedEvent,
12
12
  ResponseFunctionToolCall,
13
13
  ResponseOutputItemDoneEvent,
14
+ ResponseReasoningSummaryPartDoneEvent,
14
15
  ResponseTextDeltaEvent,
16
+ ResponseReasoningSummaryTextDeltaEvent,
17
+ ResponseReasoningSummaryTextDoneEvent,
18
+ ResponseReasoningTextDeltaEvent,
19
+ ResponseReasoningTextDoneEvent,
15
20
  )
16
21
  from pydantic import BaseModel
17
22
 
@@ -22,14 +27,18 @@ from agentex.lib.core.services.adk.streaming import (
22
27
  StreamingTaskMessageContext,
23
28
  )
24
29
  from agentex.lib.core.tracing.tracer import AsyncTracer
25
- from agentex.lib.types.task_message_updates import (
30
+ from agentex.types.task_message_update import (
26
31
  StreamTaskMessageDelta,
27
32
  StreamTaskMessageFull,
33
+ )
34
+ from agentex.types.task_message_delta import (
28
35
  TextDelta,
36
+ ReasoningSummaryDelta,
37
+ ReasoningContentDelta,
29
38
  )
30
39
  from agentex.types.task_message_content import (
31
- TextContent,
32
40
  ReasoningContent,
41
+ TextContent,
33
42
  ToolRequestContent,
34
43
  ToolResponseContent,
35
44
  )
@@ -317,6 +326,7 @@ class OpenAIService:
317
326
  update=StreamTaskMessageFull(
318
327
  parent_task_message=streaming_context.task_message,
319
328
  content=text_content,
329
+ type="full",
320
330
  ),
321
331
  )
322
332
 
@@ -341,6 +351,7 @@ class OpenAIService:
341
351
  update=StreamTaskMessageFull(
342
352
  parent_task_message=streaming_context.task_message,
343
353
  content=tool_request_content,
354
+ type="full",
344
355
  ),
345
356
  )
346
357
 
@@ -357,13 +368,14 @@ class OpenAIService:
357
368
  async with (
358
369
  self.streaming_service.streaming_task_message_context(
359
370
  task_id=task_id,
360
- initial_content=tool_response_content,
371
+ initial_content=tool_response_content
361
372
  ) as streaming_context
362
373
  ):
363
374
  await streaming_context.stream_update(
364
375
  update=StreamTaskMessageFull(
365
376
  parent_task_message=streaming_context.task_message,
366
377
  content=tool_response_content,
378
+ type="full",
367
379
  ),
368
380
  )
369
381
 
@@ -619,6 +631,7 @@ class OpenAIService:
619
631
  update=StreamTaskMessageFull(
620
632
  parent_task_message=streaming_context.task_message,
621
633
  content=tool_request_content,
634
+ type="full",
622
635
  ),
623
636
  )
624
637
 
@@ -638,7 +651,7 @@ class OpenAIService:
638
651
  async with (
639
652
  self.streaming_service.streaming_task_message_context(
640
653
  task_id=task_id,
641
- initial_content=tool_response_content,
654
+ initial_content=tool_response_content
642
655
  ) as streaming_context
643
656
  ):
644
657
  # The message has already been persisted, but we still need to send an update
@@ -646,33 +659,7 @@ class OpenAIService:
646
659
  update=StreamTaskMessageFull(
647
660
  parent_task_message=streaming_context.task_message,
648
661
  content=tool_response_content,
649
- ),
650
- )
651
-
652
- elif event.item.type == "reasoning_item":
653
- # Handle reasoning items
654
- reasoning_item = event.item.raw_item
655
-
656
- reasoning_content = ReasoningContent(
657
- author="agent",
658
- style="static",
659
- summary=[summary.text for summary in reasoning_item.summary],
660
- content=[content.text for content in reasoning_item.content] if hasattr(reasoning_item, "content") and reasoning_item.content else None,
661
- type="reasoning",
662
- )
663
-
664
- # Create reasoning content using streaming context (immediate completion)
665
- async with (
666
- self.streaming_service.streaming_task_message_context(
667
- task_id=task_id,
668
- initial_content=reasoning_content,
669
- ) as streaming_context
670
- ):
671
- # The message has already been persisted, but we still need to send an update
672
- await streaming_context.stream_update(
673
- update=StreamTaskMessageFull(
674
- parent_task_message=streaming_context.task_message,
675
- content=reasoning_content,
662
+ type="full",
676
663
  ),
677
664
  )
678
665
 
@@ -705,10 +692,117 @@ class OpenAIService:
705
692
  await streaming_context.stream_update(
706
693
  update=StreamTaskMessageDelta(
707
694
  parent_task_message=streaming_context.task_message,
708
- delta=TextDelta(text_delta=event.data.delta),
695
+ delta=TextDelta(text_delta=event.data.delta, type="text"),
696
+ type="delta",
697
+ ),
698
+ )
699
+
700
+ elif isinstance(event.data, ResponseReasoningSummaryTextDeltaEvent):
701
+ # Handle reasoning summary text delta
702
+ item_id = event.data.item_id
703
+ summary_index = event.data.summary_index
704
+
705
+ # Check if we already have a streaming context for this reasoning item
706
+ if item_id not in item_id_to_streaming_context:
707
+ # Create a new streaming context for this reasoning item
708
+ streaming_context = self.streaming_service.streaming_task_message_context(
709
+ task_id=task_id,
710
+ initial_content=ReasoningContent(
711
+ author="agent",
712
+ summary=[],
713
+ content=[],
714
+ type="reasoning",
715
+ style="active",
716
+ ),
717
+ )
718
+ # Open the streaming context
719
+ item_id_to_streaming_context[
720
+ item_id
721
+ ] = await streaming_context.open()
722
+ unclosed_item_ids.add(item_id)
723
+ else:
724
+ streaming_context = item_id_to_streaming_context[
725
+ item_id
726
+ ]
727
+
728
+ # Stream the summary delta through the streaming service
729
+ await streaming_context.stream_update(
730
+ update=StreamTaskMessageDelta(
731
+ parent_task_message=streaming_context.task_message,
732
+ delta=ReasoningSummaryDelta(
733
+ summary_index=summary_index,
734
+ summary_delta=event.data.delta,
735
+ type="reasoning_summary",
736
+ ),
737
+ type="delta",
738
+ ),
739
+ )
740
+
741
+ elif isinstance(event.data, ResponseReasoningTextDeltaEvent):
742
+ # Handle reasoning content text delta
743
+ item_id = event.data.item_id
744
+ content_index = event.data.content_index
745
+
746
+ # Check if we already have a streaming context for this reasoning item
747
+ if item_id not in item_id_to_streaming_context:
748
+ # Create a new streaming context for this reasoning item
749
+ streaming_context = self.streaming_service.streaming_task_message_context(
750
+ task_id=task_id,
751
+ initial_content=ReasoningContent(
752
+ author="agent",
753
+ summary=[],
754
+ content=[],
755
+ type="reasoning",
756
+ style="active",
757
+ ),
758
+ )
759
+ # Open the streaming context
760
+ item_id_to_streaming_context[
761
+ item_id
762
+ ] = await streaming_context.open()
763
+ unclosed_item_ids.add(item_id)
764
+ else:
765
+ streaming_context = item_id_to_streaming_context[
766
+ item_id
767
+ ]
768
+
769
+ # Stream the content delta through the streaming service
770
+ await streaming_context.stream_update(
771
+ update=StreamTaskMessageDelta(
772
+ parent_task_message=streaming_context.task_message,
773
+ delta=ReasoningContentDelta(
774
+ content_index=content_index,
775
+ content_delta=event.data.delta,
776
+ type="reasoning_content",
777
+ ),
778
+ type="delta",
709
779
  ),
710
780
  )
711
781
 
782
+ elif isinstance(event.data, ResponseReasoningSummaryTextDoneEvent):
783
+ # Handle reasoning summary text completion
784
+ item_id = event.data.item_id
785
+ summary_index = event.data.summary_index
786
+
787
+ # We do NOT close the streaming context here as there can be multiple
788
+ # reasoning summaries. The context will be closed when the entire
789
+ # output item is done (ResponseOutputItemDoneEvent)
790
+
791
+ # You would think they would use the event ResponseReasoningSummaryPartDoneEvent
792
+ # to close the streaming context, but they do!!!
793
+ # They output both a ResponseReasoningSummaryTextDoneEvent and a ResponseReasoningSummaryPartDoneEvent
794
+ # I have no idea why they do this.
795
+
796
+ elif isinstance(event.data, ResponseReasoningTextDoneEvent):
797
+ # Handle reasoning content text completion
798
+ item_id = event.data.item_id
799
+ content_index = event.data.content_index
800
+
801
+ # We do NOT close the streaming context here as there can be multiple
802
+ # reasoning content texts. The context will be closed when the entire
803
+ # output item is done (ResponseOutputItemDoneEvent)
804
+
805
+
712
806
  elif isinstance(event.data, ResponseOutputItemDoneEvent):
713
807
  # Handle item completion
714
808
  item_id = event.data.item.id
@@ -719,23 +813,32 @@ class OpenAIService:
719
813
  item_id
720
814
  ]
721
815
  await streaming_context.close()
722
- unclosed_item_ids.remove(item_id)
816
+ if item_id in unclosed_item_ids:
817
+ unclosed_item_ids.remove(item_id)
723
818
 
724
819
  elif isinstance(event.data, ResponseCompletedEvent):
725
820
  # All items complete, finish all remaining streaming contexts for this session
726
- for item_id in unclosed_item_ids:
727
- streaming_context = item_id_to_streaming_context[
728
- item_id
729
- ]
730
- await streaming_context.close()
731
- unclosed_item_ids.remove(item_id)
821
+ # Create a copy to avoid modifying set during iteration
822
+ remaining_items = list(unclosed_item_ids)
823
+ for item_id in remaining_items:
824
+ if (item_id in unclosed_item_ids and
825
+ item_id in item_id_to_streaming_context): # Check if still unclosed
826
+ streaming_context = item_id_to_streaming_context[
827
+ item_id
828
+ ]
829
+ await streaming_context.close()
830
+ unclosed_item_ids.discard(item_id)
732
831
 
733
832
  finally:
734
833
  # Cleanup: ensure all streaming contexts for this session are properly finished
735
- for item_id in unclosed_item_ids:
736
- streaming_context = item_id_to_streaming_context[item_id]
737
- await streaming_context.close()
738
- unclosed_item_ids.remove(item_id)
834
+ # Create a copy to avoid modifying set during iteration
835
+ remaining_items = list(unclosed_item_ids)
836
+ for item_id in remaining_items:
837
+ if (item_id in unclosed_item_ids and
838
+ item_id in item_id_to_streaming_context): # Check if still unclosed
839
+ streaming_context = item_id_to_streaming_context[item_id]
840
+ await streaming_context.close()
841
+ unclosed_item_ids.discard(item_id)
739
842
 
740
843
  if span:
741
844
  span.output = {
@@ -1,21 +1,24 @@
1
1
  import json
2
- from typing import Literal, cast
2
+ from typing import Literal
3
3
 
4
4
  from agentex import AsyncAgentex
5
5
  from agentex.lib.core.adapters.streams.port import StreamRepository
6
- from agentex.lib.types.task_message_updates import (
6
+ from agentex.types.task_message_update import (
7
7
  TaskMessageDelta,
8
8
  TaskMessageUpdate,
9
- TextDelta,
10
- DataDelta,
11
- ToolRequestDelta,
12
- ToolResponseDelta,
13
- StreamTaskMessage,
14
9
  StreamTaskMessageStart,
15
10
  StreamTaskMessageDelta,
16
11
  StreamTaskMessageFull,
17
12
  StreamTaskMessageDone,
18
13
  )
14
+ from agentex.types.task_message_delta import (
15
+ TextDelta,
16
+ DataDelta,
17
+ ToolRequestDelta,
18
+ ToolResponseDelta,
19
+ ReasoningSummaryDelta,
20
+ ReasoningContentDelta,
21
+ )
19
22
  from agentex.lib.utils.logging import make_logger
20
23
  from agentex.types.data_content import DataContent
21
24
  from agentex.types.task_message import (
@@ -25,6 +28,7 @@ from agentex.types.task_message import (
25
28
  from agentex.types.text_content import TextContent
26
29
  from agentex.types.tool_request_content import ToolRequestContent
27
30
  from agentex.types.tool_response_content import ToolResponseContent
31
+ from agentex.types.reasoning_content import ReasoningContent
28
32
 
29
33
  logger = make_logger(__name__)
30
34
 
@@ -36,7 +40,10 @@ def _get_stream_topic(task_id: str) -> str:
36
40
  class DeltaAccumulator:
37
41
  def __init__(self):
38
42
  self._accumulated_deltas: list[TaskMessageDelta] = []
39
- self._delta_type: Literal["text", "data", "tool_request", "tool_response"] | None = None
43
+ self._delta_type: Literal["text", "data", "tool_request", "tool_response", "reasoning"] | None = None
44
+ # For reasoning, we need to track both summary and content deltas
45
+ self._reasoning_summaries: dict[int, str] = {}
46
+ self._reasoning_contents: dict[int, str] = {}
40
47
 
41
48
  def add_delta(self, delta: TaskMessageDelta):
42
49
  if self._delta_type is None:
@@ -48,15 +55,35 @@ class DeltaAccumulator:
48
55
  self._delta_type = "tool_request"
49
56
  elif delta.type == "tool_response":
50
57
  self._delta_type = "tool_response"
58
+ elif delta.type in ["reasoning_summary", "reasoning_content"]:
59
+ self._delta_type = "reasoning"
51
60
  else:
52
61
  raise ValueError(f"Unknown delta type: {delta.type}")
53
62
  else:
54
- if self._delta_type != delta.type:
63
+ # For reasoning, we allow both summary and content deltas
64
+ if self._delta_type == "reasoning":
65
+ if delta.type not in ["reasoning_summary", "reasoning_content"]:
66
+ raise ValueError(
67
+ f"Expected reasoning delta but got: {delta.type}"
68
+ )
69
+ elif self._delta_type != delta.type:
55
70
  raise ValueError(
56
71
  f"Delta type mismatch: {self._delta_type} != {delta.type}"
57
72
  )
58
73
 
59
- self._accumulated_deltas.append(delta)
74
+ # Handle reasoning deltas specially
75
+ if delta.type == "reasoning_summary":
76
+ if isinstance(delta, ReasoningSummaryDelta):
77
+ if delta.summary_index not in self._reasoning_summaries:
78
+ self._reasoning_summaries[delta.summary_index] = ""
79
+ self._reasoning_summaries[delta.summary_index] += delta.summary_delta or ""
80
+ elif delta.type == "reasoning_content":
81
+ if isinstance(delta, ReasoningContentDelta):
82
+ if delta.content_index not in self._reasoning_contents:
83
+ self._reasoning_contents[delta.content_index] = ""
84
+ self._reasoning_contents[delta.content_index] += delta.content_delta or ""
85
+ else:
86
+ self._accumulated_deltas.append(delta)
60
87
 
61
88
  def convert_to_content(self) -> TaskMessageContent:
62
89
  if self._delta_type == "text":
@@ -107,7 +134,7 @@ class DeltaAccumulator:
107
134
  # Type assertion: we know all deltas are ToolResponseDelta when _delta_type is TOOL_RESPONSE
108
135
  tool_response_deltas = [delta for delta in self._accumulated_deltas if isinstance(delta, ToolResponseDelta)]
109
136
  tool_response_content_str = "".join(
110
- [delta.tool_response_delta or "" for delta in tool_response_deltas]
137
+ [delta.content_delta or "" for delta in tool_response_deltas]
111
138
  )
112
139
  return ToolResponseContent(
113
140
  author="agent",
@@ -115,6 +142,27 @@ class DeltaAccumulator:
115
142
  name=tool_response_deltas[0].name,
116
143
  content=tool_response_content_str,
117
144
  )
145
+ elif self._delta_type == "reasoning":
146
+ # Convert accumulated reasoning deltas to ReasoningContent
147
+ # Sort by index to maintain order
148
+ summary_list = [self._reasoning_summaries[i] for i in sorted(self._reasoning_summaries.keys()) if self._reasoning_summaries[i]]
149
+ content_list = [self._reasoning_contents[i] for i in sorted(self._reasoning_contents.keys()) if self._reasoning_contents[i]]
150
+
151
+ # Only return reasoning content if we have non-empty summaries or content
152
+ if summary_list or content_list:
153
+ return ReasoningContent(
154
+ author="agent",
155
+ summary=summary_list,
156
+ content=content_list if content_list else None,
157
+ type="reasoning",
158
+ style="static",
159
+ )
160
+ else:
161
+ # Return empty text content instead of empty reasoning
162
+ return TextContent(
163
+ author="agent",
164
+ content="",
165
+ )
118
166
  else:
119
167
  raise ValueError(f"Unknown delta type: {self._delta_type}")
120
168
 
@@ -154,6 +202,7 @@ class StreamingTaskMessageContext:
154
202
  start_event = StreamTaskMessageStart(
155
203
  parent_task_message=self.task_message,
156
204
  content=self.initial_content,
205
+ type="start",
157
206
  )
158
207
  await self._streaming_service.stream_update(start_event)
159
208
 
@@ -168,11 +217,19 @@ class StreamingTaskMessageContext:
168
217
  return self.task_message # Already done
169
218
 
170
219
  # Send the DONE event
171
- done_event = StreamTaskMessageDone(parent_task_message=self.task_message)
220
+ done_event = StreamTaskMessageDone(
221
+ parent_task_message=self.task_message,
222
+ type="done",
223
+ )
172
224
  await self._streaming_service.stream_update(done_event)
173
225
 
174
226
  # Update the task message with the final content
175
- if self._delta_accumulator._accumulated_deltas:
227
+ has_deltas = (
228
+ self._delta_accumulator._accumulated_deltas or
229
+ self._delta_accumulator._reasoning_summaries or
230
+ self._delta_accumulator._reasoning_contents
231
+ )
232
+ if has_deltas:
176
233
  self.task_message.content = self._delta_accumulator.convert_to_content()
177
234
 
178
235
  await self._agentex_client.messages.update(
@@ -187,8 +244,8 @@ class StreamingTaskMessageContext:
187
244
  return self.task_message
188
245
 
189
246
  async def stream_update(
190
- self, update: StreamTaskMessage
191
- ) -> StreamTaskMessage | None:
247
+ self, update: TaskMessageUpdate
248
+ ) -> TaskMessageUpdate | None:
192
249
  """Stream an update to the repository."""
193
250
  if self._is_closed:
194
251
  raise ValueError("Context is already done")
@@ -3,7 +3,7 @@ from enum import Enum
3
3
  from temporalio import activity
4
4
 
5
5
  from agentex.lib.core.services.adk.streaming import StreamingService
6
- from agentex.lib.types.task_message_updates import TaskMessageUpdate
6
+ from agentex.types.task_message_update import TaskMessageUpdate
7
7
  from agentex.lib.utils.logging import make_logger
8
8
  from agentex.lib.utils.model_utils import BaseModel
9
9
  from agentex.lib.utils.temporal import heartbeat_if_in_workflow
@@ -21,7 +21,7 @@ from agentex.lib.types.acp import (
21
21
  SendMessageParams,
22
22
  )
23
23
  from agentex.lib.types.json_rpc import JSONRPCError, JSONRPCRequest, JSONRPCResponse
24
- from agentex.lib.types.task_message_updates import StreamTaskMessageFull, TaskMessageUpdate
24
+ from agentex.types.task_message_update import StreamTaskMessageFull, TaskMessageUpdate
25
25
  from agentex.types.task_message_content import TaskMessageContent
26
26
  from agentex.lib.utils.logging import make_logger
27
27
  from agentex.lib.utils.model_utils import BaseModel
@@ -332,7 +332,7 @@ class BaseACPServer(FastAPI):
332
332
 
333
333
  async def async_generator(task_message_content_list: list[TaskMessageContent]):
334
334
  for i, task_message_content in enumerate(task_message_content_list):
335
- yield StreamTaskMessageFull(index=i, content=task_message_content)
335
+ yield StreamTaskMessageFull(type="full", index=i, content=task_message_content)
336
336
 
337
337
  return async_generator(task_message_content_list)
338
338
 
@@ -3,12 +3,12 @@ from typing import Any, override
3
3
 
4
4
  from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
5
5
  from agentex.lib.types.acp import SendMessageParams
6
- from agentex.lib.types.task_message_updates import (
6
+ from agentex.types.task_message_update import (
7
7
  StreamTaskMessageDelta,
8
8
  StreamTaskMessageFull,
9
9
  TaskMessageUpdate,
10
- TextDelta,
11
10
  )
11
+ from agentex.types.task_message_delta import TextDelta
12
12
  from agentex.types.task_message_content import TaskMessageContent, TextContent
13
13
  from agentex.lib.utils.logging import make_logger
14
14
 
@@ -12,7 +12,7 @@ from typing import List, Optional
12
12
  from yaspin.core import Yaspin
13
13
 
14
14
  from agentex import Agentex
15
- from agentex.types import Task, TaskMessage, TextContent, ToolRequestContent, ToolResponseContent
15
+ from agentex.types import Task, TaskMessage, TextContent, ToolRequestContent, ToolResponseContent, ReasoningContent
16
16
  from agentex.types.task_message_update import (
17
17
  TaskMessageUpdate,
18
18
  StreamTaskMessageStart,
@@ -48,6 +48,13 @@ def print_task_message(
48
48
  if isinstance(message.content, TextContent) and not message.content.content.strip():
49
49
  return
50
50
 
51
+ # Skip empty reasoning messages
52
+ if isinstance(message.content, ReasoningContent):
53
+ has_summary = message.content.summary and any(s for s in message.content.summary if s)
54
+ has_content = message.content.content and any(c for c in message.content.content if c)
55
+ if not has_summary and not has_content:
56
+ return
57
+
51
58
  timestamp = message.created_at.strftime("%m/%d/%Y %H:%M:%S") if message.created_at else "N/A"
52
59
 
53
60
  console = None
@@ -103,6 +110,26 @@ def print_task_message(
103
110
  content = f"✅ **Tool Response: {tool_name}**\n\n{tool_response}"
104
111
 
105
112
  content_type = "tool_response"
113
+ elif isinstance(message.content, ReasoningContent):
114
+ # Format reasoning content
115
+ reasoning_parts = []
116
+
117
+ # Add summary if available
118
+ if message.content.summary:
119
+ # Join summaries with double newline for better formatting
120
+ summary_text = "\n\n".join(s for s in message.content.summary if s)
121
+ if summary_text:
122
+ reasoning_parts.append(summary_text)
123
+
124
+ # Add full reasoning content if available
125
+ if message.content.content:
126
+ content_text = "\n\n".join(c for c in message.content.content if c)
127
+ if content_text:
128
+ reasoning_parts.append(content_text)
129
+
130
+ # Format reasoning content (we already checked it's not empty at the top)
131
+ content = "🧠 **Reasoning**\n\n" + "\n\n".join(reasoning_parts)
132
+ content_type = "reasoning"
106
133
  else:
107
134
  content = f"{type(message.content).__name__}: {message.content}"
108
135
  content_type = "other"
@@ -116,6 +143,8 @@ def print_task_message(
116
143
  border_style = "yellow"
117
144
  elif content_type == "tool_response":
118
145
  border_style = "bright_green"
146
+ elif content_type == "reasoning":
147
+ border_style = "bright_magenta"
119
148
  else:
120
149
  border_style = author_color
121
150
 
@@ -123,6 +152,8 @@ def print_task_message(
123
152
  console.print(panel)
124
153
  else:
125
154
  title = f"{message.content.author.upper()} [{timestamp}]"
155
+ if content_type == "reasoning":
156
+ title = f"🧠 REASONING [{timestamp}]"
126
157
  print(f"{title}\n{content}\n")
127
158
 
128
159
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: agentex-sdk
3
- Version: 0.4.6
3
+ Version: 0.4.8
4
4
  Summary: The official Python library for the agentex API
5
5
  Project-URL: Homepage, https://github.com/scaleapi/agentex-python
6
6
  Project-URL: Repository, https://github.com/scaleapi/agentex-python
@@ -11,7 +11,7 @@ agentex/_resource.py,sha256=S1t7wmR5WUvoDIhZjo_x-E7uoTJBynJ3d8tPJMQYdjw,1106
11
11
  agentex/_response.py,sha256=Tb9zazsnemO2rTxWtBjAD5WBqlhli5ZaXGbiKgdu5DE,28794
12
12
  agentex/_streaming.py,sha256=FNGJExRCF-vTRUZHFKUfoAWFhDGOB3XbioVCF37Jr7E,10104
13
13
  agentex/_types.py,sha256=KyKYySGIfHPod2hho1fPxssk5NuVn8C4MeMTtA-lg80,6198
14
- agentex/_version.py,sha256=0jOnjx7KMHpb97faXF4SWf9u49iBskkyVhnWoa4wzZc,159
14
+ agentex/_version.py,sha256=B50Ua8_D0D-KO2Gx_YEx60xydpxFLCIU8BwZh9UZhbY,159
15
15
  agentex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  agentex/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
17
17
  agentex/_utils/_logs.py,sha256=LUjFPc3fweSChBUmjhQD8uYmwQAmFMNDuVFKfjYBQfM,777
@@ -83,7 +83,7 @@ agentex/lib/cli/templates/sync/environments.yaml.j2,sha256=BGprRPca_Y2sPA7kOiSK8
83
83
  agentex/lib/cli/templates/sync/manifest.yaml.j2,sha256=V497KXzvA76sHrgIJ5zRJptpIH8sGbSXZaIsEyp5NZ4,3747
84
84
  agentex/lib/cli/templates/sync/pyproject.toml.j2,sha256=eyN6dYqJTFzb5WztJMxboy9Wc0XPXVnKYaF5JBxJE7o,507
85
85
  agentex/lib/cli/templates/sync/requirements.txt.j2,sha256=iTmO-z8qFkUa1jTctFCs0WYuq7Sqi6VNQAwATakh2fQ,94
86
- agentex/lib/cli/templates/sync/project/acp.py.j2,sha256=X5RaE9iR4Dp-kPJL0r1QAe6ohfiOTcYizwtwGW2GzHg,1003
86
+ agentex/lib/cli/templates/sync/project/acp.py.j2,sha256=PUVXnN7IikBWYnfqLMgual-iXdl_benAjEfNcRADHBk,998
87
87
  agentex/lib/cli/templates/temporal/.dockerignore.j2,sha256=hweGFxw5eDZYsb5EnRHpv27o9M1HF2PEWOxqsfBBcAE,320
88
88
  agentex/lib/cli/templates/temporal/Dockerfile-uv.j2,sha256=_FNRUdE8m1jfcmYR3rZAAkm2mqyTCwUXbLs4dm4lZs8,1401
89
89
  agentex/lib/cli/templates/temporal/Dockerfile.j2,sha256=N1Z73jb8pnxsjP9zbs-tSyNHO6usVzyOdtWorbR5gVY,1434
@@ -122,16 +122,16 @@ agentex/lib/core/services/adk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
122
122
  agentex/lib/core/services/adk/agent_task_tracker.py,sha256=7HHxzTezx0FEmUlIcWusoXT0D91QVeggOKowIA919gI,2897
123
123
  agentex/lib/core/services/adk/agents.py,sha256=MVklI4Ht8j8EAO18-0reLFRr6S5OIdEIymB1mU8FnKE,1446
124
124
  agentex/lib/core/services/adk/events.py,sha256=gzhEfodEKk2bW5e1RJdrk2MW316U5VWdxMynhtFWgTA,1949
125
- agentex/lib/core/services/adk/messages.py,sha256=aek1g4yq301JC6J9f2-kGSJIKu-oegeNIPAd4I4EMak,6047
125
+ agentex/lib/core/services/adk/messages.py,sha256=pqIYaY11tmGOD8OnU3qoy5lk82AI1FgW5ShmfxidG_I,6042
126
126
  agentex/lib/core/services/adk/state.py,sha256=O4hF7dj-uQP5VVeHmx37m36rmIlOwfQ2pL2ROndq7Zg,3830
127
- agentex/lib/core/services/adk/streaming.py,sha256=zIXxMaoL5iTTC8CvmNoG4lRQO5JHyWQmwT2KyiUQL84,9563
127
+ agentex/lib/core/services/adk/streaming.py,sha256=keZyy7CixM2_3tf2THv-X4gGOOSAk0mEKBk-WReBqJE,12406
128
128
  agentex/lib/core/services/adk/tasks.py,sha256=XEX0u4skq81Fn-gjTzSE_-Iv_mKySZHchpotxAsnJwg,2618
129
129
  agentex/lib/core/services/adk/tracing.py,sha256=w4mnIoq5m5iwlkDN_NOUjhi6hUpD958cYn1QR6hFgB8,1156
130
130
  agentex/lib/core/services/adk/acp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
- agentex/lib/core/services/adk/acp/acp.py,sha256=Ei6r5CcM1RA7DqfTRpAWCmP7Buw97b3ajQuE4DsdSaQ,7559
131
+ agentex/lib/core/services/adk/acp/acp.py,sha256=4KeRPaka8GqnF2PQiNigcijgvQ_rf8Si0EoOdQNqjN4,7926
132
132
  agentex/lib/core/services/adk/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
- agentex/lib/core/services/adk/providers/litellm.py,sha256=7RIVqQ5XaCP2cEL1pr4nl5jfG_0FDMvDTZVKu1iaN3M,9864
134
- agentex/lib/core/services/adk/providers/openai.py,sha256=tR2iKJc2SZo2eLUIWwkyl7W4QIkFnzdxT1OQxaPXQBc,33348
133
+ agentex/lib/core/services/adk/providers/litellm.py,sha256=EKzus_xohNW-85V5hwvd1WqUd3ebv2wc9vDIWO2t1Mw,10044
134
+ agentex/lib/core/services/adk/providers/openai.py,sha256=Ad7iFQDg1iz8KjswO16lzjpzEJCz5FtyXV-fB6qMPLk,39535
135
135
  agentex/lib/core/services/adk/providers/sgp.py,sha256=9gm-sPNQ_OSTaBzL0onerKhokPk_ZHndaKNO-z16wyQ,3676
136
136
  agentex/lib/core/services/adk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  agentex/lib/core/services/adk/utils/templating.py,sha256=eaXSFq31Y9p5pRD6J6SL4QdTFtxy81dilbF2XXc2JYQ,1889
@@ -144,7 +144,7 @@ agentex/lib/core/temporal/activities/adk/agents_activities.py,sha256=q3PGgOLXvcE
144
144
  agentex/lib/core/temporal/activities/adk/events_activities.py,sha256=60ygWk1aNG8Qf2IcnatXK1h86ZT32WCYkUAyRiM_p4c,1532
145
145
  agentex/lib/core/temporal/activities/adk/messages_activities.py,sha256=fmiNOAt6Ov4nYzGGbkvDcSCMXPPTrsL66xSNud3_3RQ,3053
146
146
  agentex/lib/core/temporal/activities/adk/state_activities.py,sha256=2YtAz7C2GMfyZGdp8wje1TvYjFGttdbLNAm9xSIbESA,2590
147
- agentex/lib/core/temporal/activities/adk/streaming_activities.py,sha256=HtxGBgz4UNPcFSo1izCzg2Yw__C4E6igUNrqhC38FVA,1053
147
+ agentex/lib/core/temporal/activities/adk/streaming_activities.py,sha256=PEXeFU9mNHbGoF3-kk4HNS53NX_MfdwI7LKWBl3--4c,1048
148
148
  agentex/lib/core/temporal/activities/adk/tasks_activities.py,sha256=hQjdD-TfSzxsiW9eiJ5ZTvY0Ieu0tE950_Zk2PUVc9g,1442
149
149
  agentex/lib/core/temporal/activities/adk/tracing_activities.py,sha256=RF8nSBA9x6Ui7_MD9He5ljlH_xZduIhx_JUTEyKdCxA,1523
150
150
  agentex/lib/core/temporal/activities/adk/acp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -181,9 +181,9 @@ agentex/lib/sdk/config/project_config.py,sha256=CGH_r9KbnSFMj2CnBkZnfg41L2o0TeVN
181
181
  agentex/lib/sdk/config/validation.py,sha256=QGAlAzlVJiWRlIksqxNS-JSwkk8Z4gXMSFUJc4qPrIQ,8989
182
182
  agentex/lib/sdk/fastacp/__init__.py,sha256=UvAdexdnfb4z0F4a2sfXROFyh9EjH89kf3AxHPybzCM,75
183
183
  agentex/lib/sdk/fastacp/fastacp.py,sha256=K4D7a9EiJfCgWp2hrE_TbpZBaF4Uc46MfndZK3F9mA0,3061
184
- agentex/lib/sdk/fastacp/base/base_acp_server.py,sha256=fkEVg5M4Ni2uPt_oiCP7_jfTmRvcC0o2VTg0Oka7mXA,14590
184
+ agentex/lib/sdk/fastacp/base/base_acp_server.py,sha256=vj7jPg8a8z07dTl3P-ZVTdhcuW3ulm4QrptWyYVnTAs,14598
185
185
  agentex/lib/sdk/fastacp/impl/agentic_base_acp.py,sha256=LWLAlHrs-2Lc2UICBAEFL8c3JwTA6oxPnzUzW0qQWSA,2694
186
- agentex/lib/sdk/fastacp/impl/sync_acp.py,sha256=8FEDfBxI31NoVLX9nyckQ8QwA0UV4svC3fhGKgXBIwk,3862
186
+ agentex/lib/sdk/fastacp/impl/sync_acp.py,sha256=0y_cYD-0UJOiVJv-BBMOt6PvElDf5zmc1uvbr81VcSI,3897
187
187
  agentex/lib/sdk/fastacp/impl/temporal_acp.py,sha256=hQa_zGG6l_jIHNC75H_KXlPUuVqNBc-zIm-pmCDSZ6w,3759
188
188
  agentex/lib/sdk/fastacp/tests/README.md,sha256=HejScemERLCs-wCgU3l1Xo4tcQ4gQy15GgoF-CkNh-0,8270
189
189
  agentex/lib/sdk/fastacp/tests/conftest.py,sha256=wU3DCGZNBqY-HcJ4tz_tlphhS_5xGbZ6gSd72fGY2E0,9490
@@ -209,7 +209,6 @@ agentex/lib/types/fastacp.py,sha256=nU4rT823Ckix7bFwvVXtPsk6el3U1E4TH-OEvMqIBr4,
209
209
  agentex/lib/types/files.py,sha256=sNxiuR_oEo7Z0YMqjQShErvS3txWyobrZzc4QMMM61U,320
210
210
  agentex/lib/types/json_rpc.py,sha256=9sPADVEduOnyTm1yCS8vhZDfjMQVEdzqIWpycY_NrV8,1068
211
211
  agentex/lib/types/llm_messages.py,sha256=eXsVJt_aQf3eGg_tPrDOPjFOhkbolb9IN1tU1c-IHYM,10668
212
- agentex/lib/types/task_message_updates.py,sha256=jt9RUftr13sw0WbvdHOeK0Tidzdq-xfewx1AYqV8gtg,4298
213
212
  agentex/lib/types/tracing.py,sha256=0YBdy3aKvxIcpOW0podEAqsFl3yEKW4PswNf-QnMNqo,731
214
213
  agentex/lib/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
215
214
  agentex/lib/utils/completions.py,sha256=m9TMwl9-nYK4DOQ8bNyj5YCFrxK3yN3zKvXmdINcIbo,4158
@@ -226,7 +225,7 @@ agentex/lib/utils/regex.py,sha256=Y3VcehCznAqa59D4WTwK_ki722oudHBlFqBk0I930zo,21
226
225
  agentex/lib/utils/registration.py,sha256=FAL40KSMRCltHZcDtioGeRNgfB19Twqu6Srp4x7UMSU,3781
227
226
  agentex/lib/utils/temporal.py,sha256=sXo8OPMMXiyrF7OSBCJBuN_ufyQOD2bLOXgDbVZoyds,292
228
227
  agentex/lib/utils/dev_tools/__init__.py,sha256=oaHxw6ymfhNql-kzXHv3NWVHuqD4fHumasNXJG7kHTU,261
229
- agentex/lib/utils/dev_tools/async_messages.py,sha256=-alUK1KFltcRb6xtRtIJIRJW9Sf1FwDRgaNPhOn-luw,18105
228
+ agentex/lib/utils/dev_tools/async_messages.py,sha256=dM01spww2Fy6ej_WDnPXs2eG-9yCU7Xc1IMKwJzq6cM,19543
230
229
  agentex/resources/__init__.py,sha256=74rMqWBzQ2dSrKQqsrd7-jskPws0O_ogkFltvZO3HoU,3265
231
230
  agentex/resources/agents.py,sha256=WLG7wTQcCZCtqvNiyi2wjuDA2u85nEA5o9kUr5pBQXE,46977
232
231
  agentex/resources/events.py,sha256=Zc9JhUm3bq2VFnBAolC0M7KZernzj1AjZ_vj0ibP4GY,10412
@@ -301,8 +300,8 @@ agentex/types/messages/batch_update_params.py,sha256=Ug5CThbD49a8j4qucg04OdmVrp_
301
300
  agentex/types/messages/batch_update_response.py,sha256=TbSBe6SuPzjXXWSj-nRjT1JHGBooTshHQQDa1AixQA8,278
302
301
  agentex/types/shared/__init__.py,sha256=IKs-Qn5Yja0kFh1G1kDqYZo43qrOu1hSoxlPdN-85dI,149
303
302
  agentex/types/shared/delete_response.py,sha256=8qH3zvQXaOHYQSHyXi7UQxdR4miTzR7V9K4zXVsiUyk,215
304
- agentex_sdk-0.4.6.dist-info/METADATA,sha256=u1EUOOWGKnqAOgh82EvTTThHbIh8ZcpRrRCIlqLjTPk,15094
305
- agentex_sdk-0.4.6.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
306
- agentex_sdk-0.4.6.dist-info/entry_points.txt,sha256=V7vJuMZdF0UlvgX6KiBN7XUvq_cxF5kplcYvc1QlFaQ,62
307
- agentex_sdk-0.4.6.dist-info/licenses/LICENSE,sha256=Q1AOx2FtRcMlyMgQJ9eVN2WKPq2mQ33lnB4tvWxabLA,11337
308
- agentex_sdk-0.4.6.dist-info/RECORD,,
303
+ agentex_sdk-0.4.8.dist-info/METADATA,sha256=_ZN2ZmRBA_8REs6q2Q8gsidbWdcI2kqDPPvoDgqkdZQ,15094
304
+ agentex_sdk-0.4.8.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
305
+ agentex_sdk-0.4.8.dist-info/entry_points.txt,sha256=V7vJuMZdF0UlvgX6KiBN7XUvq_cxF5kplcYvc1QlFaQ,62
306
+ agentex_sdk-0.4.8.dist-info/licenses/LICENSE,sha256=Q1AOx2FtRcMlyMgQJ9eVN2WKPq2mQ33lnB4tvWxabLA,11337
307
+ agentex_sdk-0.4.8.dist-info/RECORD,,
@@ -1,171 +0,0 @@
1
- from enum import Enum
2
- from typing import Annotated, Literal
3
-
4
- from pydantic import Field, model_validator
5
-
6
- from agentex.types.task_message import TaskMessage
7
- from agentex.types.task_message_content import TaskMessageContent
8
- from agentex.lib.utils.model_utils import BaseModel
9
-
10
-
11
- class BaseTaskMessageDelta(BaseModel):
12
- """
13
- Base class for all delta updates
14
-
15
- Attributes:
16
- type: The type of delta update
17
- """
18
-
19
- type: Literal["text", "data", "tool_request", "tool_response"]
20
-
21
-
22
- class TextDelta(BaseTaskMessageDelta):
23
- """
24
- Delta for text updates
25
-
26
- Attributes:
27
- type: The type of delta update
28
- text_delta: The delta for the text
29
- """
30
-
31
- type: Literal["text"] = "text"
32
- text_delta: str | None = ""
33
-
34
-
35
- class DataDelta(BaseTaskMessageDelta):
36
- """
37
- Delta for data updates
38
-
39
- Attributes:
40
- type: The type of delta update
41
- data_delta: The delta for the data
42
- """
43
-
44
- type: Literal["data"] = "data"
45
- data_delta: str | None = ""
46
-
47
-
48
- class ToolRequestDelta(BaseTaskMessageDelta):
49
- """
50
- Delta for tool request updates
51
-
52
- Attributes:
53
- type: The type of delta update
54
- name: The name of the tool
55
- arguments_delta: The delta for the arguments
56
- """
57
-
58
- type: Literal["tool_request"] = "tool_request"
59
- tool_call_id: str
60
- name: str
61
- arguments_delta: str | None = ""
62
-
63
-
64
- class ToolResponseDelta(BaseTaskMessageDelta):
65
- """
66
- Delta for tool response updates
67
-
68
- Attributes:
69
- type: The type of delta update
70
- tool_response_delta: The delta for the tool response
71
- """
72
-
73
- type: Literal["tool_response"] = "tool_response"
74
- tool_call_id: str
75
- name: str
76
- tool_response_delta: str | None = ""
77
-
78
-
79
- TaskMessageDelta = Annotated[
80
- TextDelta | DataDelta | ToolRequestDelta | ToolResponseDelta,
81
- Field(discriminator="type"),
82
- ]
83
-
84
-
85
- class StreamTaskMessage(BaseModel):
86
- """Base class for all task message stream events
87
-
88
- Attributes:
89
- type: The type of task message update
90
- parent_task_message: The parent task message
91
- index: The index of the task message
92
- """
93
-
94
- type: Literal["start", "delta", "full", "done"]
95
- # Used for streaming chunks to a direct parent_task_message
96
- parent_task_message: TaskMessage | None = None
97
- # Used to correlate chunks of different task messages with each other
98
- # directly in the Sync ACP case
99
- index: int | None = None
100
-
101
- @model_validator(mode="after")
102
- def validate_message_correlation(self):
103
- """Ensure exactly one of index or parent_task_message is set"""
104
- has_parent = self.parent_task_message is not None
105
- has_index = self.index is not None
106
-
107
- if not has_parent and not has_index:
108
- raise ValueError("Either 'index' or 'parent_task_message' must be set")
109
-
110
- if has_parent and has_index:
111
- raise ValueError(
112
- "Cannot set both 'index' and 'parent_task_message' - only one is allowed"
113
- )
114
-
115
- return self
116
-
117
-
118
- # Everything is streamed as a partial json blob, except for text.
119
- class StreamTaskMessageStart(StreamTaskMessage):
120
- """Event for starting a streaming message
121
-
122
- Attributes:
123
- type: The type of task message update
124
- content: The content of the task message
125
- """
126
-
127
- type: Literal["start"] = "start"
128
- content: TaskMessageContent
129
-
130
-
131
- class StreamTaskMessageDelta(StreamTaskMessage):
132
- """Event for streaming chunks of content
133
-
134
- Attributes:
135
- type: The type of task message update
136
- delta: The delta of the task message
137
- """
138
-
139
- type: Literal["delta"] = "delta"
140
- delta: TaskMessageDelta | None = None
141
-
142
-
143
- class StreamTaskMessageFull(StreamTaskMessage):
144
- """Event for streaming the full content
145
-
146
- Attributes:
147
- type: The type of task message update
148
- content: The content of the task message
149
- """
150
-
151
- type: Literal["full"] = "full"
152
- content: TaskMessageContent
153
-
154
-
155
- class StreamTaskMessageDone(StreamTaskMessage):
156
- """Event for indicating the task is done
157
-
158
- Attributes:
159
- type: The type of task message update
160
- """
161
-
162
- type: Literal["done"] = "done"
163
-
164
-
165
- TaskMessageUpdate = Annotated[
166
- StreamTaskMessageStart
167
- | StreamTaskMessageDelta
168
- | StreamTaskMessageFull
169
- | StreamTaskMessageDone,
170
- Field(discriminator="type"),
171
- ]