Skip to content

Commit 9f59f54

Browse files
Merge pull request #52 from x42en/main
1. New Ollama Implementation (✅ Well-designed) - OllamaA2AClient and OllamaA2AServer classes - Inherits from existing OpenAI classes for code reuse - Uses OpenAI SDK's base_url parameter for Ollama compatibility - Proper error handling and graceful failures 2. Security & Design (✅ Excellent) - No hardcoded API keys - uses Ollama's API endpoint approach - Proper model validation via /api/tags endpoint - Graceful error handling when Ollama is not running - Follows established patterns from existing providers 3. UI Integration (✅ Complete) - Added Ollama agent cards to the flow builder - Proper configuration forms with API URL, model fields - JavaScript validation and UI flow updates - Consistent with existing OpenAI/Anthropic patterns 4. Backwards Compatibility (✅ Maintained) - All existing imports still work - OpenAI functionality unchanged - No breaking changes to existing APIs - Core models and functionality untouched 5. Code Quality (✅ High Standards) - Proper inheritance structure - Consistent error handling - Good documentation and docstrings - Follows project's coding conventions Testing Results - ✅ All critical imports work correctly - ✅ No regressions in existing functionality - ✅ Ollama classes properly inherit from OpenAI base classes - ✅ Graceful handling of missing Ollama installation - ✅ Core models and streaming functionality unaffected - ✅ UI integration properly implemented Architecture Benefits - Code Reuse: Leverages existing OpenAI implementation - Consistency: Follows established patterns - Extensibility: Easy to add more OpenAI-compatible providers - Maintainability: Minimal duplicate code Minor Notes - Some formatting improvements in OpenAI files (whitespace, imports) - Test files needed minor import fixes (unrelated to Ollama changes)
2 parents 1cbcacc + 55c2864 commit 9f59f54

File tree

12 files changed

+1361
-905
lines changed

12 files changed

+1361
-905
lines changed

python_a2a/__init__.py

Lines changed: 128 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
A2AValidationError,
2222
A2AAuthenticationError,
2323
A2AConfigurationError,
24-
A2AStreamingError
24+
A2AStreamingError,
2525
)
2626

2727
# All core models - these should be available with basic install
@@ -35,7 +35,7 @@
3535
FunctionCallContent,
3636
FunctionResponseContent,
3737
ErrorContent,
38-
Metadata
38+
Metadata,
3939
)
4040
from .models.agent import AgentCard, AgentSkill
4141
from .models.task import Task, TaskStatus, TaskState
@@ -58,29 +58,29 @@
5858
run_registry,
5959
DiscoveryClient,
6060
enable_discovery,
61-
RegistryAgent
61+
RegistryAgent,
6262
)
6363

6464
# Utility functions
6565
from .utils.formatting import (
6666
format_message_as_text,
6767
format_conversation_as_text,
6868
pretty_print_message,
69-
pretty_print_conversation
69+
pretty_print_conversation,
7070
)
7171
from .utils.validation import (
7272
validate_message,
7373
validate_conversation,
7474
is_valid_message,
75-
is_valid_conversation
75+
is_valid_conversation,
7676
)
7777
from .utils.conversion import (
7878
create_text_message,
7979
create_function_call,
8080
create_function_response,
8181
create_error_message,
8282
format_function_params,
83-
conversation_to_messages
83+
conversation_to_messages,
8484
)
8585
from .utils.decorators import skill, agent
8686

@@ -96,7 +96,7 @@
9696
ConditionStep,
9797
ParallelStep,
9898
ParallelBuilder,
99-
StepType
99+
StepType,
100100
)
101101

102102
# MCP integration
@@ -106,7 +106,7 @@
106106
MCPConnectionError,
107107
MCPTimeoutError,
108108
MCPToolError,
109-
MCPTools
109+
MCPTools,
110110
)
111111
from .mcp.agent import MCPEnabledAgent
112112
from .mcp.fastmcp import (
@@ -116,12 +116,9 @@
116116
error_response,
117117
image_response,
118118
multi_content_response,
119-
ContentType as MCPContentType
120-
)
121-
from .mcp.integration import (
122-
FastMCPAgent,
123-
A2AMCPAgent
119+
ContentType as MCPContentType,
124120
)
121+
from .mcp.integration import FastMCPAgent, A2AMCPAgent
125122
from .mcp.proxy import create_proxy_server
126123
from .mcp.transport import create_fastapi_app
127124

