-
Notifications
You must be signed in to change notification settings - Fork 461
feat(agent-interface): introduce AgentBase abstract class as the interface for agent classes to implement #1126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| """Agent Interface. | ||
|
|
||
| Defines the minimal interface that all agent types must implement. | ||
| """ | ||
|
|
||
| from abc import ABC, abstractmethod | ||
| from typing import Any, AsyncIterator, Type | ||
|
|
||
| from pydantic import BaseModel | ||
|
|
||
| from ..types.agent import AgentInput | ||
| from .agent_result import AgentResult | ||
| from .state import AgentState | ||
|
|
||
|
|
||
| class AgentBase(ABC): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we use Protocol instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pgrayy has also called out that Protocols should be preferred in general over base-classes; it would also enable us to specify the properties as normal fields instead of getters |
||
| """Abstract interface for all agent types in Strands. | ||
|
|
||
| This interface defines the minimal contract that all agent implementations | ||
| must satisfy. | ||
| """ | ||
|
|
||
| @property | ||
| @abstractmethod | ||
| def agent_id(self) -> str: | ||
| """Unique identifier for the agent. | ||
|
|
||
| Returns: | ||
| Unique string identifier for this agent instance. | ||
| """ | ||
| pass | ||
|
|
||
| @property | ||
| @abstractmethod | ||
| def name(self) -> str: | ||
| """Human-readable name of the agent. | ||
|
|
||
| Returns: | ||
| Display name for the agent. | ||
| """ | ||
| pass | ||
|
|
||
| @property | ||
| @abstractmethod | ||
| def state(self) -> AgentState: | ||
| """Current state of the agent. | ||
|
|
||
| Returns: | ||
| AgentState object containing stateful information. | ||
| """ | ||
| pass | ||
|
|
||
| @abstractmethod | ||
| async def invoke_async( | ||
| self, | ||
| prompt: AgentInput = None, | ||
| *, | ||
| invocation_state: dict[str, Any] | None = None, | ||
| structured_output_model: Type[BaseModel] | None = None, | ||
| **kwargs: Any, | ||
| ) -> AgentResult: | ||
| """Asynchronously invoke the agent with the given prompt. | ||
|
|
||
| Args: | ||
| prompt: Input to the agent. | ||
| invocation_state: Optional state to pass to the agent invocation. | ||
| structured_output_model: Optional Pydantic model for structured output. | ||
| **kwargs: Additional provider-specific arguments. | ||
|
|
||
| Returns: | ||
| AgentResult containing the agent's response. | ||
| """ | ||
| pass | ||
|
|
||
| @abstractmethod | ||
| def __call__( | ||
| self, | ||
| prompt: AgentInput = None, | ||
| *, | ||
| invocation_state: dict[str, Any] | None = None, | ||
| structured_output_model: Type[BaseModel] | None = None, | ||
| **kwargs: Any, | ||
| ) -> AgentResult: | ||
| """Synchronously invoke the agent with the given prompt. | ||
|
|
||
| Args: | ||
| prompt: Input to the agent. | ||
| invocation_state: Optional state to pass to the agent invocation. | ||
| structured_output_model: Optional Pydantic model for structured output. | ||
| **kwargs: Additional provider-specific arguments. | ||
|
|
||
| Returns: | ||
| AgentResult containing the agent's response. | ||
| """ | ||
| pass | ||
|
|
||
| @abstractmethod | ||
| def stream_async( | ||
| self, | ||
| prompt: AgentInput = None, | ||
| *, | ||
| invocation_state: dict[str, Any] | None = None, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the use-cases that we're targeting, will |
||
| structured_output_model: Type[BaseModel] | None = None, | ||
| **kwargs: Any, | ||
| ) -> AsyncIterator[Any]: | ||
| """Stream agent execution asynchronously. | ||
|
|
||
| Args: | ||
| prompt: Input to the agent. | ||
| invocation_state: Optional state to pass to the agent invocation. | ||
| structured_output_model: Optional Pydantic model for structured output. | ||
| **kwargs: Additional provider-specific arguments. | ||
|
|
||
| Yields: | ||
| Events representing the streaming execution. | ||
| """ | ||
| pass | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you update the PR description indicating the purpose of the base class - e.g. is it just for agents or is it meant to represent things in-place of an agent (like humans) as the tracking issue #573 calls out.
Specifically, if we were starting fresh, what would implement this? MultiAgent primitives? A2AAgent, etc?