agentscope-ai / agentscope-ai/agentscope-java

对AgentEvent解析的封装

Abierto
#1,643 1 comentario 0 reacciones 0 asignados Ver en GitHub
area/core/agent enhancement
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

v2.0.0-RC1的版本,没有找到对AgentEvent的解析封装。
python版本的Msg这个类提供了append_event这个方法,这点很方便人使用。

```python
def append_event(self, event: AgentEvent) -> Self:
"""Update the message by applying a streaming event.

Mutates ``self.content``, ``self.finished_at``, and ``self.usage``:
content blocks are appended/updated by block-level events,
``finished_at`` is stamped by ``REPLY_END``, and ``usage`` is
initialized then accumulated across each ``MODEL_CALL_END``.
Events whose ``reply_id`` does not match ``self.id`` are skipped with
a warning. Block-level delta/end events whose target block cannot be
found are also skipped with a warning.

Args:
event (`AgentEvent`):
The event to apply.
"""
from ..event import EventType # local import to avoid circular dep

if event.reply_id != self.id:
logger.warning(
"Event %s with reply_id %r does not match message id %r, "
"skipping.",
event.__class__.__name__,
event.reply_id,
self.id,
)
return self

match event.type:
case EventType.REPLY_END:
self.finished_at = event.created_at

case EventType.MODEL_CALL_END:
if self.usage is None:
self.usage = Usage(
input_tokens=event.input_tokens,
output_tokens=event.output_tokens,
)
else:
self.usage.input_tokens += event.input_tokens
self.usage.output_tokens += event.output_tokens

case EventType.TEXT_BLOCK_START:
self.content.append(TextBlock(id=event.block_id, text=""))

case EventType.TEXT_BLOCK_DELTA:
block = self._find_block("text", event.block_id)
if block is None:
logger.warning(
"TextBlock %r not found, skipping.",
event.block_id,
)
else:
block.text += event.delta

case EventType.TEXT_BLOCK_END:
pass

case EventType.DATA_BLOCK_START:
self.content.append(
DataBlock(
id=event.block_id,
source=Base64Source(
data="",
media_type=event.media_type,
),
),
)

case EventType.DATA_BLOCK_DELTA:
block = self._find_block("data", event.block_id)
if block is None:
logger.warning(
"DataBlock %s not found, skipping.",
event.block_id,
)
elif event.data:
block.source.data += event.data

case EventType.DATA_BLOCK_END:
pass

case EventType.THINKING_BLOCK_START:
self.content.append(
ThinkingBlock(id=event.block_id, thinking=""),
)

case EventType.THINKING_BLOCK_DELTA:
block = self._find_block("thinking", event.block_id)
if block is None:
logger.warning(
"ThinkingBlock %r not found, skipping.",
event.block_id,
)
else:
block.thinking += event.delta

case EventType.THINKING_BLOCK_END:
pass

case EventType.HINT_BLOCK:
# One-shot event — the full HintBlock content arrives in
# a single event, so just append it to ``content`` for
# persistence and replay.
self.content.append(
HintBlock(
id=event.block_id,
source=event.source,
hint=event.hint,
),
)

case EventType.TOOL_CALL_START:
self.content.append(
ToolCallBlock(
id=event.tool_call_id,
name=event.tool_call_name,
input="",
),
)

case EventType.TOOL_CALL_DELTA:
block = self._find_block("tool_call", event.tool_call_id)
if block is None:
logger.warning(
"ToolCallBlock %r not found, skipping.",
event.tool_call_id,
)
else:
assert isinstance(block, ToolCallBlock)
block.input += event.delta

case EventType.TOOL_CALL_END:
pass

case EventType.TOOL_RESULT_START:
self.content.append(
ToolResultBlock(
id=event.tool_call_id,
name=event.tool_call_name,
output=[],
state=ToolResultState.RUNNING,
),
)

case EventType.TOOL_RESULT_TEXT_DELTA:
block = self._find_block("tool_result", event.tool_call_id)
if block is None:
logger.warning(
"ToolResultBlock %r not found, skipping.",
event.tool_call_id,
)
else:
assert isinstance(block, ToolResultBlock)
if isinstance(block.output, str):
block.output = [TextBlock(text=block.output)]
# Append the text
if not block.output or block.output[-1].type != "text":
block.output.append(TextBlock(text=event.delta))
else:
block.output[-1].text += event.delta

case EventType.TOOL_RESULT_DATA_DELTA:
block = self._find_block("tool_result", event.tool_call_id)
if block is None:
logger.warning(
"ToolResultBlock %r not found, skipping.",
event.tool_call_id,
)
else:
assert isinstance(block, ToolResultBlock)
if isinstance(block.output, str):
block.output = [TextBlock(text=block.output)]
src = (
Base64Source(
data=event.data,
media_type=event.media_type,
)
if event.data is not None
else URLSource(
url=str(event.url),
media_type=event.media_type,
)
)
block.output.append(
DataBlock(id=event.block_id, source=src),
)

case EventType.TOOL_RESULT_END:
block = self._find_block("tool_result", event.tool_call_id)
if block is None:
logger.warning(
"ToolResultBlock %r not found, skipping.",
event.tool_call_id,
)
else:
assert isinstance(block, ToolResultBlock)
block.state = event.state
# The paired ToolCallBlock's lifecycle ends with its
# result — flip it to FINISHED here so the SSE-rebuilt
# reply_msg matches ``agent.state.context``, which
# ``_update_tool_call_state`` mutates directly.
call_block = self._find_block("tool_call", event.tool_call_id)
if call_block is not None:
assert isinstance(call_block, ToolCallBlock)
call_block.state = ToolCallState.FINISHED

case EventType.REQUIRE_USER_CONFIRM:
for tool_call in event.tool_calls:
b = self._find_block("tool_call", tool_call.id)
if b is not None:
assert isinstance(b, ToolCallBlock)
# Update the state
b.state = ToolCallState.ASKING
# Record the suggestions
b.suggested_rules = tool_call.suggested_rules

case EventType.USER_CONFIRM_RESULT:
for result in event.confirm_results:
b = self._find_block("tool_call", result.tool_call.id)
if b is not None:
assert isinstance(b, ToolCallBlock)
b.state = (
ToolCallState.ALLOWED
if result.confirmed
else ToolCallState.FINISHED
)

case EventType.REQUIRE_EXTERNAL_EXECUTION:
for tool_call in event.tool_calls:
b = self._find_block("tool_call", tool_call.id)
if b is not None:
assert isinstance(b, ToolCallBlock)
b.state = ToolCallState.SUBMITTED

case EventType.EXTERNAL_EXECUTION_RESULT:
for result in event.execution_results:
self.content.append(result)

return self
```

后面会出类似这种封装吗?还是说现在就有呢?

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.