Skip to content

Models API Reference

This section provides detailed API documentation for the core data models in Protolink. These models represent the fundamental data structures used throughout the framework for agent communication, task management, and data exchange.

Table of Contents


AgentCard

@dataclass
class AgentCard:
    name: str
    description: str
    url: str
    version: str = "1.0.0"
    protocol_version: str = protolink_version
    capabilities: AgentCapabilities = field(default_factory=AgentCapabilities)
    skills: list[AgentSkill] = field(default_factory=list)
    input_formats: list[MimeType] = field(default_factory=lambda: ["text/plain"])
    output_formats: list[MimeType] = field(default_factory=lambda: ["text/plain"])
    security_schemes: dict[str, dict[str, Any]] | None = field(default_factory=dict)
    role: AgentRoleType = "worker"
    tags: list[str] = field(default_factory=list)

Agent identity and capability declaration. This is the main metadata card that describes an agent's identity, capabilities, and security requirements.

Parameters

Parameter Type Default Description
name str Required. Agent name
description str Required. Agent purpose/description
url str Required. Service endpoint URL
version str "1.0.0" Agent version
protocol_version str protolink_version Protolink Protocol version
capabilities AgentCapabilities AgentCapabilities() Supported features
skills list[AgentSkill] [] List of skills the agent can perform
input_formats list[MimeType] ["text/plain"] Supported input MIME types
output_formats list[MimeType] ["text/plain"] Supported output MIME types
security_schemes dict[SecuritySchemeType, dict[str, Any]] | None {} Authentication schemes
role AgentRoleType "worker" Agent role is a protocol-level contract that defines the agent's responsibility in the system topology (Extends A2A spec)
tags list[str] [] List of tags for categorization. These tags can be used for filtering during discovery (Protolink extension to A2A spec) E.g. "finance", "travel", "math" etc. (Extends A2A spec)

Methods

to_dict() -> dict[str, Any]

Convert the AgentCard to Python Dictionary / JSON format compatible with the A2A agent card specification.

Returns:

dict[str, Any]  # JSON dictionary representation

Example:

card = AgentCard(name="weather_agent", description="Weather service")
json_data = card.to_dict()
print(json_data["name"])  # "weather_agent"


from_dict(data: dict[str, Any]) -> AgentCard classmethod

Create an AgentCard from Python dict/JSON data. This method can also handle regular Python dictionaries and includes basic field validation via _validate_fields.

data: dict[str, Any]  # JSON dictionary or Python dict containing agent card data

Returns:

AgentCard  # New AgentCard instance

Example:

json_data = {
    "name": "weather_agent",
    "description": "Weather service",
    "url": "https://api.example.com/weather"
}
card = AgentCard.from_dict(json_data)


_validate_fields(data: dict[str, Any]) -> None

Validate the fields of the AgentCard.

Returns:

None

Example

from protolink.models import AgentCard, AgentCapabilities

card = AgentCard(
    name="weather_agent",
    description="Provides weather information",
    url="https://api.example.com/weather",
    version="1.2.0",
    input_formats=["text/plain", "application/json"],
    output_formats=["text/plain", "application/json", "text/markdown"],
    capabilities=AgentCapabilities(
        streaming=True,
        tool_calling=True,
        max_concurrency=5
    )
)

# Convert to Python dict
json_data = card.to_dict()

AgentCapabilities

@dataclass
class AgentCapabilities:
    streaming: bool = False
    push_notifications: bool = False
    state_transition_history: bool = False
    has_llm: bool = False
    max_concurrency: int = 1
    message_batching: bool = False
    tool_calling: bool = False
    multi_step_reasoning: bool = False
    timeout_support: bool = False
    delegation: bool = False
    rag: bool = False
    code_execution: bool = False

Defines the capabilities and limitations of an agent. This extends the A2A specification with additional capability flags.

Parameters

Parameter Type Default Description
streaming bool False Supports Server-Sent Events (SSE) streaming
push_notifications bool False Supports push notifications (webhooks)
state_transition_history bool False Provides detailed task state history
has_llm bool False Has an LLM component for AI processing
max_concurrency int 1 Maximum concurrent tasks
message_batching bool False Processes multiple messages per request
tool_calling bool False Can call external tools/APIs
multi_step_reasoning bool False Performs multi-step reasoning
timeout_support bool False Respects operation timeouts
delegation bool False Can delegate tasks to other agents
rag bool False Supports Retrieval-Augmented Generation
code_execution bool False Has access to safe execution sandbox

AgentSkill

@dataclass
class AgentSkill:
    id: str
    description: str = ""
    tags: list[str] = field(default_factory=list)
    examples: list[str] = field(default_factory=list)

Represents a task that an agent can perform. Skills are used to advertise specific capabilities to other agents.

Parameters

Parameter Type Default Description
id str Required. Unique Human-readable identifier for the task
description str "" Optional Detailed description of what the task does
tags list[str] [] Optional Tags for categorization
examples list[str] [] Optional Example inputs or usage scenarios

Example

skill = AgentSkill(
    id="weather_forecast",
    description="Get weather forecast for any location",
    tags=["weather", "forecast", "location"],
    examples=[
        "What's the weather in New York?",
        "Forecast for London tomorrow",
        "Weather in 90210"
    ]
)

Type Aliases in AgentCard

MimeType

Type alias for supported MIME types in Protolink. These are used to specify the input and output formats that agents can handle.

Supported Types

Category MIME Types
Text text/plain, text/markdown, text/html
Structured Data application/json
Images image/png, image/jpeg, image/webp
Audio audio/wav, audio/mpeg, audio/ogg
Video video/mp4, video/webm
Documents application/pdf

SecuritySchemeType

Type alias for supported security schemes in Protolink. These are used to specify the authentication methods that agents can use.

Category Security Schemes
API key apiKey
HTTP (bearer/basic/digest) http
full OAuth OAuth2 oauth2
Certificates mutualTLS
OIDC auto-discovery openIdConnect

Task

@dataclass
class Task:
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    state: TaskState = TaskState.SUBMITTED
    messages: list[Message] = field(default_factory=list)
    artifacts: list[Artifact] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)
    created_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())

Unit of work exchanged between agents. Tasks encapsulate a complete unit of work including messages, state, and output artifacts.

Parameters

Parameter Type Default Description
id str uuid4() Unique task identifier
state TaskState SUBMITTED Current task state
messages list[Message] [] Communication history
artifacts list[Artifact] [] Output artifacts
metadata dict[str, Any] {} Additional metadata
created_at str utc now Creation timestamp

Methods


add_message(message: Message) -> Task

Add a message to the task's communication history.

Parameters:

message: Message  # Message object to add to the task

Returns:

Task  # Self for method chaining

Example:

task = Task()
task.add_message(Message.user("What's the weather?"))
task.add_message(Message.agent("It's sunny!"))


add_artifact(artifact: Artifact) -> Task

Add an output artifact to the task (v0.2.0+).

Parameters:

artifact: Artifact  # Artifact representing task output

Returns:

Task  # Self for method chaining

Example:

artifact = Artifact()
artifact.add_text("Weather analysis complete")
task.add_artifact(artifact)


update_state(state: TaskState) -> Task

Update the task's current state.

Parameters:

state: TaskState  # New task state from TaskState enum

Returns:

Task  # Self for method chaining

Example:

task.update_state(TaskState.WORKING)
# ... process task ...
task.update_state(TaskState.COMPLETED)


complete(response_text: str) -> Task

Mark the task as completed with a response message.

Parameters:

response_text: str  # Final response message text

Returns:

Task  # Self for method chaining

Example:

task.complete("The weather is sunny and 75°F.")
print(task.state)  # TaskState.COMPLETED


fail(error_message: str) -> Task

Mark the task as failed with an error message.

Parameters:

error_message: str  # Description of the error

Returns:

Task  # Self for method chaining

Example:

task.fail("Weather API unavailable")
print(task.state)  # TaskState.FAILED
print(task.metadata["error"])  # "Weather API unavailable"


to_dict() -> dict[str, Any]

Convert the task to a dictionary for serialization.

Returns:

dict[str, Any]  # Dictionary representation of the task

Example:

task_dict = task.to_dict()
print(task_dict["id"])  # Task UUID
print(task_dict["state"])  # Current state as string


from_dict(data: dict[str, Any]) -> Task classmethod

Create a task from a dictionary.

Parameters:

data: dict[str, Any]  # Dictionary containing task data

Returns:

Task  # New Task instance

Example:

task_dict = {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "state": "completed",
    "messages": []
}
task = Task.from_dict(task_dict)


create(message: Message) -> Task classmethod

Create a new task with an initial message.

Parameters:

message: Message  # Initial message for the task

Returns:

Task  # New Task instance with the message added

Example:

task = Task.create(Message.user("Analyze this data"))
print(len(task.messages))  # 1
print(task.state)  # TaskState.SUBMITTED

Example

from protolink.models import Task, Message

# Create task with initial message
task = Task.create(Message.user("What's the weather in New York?"))

# Add response and complete
task.add_message(Message.agent("It's 72°F and sunny in New York."))
task.complete("Weather forecast provided.")

