stravinsky 0.4.18__py3-none-any.whl → 0.4.66__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 stravinsky might be problematic. Click here for more details.
- mcp_bridge/__init__.py +1 -1
- mcp_bridge/auth/__init__.py +16 -6
- mcp_bridge/auth/cli.py +202 -11
- mcp_bridge/auth/oauth.py +1 -2
- mcp_bridge/auth/openai_oauth.py +4 -7
- mcp_bridge/auth/token_store.py +0 -1
- mcp_bridge/cli/__init__.py +1 -1
- mcp_bridge/cli/install_hooks.py +503 -107
- mcp_bridge/cli/session_report.py +0 -3
- mcp_bridge/config/__init__.py +2 -2
- mcp_bridge/config/hook_config.py +3 -5
- mcp_bridge/config/rate_limits.py +108 -13
- mcp_bridge/hooks/HOOKS_SETTINGS.json +17 -4
- mcp_bridge/hooks/__init__.py +14 -4
- mcp_bridge/hooks/agent_reminder.py +4 -4
- mcp_bridge/hooks/auto_slash_command.py +5 -5
- mcp_bridge/hooks/budget_optimizer.py +2 -2
- mcp_bridge/hooks/claude_limits_hook.py +114 -0
- mcp_bridge/hooks/comment_checker.py +3 -4
- mcp_bridge/hooks/compaction.py +2 -2
- mcp_bridge/hooks/context.py +2 -1
- mcp_bridge/hooks/context_monitor.py +2 -2
- mcp_bridge/hooks/delegation_policy.py +85 -0
- mcp_bridge/hooks/directory_context.py +3 -3
- mcp_bridge/hooks/edit_recovery.py +3 -2
- mcp_bridge/hooks/edit_recovery_policy.py +49 -0
- mcp_bridge/hooks/empty_message_sanitizer.py +2 -2
- mcp_bridge/hooks/events.py +160 -0
- mcp_bridge/hooks/git_noninteractive.py +4 -4
- mcp_bridge/hooks/keyword_detector.py +8 -10
- mcp_bridge/hooks/manager.py +35 -22
- mcp_bridge/hooks/notification_hook.py +13 -6
- mcp_bridge/hooks/parallel_enforcement_policy.py +67 -0
- mcp_bridge/hooks/parallel_enforcer.py +5 -5
- mcp_bridge/hooks/parallel_execution.py +22 -10
- mcp_bridge/hooks/post_tool/parallel_validation.py +103 -0
- mcp_bridge/hooks/pre_compact.py +8 -9
- mcp_bridge/hooks/pre_tool/agent_spawn_validator.py +115 -0
- mcp_bridge/hooks/preemptive_compaction.py +2 -3
- mcp_bridge/hooks/routing_notifications.py +80 -0
- mcp_bridge/hooks/rules_injector.py +11 -19
- mcp_bridge/hooks/session_idle.py +4 -4
- mcp_bridge/hooks/session_notifier.py +4 -4
- mcp_bridge/hooks/session_recovery.py +4 -5
- mcp_bridge/hooks/stravinsky_mode.py +1 -1
- mcp_bridge/hooks/subagent_stop.py +1 -3
- mcp_bridge/hooks/task_validator.py +2 -2
- mcp_bridge/hooks/tmux_manager.py +7 -8
- mcp_bridge/hooks/todo_delegation.py +4 -1
- mcp_bridge/hooks/todo_enforcer.py +180 -10
- mcp_bridge/hooks/truncation_policy.py +37 -0
- mcp_bridge/hooks/truncator.py +1 -2
- mcp_bridge/metrics/cost_tracker.py +115 -0
- mcp_bridge/native_search.py +93 -0
- mcp_bridge/native_watcher.py +118 -0
- mcp_bridge/notifications.py +3 -4
- mcp_bridge/orchestrator/enums.py +11 -0
- mcp_bridge/orchestrator/router.py +165 -0
- mcp_bridge/orchestrator/state.py +32 -0
- mcp_bridge/orchestrator/visualization.py +14 -0
- mcp_bridge/orchestrator/wisdom.py +34 -0
- mcp_bridge/prompts/__init__.py +1 -8
- mcp_bridge/prompts/dewey.py +1 -1
- mcp_bridge/prompts/planner.py +2 -4
- mcp_bridge/prompts/stravinsky.py +53 -31
- mcp_bridge/proxy/__init__.py +0 -0
- mcp_bridge/proxy/client.py +70 -0
- mcp_bridge/proxy/model_server.py +157 -0
- mcp_bridge/routing/__init__.py +43 -0
- mcp_bridge/routing/config.py +250 -0
- mcp_bridge/routing/model_tiers.py +135 -0
- mcp_bridge/routing/provider_state.py +261 -0
- mcp_bridge/routing/task_classifier.py +190 -0
- mcp_bridge/server.py +363 -34
- mcp_bridge/server_tools.py +298 -6
- mcp_bridge/tools/__init__.py +19 -8
- mcp_bridge/tools/agent_manager.py +549 -799
- mcp_bridge/tools/background_tasks.py +13 -17
- mcp_bridge/tools/code_search.py +54 -51
- mcp_bridge/tools/continuous_loop.py +0 -1
- mcp_bridge/tools/dashboard.py +19 -0
- mcp_bridge/tools/find_code.py +296 -0
- mcp_bridge/tools/init.py +1 -0
- mcp_bridge/tools/list_directory.py +42 -0
- mcp_bridge/tools/lsp/__init__.py +8 -8
- mcp_bridge/tools/lsp/manager.py +51 -28
- mcp_bridge/tools/lsp/tools.py +98 -65
- mcp_bridge/tools/model_invoke.py +1047 -152
- mcp_bridge/tools/mux_client.py +75 -0
- mcp_bridge/tools/project_context.py +1 -2
- mcp_bridge/tools/query_classifier.py +132 -49
- mcp_bridge/tools/read_file.py +84 -0
- mcp_bridge/tools/replace.py +45 -0
- mcp_bridge/tools/run_shell_command.py +38 -0
- mcp_bridge/tools/search_enhancements.py +347 -0
- mcp_bridge/tools/semantic_search.py +677 -92
- mcp_bridge/tools/session_manager.py +0 -2
- mcp_bridge/tools/skill_loader.py +0 -1
- mcp_bridge/tools/task_runner.py +5 -7
- mcp_bridge/tools/templates.py +3 -3
- mcp_bridge/tools/tool_search.py +331 -0
- mcp_bridge/tools/write_file.py +29 -0
- mcp_bridge/update_manager.py +33 -37
- mcp_bridge/update_manager_pypi.py +6 -8
- mcp_bridge/utils/cache.py +82 -0
- mcp_bridge/utils/process.py +71 -0
- mcp_bridge/utils/session_state.py +51 -0
- mcp_bridge/utils/truncation.py +76 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/METADATA +84 -35
- stravinsky-0.4.66.dist-info/RECORD +198 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/entry_points.txt +1 -0
- stravinsky_claude_assets/HOOKS_INTEGRATION.md +316 -0
- stravinsky_claude_assets/agents/HOOKS.md +437 -0
- stravinsky_claude_assets/agents/code-reviewer.md +210 -0
- stravinsky_claude_assets/agents/comment_checker.md +580 -0
- stravinsky_claude_assets/agents/debugger.md +254 -0
- stravinsky_claude_assets/agents/delphi.md +495 -0
- stravinsky_claude_assets/agents/dewey.md +248 -0
- stravinsky_claude_assets/agents/explore.md +1198 -0
- stravinsky_claude_assets/agents/frontend.md +472 -0
- stravinsky_claude_assets/agents/implementation-lead.md +164 -0
- stravinsky_claude_assets/agents/momus.md +464 -0
- stravinsky_claude_assets/agents/research-lead.md +141 -0
- stravinsky_claude_assets/agents/stravinsky.md +730 -0
- stravinsky_claude_assets/commands/delphi.md +9 -0
- stravinsky_claude_assets/commands/dewey.md +54 -0
- stravinsky_claude_assets/commands/git-master.md +112 -0
- stravinsky_claude_assets/commands/index.md +49 -0
- stravinsky_claude_assets/commands/publish.md +86 -0
- stravinsky_claude_assets/commands/review.md +73 -0
- stravinsky_claude_assets/commands/str/agent_cancel.md +70 -0
- stravinsky_claude_assets/commands/str/agent_list.md +56 -0
- stravinsky_claude_assets/commands/str/agent_output.md +92 -0
- stravinsky_claude_assets/commands/str/agent_progress.md +74 -0
- stravinsky_claude_assets/commands/str/agent_retry.md +94 -0
- stravinsky_claude_assets/commands/str/cancel.md +51 -0
- stravinsky_claude_assets/commands/str/clean.md +97 -0
- stravinsky_claude_assets/commands/str/continue.md +38 -0
- stravinsky_claude_assets/commands/str/index.md +199 -0
- stravinsky_claude_assets/commands/str/list_watchers.md +96 -0
- stravinsky_claude_assets/commands/str/search.md +205 -0
- stravinsky_claude_assets/commands/str/start_filewatch.md +136 -0
- stravinsky_claude_assets/commands/str/stats.md +71 -0
- stravinsky_claude_assets/commands/str/stop_filewatch.md +89 -0
- stravinsky_claude_assets/commands/str/unwatch.md +42 -0
- stravinsky_claude_assets/commands/str/watch.md +45 -0
- stravinsky_claude_assets/commands/strav.md +53 -0
- stravinsky_claude_assets/commands/stravinsky.md +292 -0
- stravinsky_claude_assets/commands/verify.md +60 -0
- stravinsky_claude_assets/commands/version.md +5 -0
- stravinsky_claude_assets/hooks/README.md +248 -0
- stravinsky_claude_assets/hooks/comment_checker.py +193 -0
- stravinsky_claude_assets/hooks/context.py +38 -0
- stravinsky_claude_assets/hooks/context_monitor.py +153 -0
- stravinsky_claude_assets/hooks/dependency_tracker.py +73 -0
- stravinsky_claude_assets/hooks/edit_recovery.py +46 -0
- stravinsky_claude_assets/hooks/execution_state_tracker.py +68 -0
- stravinsky_claude_assets/hooks/notification_hook.py +103 -0
- stravinsky_claude_assets/hooks/notification_hook_v2.py +96 -0
- stravinsky_claude_assets/hooks/parallel_execution.py +241 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement.py +106 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement_v2.py +112 -0
- stravinsky_claude_assets/hooks/pre_compact.py +123 -0
- stravinsky_claude_assets/hooks/ralph_loop.py +173 -0
- stravinsky_claude_assets/hooks/session_recovery.py +263 -0
- stravinsky_claude_assets/hooks/stop_hook.py +89 -0
- stravinsky_claude_assets/hooks/stravinsky_metrics.py +164 -0
- stravinsky_claude_assets/hooks/stravinsky_mode.py +146 -0
- stravinsky_claude_assets/hooks/subagent_stop.py +98 -0
- stravinsky_claude_assets/hooks/todo_continuation.py +111 -0
- stravinsky_claude_assets/hooks/todo_delegation.py +96 -0
- stravinsky_claude_assets/hooks/tool_messaging.py +281 -0
- stravinsky_claude_assets/hooks/truncator.py +23 -0
- stravinsky_claude_assets/rules/deployment_safety.md +51 -0
- stravinsky_claude_assets/rules/integration_wiring.md +89 -0
- stravinsky_claude_assets/rules/pypi_deployment.md +220 -0
- stravinsky_claude_assets/rules/stravinsky_orchestrator.md +32 -0
- stravinsky_claude_assets/settings.json +152 -0
- stravinsky_claude_assets/skills/chrome-devtools/SKILL.md +81 -0
- stravinsky_claude_assets/skills/sqlite/SKILL.md +77 -0
- stravinsky_claude_assets/skills/supabase/SKILL.md +74 -0
- stravinsky_claude_assets/task_dependencies.json +34 -0
- stravinsky-0.4.18.dist-info/RECORD +0 -88
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/WHEEL +0 -0
mcp_bridge/notifications.py
CHANGED
|
@@ -14,7 +14,6 @@ import logging
|
|
|
14
14
|
import platform
|
|
15
15
|
import subprocess
|
|
16
16
|
from pathlib import Path
|
|
17
|
-
from typing import Dict, Optional
|
|
18
17
|
|
|
19
18
|
logger = logging.getLogger(__name__)
|
|
20
19
|
|
|
@@ -35,7 +34,7 @@ class NotificationManager:
|
|
|
35
34
|
title: str,
|
|
36
35
|
message: str,
|
|
37
36
|
sound: bool = True
|
|
38
|
-
) ->
|
|
37
|
+
) -> list | None:
|
|
39
38
|
"""Get platform-specific notification command."""
|
|
40
39
|
if self.system == "Darwin": # macOS
|
|
41
40
|
script = f'display notification "{message}" with title "{title}"'
|
|
@@ -113,7 +112,7 @@ $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
|
|
|
113
112
|
message = f"Indexing {path}..."
|
|
114
113
|
return self._send_notification_sync(title, message, sound=True)
|
|
115
114
|
|
|
116
|
-
async def notify_reindex_complete(self, stats:
|
|
115
|
+
async def notify_reindex_complete(self, stats: dict) -> bool:
|
|
117
116
|
"""Notify that codebase reindexing is complete."""
|
|
118
117
|
indexed = stats.get("indexed", 0)
|
|
119
118
|
pruned = stats.get("pruned", 0)
|
|
@@ -134,7 +133,7 @@ $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
|
|
|
134
133
|
|
|
135
134
|
|
|
136
135
|
# Global singleton instance
|
|
137
|
-
_notification_manager:
|
|
136
|
+
_notification_manager: NotificationManager | None = None
|
|
138
137
|
|
|
139
138
|
|
|
140
139
|
def get_notification_manager() -> NotificationManager:
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from ..routing.config import load_routing_config
|
|
4
|
+
from ..routing.provider_state import get_provider_tracker
|
|
5
|
+
from ..routing.task_classifier import TaskType, classify_and_route
|
|
6
|
+
from ..routing.model_tiers import get_oauth_fallback_chain
|
|
7
|
+
from .enums import OrchestrationPhase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class ModelConfig:
|
|
12
|
+
planning_model: str = "gemini-3-pro" # Default smart
|
|
13
|
+
execution_model: str = "gemini-3-flash" # Default fast
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Router:
|
|
17
|
+
"""
|
|
18
|
+
Intelligent model router with multi-provider fallback and task-based routing.
|
|
19
|
+
|
|
20
|
+
Features:
|
|
21
|
+
- Automatic fallback when providers hit rate limits
|
|
22
|
+
- Task-based routing to optimal models (code gen → OpenAI, docs → Gemini)
|
|
23
|
+
- Provider state tracking with cooldown management
|
|
24
|
+
- Project-local configuration support
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, config: ModelConfig | None = None, project_path: str = "."):
|
|
28
|
+
self.config = config or ModelConfig()
|
|
29
|
+
self.project_path = project_path
|
|
30
|
+
|
|
31
|
+
# Load routing configuration
|
|
32
|
+
self.routing_config = load_routing_config(project_path)
|
|
33
|
+
|
|
34
|
+
# Get provider state tracker singleton
|
|
35
|
+
self.provider_tracker = get_provider_tracker()
|
|
36
|
+
|
|
37
|
+
def select_model(
|
|
38
|
+
self,
|
|
39
|
+
phase: OrchestrationPhase,
|
|
40
|
+
task_type: TaskType | None = None,
|
|
41
|
+
prompt: str | None = None,
|
|
42
|
+
) -> str:
|
|
43
|
+
"""
|
|
44
|
+
Selects the best model for the given phase and task type.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
phase: Orchestration phase (PLAN, EXECUTE, etc.)
|
|
48
|
+
task_type: Optional task type override (CODE_GENERATION, DEBUGGING, etc.)
|
|
49
|
+
prompt: Optional prompt text for automatic task classification
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Model identifier string (e.g., "gemini-3-flash", "gpt-5.2-codex")
|
|
53
|
+
"""
|
|
54
|
+
# If task_type is provided or can be inferred, use task-based routing
|
|
55
|
+
if task_type or prompt:
|
|
56
|
+
# classify_and_route returns (TaskType, provider, model) tuple
|
|
57
|
+
# Extract just the TaskType
|
|
58
|
+
if task_type:
|
|
59
|
+
inferred_type = task_type
|
|
60
|
+
else:
|
|
61
|
+
# classify_and_route returns tuple: (TaskType, provider, model)
|
|
62
|
+
classification_result = classify_and_route(prompt or "")
|
|
63
|
+
inferred_type = classification_result[0] # Extract TaskType from tuple
|
|
64
|
+
|
|
65
|
+
model = self._select_by_task_type(inferred_type)
|
|
66
|
+
|
|
67
|
+
# Check provider availability and fallback if needed
|
|
68
|
+
return self._check_availability_and_fallback(model, inferred_type)
|
|
69
|
+
|
|
70
|
+
# Fallback to phase-based routing (legacy behavior)
|
|
71
|
+
if phase in [
|
|
72
|
+
OrchestrationPhase.PLAN,
|
|
73
|
+
OrchestrationPhase.VALIDATE,
|
|
74
|
+
OrchestrationPhase.WISDOM,
|
|
75
|
+
OrchestrationPhase.VERIFY,
|
|
76
|
+
]:
|
|
77
|
+
model = self.config.planning_model
|
|
78
|
+
else:
|
|
79
|
+
model = self.config.execution_model
|
|
80
|
+
|
|
81
|
+
return self._check_availability_and_fallback(model, None)
|
|
82
|
+
|
|
83
|
+
def _select_by_task_type(self, task_type: TaskType) -> str:
|
|
84
|
+
"""
|
|
85
|
+
Select model based on task type using routing config.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
task_type: Classified task type
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Primary model for this task type
|
|
92
|
+
"""
|
|
93
|
+
# Look up task routing rule in config (it's a dict[str, TaskRoutingRule])
|
|
94
|
+
task_name = task_type.name.lower()
|
|
95
|
+
if task_name in self.routing_config.task_routing:
|
|
96
|
+
rule = self.routing_config.task_routing[task_name]
|
|
97
|
+
if rule.model:
|
|
98
|
+
return rule.model
|
|
99
|
+
|
|
100
|
+
# Fallback to default execution model if no rule matches
|
|
101
|
+
return self.config.execution_model
|
|
102
|
+
|
|
103
|
+
def _check_availability_and_fallback(self, model: str, task_type: TaskType | None) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Check provider availability and apply fallback if rate-limited.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
model: Desired model
|
|
109
|
+
task_type: Task type (for finding appropriate fallback)
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Available model (original or fallback)
|
|
113
|
+
"""
|
|
114
|
+
# Determine provider from model name
|
|
115
|
+
provider = self._get_provider_from_model(model)
|
|
116
|
+
|
|
117
|
+
# Check provider availability using is_available() method
|
|
118
|
+
if self.provider_tracker.is_available(provider):
|
|
119
|
+
return model
|
|
120
|
+
|
|
121
|
+
# Prefer tier-aware OAuth fallback chain when possible.
|
|
122
|
+
# Note: use_oauth=False candidates represent non-OAuth access
|
|
123
|
+
# (currently meaningful for Gemini API key fallback).
|
|
124
|
+
try:
|
|
125
|
+
oauth_chain = get_oauth_fallback_chain(provider, model)
|
|
126
|
+
except ValueError:
|
|
127
|
+
oauth_chain = []
|
|
128
|
+
|
|
129
|
+
for candidate_provider, candidate_model, use_oauth in oauth_chain:
|
|
130
|
+
if not use_oauth and candidate_provider == "gemini":
|
|
131
|
+
return candidate_model
|
|
132
|
+
if self.provider_tracker.is_available(candidate_provider):
|
|
133
|
+
return candidate_model
|
|
134
|
+
|
|
135
|
+
# Provider unavailable - use global fallback chain (legacy)
|
|
136
|
+
# NOTE: Task-specific fallbacks from routing config are not currently
|
|
137
|
+
# implemented (TaskRoutingRule doesn't have fallback_models field)
|
|
138
|
+
for fallback_provider in self.routing_config.fallback.chain:
|
|
139
|
+
if self.provider_tracker.is_available(fallback_provider):
|
|
140
|
+
# Map provider to default model
|
|
141
|
+
return self._get_default_model_for_provider(fallback_provider)
|
|
142
|
+
|
|
143
|
+
# All providers unavailable - return original model and let caller handle error
|
|
144
|
+
return model
|
|
145
|
+
|
|
146
|
+
def _get_provider_from_model(self, model: str) -> str:
|
|
147
|
+
"""Extract provider name from model identifier."""
|
|
148
|
+
if "gemini" in model.lower():
|
|
149
|
+
return "gemini"
|
|
150
|
+
elif "gpt" in model.lower() or "openai" in model.lower():
|
|
151
|
+
return "openai"
|
|
152
|
+
elif "claude" in model.lower():
|
|
153
|
+
return "claude"
|
|
154
|
+
else:
|
|
155
|
+
# Default to gemini for unknown models
|
|
156
|
+
return "gemini"
|
|
157
|
+
|
|
158
|
+
def _get_default_model_for_provider(self, provider: str) -> str:
|
|
159
|
+
"""Get default model for a provider."""
|
|
160
|
+
defaults = {
|
|
161
|
+
"gemini": "gemini-3-flash",
|
|
162
|
+
"openai": "gpt-5.2-codex",
|
|
163
|
+
"claude": "claude-sonnet-4.5",
|
|
164
|
+
}
|
|
165
|
+
return defaults.get(provider, "gemini-3-flash")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import List, Dict, Optional, Callable
|
|
2
|
+
from .enums import OrchestrationPhase
|
|
3
|
+
|
|
4
|
+
class OrchestratorState:
|
|
5
|
+
def __init__(self, enable_phase_gates: bool = False, approver: Optional[Callable[[], bool]] = None):
|
|
6
|
+
self.current_phase = OrchestrationPhase.CLASSIFY
|
|
7
|
+
self.history: List[OrchestrationPhase] = []
|
|
8
|
+
self.artifacts: Dict[str, str] = {}
|
|
9
|
+
self.enable_phase_gates = enable_phase_gates
|
|
10
|
+
self.approver = approver
|
|
11
|
+
|
|
12
|
+
def transition_to(self, next_phase: OrchestrationPhase):
|
|
13
|
+
"""Transitions to the next phase if requirements are met."""
|
|
14
|
+
self._validate_transition(next_phase)
|
|
15
|
+
|
|
16
|
+
# Phase Gates
|
|
17
|
+
if self.enable_phase_gates and self.approver:
|
|
18
|
+
if not self.approver():
|
|
19
|
+
raise PermissionError(f"Transition to {next_phase} denied by user.")
|
|
20
|
+
|
|
21
|
+
self.history.append(self.current_phase)
|
|
22
|
+
self.current_phase = next_phase
|
|
23
|
+
|
|
24
|
+
def register_artifact(self, name: str, content: str):
|
|
25
|
+
self.artifacts[name] = content
|
|
26
|
+
|
|
27
|
+
def _validate_transition(self, next_phase: OrchestrationPhase):
|
|
28
|
+
"""Enforce strict phase requirements."""
|
|
29
|
+
# Example: Must have plan before validation
|
|
30
|
+
if next_phase == OrchestrationPhase.VALIDATE:
|
|
31
|
+
if "plan.md" not in self.artifacts and self.current_phase == OrchestrationPhase.PLAN:
|
|
32
|
+
raise ValueError("Missing artifact: plan.md is required to enter Validation phase")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .enums import OrchestrationPhase
|
|
2
|
+
|
|
3
|
+
def format_phase_progress(current_phase: OrchestrationPhase) -> str:
|
|
4
|
+
"""Formats the current phase as a progress string."""
|
|
5
|
+
phases = list(OrchestrationPhase)
|
|
6
|
+
total = len(phases)
|
|
7
|
+
|
|
8
|
+
# Find index (1-based)
|
|
9
|
+
try:
|
|
10
|
+
index = phases.index(current_phase) + 1
|
|
11
|
+
except ValueError:
|
|
12
|
+
index = 0
|
|
13
|
+
|
|
14
|
+
return f"[Phase {index}/{total}: {current_phase.name}]"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
class WisdomLoader:
|
|
5
|
+
def __init__(self, wisdom_path: str = ".stravinsky/wisdom.md"):
|
|
6
|
+
self.wisdom_path = wisdom_path
|
|
7
|
+
|
|
8
|
+
def load_wisdom(self) -> str:
|
|
9
|
+
"""Loads project wisdom/learnings."""
|
|
10
|
+
if os.path.exists(self.wisdom_path):
|
|
11
|
+
try:
|
|
12
|
+
with open(self.wisdom_path, "r") as f:
|
|
13
|
+
return f.read()
|
|
14
|
+
except Exception:
|
|
15
|
+
return ""
|
|
16
|
+
return ""
|
|
17
|
+
|
|
18
|
+
class CritiqueGenerator:
|
|
19
|
+
def generate_critique_prompt(self, plan_content: str) -> str:
|
|
20
|
+
"""Generates a prompt for self-critique."""
|
|
21
|
+
return f"""
|
|
22
|
+
You are currently in the CRITIQUE phase.
|
|
23
|
+
Review the following plan and identify potential weaknesses.
|
|
24
|
+
|
|
25
|
+
PLAN:
|
|
26
|
+
{plan_content}
|
|
27
|
+
|
|
28
|
+
INSTRUCTIONS:
|
|
29
|
+
1. List 3 ways this plan could fail (edge cases, race conditions, missing context).
|
|
30
|
+
2. Check if it violates any items in the 'Wisdom' file (if provided).
|
|
31
|
+
3. Propose specific improvements.
|
|
32
|
+
|
|
33
|
+
Respond with your critique.
|
|
34
|
+
"""
|
mcp_bridge/prompts/__init__.py
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
# Agent prompts module
|
|
2
|
-
from . import stravinsky
|
|
3
|
-
from . import delphi
|
|
4
|
-
from . import dewey
|
|
5
|
-
from . import explore
|
|
6
|
-
from . import frontend
|
|
7
|
-
from . import document_writer
|
|
8
|
-
from . import multimodal
|
|
9
|
-
from . import planner
|
|
2
|
+
from . import delphi, dewey, document_writer, explore, frontend, multimodal, planner, stravinsky
|
|
10
3
|
|
|
11
4
|
__all__ = [
|
|
12
5
|
"stravinsky",
|
mcp_bridge/prompts/dewey.py
CHANGED
|
@@ -44,7 +44,7 @@ Your job: Answer questions about open-source libraries by finding **EVIDENCE** w
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
## PHASE 0: REQUEST CLASSIFICATION (MANDATORY
|
|
47
|
+
## PHASE 0: REQUEST CLASSIFICATION (MANDATORY FUWT STEP)
|
|
48
48
|
|
|
49
49
|
Classify EVERY request into one of these categories before taking action:
|
|
50
50
|
|
mcp_bridge/prompts/planner.py
CHANGED
|
@@ -13,8 +13,6 @@ Key capabilities:
|
|
|
13
13
|
- Structured plan output for orchestrator consumption
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from typing import Optional
|
|
17
|
-
|
|
18
16
|
|
|
19
17
|
PLANNER_ROLE = """<Role>
|
|
20
18
|
You are "Planner" - a pre-implementation planning specialist.
|
|
@@ -177,8 +175,8 @@ Before finalizing plan, verify:
|
|
|
177
175
|
|
|
178
176
|
def get_planner_prompt(
|
|
179
177
|
task_description: str,
|
|
180
|
-
project_context:
|
|
181
|
-
existing_patterns:
|
|
178
|
+
project_context: str | None = None,
|
|
179
|
+
existing_patterns: str | None = None,
|
|
182
180
|
) -> str:
|
|
183
181
|
"""
|
|
184
182
|
Generate the complete planner prompt.
|
mcp_bridge/prompts/stravinsky.py
CHANGED
|
@@ -12,8 +12,6 @@ Key naming conventions (Stravinsky equivalents):
|
|
|
12
12
|
- agent_spawn (not call-omo-agent) - spawn background agents
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
from typing import Optional
|
|
16
|
-
|
|
17
15
|
# Core role definition
|
|
18
16
|
STRAVINSKY_ROLE_SECTION = """<Role>
|
|
19
17
|
You are "Stravinsky" - Powerful AI Agent with orchestration capabilities from Stravinsky MCP.
|
|
@@ -36,7 +34,7 @@ Named after the composer known for revolutionary orchestration.
|
|
|
36
34
|
</Role>"""
|
|
37
35
|
|
|
38
36
|
|
|
39
|
-
STRAVINSKY_PHASE0_STEP1_3 = """### Step 0: Check Skills
|
|
37
|
+
STRAVINSKY_PHASE0_STEP1_3 = """### Step 0: Check Skills FUWT (BLOCKING)
|
|
40
38
|
|
|
41
39
|
**Before ANY classification or action, scan for matching skills.**
|
|
42
40
|
|
|
@@ -54,7 +52,7 @@ Skills are specialized workflows. When relevant, they handle the task better tha
|
|
|
54
52
|
|
|
55
53
|
| Type | Signal | Action |
|
|
56
54
|
|------|--------|--------|
|
|
57
|
-
| **Skill Match** | Matches skill trigger phrase | **INVOKE skill
|
|
55
|
+
| **Skill Match** | Matches skill trigger phrase | **INVOKE skill FUWT** via `skill_get` tool |
|
|
58
56
|
| **Trivial** | Single file, known location, direct answer | Direct tools only (UNLESS Key Trigger applies) |
|
|
59
57
|
| **Explicit** | Specific file/line, clear command | Execute directly |
|
|
60
58
|
| **Exploratory** | "How does X work?", "Find Y" | Fire explore (1-3) + tools in parallel |
|
|
@@ -159,7 +157,7 @@ STOP searching when:
|
|
|
159
157
|
**DO NOT over-explore. Time is precious.**"""
|
|
160
158
|
|
|
161
159
|
|
|
162
|
-
STRAVINSKY_PHASE2B_PRE_IMPLEMENTATION = """## ⚠️ CRITICAL: PARALLEL-
|
|
160
|
+
STRAVINSKY_PHASE2B_PRE_IMPLEMENTATION = """## ⚠️ CRITICAL: PARALLEL-FUWT WORKFLOW
|
|
163
161
|
|
|
164
162
|
**BLOCKING REQUIREMENT**: For implementation tasks, your response structure MUST be:
|
|
165
163
|
|
|
@@ -204,54 +202,78 @@ todowrite([todo1, todo2, todo3])
|
|
|
204
202
|
4. THEN mark todos complete"""
|
|
205
203
|
|
|
206
204
|
|
|
207
|
-
STRAVINSKY_DELEGATION_PROMPT_STRUCTURE = """### Delegation Prompt Structure (
|
|
205
|
+
STRAVINSKY_DELEGATION_PROMPT_STRUCTURE = """### Delegation Prompt Structure (RECOMMENDED - 5 KEY SECTIONS):
|
|
208
206
|
|
|
209
|
-
When delegating via `agent_spawn`, your prompt
|
|
207
|
+
When delegating via `agent_spawn`, your prompt SHOULD include these sections:
|
|
210
208
|
|
|
211
209
|
```
|
|
212
|
-
1. TASK:
|
|
210
|
+
1. TASK: Clear, natural language description of what needs to be found/analyzed
|
|
213
211
|
2. EXPECTED OUTCOME: Concrete deliverables with success criteria
|
|
214
|
-
3.
|
|
215
|
-
4. MUST DO:
|
|
216
|
-
5.
|
|
217
|
-
6. CONTEXT: File paths, existing patterns, constraints
|
|
218
|
-
7. SUCCESS CRITERIA: How to verify completion
|
|
212
|
+
3. MUST DO: Exhaustive requirements list
|
|
213
|
+
4. MUST NOT DO: Forbidden actions (prevent rogue behavior)
|
|
214
|
+
5. CONTEXT: File paths, existing patterns, constraints (if known)
|
|
219
215
|
```
|
|
220
216
|
|
|
221
|
-
|
|
217
|
+
**❌ WRONG - Over-Prescribing Tools:**
|
|
222
218
|
```
|
|
223
219
|
## TASK
|
|
224
220
|
Find all API endpoint definitions in the auth module.
|
|
225
221
|
|
|
226
|
-
## EXPECTED OUTCOME
|
|
227
|
-
List of endpoints with: path, method, handler function, file location.
|
|
228
|
-
|
|
229
222
|
## REQUIRED TOOLS
|
|
230
|
-
Read, Grep, Glob
|
|
223
|
+
Read, Grep, Glob # ❌ DON'T PRESCRIBE TOOLS - agents choose optimal approach
|
|
224
|
+
|
|
225
|
+
## MUST DO
|
|
226
|
+
- Use grep_search to find "def" patterns # ❌ TOO SPECIFIC
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**✅ CORRECT - Natural Language + Trust Agent Intelligence:**
|
|
230
|
+
```
|
|
231
|
+
## TASK
|
|
232
|
+
Find and explain all API endpoint definitions in the auth module, including their request/response patterns and how they connect to each other.
|
|
233
|
+
|
|
234
|
+
## EXPECTED OUTCOME
|
|
235
|
+
Complete list of endpoints with: path, method, handler function, file location, and architectural notes on how they integrate.
|
|
231
236
|
|
|
232
237
|
## MUST DO
|
|
233
|
-
- Search in src/auth/ directory
|
|
234
|
-
- Include path parameters
|
|
235
|
-
- Report line numbers
|
|
238
|
+
- Search in src/auth/ directory and related integration points
|
|
239
|
+
- Include path parameters and query string handling
|
|
240
|
+
- Report exact line numbers for each endpoint
|
|
241
|
+
- Explain the authentication flow across endpoints
|
|
236
242
|
|
|
237
243
|
## MUST NOT DO
|
|
238
244
|
- Modify any files
|
|
239
|
-
-
|
|
245
|
+
- Skip integration patterns (how endpoints call each other)
|
|
240
246
|
|
|
241
247
|
## CONTEXT
|
|
242
248
|
Project uses FastAPI. Auth endpoints handle login, logout, token refresh.
|
|
249
|
+
This is a CONCEPTUAL/ARCHITECTURAL query - the agent should use semantic_search + grep for comprehensive coverage.
|
|
243
250
|
|
|
244
251
|
## SUCCESS CRITERIA
|
|
245
|
-
All endpoints documented with complete paths
|
|
252
|
+
All endpoints documented with complete paths, handlers, AND architectural understanding of how they work together.
|
|
246
253
|
```
|
|
247
254
|
|
|
255
|
+
**WHY THIS WORKS BETTER:**
|
|
256
|
+
- ✅ Explore agent has `semantic_search` in its toolset and knows when to use it
|
|
257
|
+
- ✅ Natural language tasks → agent classifies as SEMANTIC → uses semantic_search
|
|
258
|
+
- ✅ Agent combines semantic_search (concepts) + grep_search (exact matches) automatically
|
|
259
|
+
- ❌ "REQUIRED TOOLS: grep_search" → blocks semantic_search even for conceptual queries
|
|
260
|
+
|
|
261
|
+
**TRUST THE AGENTS:**
|
|
262
|
+
The explore agent already has comprehensive tool selection logic:
|
|
263
|
+
- Semantic queries → semantic_search (primary)
|
|
264
|
+
- Exact syntax → grep_search
|
|
265
|
+
- Code structure → ast_grep_search
|
|
266
|
+
- Symbol navigation → LSP tools
|
|
267
|
+
|
|
268
|
+
Let them choose the optimal search strategy based on your TASK description, not prescriptive tool lists.
|
|
269
|
+
|
|
248
270
|
AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS:
|
|
249
271
|
- DOES IT WORK AS EXPECTED?
|
|
250
272
|
- DOES IT FOLLOW THE EXISTING CODEBASE PATTERN?
|
|
251
273
|
- EXPECTED RESULT CAME OUT?
|
|
252
274
|
- DID THE AGENT FOLLOW "MUST DO" AND "MUST NOT DO" REQUIREMENTS?
|
|
253
275
|
|
|
254
|
-
**
|
|
276
|
+
**Natural language task descriptions = agent intelligence. Tool prescriptions = micromanagement.**"""
|
|
255
277
|
|
|
256
278
|
|
|
257
279
|
STRAVINSKY_GITHUB_WORKFLOW = """### GitHub Workflow (CRITICAL - When mentioned in issues/PRs):
|
|
@@ -358,7 +380,7 @@ If verification fails:
|
|
|
358
380
|
|
|
359
381
|
STRAVINSKY_KEY_TRIGGERS = """### Key Triggers (check BEFORE classification):
|
|
360
382
|
|
|
361
|
-
**BLOCKING: Check skills
|
|
383
|
+
**BLOCKING: Check skills FUWT before any action.**
|
|
362
384
|
If a skill matches, invoke it IMMEDIATELY via `skill_get` tool.
|
|
363
385
|
|
|
364
386
|
- External library/source mentioned -> fire `dewey` background via `agent_spawn`
|
|
@@ -472,12 +494,12 @@ Delphi is an expensive, high-quality reasoning model. Use it wisely via `agent_s
|
|
|
472
494
|
|
|
473
495
|
| Trigger | Action |
|
|
474
496
|
|---------|--------|
|
|
475
|
-
| Complex architecture design | Delphi
|
|
476
|
-
| After completing significant work | Delphi
|
|
477
|
-
| 2+ failed fix attempts | Delphi
|
|
478
|
-
| Unfamiliar code patterns | Delphi
|
|
479
|
-
| Security/performance concerns | Delphi
|
|
480
|
-
| Multi-system tradeoffs | Delphi
|
|
497
|
+
| Complex architecture design | Delphi FUWT, then implement |
|
|
498
|
+
| After completing significant work | Delphi FUWT, then implement |
|
|
499
|
+
| 2+ failed fix attempts | Delphi FUWT, then implement |
|
|
500
|
+
| Unfamiliar code patterns | Delphi FUWT, then implement |
|
|
501
|
+
| Security/performance concerns | Delphi FUWT, then implement |
|
|
502
|
+
| Multi-system tradeoffs | Delphi FUWT, then implement |
|
|
481
503
|
|
|
482
504
|
### WHEN NOT to Consult:
|
|
483
505
|
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger("stravinsky.proxy_client")
|
|
7
|
+
|
|
8
|
+
PROXY_URL = os.getenv("STRAVINSKY_PROXY_URL", "http://127.0.0.1:8765")
|
|
9
|
+
|
|
10
|
+
async def proxy_invoke_gemini(
|
|
11
|
+
prompt: str,
|
|
12
|
+
model: str = "gemini-3-flash",
|
|
13
|
+
temperature: float = 0.7,
|
|
14
|
+
max_tokens: int = 8192,
|
|
15
|
+
thinking_budget: int = 0,
|
|
16
|
+
image_path: Optional[str] = None,
|
|
17
|
+
agent_context: Optional[dict[str, Any]] = None
|
|
18
|
+
) -> str:
|
|
19
|
+
"""Routes Gemini invocation to the proxy server."""
|
|
20
|
+
payload = {
|
|
21
|
+
"prompt": prompt,
|
|
22
|
+
"model": model,
|
|
23
|
+
"temperature": temperature,
|
|
24
|
+
"max_tokens": max_tokens,
|
|
25
|
+
"thinking_budget": thinking_budget,
|
|
26
|
+
"image_path": image_path,
|
|
27
|
+
"agent_context": agent_context
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async with httpx.AsyncClient(timeout=130.0) as client:
|
|
31
|
+
try:
|
|
32
|
+
response = await client.post(f"{PROXY_URL}/v1/gemini/generate", json=payload)
|
|
33
|
+
response.raise_for_status()
|
|
34
|
+
return response.json()["response"]
|
|
35
|
+
except Exception as e:
|
|
36
|
+
logger.error(f"Proxy request failed: {e}")
|
|
37
|
+
raise
|
|
38
|
+
|
|
39
|
+
async def proxy_invoke_openai(
|
|
40
|
+
prompt: str,
|
|
41
|
+
model: str = "gpt-5.2-codex",
|
|
42
|
+
temperature: float = 0.7,
|
|
43
|
+
max_tokens: int = 4096,
|
|
44
|
+
thinking_budget: int = 0,
|
|
45
|
+
reasoning_effort: str = "medium",
|
|
46
|
+
agent_context: Optional[dict[str, Any]] = None
|
|
47
|
+
) -> str:
|
|
48
|
+
"""Routes OpenAI invocation to the proxy server."""
|
|
49
|
+
payload = {
|
|
50
|
+
"prompt": prompt,
|
|
51
|
+
"model": model,
|
|
52
|
+
"temperature": temperature,
|
|
53
|
+
"max_tokens": max_tokens,
|
|
54
|
+
"thinking_budget": thinking_budget,
|
|
55
|
+
"reasoning_effort": reasoning_effort,
|
|
56
|
+
"agent_context": agent_context
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async with httpx.AsyncClient(timeout=130.0) as client:
|
|
60
|
+
try:
|
|
61
|
+
response = await client.post(f"{PROXY_URL}/v1/openai/chat", json=payload)
|
|
62
|
+
response.raise_for_status()
|
|
63
|
+
return response.json()["response"]
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.error(f"Proxy request failed: {e}")
|
|
66
|
+
raise
|
|
67
|
+
|
|
68
|
+
def is_proxy_enabled() -> bool:
|
|
69
|
+
"""Checks if proxy usage is enabled via environment variable."""
|
|
70
|
+
return os.getenv("STRAVINSKY_USE_PROXY", "false").lower() == "true"
|