ouroboros-ai 0.2.3__py3-none-any.whl → 0.4.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.

Potentially problematic release.


This version of ouroboros-ai might be problematic. Click here for more details.

Files changed (44) hide show
  1. ouroboros/__init__.py +1 -1
  2. ouroboros/bigbang/__init__.py +9 -0
  3. ouroboros/bigbang/interview.py +16 -18
  4. ouroboros/bigbang/ontology.py +180 -0
  5. ouroboros/cli/commands/__init__.py +2 -0
  6. ouroboros/cli/commands/init.py +162 -97
  7. ouroboros/cli/commands/mcp.py +161 -0
  8. ouroboros/cli/commands/run.py +165 -27
  9. ouroboros/cli/main.py +2 -1
  10. ouroboros/core/ontology_aspect.py +455 -0
  11. ouroboros/core/ontology_questions.py +462 -0
  12. ouroboros/evaluation/__init__.py +16 -1
  13. ouroboros/evaluation/consensus.py +569 -11
  14. ouroboros/evaluation/models.py +81 -0
  15. ouroboros/events/ontology.py +135 -0
  16. ouroboros/mcp/__init__.py +83 -0
  17. ouroboros/mcp/client/__init__.py +20 -0
  18. ouroboros/mcp/client/adapter.py +632 -0
  19. ouroboros/mcp/client/manager.py +600 -0
  20. ouroboros/mcp/client/protocol.py +161 -0
  21. ouroboros/mcp/errors.py +377 -0
  22. ouroboros/mcp/resources/__init__.py +22 -0
  23. ouroboros/mcp/resources/handlers.py +328 -0
  24. ouroboros/mcp/server/__init__.py +21 -0
  25. ouroboros/mcp/server/adapter.py +408 -0
  26. ouroboros/mcp/server/protocol.py +291 -0
  27. ouroboros/mcp/server/security.py +636 -0
  28. ouroboros/mcp/tools/__init__.py +24 -0
  29. ouroboros/mcp/tools/definitions.py +351 -0
  30. ouroboros/mcp/tools/registry.py +269 -0
  31. ouroboros/mcp/types.py +333 -0
  32. ouroboros/orchestrator/__init__.py +31 -0
  33. ouroboros/orchestrator/events.py +40 -0
  34. ouroboros/orchestrator/mcp_config.py +419 -0
  35. ouroboros/orchestrator/mcp_tools.py +483 -0
  36. ouroboros/orchestrator/runner.py +119 -2
  37. ouroboros/providers/claude_code_adapter.py +75 -0
  38. ouroboros/strategies/__init__.py +23 -0
  39. ouroboros/strategies/devil_advocate.py +197 -0
  40. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/METADATA +73 -17
  41. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/RECORD +44 -19
  42. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/WHEEL +0 -0
  43. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/entry_points.txt +0 -0
  44. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,13 +8,16 @@ from __future__ import annotations
8
8
 
9
9
  import asyncio
10
10
  from pathlib import Path
11
- from typing import Annotated
11
+ from typing import TYPE_CHECKING, Annotated, Any
12
12
 
13
13
  import typer
14
14
  import yaml
15
15
 
16
+ if TYPE_CHECKING:
17
+ from ouroboros.mcp.client.manager import MCPClientManager
18
+
16
19
  from ouroboros.cli.formatters import console
17
- from ouroboros.cli.formatters.panels import print_error, print_info, print_success
20
+ from ouroboros.cli.formatters.panels import print_error, print_info, print_success, print_warning
18
21
  from ouroboros.core.security import InputValidator
19
22
 
