idun-agent-engine 0.3.4__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.
- idun_agent_engine/__init__.py +24 -0
- idun_agent_engine/_version.py +3 -0
- idun_agent_engine/agent/__init__.py +10 -0
- idun_agent_engine/agent/adk/__init__.py +5 -0
- idun_agent_engine/agent/adk/adk.py +296 -0
- idun_agent_engine/agent/base.py +112 -0
- idun_agent_engine/agent/haystack/__init__.py +9 -0
- idun_agent_engine/agent/haystack/haystack.py +274 -0
- idun_agent_engine/agent/haystack/haystack_model.py +13 -0
- idun_agent_engine/agent/haystack/utils.py +13 -0
- idun_agent_engine/agent/langgraph/__init__.py +7 -0
- idun_agent_engine/agent/langgraph/langgraph.py +553 -0
- idun_agent_engine/core/__init__.py +11 -0
- idun_agent_engine/core/app_factory.py +73 -0
- idun_agent_engine/core/config_builder.py +657 -0
- idun_agent_engine/core/engine_config.py +21 -0
- idun_agent_engine/core/server_runner.py +145 -0
- idun_agent_engine/guardrails/__init__.py +0 -0
- idun_agent_engine/guardrails/base.py +24 -0
- idun_agent_engine/guardrails/guardrails_hub/guardrails_hub.py +101 -0
- idun_agent_engine/guardrails/guardrails_hub/utils.py +1 -0
- idun_agent_engine/mcp/__init__.py +5 -0
- idun_agent_engine/mcp/helpers.py +97 -0
- idun_agent_engine/mcp/registry.py +109 -0
- idun_agent_engine/observability/__init__.py +17 -0
- idun_agent_engine/observability/base.py +172 -0
- idun_agent_engine/observability/gcp_logging/__init__.py +0 -0
- idun_agent_engine/observability/gcp_logging/gcp_logging_handler.py +52 -0
- idun_agent_engine/observability/gcp_trace/__init__.py +0 -0
- idun_agent_engine/observability/gcp_trace/gcp_trace_handler.py +116 -0
- idun_agent_engine/observability/langfuse/__init__.py +5 -0
- idun_agent_engine/observability/langfuse/langfuse_handler.py +79 -0
- idun_agent_engine/observability/phoenix/__init__.py +5 -0
- idun_agent_engine/observability/phoenix/phoenix_handler.py +65 -0
- idun_agent_engine/observability/phoenix_local/__init__.py +5 -0
- idun_agent_engine/observability/phoenix_local/phoenix_local_handler.py +123 -0
- idun_agent_engine/py.typed +0 -0
- idun_agent_engine/server/__init__.py +5 -0
- idun_agent_engine/server/dependencies.py +52 -0
- idun_agent_engine/server/lifespan.py +106 -0
- idun_agent_engine/server/routers/__init__.py +5 -0
- idun_agent_engine/server/routers/agent.py +204 -0
- idun_agent_engine/server/routers/agui.py +47 -0
- idun_agent_engine/server/routers/base.py +114 -0
- idun_agent_engine/server/server_config.py +8 -0
- idun_agent_engine/templates/__init__.py +1 -0
- idun_agent_engine/templates/correction.py +65 -0
- idun_agent_engine/templates/deep_research.py +40 -0
- idun_agent_engine/templates/translation.py +70 -0
- idun_agent_engine-0.3.4.dist-info/METADATA +335 -0
- idun_agent_engine-0.3.4.dist-info/RECORD +60 -0
- idun_agent_engine-0.3.4.dist-info/WHEEL +4 -0
- idun_agent_engine-0.3.4.dist-info/entry_points.txt +2 -0
- idun_platform_cli/__init__.py +0 -0
- idun_platform_cli/groups/__init__.py +0 -0
- idun_platform_cli/groups/agent/__init__.py +0 -0
- idun_platform_cli/groups/agent/main.py +16 -0
- idun_platform_cli/groups/agent/package.py +70 -0
- idun_platform_cli/groups/agent/serve.py +107 -0
- idun_platform_cli/main.py +14 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Idun Agent Engine public API.
|
|
2
|
+
|
|
3
|
+
Exports top-level helpers for convenience imports in examples and user code.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from ._version import __version__
|
|
7
|
+
from .agent.base import BaseAgent
|
|
8
|
+
from .core.app_factory import create_app
|
|
9
|
+
from .core.config_builder import ConfigBuilder
|
|
10
|
+
from .core.server_runner import (
|
|
11
|
+
run_server,
|
|
12
|
+
run_server_from_builder,
|
|
13
|
+
run_server_from_config,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"create_app",
|
|
18
|
+
"run_server",
|
|
19
|
+
"run_server_from_config",
|
|
20
|
+
"run_server_from_builder",
|
|
21
|
+
"ConfigBuilder",
|
|
22
|
+
"BaseAgent",
|
|
23
|
+
"__version__",
|
|
24
|
+
]
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""ADK agent adapter implementing the BaseAgent protocol."""
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import uuid
|
|
5
|
+
from collections.abc import AsyncGenerator
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from google.adk.apps.app import App
|
|
9
|
+
from google.adk.memory import (
|
|
10
|
+
InMemoryMemoryService,
|
|
11
|
+
VertexAiMemoryBankService,
|
|
12
|
+
)
|
|
13
|
+
from google.adk.sessions import (
|
|
14
|
+
DatabaseSessionService,
|
|
15
|
+
InMemorySessionService,
|
|
16
|
+
VertexAiSessionService,
|
|
17
|
+
)
|
|
18
|
+
from idun_agent_schema.engine.adk import (
|
|
19
|
+
AdkAgentConfig,
|
|
20
|
+
AdkDatabaseSessionConfig,
|
|
21
|
+
AdkInMemoryMemoryConfig,
|
|
22
|
+
AdkInMemorySessionConfig,
|
|
23
|
+
AdkVertexAiMemoryConfig,
|
|
24
|
+
AdkVertexAiSessionConfig,
|
|
25
|
+
)
|
|
26
|
+
from idun_agent_schema.engine.observability_v2 import ObservabilityConfig
|
|
27
|
+
|
|
28
|
+
from ag_ui_adk import ADKAgent as ADKAGUIAgent
|
|
29
|
+
from idun_agent_engine.agent import base as agent_base
|
|
30
|
+
from idun_agent_engine import observability
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AdkAgent(agent_base.BaseAgent):
|
|
34
|
+
"""ADK agent adapter implementing the BaseAgent protocol."""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
"""Initialize an unconfigured AdkAgent with default state."""
|
|
38
|
+
self._id = str(uuid.uuid4())
|
|
39
|
+
self._agent_type = "ADK"
|
|
40
|
+
self._agent_instance: Any = None
|
|
41
|
+
self._copilotkit_agent_instance: ADKAGUIAgent | None = None
|
|
42
|
+
self._configuration: AdkAgentConfig | None = None
|
|
43
|
+
self._name: str = "Unnamed ADK Agent"
|
|
44
|
+
self._infos: dict[str, Any] = {
|
|
45
|
+
"status": "Uninitialized",
|
|
46
|
+
"name": self._name,
|
|
47
|
+
"id": self._id,
|
|
48
|
+
}
|
|
49
|
+
self._session_service: Any = None
|
|
50
|
+
self._memory_service: Any = None
|
|
51
|
+
# Observability (provider-agnostic)
|
|
52
|
+
self._obs_callbacks: list[Any] | None = None
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def id(self) -> str:
|
|
56
|
+
"""Return unique identifier for this agent instance."""
|
|
57
|
+
return self._id
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def agent_type(self) -> str:
|
|
61
|
+
"""Return agent type label."""
|
|
62
|
+
return self._agent_type
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def name(self) -> str:
|
|
66
|
+
"""Return configured human-readable agent name."""
|
|
67
|
+
return self._name
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def agent_instance(self) -> Any:
|
|
71
|
+
"""Return the underlying ADK agent instance.
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
RuntimeError: If the agent is not yet initialized.
|
|
75
|
+
"""
|
|
76
|
+
if self._agent_instance is None:
|
|
77
|
+
raise RuntimeError("Agent not initialized. Call initialize() first.")
|
|
78
|
+
return self._agent_instance
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def copilotkit_agent_instance(self) -> ADKAGUIAgent:
|
|
82
|
+
"""Return the CopilotKit agent instance.
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
RuntimeError: If the CopilotKit agent is not yet initialized.
|
|
86
|
+
"""
|
|
87
|
+
if self._copilotkit_agent_instance is None:
|
|
88
|
+
raise RuntimeError(
|
|
89
|
+
"CopilotKit agent not initialized. Call initialize() first."
|
|
90
|
+
)
|
|
91
|
+
return self._copilotkit_agent_instance
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def configuration(self) -> AdkAgentConfig:
|
|
95
|
+
"""Return validated configuration.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
RuntimeError: If the agent has not been configured yet.
|
|
99
|
+
"""
|
|
100
|
+
if not self._configuration:
|
|
101
|
+
raise RuntimeError("Agent not configured. Call initialize() first.")
|
|
102
|
+
return self._configuration
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def infos(self) -> dict[str, Any]:
|
|
106
|
+
"""Return diagnostic information about the agent instance."""
|
|
107
|
+
self._infos["underlying_agent_type"] = (
|
|
108
|
+
str(type(self._agent_instance)) if self._agent_instance else "N/A"
|
|
109
|
+
)
|
|
110
|
+
return self._infos
|
|
111
|
+
|
|
112
|
+
async def initialize(
|
|
113
|
+
self,
|
|
114
|
+
config: AdkAgentConfig,
|
|
115
|
+
observability_config: list[ObservabilityConfig] | None = None,
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Initialize the ADK agent asynchronously."""
|
|
118
|
+
self._configuration = AdkAgentConfig.model_validate(config)
|
|
119
|
+
|
|
120
|
+
self._name = self._configuration.app_name or "Unnamed ADK Agent"
|
|
121
|
+
self._infos["name"] = self._name
|
|
122
|
+
|
|
123
|
+
# Observability (provider-agnostic)
|
|
124
|
+
if observability_config:
|
|
125
|
+
handlers, infos = observability.create_observability_handlers(
|
|
126
|
+
observability_config # type: ignore[arg-type]
|
|
127
|
+
)
|
|
128
|
+
self._obs_callbacks = []
|
|
129
|
+
for handler in handlers:
|
|
130
|
+
# Even if callbacks aren't used by ADK directly, instantiating the handler
|
|
131
|
+
# might set up global instrumentation (e.g. Phoenix, Langfuse env vars).
|
|
132
|
+
self._obs_callbacks.extend(handler.get_callbacks())
|
|
133
|
+
|
|
134
|
+
if infos:
|
|
135
|
+
self._infos["observability"] = infos
|
|
136
|
+
|
|
137
|
+
if observability_config:
|
|
138
|
+
try:
|
|
139
|
+
# Check if langfuse is enabled in any of the observability configs
|
|
140
|
+
def _is_langfuse_provider(c: Any) -> bool:
|
|
141
|
+
provider = getattr(c, "provider", None)
|
|
142
|
+
if provider is None and isinstance(c, dict):
|
|
143
|
+
provider = c.get("provider")
|
|
144
|
+
|
|
145
|
+
if provider is not None and hasattr(provider, "value"):
|
|
146
|
+
provider = provider.value
|
|
147
|
+
|
|
148
|
+
return str(provider).lower() == "langfuse"
|
|
149
|
+
|
|
150
|
+
is_langfuse_enabled = any(
|
|
151
|
+
_is_langfuse_provider(config) for config in observability_config
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if is_langfuse_enabled:
|
|
155
|
+
import os
|
|
156
|
+
langfuse_pk = os.environ.get("LANGFUSE_PUBLIC_KEY")
|
|
157
|
+
langfuse_host = os.environ.get("LANGFUSE_BASE_URL")
|
|
158
|
+
print(f"LANGFUSE_PUBLIC_KEY: {langfuse_pk}")
|
|
159
|
+
print(f"LANGFUSE_BASE_URL: {langfuse_host}")
|
|
160
|
+
try:
|
|
161
|
+
from openinference.instrumentation.google_adk import (
|
|
162
|
+
GoogleADKInstrumentor,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
GoogleADKInstrumentor().instrument()
|
|
166
|
+
print("GoogleADKInstrumentor instrumented successfully.")
|
|
167
|
+
except ImportError:
|
|
168
|
+
print(
|
|
169
|
+
"openinference-instrumentation-google-adk not installed, skipping Google ADK instrumentation."
|
|
170
|
+
)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
print(f"Failed to instrument Google ADK: {e}")
|
|
173
|
+
except Exception as e:
|
|
174
|
+
print(f"Error checking observability config for ADK instrumentation: {e}")
|
|
175
|
+
|
|
176
|
+
# Initialize Session Service
|
|
177
|
+
await self._initialize_session_service()
|
|
178
|
+
|
|
179
|
+
# Initialize Memory Service
|
|
180
|
+
await self._initialize_memory_service()
|
|
181
|
+
|
|
182
|
+
# Load the agent instance
|
|
183
|
+
agent = self._load_agent(self._configuration.agent)
|
|
184
|
+
|
|
185
|
+
self._agent_instance = App(root_agent=agent, name=self._name)
|
|
186
|
+
|
|
187
|
+
# Initialize CopilotKit/AG-UI Agent Wrapper
|
|
188
|
+
# TODO: Pass session and memory services when supported by AG-UI ADK adapter if needed
|
|
189
|
+
self._copilotkit_agent_instance = ADKAGUIAgent(
|
|
190
|
+
adk_agent=agent,
|
|
191
|
+
session_service=self._session_service,
|
|
192
|
+
memory_service=self._memory_service,
|
|
193
|
+
app_name=self._name,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
self._infos["status"] = "Initialized"
|
|
197
|
+
self._infos["config_used"] = self._configuration.model_dump()
|
|
198
|
+
|
|
199
|
+
async def _initialize_session_service(self) -> None:
|
|
200
|
+
"""Initialize the session service based on configuration."""
|
|
201
|
+
if not self._configuration:
|
|
202
|
+
raise RuntimeError("Configuration not initialized")
|
|
203
|
+
|
|
204
|
+
if not self._configuration.session_service:
|
|
205
|
+
# Default to InMemory if not specified
|
|
206
|
+
self._session_service = InMemorySessionService()
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
config = self._configuration.session_service
|
|
210
|
+
if isinstance(config, AdkInMemorySessionConfig):
|
|
211
|
+
self._session_service = InMemorySessionService()
|
|
212
|
+
elif isinstance(config, AdkVertexAiSessionConfig):
|
|
213
|
+
self._session_service = VertexAiSessionService(
|
|
214
|
+
project=config.project_id,
|
|
215
|
+
location=config.location,
|
|
216
|
+
agent_engine_id=config.reasoning_engine_app_name,
|
|
217
|
+
)
|
|
218
|
+
elif isinstance(config, AdkDatabaseSessionConfig):
|
|
219
|
+
self._session_service = DatabaseSessionService(db_url=config.db_url)
|
|
220
|
+
else:
|
|
221
|
+
raise ValueError(f"Unsupported session service type: {config.type}") # type: ignore
|
|
222
|
+
|
|
223
|
+
async def _initialize_memory_service(self) -> None:
|
|
224
|
+
"""Initialize the memory service based on configuration."""
|
|
225
|
+
if not self._configuration:
|
|
226
|
+
raise RuntimeError("Configuration not initialized")
|
|
227
|
+
|
|
228
|
+
if not self._configuration.memory_service:
|
|
229
|
+
# Default to InMemory if not specified
|
|
230
|
+
self._memory_service = InMemoryMemoryService()
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
config = self._configuration.memory_service
|
|
234
|
+
if isinstance(config, AdkInMemoryMemoryConfig):
|
|
235
|
+
self._memory_service = InMemoryMemoryService()
|
|
236
|
+
elif isinstance(config, AdkVertexAiMemoryConfig):
|
|
237
|
+
self._memory_service = VertexAiMemoryBankService(
|
|
238
|
+
project=config.project_id,
|
|
239
|
+
location=config.location,
|
|
240
|
+
agent_engine_id=config.memory_bank_id,
|
|
241
|
+
)
|
|
242
|
+
else:
|
|
243
|
+
raise ValueError(f"Unsupported memory service type: {config.type}") # type: ignore
|
|
244
|
+
|
|
245
|
+
def _load_agent(self, agent_definition: str) -> Any:
|
|
246
|
+
"""Loads an agent instance from a specified path."""
|
|
247
|
+
try:
|
|
248
|
+
module_path, agent_variable_name = agent_definition.rsplit(":", 1)
|
|
249
|
+
except ValueError:
|
|
250
|
+
raise ValueError(
|
|
251
|
+
"agent_definition must be in the format 'path/to/file.py:variable_name'"
|
|
252
|
+
) from None
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
from pathlib import Path
|
|
256
|
+
|
|
257
|
+
resolved_path = Path(module_path).resolve()
|
|
258
|
+
spec = importlib.util.spec_from_file_location(
|
|
259
|
+
agent_variable_name, str(resolved_path)
|
|
260
|
+
)
|
|
261
|
+
if spec is None or spec.loader is None:
|
|
262
|
+
raise ImportError(f"Could not load spec for module at {module_path}")
|
|
263
|
+
|
|
264
|
+
module = importlib.util.module_from_spec(spec)
|
|
265
|
+
spec.loader.exec_module(module)
|
|
266
|
+
|
|
267
|
+
agent_instance = getattr(module, agent_variable_name)
|
|
268
|
+
return agent_instance
|
|
269
|
+
except (FileNotFoundError, ImportError, AttributeError) as e:
|
|
270
|
+
raise ValueError(
|
|
271
|
+
f"Failed to load agent from {agent_definition}: {e}"
|
|
272
|
+
) from e
|
|
273
|
+
|
|
274
|
+
async def invoke(self, message: Any) -> Any:
|
|
275
|
+
"""Process a single input to chat with the agent."""
|
|
276
|
+
if self._agent_instance is None:
|
|
277
|
+
raise RuntimeError(
|
|
278
|
+
"Agent not initialized. Call initialize() before processing messages."
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# TODO: Implement ADK invoke logic using session and memory services
|
|
282
|
+
raise NotImplementedError("ADK invoke not implemented yet")
|
|
283
|
+
|
|
284
|
+
async def stream(self, message: Any) -> AsyncGenerator[Any]:
|
|
285
|
+
"""Process a single input message and return an asynchronous stream."""
|
|
286
|
+
if self._agent_instance is None:
|
|
287
|
+
raise RuntimeError(
|
|
288
|
+
"Agent not initialized. Call initialize() before processing messages."
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# TODO: Implement ADK stream logic using session and memory services
|
|
292
|
+
raise NotImplementedError("ADK stream not implemented yet")
|
|
293
|
+
|
|
294
|
+
# Required to make this a generator
|
|
295
|
+
if False:
|
|
296
|
+
yield
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Agent base interfaces.
|
|
2
|
+
|
|
3
|
+
Defines the abstract `BaseAgent` used by all agent implementations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from collections.abc import AsyncGenerator
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from idun_agent_schema.engine.agent import BaseAgentConfig
|
|
11
|
+
from idun_agent_schema.engine.observability_v2 import ObservabilityConfig
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseAgent[ConfigType: BaseAgentConfig](ABC):
|
|
15
|
+
"""Abstract base for agents pluggable into the Idun Agent Engine.
|
|
16
|
+
|
|
17
|
+
Implements the public protocol that concrete agent adapters must follow.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
_configuration: ConfigType
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def id(self) -> str:
|
|
25
|
+
"""Unique identifier for the agent instance."""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def agent_type(self) -> str:
|
|
31
|
+
"""Type or category of the agent (e.g., 'LangGraph', 'ADK')."""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def agent_instance(self) -> Any:
|
|
37
|
+
"""Get the underlying agent instance from the specific framework.
|
|
38
|
+
|
|
39
|
+
This might be set after initialization.
|
|
40
|
+
"""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
@abstractmethod
|
|
45
|
+
def copilotkit_agent_instance(self) -> Any:
|
|
46
|
+
"""Get the CopilotKit agent instance.
|
|
47
|
+
|
|
48
|
+
This might be set after initialization.
|
|
49
|
+
"""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def configuration(self) -> ConfigType:
|
|
54
|
+
"""Return current configuration settings for the agent.
|
|
55
|
+
|
|
56
|
+
This is typically the configuration used during initialization.
|
|
57
|
+
"""
|
|
58
|
+
return self._configuration
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def infos(self) -> dict[str, Any]:
|
|
63
|
+
"""General information about the agent instance (e.g., version, status, metadata)."""
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
async def initialize(
|
|
68
|
+
self,
|
|
69
|
+
config: dict[str, Any],
|
|
70
|
+
observability: list[ObservabilityConfig] | None = None,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Initialize the agent with a given configuration.
|
|
73
|
+
|
|
74
|
+
This method should set up the underlying agent framework instance.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
config: A dictionary containing the agent's configuration.
|
|
78
|
+
observability: Optional list of observability configurations.
|
|
79
|
+
"""
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
@abstractmethod
|
|
83
|
+
async def invoke(self, message: Any) -> Any:
|
|
84
|
+
"""Process a single input message and return a response.
|
|
85
|
+
|
|
86
|
+
This should be an awaitable method if the underlying agent processes
|
|
87
|
+
asynchronously.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
message: The input message for the agent.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
The agent's response.
|
|
94
|
+
"""
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
async def stream(self, message: Any) -> AsyncGenerator[Any]:
|
|
99
|
+
"""Process a single input message and return an asynchronous stream.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
message: The input message for the agent.
|
|
103
|
+
|
|
104
|
+
Yields:
|
|
105
|
+
Chunks of the agent's response.
|
|
106
|
+
"""
|
|
107
|
+
# This is an async generator, so it needs `async def` and `yield`
|
|
108
|
+
# For the ABC, we can't have a `yield` directly in the abstract method body.
|
|
109
|
+
# The signature itself defines it as an async generator.
|
|
110
|
+
# Example: async for chunk in agent.stream(message): ...
|
|
111
|
+
if False: # pragma: no cover (This is just to make it a generator type for static analysis)
|
|
112
|
+
yield
|