# Or use convenience method
task = Task.create(Message.user("Hello")).complete("Hi there!")

TaskState

class TaskState(Enum):
    SUBMITTED = "submitted"
    WORKING = "working"
    INPUT_REQUIRED = "input-required"
    COMPLETED = "completed"
    CANCELED = "canceled"
    FAILED = "failed"
    UNKNOWN = "unknown"

Enumeration of possible task states.

Values

Value Description
SUBMITTED Task has been submitted to the agent
WORKING Agent is actively processing the task
INPUT_REQUIRED Agent needs additional input from user
COMPLETED Task has been successfully completed
CANCELED Task was canceled by user or agent
FAILED Task failed due to an error
UNKNOWN Task state is unknown

Message

@dataclass
class Message:
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    role: MessageRoleType = "user"
    parts: list[Part] = field(default_factory=list)
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())

Single unit of communication between agents. Messages contain one or more parts and have a specific role.

Parameters

Parameter Type Default Description
id str uuid4() Unique message identifier
role MessageRoleType "user" Sender role
parts list[Part] [] Message content parts
timestamp str now Creation timestamp

Role Types

  • "user": Message from a human user
  • "agent": Message from an agent
  • "system": System-level message

Methods


add_text(text: str) -> Message

Add a text part to the message.

Parameters:

text: str  # Text content to add

Returns:

Message  # Self for method chaining

Example:

msg = Message(role="user")
msg.add_text("Hello, world!")
print(len(msg.parts))  # 1
print(msg.parts[0].content)  # "Hello, world!"


add_part(part: Part) -> Message

Add a content part to the message.

Parameters:

part: Part  # Part object to add (text, image, file, etc.)

Returns:

Message  # Self for method chaining

Example:

msg = Message(role="agent")
msg.add_part(Part("text", "Here's the analysis:"))
msg.add_part(Part("data", {"result": "success"}))


to_dict() -> dict[str, Any]

Convert the message to a dictionary for serialization.

Returns:

dict[str, Any]  # Dictionary representation of the message

Example:

msg = Message.user("Hello")
msg_dict = msg.to_dict()
print(msg_dict["role"])  # "user"
print(msg_dict["parts"][0]["content"])  # "Hello"


from_dict(data: dict[str, Any]) -> Message classmethod

Create a message from a dictionary.

Parameters:

data: dict[str, Any]  # Dictionary containing message data

Returns:

Message  # New Message instance

Example:

msg_dict = {
    "id": "msg-123",
    "role": "user",
    "parts": [{"type": "text", "content": "Hello"}],
    "timestamp": "2023-01-01T00:00:00Z"
}
msg = Message.from_dict(msg_dict)


user(text: str) -> Message classmethod

Create a user message with text content (convenience method).

Parameters:

text: str  # Message text content

Returns:

Message  # New Message instance with role "user"

Example:

msg = Message.user("What's the weather?")
print(msg.role)  # "user"
print(msg.parts[0].content)  # "What's the weather?"


agent(text: str) -> Message classmethod

Create an agent message with text content (convenience method).

Parameters:

text: str  # Message text content

Returns:

Message  # New Message instance with role "agent"

Example:

msg = Message.agent("It's sunny and 75°F.")
print(msg.role)  # "agent"
print(msg.parts[0].content)  # "It's sunny and 75°F."

Example

from protolink.models import Message, Part

# Create messages using convenience methods
user_msg = Message.user("What's the weather?")
agent_msg = Message.agent("It's sunny and 75°F.")

# Create message with multiple parts
msg = Message(role="user")
msg.add_text("Here's an image:")
msg.add_part(Part("image", image_data))

Part

@dataclass
class Part:
    type: PartType
    content: Any

Atomic content unit within a message. Parts represent individual pieces of content like text, images, or files.

Parameters

Parameter Type Description
type PartType Content type (e.g., 'text', 'image', 'file')
content Any The actual content data

Methods

to_dict() -> dict[str, Any]

Convert to dictionary.

Returns: Dictionary representation

from_dict(data: dict[str, Any]) -> Part

Create from dictionary.

Parameters: - data: Dictionary data

Returns: New Part instance

text(content: str) -> Part (classmethod)

Create a text part.

Parameters: - content: Text content

Returns: New Part instance with type "text"

Example

from protolink.models import Part

# Create different types of parts
text_part = Part.text("Hello, world!")
image_part = Part("image", binary_image_data)
file_part = Part("file", {"filename": "report.pdf", "data": pdf_data})

Artifact

@dataclass
class Artifact:
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    parts: list[Part] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)
    created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())

