将 StreamEvent 列表转换为 AssistantEvent 列表。 这个函数模拟了 Claude Code 中从 API 流式事件 到 Agentic Loop 可用事件的转换过程。 对应源码: - api/client.rs:538-562 (MessageStream::next_event) - conversation.rs:353-390 (build_assistant_message)
(stream_events: list[StreamEvent])
| 412 | |
| 413 | |
| 414 | def process_stream_events(stream_events: list[StreamEvent]) -> list[AssistantEvent]: |
| 415 | """ |
| 416 | 将 StreamEvent 列表转换为 AssistantEvent 列表。 |
| 417 | |
| 418 | 这个函数模拟了 Claude Code 中从 API 流式事件 |
| 419 | 到 Agentic Loop 可用事件的转换过程。 |
| 420 | |
| 421 | 对应源码: |
| 422 | - api/client.rs:538-562 (MessageStream::next_event) |
| 423 | - conversation.rs:353-390 (build_assistant_message) |
| 424 | """ |
| 425 | assistant_events = [] |
| 426 | # 正在构建中的内容块 (key = index) |
| 427 | building_blocks: dict[int, ContentBlockState] = {} |
| 428 | |
| 429 | for event in stream_events: |
| 430 | event_type = event.event_type |
| 431 | |
| 432 | if event_type == "message_start": |
| 433 | # 消息开始,通常包含元信息(model, id 等) |
| 434 | # 我们这里不需要特别处理 |
| 435 | pass |
| 436 | |
| 437 | elif event_type == "content_block_start": |
| 438 | # 一个新的内容块开始了 |
| 439 | index = event.data["index"] |
| 440 | block = event.data["content_block"] |
| 441 | block_type = block["type"] # "text" or "tool_use" |
| 442 | |
| 443 | state = ContentBlockState( |
| 444 | index=index, |
| 445 | block_type=block_type, |
| 446 | ) |
| 447 | |
| 448 | if block_type == "tool_use": |
| 449 | state.tool_id = block.get("id", "") |
| 450 | state.tool_name = block.get("name", "") |
| 451 | |
| 452 | if block_type == "text" and block.get("text"): |
| 453 | # 有些 content_block_start 自带初始文本 |
| 454 | state.text = block["text"] |
| 455 | assistant_events.append(AssistantEvent( |
| 456 | event_type=AssistantEventType.TEXT_DELTA, |
| 457 | text=block["text"], |
| 458 | )) |
| 459 | |
| 460 | building_blocks[index] = state |
| 461 | |
| 462 | elif event_type == "content_block_delta": |
| 463 | # 增量更新 |
| 464 | index = event.data["index"] |
| 465 | delta = event.data["delta"] |
| 466 | delta_type = delta["type"] |
| 467 | |
| 468 | state = building_blocks.get(index) |
| 469 | if state is None: |
| 470 | continue |
| 471 |
no test coverage detected