Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ __pycache__
.venv
coverage.xml
.nox
spec.json
9 changes: 9 additions & 0 deletions development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Development

## Type generation from spec

<!-- TODO replace spec.json with the public url so we always get the latest version-->

```bash
uv run datamodel-codegen --input ./spec.json --input-file-type jsonschema --output ./src/a2a/types.py --target-python-version 3.10 --output-model-type pydantic_v2.BaseModel --disable-timestamp --use-schema-description --use-union-operator --use-field-description --use-default --use-default-kwarg --use-one-literal-as-default --class-name A2A --use-standard-collections

Check failure on line 8 in development.md

View workflow job for this annotation

GitHub Actions / Check Spelling

`kwarg` is not a recognized word. (unrecognized-spelling)
```
2 changes: 1 addition & 1 deletion examples/helloworld/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def main() -> None:
'message': {
'role': 'user',
'parts': [
{'type': 'text', 'text': 'how much is 10 USD in INR?'}
{'kind': 'text', 'text': 'how much is 10 USD in INR?'}
],
'messageId': uuid4().hex,
},
Expand Down
2 changes: 1 addition & 1 deletion examples/langgraph/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def create_send_message_payload(
payload: dict[str, Any] = {
'message': {
'role': 'user',
'parts': [{'type': 'text', 'text': text}],
'parts': [{'kind': 'text', 'text': text}],
'messageId': uuid4().hex,
},
}
Expand Down
76 changes: 32 additions & 44 deletions src/a2a/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ class DataPart(BaseModel):
"""
Structured data content
"""
metadata: dict[str, Any] | None = None
kind: Literal['data'] = 'data'
"""
Optional metadata associated with the part.
Part type - data for DataParts
"""
type: Literal['data'] = 'data'
metadata: dict[str, Any] | None = None
"""
Part type - data for DataParts
Optional metadata associated with the part.
"""


Expand Down Expand Up @@ -577,11 +577,11 @@ class TaskState(Enum):
submitted = 'submitted'
working = 'working'
input_required = 'input-required'
auth_required = 'auth-required'
completed = 'completed'
canceled = 'canceled'
failed = 'failed'
rejected = 'rejected'
auth_required = 'auth-required'
unknown = 'unknown'


Expand All @@ -590,6 +590,10 @@ class TextPart(BaseModel):
Represents a text segment within parts.
"""

kind: Literal['text'] = 'text'
"""
Part type - text for TextParts
"""
metadata: dict[str, Any] | None = None
"""
Optional metadata associated with the part.
Expand All @@ -598,10 +602,6 @@ class TextPart(BaseModel):
"""
Text content
"""
type: Literal['text'] = 'text'
"""
Part type - text for TextParts
"""


class UnsupportedOperationError(BaseModel):
Expand Down Expand Up @@ -745,13 +745,13 @@ class FilePart(BaseModel):
"""
File content either as url or bytes
"""
metadata: dict[str, Any] | None = None
kind: Literal['file'] = 'file'
"""
Optional metadata associated with the part.
Part type - file for FileParts
"""
type: Literal['file'] = 'file'
metadata: dict[str, Any] | None = None
"""
Part type - file for FileParts
Optional metadata associated with the part.
"""


Expand Down Expand Up @@ -933,7 +933,7 @@ class SetTaskPushNotificationConfigSuccessResponse(BaseModel):

class Artifact(BaseModel):
"""
Represents an artifact generated for a task.
Represents an artifact generated for a task task.
"""

artifactId: str
Expand All @@ -959,9 +959,7 @@ class Artifact(BaseModel):


class GetTaskPushNotificationConfigResponse(
RootModel[
JSONRPCErrorResponse | GetTaskPushNotificationConfigSuccessResponse
]
RootModel[JSONRPCErrorResponse | GetTaskPushNotificationConfigSuccessResponse]
):
root: JSONRPCErrorResponse | GetTaskPushNotificationConfigSuccessResponse
"""
Expand All @@ -978,9 +976,9 @@ class Message(BaseModel):
"""
the context the message is associated with
"""
final: bool | None = None
kind: Literal['message'] = 'message'
"""
indicates the end of the event stream
event type
"""
messageId: str
"""
Expand All @@ -1002,10 +1000,6 @@ class Message(BaseModel):
"""
identifier of task the message is related to
"""
type: Literal['message'] = 'message'
"""
event type
"""


class MessageSendParams(BaseModel):
Expand Down Expand Up @@ -1076,9 +1070,7 @@ class SendStreamingMessageRequest(BaseModel):


class SetTaskPushNotificationConfigResponse(
RootModel[
JSONRPCErrorResponse | SetTaskPushNotificationConfigSuccessResponse
]
RootModel[JSONRPCErrorResponse | SetTaskPushNotificationConfigSuccessResponse]
):
root: JSONRPCErrorResponse | SetTaskPushNotificationConfigSuccessResponse
"""
Expand All @@ -1103,6 +1095,10 @@ class TaskArtifactUpdateEvent(BaseModel):
"""
the context the task is associated with
"""
kind: Literal['artifact-update'] = 'artifact-update'
"""
event type
"""
lastChunk: bool | None = None
"""
Indicates if this is the last chunk of the artifact
Expand All @@ -1115,10 +1111,6 @@ class TaskArtifactUpdateEvent(BaseModel):
"""
Task id
"""
type: Literal['artifact-update'] = 'artifact-update'
"""
event type
"""


class TaskStatus(BaseModel):
Expand Down Expand Up @@ -1150,6 +1142,10 @@ class TaskStatusUpdateEvent(BaseModel):
"""
indicates the end of the event stream
"""
kind: Literal['status-update'] = 'status-update'
"""
event type
"""
metadata: dict[str, Any] | None = None
"""
extension metadata
Expand All @@ -1162,10 +1158,6 @@ class TaskStatusUpdateEvent(BaseModel):
"""
Task id
"""
type: Literal['status-update'] = 'status-update'
"""
event type
"""


class A2ARequest(
Expand Down Expand Up @@ -1207,6 +1199,10 @@ class Task(BaseModel):
"""
unique identifier for the task
"""
kind: Literal['task'] = 'task'
"""
event type
"""
metadata: dict[str, Any] | None = None
"""
extension metadata
Expand All @@ -1215,10 +1211,6 @@ class Task(BaseModel):
"""
current status of the task
"""
type: Literal['task'] = 'task'
"""
event type
"""


class CancelTaskSuccessResponse(BaseModel):
Expand Down Expand Up @@ -1301,9 +1293,7 @@ class SendStreamingMessageSuccessResponse(BaseModel):
"""


class CancelTaskResponse(
RootModel[JSONRPCErrorResponse | CancelTaskSuccessResponse]
):
class CancelTaskResponse(RootModel[JSONRPCErrorResponse | CancelTaskSuccessResponse]):
root: JSONRPCErrorResponse | CancelTaskSuccessResponse
"""
JSON-RPC response for the 'tasks/cancel' method.
Expand Down Expand Up @@ -1342,9 +1332,7 @@ class JSONRPCResponse(
"""


class SendMessageResponse(
RootModel[JSONRPCErrorResponse | SendMessageSuccessResponse]
):
class SendMessageResponse(RootModel[JSONRPCErrorResponse | SendMessageSuccessResponse]):
root: JSONRPCErrorResponse | SendMessageSuccessResponse
"""
JSON-RPC response model for the 'message/send' method.
Expand Down
4 changes: 2 additions & 2 deletions tests/client/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@
'id': 'task-abc',
'contextId': 'session-xyz',
'status': {'state': 'working'},
'type': 'task',
'kind': 'task',
}

MINIMAL_CANCELLED_TASK: dict[str, Any] = {
'id': 'task-abc',
'contextId': 'session-xyz',
'status': {'state': 'canceled'},
'type': 'task',
'kind': 'task',
}


Expand Down Expand Up @@ -237,7 +237,7 @@
client = A2AClient(
httpx_client=mock_httpx_client,
agent_card=mock_agent_card,
url='http://otherurl.com',

Check failure on line 240 in tests/client/test_client.py

View workflow job for this annotation

GitHub Actions / Check Spelling

`otherurl` is not a recognized word. (unrecognized-spelling)
)
assert (
client.url == mock_agent_card.url
Expand Down
2 changes: 1 addition & 1 deletion tests/server/events/test_event_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
'id': '123',
'contextId': 'session-xyz',
'status': {'state': 'submitted'},
'type': 'task',
'kind': 'task',
}

MESSAGE_PAYLOAD: dict[str, Any] = {
Expand Down
2 changes: 1 addition & 1 deletion tests/server/events/test_event_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
'id': '123',
'contextId': 'session-xyz',
'status': {'state': 'submitted'},
'type': 'task',
'kind': 'task',
}
MESSAGE_PAYLOAD: dict[str, Any] = {
'role': 'agent',
Expand Down
2 changes: 1 addition & 1 deletion tests/server/request_handlers/test_jsonrpc_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
'id': 'task_123',
'contextId': 'session-xyz',
'status': {'state': 'submitted'},
'type': 'task',
'kind': 'task',
}
MESSAGE_PAYLOAD: dict[str, Any] = {
'role': 'agent',
Expand Down
2 changes: 1 addition & 1 deletion tests/server/tasks/test_inmemory_task_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'id': 'task-abc',
'contextId': 'session-xyz',
'status': {'state': 'submitted'},
'type': 'task',
'kind': 'task',
}


Expand Down
4 changes: 2 additions & 2 deletions tests/server/tasks/test_task_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
'id': 'task-abc',
'contextId': 'session-xyz',
'status': {'state': 'submitted'},
'type': 'task',
'kind': 'task',
}


Expand Down Expand Up @@ -205,7 +205,7 @@ async def test_save_task_event_new_task_no_task_id(
'id': 'new-task-id',
'contextId': 'some-context',
'status': {'state': 'working'},
'type': 'task',
'kind': 'task',
}
task = Task(**task_data)
await task_manager_without_id.save_task_event(task)
Expand Down
Loading