|
6 | 6 | from typing import Any |
7 | 7 |
|
8 | 8 | from google.protobuf import struct_pb2 |
9 | | -from google.protobuf.json_format import ParseDict |
| 9 | +from google.protobuf.json_format import MessageToDict, ParseDict |
10 | 10 |
|
11 | 11 | from a2a.types.a2a_pb2 import ( |
12 | 12 | Artifact, |
@@ -401,6 +401,45 @@ def get_text_parts(parts: Sequence[Part]) -> list[str]: |
401 | 401 | return [part.text for part in parts if part.HasField('text')] |
402 | 402 |
|
403 | 403 |
|
| 404 | +def get_data_parts(parts: Sequence[Part]) -> list[Any]: |
| 405 | + """Extracts structured data from all data Parts. |
| 406 | +
|
| 407 | + Each returned element is the Python object obtained by converting |
| 408 | + the ``google.protobuf.Value`` back via ``MessageToDict``. |
| 409 | +
|
| 410 | + Args: |
| 411 | + parts: A sequence of ``Part`` objects. |
| 412 | +
|
| 413 | + Returns: |
| 414 | + A list of deserialized Python objects from any data Parts found. |
| 415 | + """ |
| 416 | + return [MessageToDict(part.data) for part in parts if part.HasField('data')] |
| 417 | + |
| 418 | + |
| 419 | +def get_raw_parts(parts: Sequence[Part]) -> list[bytes]: |
| 420 | + """Extracts raw bytes content from all raw Parts. |
| 421 | +
|
| 422 | + Args: |
| 423 | + parts: A sequence of ``Part`` objects. |
| 424 | +
|
| 425 | + Returns: |
| 426 | + A list of ``bytes`` from any raw Parts found. |
| 427 | + """ |
| 428 | + return [part.raw for part in parts if part.HasField('raw')] |
| 429 | + |
| 430 | + |
| 431 | +def get_url_parts(parts: Sequence[Part]) -> list[str]: |
| 432 | + """Extracts URL strings from all URL Parts. |
| 433 | +
|
| 434 | + Args: |
| 435 | + parts: A sequence of ``Part`` objects. |
| 436 | +
|
| 437 | + Returns: |
| 438 | + A list of URL strings from any URL Parts found. |
| 439 | + """ |
| 440 | + return [part.url for part in parts if part.HasField('url')] |
| 441 | + |
| 442 | + |
404 | 443 | # --- Event & Stream Helpers --- |
405 | 444 |
|
406 | 445 |
|
@@ -447,6 +486,129 @@ def new_text_artifact_update_event( # noqa: PLR0913 |
447 | 486 | ) |
448 | 487 |
|
449 | 488 |
|
| 489 | +def new_data_artifact_update_event( # noqa: PLR0913 |
| 490 | + task_id: str, |
| 491 | + context_id: str, |
| 492 | + name: str, |
| 493 | + data: Any, |
| 494 | + media_type: str | None = None, |
| 495 | + append: bool = False, |
| 496 | + last_chunk: bool = False, |
| 497 | + artifact_id: str | None = None, |
| 498 | +) -> TaskArtifactUpdateEvent: |
| 499 | + """Creates a TaskArtifactUpdateEvent with a single data artifact. |
| 500 | +
|
| 501 | + Args: |
| 502 | + task_id: The task ID. |
| 503 | + context_id: The context ID. |
| 504 | + name: The name of the artifact. |
| 505 | + data: JSON-serializable data to embed (dict, list, str, etc.). |
| 506 | + media_type: Optional MIME type of the part content. |
| 507 | + append: Whether to append to the existing artifact. |
| 508 | + last_chunk: Whether this is the last chunk. |
| 509 | + artifact_id: Optional artifact ID (auto-generated if not provided). |
| 510 | +
|
| 511 | + Returns: |
| 512 | + A TaskArtifactUpdateEvent with a single data artifact. |
| 513 | + """ |
| 514 | + return TaskArtifactUpdateEvent( |
| 515 | + task_id=task_id, |
| 516 | + context_id=context_id, |
| 517 | + artifact=new_data_artifact( |
| 518 | + name=name, |
| 519 | + data=data, |
| 520 | + media_type=media_type, |
| 521 | + artifact_id=artifact_id, |
| 522 | + ), |
| 523 | + append=append, |
| 524 | + last_chunk=last_chunk, |
| 525 | + ) |
| 526 | + |
| 527 | + |
| 528 | +def new_raw_artifact_update_event( # noqa: PLR0913 |
| 529 | + task_id: str, |
| 530 | + context_id: str, |
| 531 | + name: str, |
| 532 | + raw: bytes, |
| 533 | + media_type: str | None = None, |
| 534 | + filename: str | None = None, |
| 535 | + append: bool = False, |
| 536 | + last_chunk: bool = False, |
| 537 | + artifact_id: str | None = None, |
| 538 | +) -> TaskArtifactUpdateEvent: |
| 539 | + """Creates a TaskArtifactUpdateEvent with a single raw bytes artifact. |
| 540 | +
|
| 541 | + Args: |
| 542 | + task_id: The task ID. |
| 543 | + context_id: The context ID. |
| 544 | + name: The name of the artifact. |
| 545 | + raw: The raw bytes content. |
| 546 | + media_type: Optional MIME type (e.g. 'image/png'). |
| 547 | + filename: Optional filename. |
| 548 | + append: Whether to append to the existing artifact. |
| 549 | + last_chunk: Whether this is the last chunk. |
| 550 | + artifact_id: Optional artifact ID (auto-generated if not provided). |
| 551 | +
|
| 552 | + Returns: |
| 553 | + A TaskArtifactUpdateEvent with a single raw artifact. |
| 554 | + """ |
| 555 | + return TaskArtifactUpdateEvent( |
| 556 | + task_id=task_id, |
| 557 | + context_id=context_id, |
| 558 | + artifact=new_raw_artifact( |
| 559 | + name=name, |
| 560 | + raw=raw, |
| 561 | + media_type=media_type, |
| 562 | + filename=filename, |
| 563 | + artifact_id=artifact_id, |
| 564 | + ), |
| 565 | + append=append, |
| 566 | + last_chunk=last_chunk, |
| 567 | + ) |
| 568 | + |
| 569 | + |
| 570 | +def new_url_artifact_update_event( # noqa: PLR0913 |
| 571 | + task_id: str, |
| 572 | + context_id: str, |
| 573 | + name: str, |
| 574 | + url: str, |
| 575 | + media_type: str | None = None, |
| 576 | + filename: str | None = None, |
| 577 | + append: bool = False, |
| 578 | + last_chunk: bool = False, |
| 579 | + artifact_id: str | None = None, |
| 580 | +) -> TaskArtifactUpdateEvent: |
| 581 | + """Creates a TaskArtifactUpdateEvent with a single URL artifact. |
| 582 | +
|
| 583 | + Args: |
| 584 | + task_id: The task ID. |
| 585 | + context_id: The context ID. |
| 586 | + name: The name of the artifact. |
| 587 | + url: The URL pointing to the file content. |
| 588 | + media_type: Optional MIME type (e.g. 'image/png'). |
| 589 | + filename: Optional filename. |
| 590 | + append: Whether to append to the existing artifact. |
| 591 | + last_chunk: Whether this is the last chunk. |
| 592 | + artifact_id: Optional artifact ID (auto-generated if not provided). |
| 593 | +
|
| 594 | + Returns: |
| 595 | + A TaskArtifactUpdateEvent with a single URL artifact. |
| 596 | + """ |
| 597 | + return TaskArtifactUpdateEvent( |
| 598 | + task_id=task_id, |
| 599 | + context_id=context_id, |
| 600 | + artifact=new_url_artifact( |
| 601 | + name=name, |
| 602 | + url=url, |
| 603 | + media_type=media_type, |
| 604 | + filename=filename, |
| 605 | + artifact_id=artifact_id, |
| 606 | + ), |
| 607 | + append=append, |
| 608 | + last_chunk=last_chunk, |
| 609 | + ) |
| 610 | + |
| 611 | + |
450 | 612 | def get_stream_response_text( |
451 | 613 | response: StreamResponse, delimiter: str = '\n' |
452 | 614 | ) -> str: |
|
0 commit comments