@@ -130,23 +127,33 @@
130127
to_a2a_server,
131128
to_langchain_agent,
132129
to_mcp_server,
133-
to_langchain_tool
130+
to_langchain_tool,
134131
)
135132
from .langchain.exceptions import (
136133
LangChainIntegrationError,
137134
LangChainNotInstalledError,
138135
LangChainToolConversionError,
139136
MCPToolConversionError,
140137
LangChainAgentConversionError,
141-
A2AAgentConversionError
138+
A2AAgentConversionError,
139+
)
140+
141+
HAS_LANGCHAIN = (
142+
importlib.util.find_spec("langchain") is not None
143+
or importlib.util.find_spec("langchain_core") is not None
142144
)
143-
HAS_LANGCHAIN = importlib.util.find_spec("langchain") is not None or importlib.util.find_spec("langchain_core") is not None
144145

145146
# Optional integration with LLM providers
146147
# These might not be available if the specific provider packages are not installed
147148
try:
148-
from .client.llm import OpenAIA2AClient, AnthropicA2AClient
149-
from .server.llm import OpenAIA2AServer, AnthropicA2AServer, BedrockA2AServer
149+
from .client.llm import OpenAIA2AClient, OllamaA2AClient, AnthropicA2AClient
150+
from .server.llm import (
151+
OpenAIA2AServer,
152+
OllamaA2AServer,
153+
AnthropicA2AServer,
154+
BedrockA2AServer,
155+
)
156+
150157
HAS_LLM_CLIENTS = True
151158
HAS_LLM_SERVERS = True
152159
except ImportError:
@@ -156,20 +163,23 @@
156163
# Optional doc generation
157164
try:
158165
from .docs import generate_a2a_docs, generate_html_docs
166+
159167
HAS_DOCS = True
160168
except ImportError:
161169
HAS_DOCS = False
162170

163171
# Optional CLI
164172
try:
165173
from .cli import main as cli_main
174+
166175
HAS_CLI = True
167176
except ImportError:
168177
HAS_CLI = False
169178

170179
# Agent Flow import - optional but integrated by default
171180
try:
172181
from .agent_flow import models, engine, server, storage
182+
173183
HAS_AGENT_FLOW_IMPORT = True
174184
except ImportError:
175185
HAS_AGENT_FLOW_IMPORT = False
@@ -193,130 +203,123 @@
193203
# Define __all__ for explicit exports
194204
__all__ = [
195205
# Version
196-
'__version__',
197-
206+
"__version__",
198207
# Exceptions
199-
'A2AError',
200-
'A2AImportError',
201-
'A2AConnectionError',
202-
'A2AResponseError',
203-
'A2ARequestError',
204-
'A2AValidationError',
205-
'A2AAuthenticationError',
206-
'A2AConfigurationError',
207-
'A2AStreamingError',
208-
208+
"A2AError",
209+
"A2AImportError",
210+
"A2AConnectionError",
211+
"A2AResponseError",
212+
"A2ARequestError",
213+
"A2AValidationError",
214+
"A2AAuthenticationError",
215+
"A2AConfigurationError",
216+
"A2AStreamingError",
209217
# Models
210-
'BaseModel',
211-
'Message',
212-
'MessageRole',
213-
'Conversation',
214-
'ContentType',
215-
'TextContent',
216-
'FunctionParameter',
217-
'FunctionCallContent',
218-
'FunctionResponseContent',
219-
'ErrorContent',
220-
'Metadata',
221-
'AgentCard',
222-
'AgentSkill',
223-
'Task',
224-
'TaskStatus',
225-
'TaskState',
226-
218+
"BaseModel",
219+
"Message",
220+
"MessageRole",
221+
"Conversation",
222+
"ContentType",
223+
"TextContent",
224+
"FunctionParameter",
225+
"FunctionCallContent",
226+
"FunctionResponseContent",
227+
"ErrorContent",
228+
"Metadata",
229+
"AgentCard",
230+
"AgentSkill",
231+
"Task",
232+
"TaskStatus",
233+
"TaskState",
227234
# Client
228-
'BaseA2AClient',
229-
'A2AClient',
230-
'AgentNetwork',
231-
'AIAgentRouter',
232-
'StreamingClient',
233-
235+
"BaseA2AClient",
236+
"A2AClient",
237+
"AgentNetwork",
238+
"AIAgentRouter",
239+
"StreamingClient",
234240
# Server
235-
'BaseA2AServer',
236-
'A2AServer',
237-
'run_server',
238-
241+
"BaseA2AServer",
242+
"A2AServer",
243+
"run_server",
239244
# Discovery
240-
'AgentRegistry',
241-
'run_registry',
242-
'DiscoveryClient',
243-
'enable_discovery',
244-
'RegistryAgent',
245-
245+
"AgentRegistry",
246+
"run_registry",
247+
"DiscoveryClient",
248+
"enable_discovery",
249+
"RegistryAgent",
246250
# Utilities
247-
'format_message_as_text',
248-
'format_conversation_as_text',
249-
'pretty_print_message',
250-
'pretty_print_conversation',
251-
'validate_message',
252-
'validate_conversation',
253-
'is_valid_message',
254-
'is_valid_conversation',
255-
'create_text_message',
256-
'create_function_call',
257-
'create_function_response',
258-
'create_error_message',
259-
'format_function_params',
260-
'conversation_to_messages',
261-
'skill',
262-
'agent',
263-
251+
"format_message_as_text",
252+
"format_conversation_as_text",
253+
"pretty_print_message",
254+
"pretty_print_conversation",
255+
"validate_message",
256+
"validate_conversation",
257+
"is_valid_message",
258+
"is_valid_conversation",
259+
"create_text_message",
260+
"create_function_call",
261+
"create_function_response",
262+
"create_error_message",
263+
"format_function_params",
264+
"conversation_to_messages",
265+
"skill",
266+
"agent",
264267
# Workflow
265-
'Flow',
266-
'WorkflowContext',
267-
'WorkflowStep',
268-
'QueryStep',
269-
'AutoRouteStep',
270-
'FunctionStep',
271-
'ConditionalBranch',
272-
'ConditionStep',
273-
'ParallelStep',
274-
'ParallelBuilder',
275-
'StepType',
276-
268+
"Flow",
269+
"WorkflowContext",
270+
"WorkflowStep",
271+
"QueryStep",
272+
"AutoRouteStep",
273+
"FunctionStep",
274+
"ConditionalBranch",
275+
"ConditionStep",
276+
"ParallelStep",
277+
"ParallelBuilder",
278+
"StepType",
277279
# MCP
278-
'MCPClient',
279-
'MCPError',
280-
'MCPConnectionError',
281-
'MCPTimeoutError',
282-
'MCPToolError',
283-
'MCPTools',
284-
'MCPEnabledAgent',
285-
'FastMCP',
286-
'MCPResponse',
287-
'text_response',
288-
'error_response',
289-
'image_response',
290-
'multi_content_response',
291-
'MCPContentType',
292-
'FastMCPAgent',
293-
'A2AMCPAgent',
294-
'create_proxy_server',
295-
'create_fastapi_app',
296-
280+
"MCPClient",
281+
"MCPError",
282+
"MCPConnectionError",
283+
"MCPTimeoutError",
284+
"MCPToolError",
285+
"MCPTools",
286+
"MCPEnabledAgent",
287+
"FastMCP",
288+
"MCPResponse",
289+
"text_response",
290+
"error_response",
291+
"image_response",
292+
"multi_content_response",
293+
"MCPContentType",
294+
"FastMCPAgent",
295+
"A2AMCPAgent",
296+
"create_proxy_server",
297+
"create_fastapi_app",
297298
# LangChain Integration (always included)
298-
'to_a2a_server',
299-
'to_langchain_agent',
300-
'to_mcp_server',
301-
'to_langchain_tool',
302-
'LangChainIntegrationError',
303-
'LangChainNotInstalledError',
304-
'LangChainToolConversionError',
305-
'MCPToolConversionError',
306-
'LangChainAgentConversionError',
307-
'A2AAgentConversionError',
299+
"to_a2a_server",
300+
"to_langchain_agent",
301+
"to_mcp_server",
302+
"to_langchain_tool",
303+
"LangChainIntegrationError",
304+
"LangChainNotInstalledError",
305+
"LangChainToolConversionError",
306+
"MCPToolConversionError",
307+
"LangChainAgentConversionError",
308+
"A2AAgentConversionError",
308309
]
309310

310311
# Conditionally add LLM clients/servers
311312
if HAS_LLM_CLIENTS:
312-
__all__.extend(['OpenAIA2AClient', 'AnthropicA2AClient'])
313+
__all__.extend(["OpenAIA2AClient", "OllamaA2AClient", "AnthropicA2AClient"])
313314
if HAS_LLM_SERVERS:
314-
__all__.extend(['OpenAIA2AServer', 'AnthropicA2AServer', 'BedrockA2AServer'])
315+
__all__.extend(
316+
["OpenAIA2AServer", "OllamaA2AServer", "AnthropicA2AServer", "BedrockA2AServer"]
317+
)
315318

316319
# Conditionally add docs
317320
if HAS_DOCS:
318-
__all__.extend(['generate_a2a_docs', 'generate_html_docs'])
321+
__all__.extend(["generate_a2a_docs", "generate_html_docs"])
319322

320323
# Conditionally add CLI
321324
if HAS_CLI:
322-
__all__.append('cli_main')
325+
__all__.append("cli_main")

0 commit comments

Comments
 (0)