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.
- ouroboros/__init__.py +1 -1
- ouroboros/bigbang/__init__.py +9 -0
- ouroboros/bigbang/interview.py +16 -18
- ouroboros/bigbang/ontology.py +180 -0
- ouroboros/cli/commands/__init__.py +2 -0
- ouroboros/cli/commands/init.py +162 -97
- ouroboros/cli/commands/mcp.py +161 -0
- ouroboros/cli/commands/run.py +165 -27
- ouroboros/cli/main.py +2 -1
- ouroboros/core/ontology_aspect.py +455 -0
- ouroboros/core/ontology_questions.py +462 -0
- ouroboros/evaluation/__init__.py +16 -1
- ouroboros/evaluation/consensus.py +569 -11
- ouroboros/evaluation/models.py +81 -0
- ouroboros/events/ontology.py +135 -0
- ouroboros/mcp/__init__.py +83 -0
- ouroboros/mcp/client/__init__.py +20 -0
- ouroboros/mcp/client/adapter.py +632 -0
- ouroboros/mcp/client/manager.py +600 -0
- ouroboros/mcp/client/protocol.py +161 -0
- ouroboros/mcp/errors.py +377 -0
- ouroboros/mcp/resources/__init__.py +22 -0
- ouroboros/mcp/resources/handlers.py +328 -0
- ouroboros/mcp/server/__init__.py +21 -0
- ouroboros/mcp/server/adapter.py +408 -0
- ouroboros/mcp/server/protocol.py +291 -0
- ouroboros/mcp/server/security.py +636 -0
- ouroboros/mcp/tools/__init__.py +24 -0
- ouroboros/mcp/tools/definitions.py +351 -0
- ouroboros/mcp/tools/registry.py +269 -0
- ouroboros/mcp/types.py +333 -0
- ouroboros/orchestrator/__init__.py +31 -0
- ouroboros/orchestrator/events.py +40 -0
- ouroboros/orchestrator/mcp_config.py +419 -0
- ouroboros/orchestrator/mcp_tools.py +483 -0
- ouroboros/orchestrator/runner.py +119 -2
- ouroboros/providers/claude_code_adapter.py +75 -0
- ouroboros/strategies/__init__.py +23 -0
- ouroboros/strategies/devil_advocate.py +197 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/METADATA +73 -17
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/RECORD +44 -19
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/WHEEL +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/entry_points.txt +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/licenses/LICENSE +0 -0
ouroboros/cli/commands/run.py
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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("
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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(
|
|
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:
|