20
23
  app = typer.Typer(
@@ -24,7 +27,7 @@ app = typer.Typer(
24
27
  )
25
28
 
26
29
 
27
- def _load_seed_from_yaml(seed_file: Path) -> dict:
30
+ def _load_seed_from_yaml(seed_file: Path) -> dict[str, Any]:
28
31
  """Load seed configuration from YAML file.
29
32
 
30
33
  Args:
@@ -45,21 +48,88 @@ def _load_seed_from_yaml(seed_file: Path) -> dict:
45
48
 
46
49
  try:
47
50
  with open(seed_file) as f:
48
- return yaml.safe_load(f)
51
+ data: dict[str, Any] = yaml.safe_load(f)
52
+ return data
49
53
  except Exception as e:
50
54
  print_error(f"Failed to load seed file: {e}")
51
55
  raise typer.Exit(1) from e
52
56
 
53
57
 
58
+ async def _initialize_mcp_manager(
59
+ config_path: Path,
60
+ tool_prefix: str,
61
+ ) -> "MCPClientManager | None":
62
+ """Initialize MCPClientManager from config file.
63
+
64
+ Args:
65
+ config_path: Path to MCP config YAML.
66
+ tool_prefix: Prefix to add to MCP tool names.
67
+
68
+ Returns:
69
+ Configured MCPClientManager or None on error.
70
+ """
71
+ from ouroboros.mcp.client.manager import MCPClientManager
72
+ from ouroboros.orchestrator.mcp_config import load_mcp_config
73
+
74
+ # Load configuration
75
+ result = load_mcp_config(config_path)
76
+ if result.is_err:
77
+ print_error(f"Failed to load MCP config: {result.error}")
78
+ return None
79
+
80
+ config = result.value
81
+
82
+ # Create manager with connection settings
83
+ manager = MCPClientManager(
84
+ max_retries=config.connection.retry_attempts,
85
+ health_check_interval=config.connection.health_check_interval,
86
+ default_timeout=config.connection.timeout_seconds,
87
+ )
88
+
89
+ # Add all servers
90
+ for server_config in config.servers:
91
+ add_result = await manager.add_server(server_config)
92
+ if add_result.is_err:
93
+ print_warning(f"Failed to add MCP server '{server_config.name}': {add_result.error}")
94
+ else:
95
+ print_info(f"Added MCP server: {server_config.name}")
96
+
97
+ # Connect to all servers
98
+ if manager.servers:
99
+ print_info("Connecting to MCP servers...")
100
+ connect_results = await manager.connect_all()
101
+
102
+ connected_count = 0
103
+ for server_name, connect_result in connect_results.items():
104
+ if connect_result.is_ok:
105
+ server_info = connect_result.value
106
+ print_success(f" Connected to '{server_name}' ({len(server_info.tools)} tools)")
107
+ connected_count += 1
108
+ else:
109
+ print_warning(f" Failed to connect to '{server_name}': {connect_result.error}")
110
+
111
+ if connected_count == 0:
112
+ print_warning("No MCP servers connected. Continuing without external tools.")
113
+ return None
114
+
115
+ print_info(f"Connected to {connected_count}/{len(manager.servers)} MCP servers")
116
+
117
+ return manager
118
+
119
+
54
120
  async def _run_orchestrator(
55
121
  seed_file: Path,
56
122
  resume_session: str | None = None,
123
+ mcp_config: Path | None = None,
124
+ mcp_tool_prefix: str = "",
57
125
  ) -> None:
58
126
  """Run workflow via orchestrator mode (Claude Agent SDK).
59
127
 
60
128
  Args:
61
129
  seed_file: Path to seed YAML file.
62
130
  resume_session: Optional session ID to resume.
131
+ mcp_config: Optional path to MCP config file.
132
+ mcp_tool_prefix: Prefix for MCP tool names.
63
133
  """
64
134
  from ouroboros.core.seed import Seed
65
135
  from ouroboros.orchestrator import ClaudeAgentAdapter, OrchestratorRunner
@@ -77,6 +147,12 @@ async def _run_orchestrator(
77
147
  print_info(f"Loaded seed: {seed.goal[:80]}...")
78
148
  print_info(f"Acceptance criteria: {len(seed.acceptance_criteria)}")
79
149
 
150
+ # Initialize MCP manager if config provided
151
+ mcp_manager = None
152
+ if mcp_config:
153
+ print_info(f"Loading MCP configuration from: {mcp_config}")
154
+ mcp_manager = await _initialize_mcp_manager(mcp_config, mcp_tool_prefix)
155
+
80
156
  # Initialize components
81
157
  import os
82
158
  db_path = os.path.expanduser("~/.ouroboros/ouroboros.db")
@@ -85,32 +161,44 @@ async def _run_orchestrator(
85
161
  await event_store.initialize()
86
162
 
87
163
  adapter = ClaudeAgentAdapter()
88
- runner = OrchestratorRunner(adapter, event_store, console)
164
+ runner = OrchestratorRunner(
165
+ adapter,
166
+ event_store,
167
+ console,
168
+ mcp_manager=mcp_manager,
169
+ mcp_tool_prefix=mcp_tool_prefix,
170
+ )
89
171
 
90
172
  # Execute
91
- if resume_session:
92
- print_info(f"Resuming session: {resume_session}")
93
- result = await runner.resume_session(resume_session, seed)
94
- else:
95
- print_info("Starting new orchestrator execution...")
96
- result = await runner.execute_seed(seed)
97
-
98
- # Handle result
99
- if result.is_ok:
100
- res = result.value
101
- if res.success:
102
- print_success("Execution completed successfully!")
103
- print_info(f"Session ID: {res.session_id}")
104
- print_info(f"Messages processed: {res.messages_processed}")
105
- print_info(f"Duration: {res.duration_seconds:.1f}s")
173
+ try:
174
+ if resume_session:
175
+ print_info(f"Resuming session: {resume_session}")
176
+ result = await runner.resume_session(resume_session, seed)
177
+ else:
178
+ print_info("Starting new orchestrator execution...")
179
+ result = await runner.execute_seed(seed)
180
+
181
+ # Handle result
182
+ if result.is_ok:
183
+ res = result.value
184
+ if res.success:
185
+ print_success("Execution completed successfully!")
186
+ print_info(f"Session ID: {res.session_id}")
187
+ print_info(f"Messages processed: {res.messages_processed}")
188
+ print_info(f"Duration: {res.duration_seconds:.1f}s")
189
+ else:
190
+ print_error("Execution failed")
191
+ print_info(f"Session ID: {res.session_id}")
192
+ console.print(f"[dim]Error: {res.final_message[:200]}[/dim]")
193
+ raise typer.Exit(1)
106
194
  else:
107
- print_error("Execution failed")
108
- print_info(f"Session ID: {res.session_id}")
109
- console.print(f"[dim]Error: {res.final_message[:200]}[/dim]")
195
+ print_error(f"Orchestrator error: {result.error}")
110
196
  raise typer.Exit(1)
111
- else:
112
- print_error(f"Orchestrator error: {result.error}")
113
- raise typer.Exit(1)
197
+ finally:
198
+ # Cleanup MCP connections
199
+ if mcp_manager:
200
+ print_info("Disconnecting MCP servers...")
201
+ await mcp_manager.disconnect_all()
114
202
 
115
203
 
116
204
  @app.command()
@@ -141,6 +229,20 @@ def workflow(
141
229
  help="Resume a previous orchestrator session by ID.",
142
230
  ),
143
231
  ] = None,
232
+ mcp_config: Annotated[
233
+ Path | None,
234
+ typer.Option(
235
+ "--mcp-config",
236
+ help="Path to MCP client configuration YAML file for external tool integration.",
237
+ ),
238
+ ] = None,
239
+ mcp_tool_prefix: Annotated[
240
+ str,
241
+ typer.Option(
242
+ "--mcp-tool-prefix",
243
+ help="Prefix to add to all MCP tool names (e.g., 'mcp_').",
244
+ ),
245
+ ] = "",
144
246
  dry_run: Annotated[
145
247
  bool,
146
248
  typer.Option("--dry-run", "-n", help="Validate seed without executing."),
@@ -156,6 +258,24 @@ def workflow(
156
258
 
157
259
  Use --orchestrator to execute via Claude Agent SDK (Epic 8).
158
260
  Use --resume with --orchestrator to continue a previous session.
261
+ Use --mcp-config to connect to external MCP servers for additional tools.
262
+
263
+ MCP Configuration File Format (YAML):
264
+
265
+ mcp_servers:
266
+ - name: "filesystem"
267
+ transport: "stdio"
268
+ command: "npx"
269
+ args: ["-y", "@anthropic/mcp-server-filesystem", "/workspace"]
270
+ - name: "github"
271
+ transport: "stdio"
272
+ command: "npx"
273
+ args: ["-y", "@anthropic/mcp-server-github"]
274
+ env:
275
+ GITHUB_TOKEN: "${GITHUB_TOKEN}"
276
+ connection:
277
+ timeout_seconds: 30
278
+ retry_attempts: 3
159
279
 
160
280
  Examples:
161
281
 
@@ -165,9 +285,22 @@ def workflow(
165
285
  # Orchestrator mode (Claude Agent SDK)
166
286
  ouroboros run workflow --orchestrator seed.yaml
167
287
 
288
+ # With MCP server integration
289
+ ouroboros run workflow --orchestrator --mcp-config mcp.yaml seed.yaml
290
+
291
+ # With MCP tool prefix
292
+ ouroboros run workflow -o --mcp-config mcp.yaml --mcp-tool-prefix "ext_" seed.yaml
293
+
168
294
  # Resume a previous orchestrator session
169
295
  ouroboros run workflow --orchestrator --resume orch_abc123 seed.yaml
170
296
  """
297
+ # Validate MCP config requires orchestrator mode
298
+ if mcp_config and not orchestrator and not resume_session:
299
+ print_warning(
300
+ "--mcp-config requires --orchestrator flag. Enabling orchestrator mode."
301
+ )
302
+ orchestrator = True
303
+
171
304
  if orchestrator or resume_session:
172
305
  # Orchestrator mode
173
306
  if resume_session and not orchestrator:
@@ -175,7 +308,12 @@ def workflow(
175
308
  "[yellow]Warning: --resume requires --orchestrator flag. "
176
309
  "Enabling orchestrator mode.[/yellow]"
177
310
  )
178
- asyncio.run(_run_orchestrator(seed_file, resume_session))
311
+ asyncio.run(_run_orchestrator(
312
+ seed_file,
313
+ resume_session,
314
+ mcp_config,
315
+ mcp_tool_prefix,
316
+ ))
179
317
  else:
180
318
  # Standard workflow (placeholder)
181
319
  print_info(f"Would execute workflow from: {seed_file}")
ouroboros/cli/main.py CHANGED
@@ -9,7 +9,7 @@ from typing import Annotated
9
9
  import typer
10
10
 
11
11
  from ouroboros import __version__
12
- from ouroboros.cli.commands import config, init, run, status
12
+ from ouroboros.cli.commands import config, init, mcp, run, status
13
13
  from ouroboros.cli.formatters import console
14
14
 
15
15
  # Create the main Typer app
@@ -25,6 +25,7 @@ app.add_typer(init.app, name="init")
25
25
  app.add_typer(run.app, name="run")
26
26
  app.add_typer(config.app, name="config")
27
27
  app.add_typer(status.app, name="status")
28
+ app.add_typer(mcp.app, name="mcp")
28
29
 
29
30
 
30
31
  def version_callback(value: bool) -> None: