aigency 0.0.1rc235167702__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aigency/agents/client.py +78 -0
- aigency/agents/communicator.py +157 -0
- aigency/agents/executor.py +58 -2
- aigency/agents/generator.py +123 -3
- aigency/schemas/agent/agent.py +41 -3
- aigency/schemas/agent/model.py +37 -3
- aigency/schemas/agent/remote_agent.py +41 -0
- aigency/schemas/agent/skills.py +34 -2
- aigency/schemas/agent/tools.py +99 -12
- aigency/schemas/aigency_config.py +35 -1
- aigency/schemas/metadata/metadata.py +32 -2
- aigency/schemas/observability/observability.py +38 -3
- aigency/schemas/observability/phoenix.py +32 -2
- aigency/schemas/service/capabilities.py +29 -2
- aigency/schemas/service/interface.py +32 -2
- aigency/schemas/service/service.py +35 -2
- aigency/tools/generator.py +59 -8
- aigency/utils/config_service.py +82 -10
- aigency/utils/logger.py +135 -46
- aigency/utils/singleton.py +62 -1
- aigency/utils/utils.py +63 -6
- aigency-0.1.0.dist-info/METADATA +171 -0
- aigency-0.1.0.dist-info/RECORD +26 -0
- aigency-0.0.1rc235167702.dist-info/METADATA +0 -267
- aigency-0.0.1rc235167702.dist-info/RECORD +0 -23
- {aigency-0.0.1rc235167702.dist-info → aigency-0.1.0.dist-info}/WHEEL +0 -0
- {aigency-0.0.1rc235167702.dist-info → aigency-0.1.0.dist-info}/top_level.txt +0 -0
aigency/agents/client.py
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
"""Remote agent client module.
|
2
|
+
|
3
|
+
This module provides client functionality for connecting to and communicating with
|
4
|
+
remote agents in the A2A (Agent-to-Agent) ecosystem. It encapsulates the HTTP
|
5
|
+
client setup and agent card management required for inter-agent communication.
|
6
|
+
|
7
|
+
The AgentClient class serves as a wrapper around the A2A client factory and
|
8
|
+
provides a simplified interface for sending messages to remote agents while
|
9
|
+
handling connection management and protocol details.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
Creating and using an agent client:
|
13
|
+
|
14
|
+
>>> agent_card = AgentCard(name="remote_agent", url="http://localhost:8080")
|
15
|
+
>>> client = AgentClient(agent_card)
|
16
|
+
>>> response = await client.send_message(message_request)
|
17
|
+
|
18
|
+
Attributes:
|
19
|
+
None: This module contains only class definitions.
|
20
|
+
"""
|
21
|
+
|
22
|
+
import httpx
|
23
|
+
|
24
|
+
from a2a.client.client import ClientConfig
|
25
|
+
from a2a.client.client_factory import ClientFactory
|
26
|
+
from a2a.types import AgentCard, Message, SendMessageResponse
|
27
|
+
|
28
|
+
|
29
|
+
class AgentClient:
|
30
|
+
"""A class to hold the connections to the remote agents.
|
31
|
+
|
32
|
+
This class manages connections to remote agents using the A2A protocol.
|
33
|
+
It provides methods for retrieving agent information and sending messages
|
34
|
+
to remote agents.
|
35
|
+
|
36
|
+
Attributes:
|
37
|
+
_httpx_client (httpx.AsyncClient): The HTTP client used for asynchronous requests.
|
38
|
+
agent_card (AgentCard): The agent card containing metadata about the remote agent.
|
39
|
+
"""
|
40
|
+
|
41
|
+
def __init__(self, agent_card: AgentCard):
|
42
|
+
"""Initialize a connection to a remote agent.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
agent_card (AgentCard): The agent card containing metadata about the remote agent.
|
46
|
+
|
47
|
+
Raises:
|
48
|
+
None
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
None
|
52
|
+
"""
|
53
|
+
self._httpx_client = httpx.AsyncClient(timeout=60)
|
54
|
+
self.card = agent_card
|
55
|
+
|
56
|
+
config = ClientConfig(httpx_client=self._httpx_client)
|
57
|
+
factory = ClientFactory(config=config)
|
58
|
+
self.agent_client = factory.create(agent_card)
|
59
|
+
|
60
|
+
def get_agent(self) -> AgentCard:
|
61
|
+
"""Get the agent card for this remote agent connection.
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
AgentCard: The agent card containing metadata about the remote agent.
|
65
|
+
"""
|
66
|
+
return self.card
|
67
|
+
|
68
|
+
async def send_message(self, message_request: Message) -> SendMessageResponse:
|
69
|
+
"""Send a message to the remote agent.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
message_request (Message): The message request to send to the remote agent.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
SendMessageResponse: The response from the remote agent.
|
76
|
+
"""
|
77
|
+
async for response in self.agent_client.send_message(message_request):
|
78
|
+
yield response
|
@@ -0,0 +1,157 @@
|
|
1
|
+
"""Agent-to-Agent communication module.
|
2
|
+
|
3
|
+
This module provides the core communication infrastructure for agents to interact
|
4
|
+
with each other using the A2A (Agent-to-Agent) protocol. It handles message
|
5
|
+
creation, payload formatting, and remote agent connection management.
|
6
|
+
|
7
|
+
The main component is the Communicator class which manages connections to remote
|
8
|
+
agents and provides methods for delegating tasks and sending messages between
|
9
|
+
agents in a distributed system.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
Basic usage for agent communication:
|
13
|
+
|
14
|
+
>>> connections = {"agent1": client1, "agent2": client2}
|
15
|
+
>>> communicator = Communicator(connections)
|
16
|
+
>>> task_result = await communicator.send_message("agent1", "task description", context)
|
17
|
+
|
18
|
+
Attributes:
|
19
|
+
logger: Module-level logger instance for communication events.
|
20
|
+
"""
|
21
|
+
|
22
|
+
import uuid
|
23
|
+
from typing import Any, Awaitable
|
24
|
+
|
25
|
+
from a2a.types import Message, Task
|
26
|
+
from google.adk.tools.tool_context import ToolContext
|
27
|
+
|
28
|
+
from aigency.utils.logger import get_logger
|
29
|
+
|
30
|
+
logger = get_logger()
|
31
|
+
|
32
|
+
|
33
|
+
class Communicator:
|
34
|
+
"""Base class for agent-to-agent communication.
|
35
|
+
|
36
|
+
This class manages connections to remote agents and provides methods for
|
37
|
+
sending messages and delegating tasks to them.
|
38
|
+
|
39
|
+
Attributes:
|
40
|
+
remote_agent_connections (dict[str, Any]): Dictionary mapping agent names
|
41
|
+
to their client connection objects.
|
42
|
+
"""
|
43
|
+
|
44
|
+
def __init__(self, remote_agent_connections: dict[str, Any] | None = None):
|
45
|
+
"""Initialize the communicator with remote agent connections.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
remote_agent_connections (dict[str, Any] | None, optional): A dictionary
|
49
|
+
that maps agent names to their client connection objects.
|
50
|
+
Defaults to None.
|
51
|
+
"""
|
52
|
+
self.remote_agent_connections: dict[str, Any] = remote_agent_connections or {}
|
53
|
+
|
54
|
+
async def send_message(
|
55
|
+
self, agent_name: str, task: str, tool_context: ToolContext
|
56
|
+
) -> Awaitable[Task | None]:
|
57
|
+
"""Delegate a task to a specific remote agent.
|
58
|
+
|
59
|
+
This method sends a message to a remote agent, requesting it to perform a
|
60
|
+
task. It handles message payload creation and communication.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
agent_name (str): Name of the remote agent to send the task to.
|
64
|
+
task (str): Detailed description of the task for the remote agent.
|
65
|
+
tool_context (ToolContext): Context object containing state and other
|
66
|
+
information.
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
Task | None: A Task object if communication is successful, or None
|
70
|
+
otherwise.
|
71
|
+
|
72
|
+
Raises:
|
73
|
+
ValueError: If the specified agent is not found in connections.
|
74
|
+
"""
|
75
|
+
logger.info(
|
76
|
+
f"`send_message` started for agent: '{agent_name}' with task: '{task}'"
|
77
|
+
)
|
78
|
+
client = self.remote_agent_connections.get(agent_name)
|
79
|
+
if not client:
|
80
|
+
available_agents = list(self.remote_agent_connections.keys())
|
81
|
+
logger.error(
|
82
|
+
f"The LLM tried to call '{agent_name}', but it was not found. "
|
83
|
+
f"Available agents: {available_agents}"
|
84
|
+
)
|
85
|
+
raise ValueError(
|
86
|
+
f"Agent '{agent_name}' not found. Available agents: {available_agents}"
|
87
|
+
)
|
88
|
+
|
89
|
+
state = tool_context.state
|
90
|
+
|
91
|
+
contexts = state.setdefault("remote_agent_contexts", {})
|
92
|
+
agent_context = contexts.setdefault(
|
93
|
+
agent_name, {"context_id": str(uuid.uuid4())}
|
94
|
+
)
|
95
|
+
context_id = agent_context["context_id"]
|
96
|
+
|
97
|
+
task_id = state.get("task_id")
|
98
|
+
input_metadata = state.get("input_message_metadata", {})
|
99
|
+
message_id = input_metadata.get("message_id")
|
100
|
+
|
101
|
+
payload = self.create_send_message_payload(
|
102
|
+
text=task, task_id=task_id, context_id=context_id, message_id=message_id
|
103
|
+
)
|
104
|
+
logger.debug("`send_message` with the following payload: %s", payload)
|
105
|
+
|
106
|
+
send_response = None
|
107
|
+
|
108
|
+
async for resp in client.send_message(
|
109
|
+
message_request=Message(**payload["message"])
|
110
|
+
):
|
111
|
+
send_response = resp
|
112
|
+
|
113
|
+
if isinstance(send_response, tuple):
|
114
|
+
send_response, _ = send_response
|
115
|
+
|
116
|
+
if not isinstance(send_response, Task):
|
117
|
+
logger.warning(
|
118
|
+
f"The response received from agent '{agent_name}' is not a Task object. "
|
119
|
+
f"Received type: {type(send_response)}"
|
120
|
+
)
|
121
|
+
return None
|
122
|
+
|
123
|
+
return send_response
|
124
|
+
|
125
|
+
@staticmethod
|
126
|
+
def create_send_message_payload(
|
127
|
+
text: str,
|
128
|
+
task_id: str | None = None,
|
129
|
+
context_id: str | None = None,
|
130
|
+
message_id: str | None = None,
|
131
|
+
) -> dict[str, Any]:
|
132
|
+
"""Create a message payload to send to a remote agent.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
text (str): The text content of the message.
|
136
|
+
task_id (str | None, optional): Task ID to associate with the message.
|
137
|
+
Defaults to None.
|
138
|
+
context_id (str | None, optional): Context ID to associate with the
|
139
|
+
message. Defaults to None.
|
140
|
+
message_id (str | None, optional): Message ID. If None, a new one will
|
141
|
+
be generated. Defaults to None.
|
142
|
+
|
143
|
+
Returns:
|
144
|
+
dict[str, Any]: A dictionary containing the formatted message payload.
|
145
|
+
"""
|
146
|
+
payload: dict[str, Any] = {
|
147
|
+
"message": {
|
148
|
+
"role": "user",
|
149
|
+
"parts": [{"type": "text", "text": text}],
|
150
|
+
"message_id": message_id or uuid.uuid4().hex,
|
151
|
+
},
|
152
|
+
}
|
153
|
+
if task_id:
|
154
|
+
payload["message"]["task_id"] = task_id
|
155
|
+
if context_id:
|
156
|
+
payload["message"]["context_id"] = context_id
|
157
|
+
return payload
|
aigency/agents/executor.py
CHANGED
@@ -1,4 +1,27 @@
|
|
1
|
-
"""Agent executor module for A2A integration.
|
1
|
+
"""Agent executor module for A2A integration.
|
2
|
+
|
3
|
+
This module provides the execution engine for agents within the A2A (Agent-to-Agent)
|
4
|
+
protocol framework. It handles the lifecycle of agent tasks, session management,
|
5
|
+
and integration with Google ADK runners for processing agent requests.
|
6
|
+
|
7
|
+
The AgentA2AExecutor class manages the execution flow from task submission through
|
8
|
+
completion, handling streaming responses, function calls, and error conditions
|
9
|
+
while maintaining compatibility with the A2A protocol specifications.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
Creating and using an agent executor:
|
13
|
+
|
14
|
+
>>> runner = Runner(app_name="my_agent", agent=agent)
|
15
|
+
>>> executor = AgentA2AExecutor(runner, agent_card)
|
16
|
+
>>> await executor.execute(context, event_queue)
|
17
|
+
|
18
|
+
Attributes:
|
19
|
+
logger: Module-level logger instance for execution events.
|
20
|
+
DEFAULT_USER_ID (str): Default user identifier for session management.
|
21
|
+
|
22
|
+
Todo:
|
23
|
+
* Replace DEFAULT_USER_ID with proper user management system.
|
24
|
+
"""
|
2
25
|
|
3
26
|
from a2a.server.agent_execution import AgentExecutor
|
4
27
|
from a2a.server.agent_execution.context import RequestContext
|
@@ -20,13 +43,24 @@ logger = get_logger()
|
|
20
43
|
# TODO: This needs to be changed
|
21
44
|
DEFAULT_USER_ID = "self"
|
22
45
|
|
46
|
+
|
23
47
|
class AgentA2AExecutor(AgentExecutor):
|
24
|
-
"""Agent executor for A2A integration with Google ADK runners.
|
48
|
+
"""Agent executor for A2A integration with Google ADK runners.
|
49
|
+
|
50
|
+
This class handles the execution of agent tasks within the A2A protocol,
|
51
|
+
managing sessions, processing requests, and handling task lifecycle.
|
52
|
+
|
53
|
+
Attributes:
|
54
|
+
_card (AgentCard): The agent card containing metadata about the agent.
|
55
|
+
_active_sessions (set[str]): Set of active session IDs for tracking.
|
56
|
+
runner (Runner): The Google ADK runner instance for executing agent logic.
|
57
|
+
"""
|
25
58
|
|
26
59
|
def __init__(self, runner: Runner, card: AgentCard):
|
27
60
|
"""Initialize the BaseAgentA2AExecutor.
|
28
61
|
|
29
62
|
Args:
|
63
|
+
runner (Runner): The Google ADK runner instance.
|
30
64
|
card (AgentCard): The agent card containing metadata about the agent.
|
31
65
|
"""
|
32
66
|
self._card = card
|
@@ -65,6 +99,13 @@ class AgentA2AExecutor(AgentExecutor):
|
|
65
99
|
session_id: str,
|
66
100
|
task_updater: TaskUpdater,
|
67
101
|
) -> None:
|
102
|
+
"""Process a request through the agent runner.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
new_message (types.Content): The message content to process.
|
106
|
+
session_id (str): The session ID for this request.
|
107
|
+
task_updater (TaskUpdater): Task updater for reporting progress.
|
108
|
+
"""
|
68
109
|
session_obj = await self._upsert_session(session_id)
|
69
110
|
session_id = session_obj.id
|
70
111
|
|
@@ -112,6 +153,12 @@ class AgentA2AExecutor(AgentExecutor):
|
|
112
153
|
context: RequestContext,
|
113
154
|
event_queue: EventQueue,
|
114
155
|
):
|
156
|
+
"""Execute an agent task.
|
157
|
+
|
158
|
+
Args:
|
159
|
+
context (RequestContext): The request context containing task information.
|
160
|
+
event_queue (EventQueue): Event queue for task updates.
|
161
|
+
"""
|
115
162
|
# Run the agent until either complete or the task is suspended.
|
116
163
|
updater = TaskUpdater(event_queue, context.task_id, context.context_id)
|
117
164
|
# Immediately notify that the task is submitted.
|
@@ -131,6 +178,15 @@ class AgentA2AExecutor(AgentExecutor):
|
|
131
178
|
logger.debug("[ADKAgentA2AExecutor] execute exiting")
|
132
179
|
|
133
180
|
async def cancel(self, context: RequestContext, event_queue: EventQueue):
|
181
|
+
"""Cancel an active agent task.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
context (RequestContext): The request context for the task to cancel.
|
185
|
+
event_queue (EventQueue): Event queue for task updates.
|
186
|
+
|
187
|
+
Raises:
|
188
|
+
ServerError: Always raised as cancellation is not currently supported.
|
189
|
+
"""
|
134
190
|
session_id = context.context_id
|
135
191
|
if session_id in self._active_sessions:
|
136
192
|
logger.info("Cancellation requested for active session: %s", session_id)
|
aigency/agents/generator.py
CHANGED
@@ -1,8 +1,29 @@
|
|
1
|
-
"""Agent
|
1
|
+
"""Agent generation and factory module.
|
2
2
|
|
3
|
-
|
3
|
+
This module provides factory methods for creating A2A-compatible agents and their
|
4
|
+
associated components. It handles the complete agent lifecycle from configuration
|
5
|
+
parsing to executable agent creation, including remote agent connection management.
|
4
6
|
|
7
|
+
The AgentA2AGenerator class uses static factory methods to create agents, agent cards,
|
8
|
+
executors, and establish connections to remote agents. It integrates with various
|
9
|
+
components like tools, models, and communication systems to produce fully functional
|
10
|
+
agents ready for deployment in the A2A ecosystem.
|
11
|
+
|
12
|
+
Example:
|
13
|
+
Creating a complete agent from configuration:
|
14
|
+
|
15
|
+
>>> config = AigencyConfig.from_yaml("agent_config.yaml")
|
16
|
+
>>> agent = AgentA2AGenerator.create_agent(config)
|
17
|
+
>>> agent_card = AgentA2AGenerator.build_agent_card(config)
|
18
|
+
>>> executor = AgentA2AGenerator.build_executor(agent, agent_card)
|
19
|
+
|
20
|
+
Attributes:
|
21
|
+
logger: Module-level logger instance for generation events.
|
22
|
+
"""
|
23
|
+
|
24
|
+
import httpx
|
5
25
|
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
26
|
+
from a2a.client import A2ACardResolver
|
6
27
|
from google.adk.agents import Agent
|
7
28
|
from google.adk.artifacts import InMemoryArtifactService
|
8
29
|
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
|
@@ -10,20 +31,50 @@ from google.adk.runners import Runner
|
|
10
31
|
from google.adk.sessions import InMemorySessionService
|
11
32
|
|
12
33
|
from aigency.agents.executor import AgentA2AExecutor
|
34
|
+
from aigency.agents.client import AgentClient
|
13
35
|
from aigency.schemas.aigency_config import AigencyConfig
|
14
36
|
from aigency.tools.generator import ToolGenerator
|
37
|
+
from aigency.utils.utils import generate_url, safe_async_run
|
38
|
+
from aigency.agents.communicator import Communicator
|
39
|
+
from aigency.utils.logger import get_logger
|
40
|
+
|
41
|
+
logger = get_logger()
|
15
42
|
|
16
43
|
|
17
44
|
class AgentA2AGenerator:
|
18
|
-
"""Generator for creating A2A agents and
|
45
|
+
"""Generator for creating A2A-compatible agents and their components.
|
46
|
+
|
47
|
+
This class provides static methods to create agents, agent cards, executors,
|
48
|
+
and manage remote agent connections for the A2A (Agent-to-Agent) protocol.
|
49
|
+
"""
|
19
50
|
|
20
51
|
@staticmethod
|
21
52
|
def create_agent(agent_config: AigencyConfig) -> Agent:
|
53
|
+
"""Create an Agent instance from configuration.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
agent_config (AigencyConfig): Complete agent configuration containing
|
57
|
+
metadata, service, agent, and observability settings.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
Agent: Configured Agent instance ready for execution.
|
61
|
+
"""
|
22
62
|
|
23
63
|
tools = [
|
24
64
|
ToolGenerator.create_tool(tool_cfg) for tool_cfg in agent_config.agent.tools
|
25
65
|
]
|
26
66
|
|
67
|
+
remote_agents = agent_config.agent.remote_agents
|
68
|
+
if remote_agents:
|
69
|
+
remote_agent_connections = AgentA2AGenerator.build_remote_agent_connections(
|
70
|
+
agent_config
|
71
|
+
)
|
72
|
+
logger.info(f"Remote agent connections: {remote_agent_connections}")
|
73
|
+
communicator = Communicator(
|
74
|
+
remote_agent_connections=remote_agent_connections
|
75
|
+
)
|
76
|
+
tools.append(communicator.send_message)
|
77
|
+
|
27
78
|
return Agent(
|
28
79
|
name=agent_config.metadata.name,
|
29
80
|
model=agent_config.agent.model.name,
|
@@ -33,6 +84,14 @@ class AgentA2AGenerator:
|
|
33
84
|
|
34
85
|
@staticmethod
|
35
86
|
def build_agent_card(agent_config: AigencyConfig) -> AgentCard:
|
87
|
+
"""Build an AgentCard from configuration.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
agent_config (AigencyConfig): Complete agent configuration.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
AgentCard: Agent card containing metadata and capabilities for A2A protocol.
|
94
|
+
"""
|
36
95
|
|
37
96
|
# TODO: Parse properly
|
38
97
|
capabilities = AgentCapabilities(
|
@@ -63,6 +122,15 @@ class AgentA2AGenerator:
|
|
63
122
|
|
64
123
|
@staticmethod
|
65
124
|
def build_executor(agent: Agent, agent_card: AgentCard) -> AgentA2AExecutor:
|
125
|
+
"""Build an AgentA2AExecutor for the given agent.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
agent (Agent): The agent instance to create an executor for.
|
129
|
+
agent_card (AgentCard): The agent card containing metadata.
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
AgentA2AExecutor: Configured executor ready to handle A2A requests.
|
133
|
+
"""
|
66
134
|
|
67
135
|
runner = Runner(
|
68
136
|
app_name=agent.name,
|
@@ -73,3 +141,55 @@ class AgentA2AGenerator:
|
|
73
141
|
)
|
74
142
|
|
75
143
|
return AgentA2AExecutor(runner=runner, card=agent_card)
|
144
|
+
|
145
|
+
@staticmethod
|
146
|
+
def build_remote_agent_connections(agent_config: AigencyConfig):
|
147
|
+
"""Initialize connections to all remote agents asynchronously.
|
148
|
+
|
149
|
+
Tests each connection individually with detailed logging to help identify
|
150
|
+
any connection issues. It attempts to connect to each remote agent address,
|
151
|
+
retrieve its agent card, and store the connection for later use.
|
152
|
+
|
153
|
+
Args:
|
154
|
+
agent_config (AigencyConfig): Configuration containing remote agent details.
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
dict[str, AgentClient]: Dictionary mapping agent names to their client
|
158
|
+
connections.
|
159
|
+
|
160
|
+
Raises:
|
161
|
+
Exception: If any critical failure occurs during connection establishment.
|
162
|
+
"""
|
163
|
+
|
164
|
+
if not agent_config.agent.remote_agents:
|
165
|
+
return {}
|
166
|
+
|
167
|
+
remote_agent_configs = [
|
168
|
+
{"url": generate_url(host=remote_agent.host, port=remote_agent.port)}
|
169
|
+
for remote_agent in agent_config.agent.remote_agents
|
170
|
+
]
|
171
|
+
|
172
|
+
async def _connect():
|
173
|
+
remote_agent_connections = {}
|
174
|
+
async with httpx.AsyncClient(timeout=60) as client:
|
175
|
+
for config in remote_agent_configs:
|
176
|
+
address = config.get("url")
|
177
|
+
logger.debug(f"--- Attempting connection to: {address} ---")
|
178
|
+
try:
|
179
|
+
card_resolver = A2ACardResolver(client, address)
|
180
|
+
card = await card_resolver.get_agent_card()
|
181
|
+
remote_connection = AgentClient(agent_card=card)
|
182
|
+
remote_agent_connections[card.name] = remote_connection
|
183
|
+
except Exception as e:
|
184
|
+
logger.error(
|
185
|
+
f"--- CRITICAL FAILURE for address: {address} ---",
|
186
|
+
exc_info=True,
|
187
|
+
)
|
188
|
+
raise e
|
189
|
+
return remote_agent_connections
|
190
|
+
|
191
|
+
try:
|
192
|
+
return safe_async_run(_connect())
|
193
|
+
except Exception as e:
|
194
|
+
logger.error("--- CRITICAL FAILURE", exc_info=True)
|
195
|
+
raise e
|
aigency/schemas/agent/agent.py
CHANGED
@@ -1,12 +1,50 @@
|
|
1
|
+
"""Agent core logic and capabilities schema definition.
|
2
|
+
|
3
|
+
This module defines the Agent Pydantic model that represents the core logic,
|
4
|
+
AI model configuration, and capabilities of an Aigency agent. It serves as
|
5
|
+
the central configuration for an agent's behavior, skills, tools, and
|
6
|
+
communication capabilities with other agents.
|
7
|
+
|
8
|
+
The Agent class encapsulates all the essential components needed to define
|
9
|
+
an intelligent agent including its instruction set, model configuration,
|
10
|
+
available skills, tools, and connections to remote agents.
|
11
|
+
|
12
|
+
Example:
|
13
|
+
Creating an agent configuration:
|
14
|
+
|
15
|
+
>>> agent = Agent(
|
16
|
+
... model=AgentModel(name="gpt-4", provider="openai"),
|
17
|
+
... instruction="You are a helpful assistant",
|
18
|
+
... skills=[Skill(name="math", description="Mathematical operations")],
|
19
|
+
... tools=[Tool(name="calculator", type=ToolType.FUNCTION)]
|
20
|
+
... )
|
21
|
+
|
22
|
+
Attributes:
|
23
|
+
None: This module contains only Pydantic model definitions.
|
24
|
+
"""
|
25
|
+
|
1
26
|
from pydantic import BaseModel
|
2
27
|
from typing import List, Optional
|
3
28
|
from aigency.schemas.agent.model import AgentModel
|
4
29
|
from aigency.schemas.agent.skills import Skill
|
5
|
-
from aigency.schemas.agent.tools import
|
30
|
+
from aigency.schemas.agent.tools import Tool
|
31
|
+
from aigency.schemas.agent.remote_agent import RemoteAgent
|
32
|
+
|
6
33
|
|
7
34
|
class Agent(BaseModel):
|
8
|
-
"""
|
35
|
+
"""The agent's 'brain': its logic, model and capabilities.
|
36
|
+
|
37
|
+
Attributes:
|
38
|
+
model (AgentModel): Configuration for the AI model to use.
|
39
|
+
instruction (str): System instruction that defines the agent's behavior.
|
40
|
+
skills (List[Skill]): List of skills the agent possesses.
|
41
|
+
tools (List[Tool], optional): List of tools available to the agent.
|
42
|
+
remote_agents (List[RemoteAgent], optional): List of remote agents this
|
43
|
+
agent can communicate with.
|
44
|
+
"""
|
45
|
+
|
9
46
|
model: AgentModel
|
10
47
|
instruction: str
|
11
48
|
skills: List[Skill]
|
12
|
-
tools: Optional[List[
|
49
|
+
tools: Optional[List[Tool]] = []
|
50
|
+
remote_agents: Optional[List[RemoteAgent]] = []
|
aigency/schemas/agent/model.py
CHANGED
@@ -1,12 +1,46 @@
|
|
1
|
+
"""AI model configuration schemas for agent setup.
|
2
|
+
|
3
|
+
This module defines Pydantic models for configuring AI models and their providers
|
4
|
+
within the Aigency framework. It provides structured configuration for different
|
5
|
+
AI model providers and their specific parameters, enabling flexible model
|
6
|
+
selection and configuration for agents.
|
7
|
+
|
8
|
+
The models support various AI providers and allow for extensible configuration
|
9
|
+
of model-specific parameters, API keys, and other provider-specific settings.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
Creating model configurations:
|
13
|
+
|
14
|
+
>>> provider_config = ProviderConfig(name="openai", endpoint="https://api.openai.com")
|
15
|
+
>>> model = AgentModel(name="gpt-4", provider=provider_config)
|
16
|
+
|
17
|
+
Attributes:
|
18
|
+
None: This module contains only Pydantic model definitions.
|
19
|
+
"""
|
20
|
+
|
1
21
|
from typing import Optional
|
2
22
|
from pydantic import BaseModel
|
3
23
|
|
24
|
+
|
4
25
|
class ProviderConfig(BaseModel):
|
5
|
-
"""Configuration for AI model provider.
|
26
|
+
"""Configuration for AI model provider.
|
27
|
+
|
28
|
+
Attributes:
|
29
|
+
name (str): Name of the AI provider.
|
30
|
+
endpoint (str, optional): Custom endpoint URL for the provider.
|
31
|
+
"""
|
32
|
+
|
6
33
|
name: str
|
7
34
|
endpoint: Optional[str] = None
|
8
35
|
|
36
|
+
|
9
37
|
class AgentModel(BaseModel):
|
10
|
-
"""Configuration for AI model.
|
38
|
+
"""Configuration for AI model.
|
39
|
+
|
40
|
+
Attributes:
|
41
|
+
name (str): Name of the AI model to use.
|
42
|
+
provider (ProviderConfig, optional): Provider configuration details.
|
43
|
+
"""
|
44
|
+
|
11
45
|
name: str
|
12
|
-
provider: Optional[ProviderConfig] = None
|
46
|
+
provider: Optional[ProviderConfig] = None
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"""Remote agent connection configuration schema.
|
2
|
+
|
3
|
+
This module defines the RemoteAgent Pydantic model for configuring connections
|
4
|
+
to remote agents in the Aigency framework. It provides the necessary structure
|
5
|
+
for establishing communication with agents running on different services or
|
6
|
+
locations within the A2A ecosystem.
|
7
|
+
|
8
|
+
The RemoteAgent configuration enables agents to discover and communicate with
|
9
|
+
other agents, facilitating distributed agent architectures and collaborative
|
10
|
+
agent workflows.
|
11
|
+
|
12
|
+
Example:
|
13
|
+
Configuring a remote agent connection:
|
14
|
+
|
15
|
+
>>> remote_agent = RemoteAgent(
|
16
|
+
... name="data_processor",
|
17
|
+
... host="agent-data-processor",
|
18
|
+
... port=8080
|
19
|
+
... )
|
20
|
+
|
21
|
+
Attributes:
|
22
|
+
None: This module contains only Pydantic model definitions.
|
23
|
+
"""
|
24
|
+
|
25
|
+
from pydantic import BaseModel, Field
|
26
|
+
|
27
|
+
|
28
|
+
class RemoteAgent(BaseModel):
|
29
|
+
"""Remote agent configuration.
|
30
|
+
|
31
|
+
Configuration for connecting to remote agents in the A2A protocol.
|
32
|
+
|
33
|
+
Attributes:
|
34
|
+
name (str): Name identifier for the remote agent.
|
35
|
+
host (str): Hostname or IP address of the remote agent.
|
36
|
+
port (int): Port number for the remote agent connection (1-65535).
|
37
|
+
"""
|
38
|
+
|
39
|
+
name: str
|
40
|
+
host: str
|
41
|
+
port: int = Field(..., ge=1, le=65535)
|