gopher-mcp-python 0.1.1__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.
@@ -0,0 +1,52 @@
1
+ """
2
+ Gopher Orch Python SDK - AI Agent orchestration framework with native performance.
3
+
4
+ This module provides Python bindings to the gopher-mcp-python native library through ctypes FFI.
5
+
6
+ Example:
7
+ >>> from gopher_mcp_python import GopherAgent, GopherAgentConfig
8
+ >>>
9
+ >>> # Create an agent with API key
10
+ >>> config = (GopherAgentConfig.builder()
11
+ ... .provider("AnthropicProvider")
12
+ ... .model("claude-3-haiku-20240307")
13
+ ... .api_key("your-api-key")
14
+ ... .build())
15
+ >>> agent = GopherAgent.create(config)
16
+ >>>
17
+ >>> # Run a query
18
+ >>> answer = agent.run("What time is it in Tokyo?")
19
+ >>> print(answer)
20
+ >>>
21
+ >>> # Cleanup
22
+ >>> agent.dispose()
23
+ """
24
+
25
+ from gopher_mcp_python.agent import GopherAgent
26
+ from gopher_mcp_python.config import GopherAgentConfig, GopherAgentConfigBuilder
27
+ from gopher_mcp_python.result import AgentResult, AgentResultStatus, AgentResultBuilder
28
+ from gopher_mcp_python.errors import AgentError, ApiKeyError, ConnectionError, TimeoutError
29
+ from gopher_mcp_python.server_config import ServerConfig
30
+ from gopher_mcp_python.ffi import GopherOrchLibrary
31
+
32
+ __version__ = "0.1.1"
33
+
34
+ __all__ = [
35
+ # Main classes
36
+ "GopherAgent",
37
+ "GopherAgentConfig",
38
+ "GopherAgentConfigBuilder",
39
+ "AgentResult",
40
+ "AgentResultStatus",
41
+ "AgentResultBuilder",
42
+ "ServerConfig",
43
+ # Errors
44
+ "AgentError",
45
+ "ApiKeyError",
46
+ "ConnectionError",
47
+ "TimeoutError",
48
+ # FFI
49
+ "GopherOrchLibrary",
50
+ # Version
51
+ "__version__",
52
+ ]
@@ -0,0 +1,267 @@
1
+ """
2
+ GopherAgent - Main entry point for the gopher-mcp-python Python SDK.
3
+
4
+ Provides a clean, Pythonic interface to the gopher-mcp-python agent functionality.
5
+
6
+ Example:
7
+ # Create an agent with API key
8
+ config = (GopherAgentConfig.builder()
9
+ .provider("AnthropicProvider")
10
+ .model("claude-3-haiku-20240307")
11
+ .api_key("your-api-key")
12
+ .build())
13
+
14
+ agent = GopherAgent.create(config)
15
+
16
+ # Run a query
17
+ answer = agent.run("What time is it in Tokyo?")
18
+ print(answer)
19
+
20
+ # Cleanup
21
+ agent.dispose()
22
+
23
+ Example with context manager:
24
+ with GopherAgent.create(config) as agent:
25
+ answer = agent.run("What time is it in Tokyo?")
26
+ print(answer)
27
+ """
28
+
29
+ import atexit
30
+ from typing import Optional
31
+
32
+ from gopher_mcp_python.config import GopherAgentConfig
33
+ from gopher_mcp_python.result import AgentResult, AgentResultStatus
34
+ from gopher_mcp_python.errors import AgentError, TimeoutError
35
+ from gopher_mcp_python.ffi import GopherOrchLibrary, GopherOrchHandle
36
+
37
+
38
+ _initialized = False
39
+ _cleanup_handler_registered = False
40
+
41
+
42
+ class GopherAgent:
43
+ """
44
+ Main agent class for interacting with the gopher-mcp-python native library.
45
+ """
46
+
47
+ def __init__(self, handle: GopherOrchHandle) -> None:
48
+ """
49
+ Initialize a GopherAgent with a native handle.
50
+
51
+ Note: Use create() factory method instead of direct instantiation.
52
+ """
53
+ self._handle = handle
54
+ self._disposed = False
55
+
56
+ def __enter__(self) -> "GopherAgent":
57
+ """Context manager entry."""
58
+ return self
59
+
60
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
61
+ """Context manager exit with automatic cleanup."""
62
+ self.dispose()
63
+
64
+ @staticmethod
65
+ def init() -> None:
66
+ """
67
+ Initialize the gopher-mcp-python library.
68
+
69
+ Must be called before creating any agents. Called automatically by
70
+ create() if not already initialized.
71
+
72
+ Raises:
73
+ AgentError: if initialization fails
74
+ """
75
+ global _initialized
76
+ if _initialized:
77
+ return
78
+
79
+ lib = GopherOrchLibrary.get_instance()
80
+ if lib is None:
81
+ raise AgentError("Failed to load gopher-mcp-python native library")
82
+
83
+ _initialized = True
84
+ _setup_cleanup_handler()
85
+
86
+ @staticmethod
87
+ def shutdown() -> None:
88
+ """
89
+ Shutdown the gopher-mcp-python library.
90
+
91
+ Called automatically on process exit, but can be called manually.
92
+ """
93
+ global _initialized
94
+ _initialized = False
95
+
96
+ @staticmethod
97
+ def is_initialized() -> bool:
98
+ """Check if the library is initialized."""
99
+ return _initialized
100
+
101
+ @staticmethod
102
+ def create(config: GopherAgentConfig) -> "GopherAgent":
103
+ """
104
+ Create a new GopherAgent instance.
105
+
106
+ Args:
107
+ config: Agent configuration
108
+
109
+ Returns:
110
+ GopherAgent instance
111
+
112
+ Raises:
113
+ AgentError: if agent creation fails
114
+ """
115
+ if not _initialized:
116
+ GopherAgent.init()
117
+
118
+ lib = GopherOrchLibrary.get_instance()
119
+ if lib is None:
120
+ raise AgentError("Native library not available")
121
+
122
+ handle: Optional[GopherOrchHandle] = None
123
+ try:
124
+ if config.has_api_key():
125
+ handle = lib.agent_create_by_api_key(
126
+ config.provider, config.model, config.api_key
127
+ )
128
+ else:
129
+ handle = lib.agent_create_by_json(
130
+ config.provider, config.model, config.server_config
131
+ )
132
+ except Exception as e:
133
+ raise AgentError(f"Failed to create agent: {e}")
134
+
135
+ if handle is None:
136
+ error = lib.get_last_error_message()
137
+ lib.clear_error()
138
+ raise AgentError(error or "Failed to create agent")
139
+
140
+ return GopherAgent(handle)
141
+
142
+ @staticmethod
143
+ def create_with_api_key(provider: str, model: str, api_key: str) -> "GopherAgent":
144
+ """
145
+ Create a new GopherAgent with API key.
146
+
147
+ Args:
148
+ provider: Provider name (e.g., "AnthropicProvider")
149
+ model: Model name (e.g., "claude-3-haiku-20240307")
150
+ api_key: API key for fetching remote server config
151
+
152
+ Returns:
153
+ GopherAgent instance
154
+ """
155
+ return GopherAgent.create(
156
+ GopherAgentConfig.builder()
157
+ .provider(provider)
158
+ .model(model)
159
+ .api_key(api_key)
160
+ .build()
161
+ )
162
+
163
+ @staticmethod
164
+ def create_with_server_config(
165
+ provider: str, model: str, server_config: str
166
+ ) -> "GopherAgent":
167
+ """
168
+ Create a new GopherAgent with JSON server config.
169
+
170
+ Args:
171
+ provider: Provider name (e.g., "AnthropicProvider")
172
+ model: Model name (e.g., "claude-3-haiku-20240307")
173
+ server_config: JSON server configuration
174
+
175
+ Returns:
176
+ GopherAgent instance
177
+ """
178
+ return GopherAgent.create(
179
+ GopherAgentConfig.builder()
180
+ .provider(provider)
181
+ .model(model)
182
+ .server_config(server_config)
183
+ .build()
184
+ )
185
+
186
+ def run(self, query: str, timeout_ms: int = 60000) -> str:
187
+ """
188
+ Run a query against the agent.
189
+
190
+ Args:
191
+ query: The user query to process
192
+ timeout_ms: Timeout in milliseconds (default: 60000)
193
+
194
+ Returns:
195
+ The agent's response
196
+
197
+ Raises:
198
+ AgentError: if the query fails
199
+ """
200
+ self._ensure_not_disposed()
201
+
202
+ lib = GopherOrchLibrary.get_instance()
203
+ if lib is None:
204
+ raise AgentError("Native library not available")
205
+
206
+ try:
207
+ response = lib.agent_run(self._handle, query, timeout_ms)
208
+ if response is None:
209
+ return f'No response for query: "{query}"'
210
+ return response
211
+ except Exception as e:
212
+ raise AgentError(f"Query execution failed: {e}")
213
+
214
+ def run_detailed(self, query: str, timeout_ms: int = 60000) -> AgentResult:
215
+ """
216
+ Run a query with detailed result information.
217
+
218
+ Args:
219
+ query: The user query to process
220
+ timeout_ms: Timeout in milliseconds (default: 60000)
221
+
222
+ Returns:
223
+ AgentResult with response and metadata
224
+ """
225
+ try:
226
+ response = self.run(query, timeout_ms)
227
+ return (
228
+ AgentResult.builder()
229
+ .response(response)
230
+ .status(AgentResultStatus.SUCCESS)
231
+ .iteration_count(1)
232
+ .tokens_used(0)
233
+ .build()
234
+ )
235
+ except TimeoutError as e:
236
+ return AgentResult.timeout(str(e))
237
+ except Exception as e:
238
+ return AgentResult.error(str(e))
239
+
240
+ def dispose(self) -> None:
241
+ """Dispose of the agent and free resources."""
242
+ if self._disposed:
243
+ return
244
+
245
+ self._disposed = True
246
+ lib = GopherOrchLibrary.get_instance()
247
+ if lib is not None and self._handle is not None:
248
+ lib.agent_release(self._handle)
249
+
250
+ def is_disposed(self) -> bool:
251
+ """Check if agent is disposed."""
252
+ return self._disposed
253
+
254
+ def _ensure_not_disposed(self) -> None:
255
+ """Ensure agent has not been disposed."""
256
+ if self._disposed:
257
+ raise AgentError("Agent has been disposed")
258
+
259
+
260
+ def _setup_cleanup_handler() -> None:
261
+ """Register cleanup handler for process exit."""
262
+ global _cleanup_handler_registered
263
+ if _cleanup_handler_registered:
264
+ return
265
+
266
+ _cleanup_handler_registered = True
267
+ atexit.register(GopherAgent.shutdown)
@@ -0,0 +1,172 @@
1
+ """
2
+ Configuration classes for the Gopher Security MCP SDK.
3
+
4
+ Provides a builder pattern for creating agent configurations with validation.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+
10
+ class GopherAgentConfig:
11
+ """
12
+ Immutable configuration for GopherAgent.
13
+
14
+ Use the builder() method to create configurations.
15
+
16
+ Example:
17
+ >>> config = (GopherAgentConfig.builder()
18
+ ... .provider("AnthropicProvider")
19
+ ... .model("claude-3-haiku-20240307")
20
+ ... .api_key("your-api-key")
21
+ ... .build())
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ provider: str,
27
+ model: str,
28
+ api_key: Optional[str] = None,
29
+ server_config: Optional[str] = None,
30
+ ) -> None:
31
+ """
32
+ Initialize a GopherAgentConfig.
33
+
34
+ Args:
35
+ provider: The LLM provider name (e.g., "AnthropicProvider")
36
+ model: The model name (e.g., "claude-3-haiku-20240307")
37
+ api_key: API key for fetching remote server config
38
+ server_config: JSON server configuration string
39
+ """
40
+ self._provider = provider
41
+ self._model = model
42
+ self._api_key = api_key
43
+ self._server_config = server_config
44
+
45
+ @property
46
+ def provider(self) -> str:
47
+ """Get the provider name."""
48
+ return self._provider
49
+
50
+ @property
51
+ def model(self) -> str:
52
+ """Get the model name."""
53
+ return self._model
54
+
55
+ @property
56
+ def api_key(self) -> Optional[str]:
57
+ """Get the API key."""
58
+ return self._api_key
59
+
60
+ @property
61
+ def server_config(self) -> Optional[str]:
62
+ """Get the server configuration JSON."""
63
+ return self._server_config
64
+
65
+ def has_api_key(self) -> bool:
66
+ """Check if configuration uses API key."""
67
+ return self._api_key is not None
68
+
69
+ def has_server_config(self) -> bool:
70
+ """Check if configuration uses server config."""
71
+ return self._server_config is not None
72
+
73
+ @staticmethod
74
+ def builder() -> "GopherAgentConfigBuilder":
75
+ """Create a new configuration builder."""
76
+ return GopherAgentConfigBuilder()
77
+
78
+
79
+ class GopherAgentConfigBuilder:
80
+ """
81
+ Builder for GopherAgentConfig.
82
+
83
+ Provides a fluent interface for building configurations with validation.
84
+ """
85
+
86
+ def __init__(self) -> None:
87
+ self._provider: Optional[str] = None
88
+ self._model: Optional[str] = None
89
+ self._api_key: Optional[str] = None
90
+ self._server_config: Optional[str] = None
91
+
92
+ def provider(self, provider: str) -> "GopherAgentConfigBuilder":
93
+ """
94
+ Set the LLM provider.
95
+
96
+ Args:
97
+ provider: The provider name (e.g., "AnthropicProvider", "OpenAIProvider")
98
+
99
+ Returns:
100
+ self for chaining
101
+ """
102
+ self._provider = provider
103
+ return self
104
+
105
+ def model(self, model: str) -> "GopherAgentConfigBuilder":
106
+ """
107
+ Set the model name.
108
+
109
+ Args:
110
+ model: The model name (e.g., "claude-3-haiku-20240307")
111
+
112
+ Returns:
113
+ self for chaining
114
+ """
115
+ self._model = model
116
+ return self
117
+
118
+ def api_key(self, api_key: str) -> "GopherAgentConfigBuilder":
119
+ """
120
+ Set the API key for fetching remote server config.
121
+
122
+ Mutually exclusive with server_config().
123
+
124
+ Args:
125
+ api_key: The API key
126
+
127
+ Returns:
128
+ self for chaining
129
+ """
130
+ self._api_key = api_key
131
+ return self
132
+
133
+ def server_config(self, server_config: str) -> "GopherAgentConfigBuilder":
134
+ """
135
+ Set the JSON server configuration.
136
+
137
+ Mutually exclusive with api_key().
138
+
139
+ Args:
140
+ server_config: JSON string containing server configuration
141
+
142
+ Returns:
143
+ self for chaining
144
+ """
145
+ self._server_config = server_config
146
+ return self
147
+
148
+ def build(self) -> GopherAgentConfig:
149
+ """
150
+ Build the configuration.
151
+
152
+ Returns:
153
+ GopherAgentConfig instance
154
+
155
+ Raises:
156
+ ValueError: If required fields are missing or configuration is invalid
157
+ """
158
+ if not self._provider:
159
+ raise ValueError("Provider is required")
160
+ if not self._model:
161
+ raise ValueError("Model is required")
162
+ if not self._api_key and not self._server_config:
163
+ raise ValueError("Either api_key or server_config is required")
164
+ if self._api_key and self._server_config:
165
+ raise ValueError("Cannot specify both api_key and server_config")
166
+
167
+ return GopherAgentConfig(
168
+ provider=self._provider,
169
+ model=self._model,
170
+ api_key=self._api_key,
171
+ server_config=self._server_config,
172
+ )
@@ -0,0 +1,38 @@
1
+ """
2
+ Custom error classes for the Gopher Security MCP SDK.
3
+
4
+ Provides typed exceptions for different error conditions:
5
+ - AgentError: Base class for all agent-related errors
6
+ - ApiKeyError: Invalid or missing API key
7
+ - ConnectionError: Network or connection failures
8
+ - TimeoutError: Operation timed out
9
+ """
10
+
11
+
12
+ class AgentError(Exception):
13
+ """Base exception for agent-related errors."""
14
+
15
+ def __init__(self, message: str) -> None:
16
+ self.message = message
17
+ super().__init__(message)
18
+
19
+
20
+ class ApiKeyError(AgentError):
21
+ """Exception raised when API key is invalid or missing."""
22
+
23
+ def __init__(self, message: str = "Invalid or missing API key") -> None:
24
+ super().__init__(message)
25
+
26
+
27
+ class ConnectionError(AgentError):
28
+ """Exception raised when connection to server fails."""
29
+
30
+ def __init__(self, message: str = "Connection failed") -> None:
31
+ super().__init__(message)
32
+
33
+
34
+ class TimeoutError(AgentError):
35
+ """Exception raised when operation times out."""
36
+
37
+ def __init__(self, message: str = "Operation timed out") -> None:
38
+ super().__init__(message)
@@ -0,0 +1,7 @@
1
+ """
2
+ FFI bindings for the gopher-mcp-python native library.
3
+ """
4
+
5
+ from gopher_mcp_python.ffi.library import GopherOrchLibrary, GopherOrchHandle
6
+
7
+ __all__ = ["GopherOrchLibrary", "GopherOrchHandle"]