Output produced by a task (v0.2.0+). Artifacts represent results from task execution - files, structured data, analysis results, etc.

Parameters

Parameter Type Default Description
id str uuid4() Unique artifact identifier
parts list[Part] [] Content parts of the artifact
metadata dict[str, Any] {} Artifact metadata
created_at str utc now Creation timestamp

Methods

add_part(part: Part) -> Artifact

Add content part to artifact.

Parameters: - part: Part to add

Returns: Self for method chaining

add_text(text: str) -> Artifact

Add text content (convenience method).

Parameters: - text: Text content

Returns: Self for method chaining

to_dict() -> dict[str, Any]

Convert to dictionary.

Returns: Dictionary representation

from_dict(data: dict[str, Any]) -> Artifact

Create from dictionary.

Parameters: - data: Dictionary data

Returns: New Artifact instance

Example

from protolink.models import Artifact, Part

# Create artifact with multiple parts
artifact = Artifact()
artifact.add_text("Analysis Results:")
artifact.add_part(Part("data", {"results": [1, 2, 3]}))
artifact.add_part(Part("chart", chart_image_data))

# Set metadata
artifact.metadata["type"] = "analysis_report"
artifact.metadata["version"] = "1.0"


EndpointSpec

@dataclass(frozen=True)
class EndpointSpec:
    name: str
    path: str
    method: HttpMethod
    handler: Callable[..., Awaitable]
    content_type: Literal["json", "html"] = "json"
    streaming: bool = False
    mode: Literal["request_response", "stream"] = "request_response"
    request_parser: Callable[[Any], Any] | None = None
    request_source: RequestSourceType = "none"

Defines the contract for a server endpoint. This model bridges the gap between the server implementation (Agent/Registry) and the underlying transport.

Parameters

Parameter Type Default Description
name str Required. Unique internal name for the endpoint
path str Required. URL path (e.g., /tasks/)
method HttpMethod Required. HTTP method (GET, POST, etc.)
handler Callable Required. Async function that handles the request
content_type str "json" Response content type (json or html)
streaming bool False Whether the endpoint supports streaming responses
mode str "request_response" Interaction mode (request_response or stream)
request_parser Callable None Optional function to parse raw request data
request_source RequestSourceType "none" Source of request data (body, query_params, etc.)

Context

@dataclass
class Context:
    context_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    messages: list = field(default_factory=list)  # List[Message]
    metadata: dict[str, Any] = field(default_factory=dict)
    created_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
    last_accessed: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())

Represents a conversation context (session). Contexts group messages across multiple turns, enabling long-running conversations and session persistence.

Parameters

Parameter Type Default Description
context_id str uuid4() Unique context identifier
messages list [] All messages in this context
metadata dict[str, Any] {} Custom context data
created_at str utc now Creation timestamp
last_accessed str utc now Last activity timestamp

Methods

add_message(message) -> Context

Add a message to this context.

Parameters: - message: Message object to add

Returns: Self for method chaining

to_dict() -> dict

Convert context to dictionary.

Returns: Dictionary representation

from_dict(data: dict) -> Context

Create context from dictionary.

Parameters: - data: Dictionary data

Returns: New Context instance

Example

from protolink.models import Context, Message

# Create new context
context = Context()
context.metadata["user_id"] = "user123"
context.metadata["session_type"] = "weather_chat"

# Add messages
context.add_message(Message.user("What's the weather?"))
context.add_message(Message.agent("It's sunny!"))

# Context maintains conversation history
for msg in context.messages:
    print(f"{msg.role}: {msg.parts[0].content}")

Usage Patterns

Task Workflow

from protolink.models import Task, Message, Artifact, TaskState

# Create and submit task
task = Task.create(Message.user("Analyze this data"))

# Process task
task.update_state(TaskState.WORKING)

# Add results
artifact = Artifact()
artifact.add_text("Analysis complete")
artifact.add_part(Part("data", {"result": "success"}))

task.add_artifact(artifact)
task.add_message(Message.agent("Analysis complete"))
task.update_state(TaskState.COMPLETED)

Context Management

from protolink.models import Context, Message

# Long-running conversation
context = Context()
context.add_message(Message.user("Hello"))
context.add_message(Message.agent("Hi! How can I help?"))

# Continue conversation later
context.add_message(Message.user("What did we discuss?"))
# Context maintains full history

Serialization

All models support JSON/dict serialization:

# Convert to dict
task_dict = task.to_dict()

# Restore from dict
restored_task = Task.from_dict(task_dict)

# Works for all models
context_dict = context.to_dict()
restored_context = Context.from_dict(context_dict)