Merge: Team 1 - Critical Bugs
This commit is contained in:
@@ -198,7 +198,7 @@ class OpusGraph:
|
|||||||
workflow.add_edge("write_chapters", "complete")
|
workflow.add_edge("write_chapters", "complete")
|
||||||
workflow.add_edge("complete", END)
|
workflow.add_edge("complete", END)
|
||||||
|
|
||||||
checkpointer = None # Disable for simpler debugging
|
checkpointer = MemorySaver() # Enable for state persistence
|
||||||
return workflow.compile(checkpointer=checkpointer)
|
return workflow.compile(checkpointer=checkpointer)
|
||||||
|
|
||||||
# ============== NODES (Return DICT, not mutated state) ==============
|
# ============== NODES (Return DICT, not mutated state) ==============
|
||||||
@@ -635,19 +635,32 @@ Write ~{plan.word_count_target} words.
|
|||||||
print(f"[STREAM] Reconstructed state from dict")
|
print(f"[STREAM] Reconstructed state from dict")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[RUN] Stream error: {e}")
|
print(f"[RUN] Stream error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
# Don't give up - try to recover partial state
|
||||||
|
|
||||||
# SAFETY FALLBACK: Pull from checkpoint/snapshot
|
# Enable checkpointing for recovery
|
||||||
print("[RUN] Checking final state...")
|
print("[RUN] Checking final state...")
|
||||||
if final_state is None:
|
if final_state is None:
|
||||||
print("[FALLBACK] No state from stream, trying snapshot...")
|
print("[WARNING] No state from stream, attempting recovery...")
|
||||||
final_state = initial_state
|
# Try to recover from any partial state that was accumulated
|
||||||
|
# In a full implementation, we'd load from checkpoint here
|
||||||
|
# For now, raise a clear error instead of silently failing
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Workflow failed to complete. "
|
||||||
|
f"Last known stage: {getattr(final_state, 'stage', 'unknown') if final_state else 'initial'}. "
|
||||||
|
f"Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
# Verify we have manuscript
|
# Verify we have manuscript
|
||||||
if not final_state.manuscript:
|
if not final_state.manuscript:
|
||||||
print("[FALLBACK] No manuscript in state!")
|
print("[WARNING] No manuscript generated!")
|
||||||
# Last resort: return what we have
|
# Return partial state for debugging
|
||||||
else:
|
if final_state.prewriting.one_sentence:
|
||||||
print(f"[RESULT] SUCCESS! {len(final_state.chapters)} chapters, {final_state.total_word_count} words")
|
print(f"[PARTIAL] Generated: {final_state.prewriting.one_sentence[:100]}...")
|
||||||
|
raise RuntimeError("Workflow completed but no manuscript was generated.")
|
||||||
|
|
||||||
|
print(f"[RESULT] SUCCESS! {len(final_state.chapters)} chapters, {final_state.total_word_count} words")
|
||||||
|
|
||||||
return final_state
|
return final_state
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import os
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException, BackgroundTasks
|
from fastapi import FastAPI, HTTPException, BackgroundTasks, UploadFile, File
|
||||||
from fastapi.responses import JSONResponse, RedirectResponse
|
from fastapi.responses import JSONResponse, RedirectResponse
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class LLMClient:
|
|||||||
if max_tokens:
|
if max_tokens:
|
||||||
payload["max_tokens"] = max_tokens
|
payload["max_tokens"] = max_tokens
|
||||||
|
|
||||||
response = await self.client.post(
|
response = await self._async_client.post(
|
||||||
f"{self.base_url}/text/chatcompletion_v2",
|
f"{self.base_url}/text/chatcompletion_v2",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=payload,
|
json=payload,
|
||||||
@@ -157,7 +157,7 @@ class LLMClient:
|
|||||||
if max_tokens:
|
if max_tokens:
|
||||||
payload["max_tokens"] = max_tokens
|
payload["max_tokens"] = max_tokens
|
||||||
|
|
||||||
response = await self.client.post(
|
response = await self._async_client.post(
|
||||||
f"{self.base_url}/chat/completions",
|
f"{self.base_url}/chat/completions",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=payload,
|
json=payload,
|
||||||
|
|||||||
+263
@@ -0,0 +1,263 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
CrewAI Agent Teams for Opus Orchestrator
|
||||||
|
========================================
|
||||||
|
Creates 5 specialized CrewAI agents to fix issues in parallel.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Add project to path
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
from crewai import Agent, Task, Crew, Process
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Get API key
|
||||||
|
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
|
||||||
|
if not OPENAI_API_KEY:
|
||||||
|
print("❌ OPENAI_API_KEY not found in environment")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def create_agent(name: str, role: str, goal: str, backstory: str):
|
||||||
|
"""Create a specialized CrewAI agent."""
|
||||||
|
return Agent(
|
||||||
|
name=name,
|
||||||
|
role=role,
|
||||||
|
goal=goal,
|
||||||
|
backstory=backstory,
|
||||||
|
verbose=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# TEAM 1: Critical Bug Fix Squad
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TEAM_1_AGENT = create_agent(
|
||||||
|
name="CriticalBugSquad",
|
||||||
|
role="Senior Python Developer - Bug Fixer",
|
||||||
|
goal="Fix critical bugs that prevent Opus from running",
|
||||||
|
backstory="""You are a senior Python developer with 15+ years of experience.
|
||||||
|
You specialize in debugging complex async code, FastAPI applications, and LangGraph workflows.
|
||||||
|
You have a reputation for finding and fixing bugs that others miss.
|
||||||
|
Your code is always tested and follows best practices.
|
||||||
|
You are methodical: you read the code, understand the bug, fix it, and verify."""
|
||||||
|
)
|
||||||
|
|
||||||
|
TEAM_1_TASK = Task(
|
||||||
|
description="""Fix these critical bugs in Opus Orchestrator:
|
||||||
|
|
||||||
|
1. opus_orchestrator/utils/llm.py - The async methods use `self.client` which is undefined.
|
||||||
|
Should use `self._async_client` instead.
|
||||||
|
|
||||||
|
2. opus_orchestrator/server.py - The /upload endpoint uses UploadFile and File
|
||||||
|
without importing them from FastAPI.
|
||||||
|
|
||||||
|
3. opus_orchestrator/langgraph_workflow.py - The fallback mechanism just returns
|
||||||
|
initial_state instead of real recovery. Implement proper error handling.
|
||||||
|
|
||||||
|
Read each file, identify the exact bug, fix it, and ensure the fix is correct.""",
|
||||||
|
agent=TEAM_1_AGENT,
|
||||||
|
expected_output="Fixed Python files with bug corrections applied"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# TEAM 2: Agent & Workflow Repair
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TEAM_2_AGENT = create_agent(
|
||||||
|
name="AgentWorkflowRepair",
|
||||||
|
role="Multi-Agent Systems Specialist",
|
||||||
|
goal="Fix agent behavior and workflow logic issues",
|
||||||
|
backstory="""You are a specialist in multi-agent AI systems.
|
||||||
|
You have deep experience with AutoGen, CrewAI, and LangGraph.
|
||||||
|
You understand how agents should collaborate, critique, and revise work.
|
||||||
|
You fixed many bugs in agent orchestration systems.
|
||||||
|
Your specialty is making agents actually do what they're supposed to do."""
|
||||||
|
)
|
||||||
|
|
||||||
|
TEAM_2_TASK = Task(
|
||||||
|
description="""Fix these agent/workflow bugs in Opus Orchestrator:
|
||||||
|
|
||||||
|
1. opus_orchestrator/autogen_critique.py - The iterate_chapter() method runs
|
||||||
|
a critique loop but never actually revises the chapter. The comment says
|
||||||
|
"In production: pass feedback to writer agent for revision" but it's commented out.
|
||||||
|
Implement actual revision logic.
|
||||||
|
|
||||||
|
2. opus_orchestrator/crews/base_crew.py - The get_crewai_llm() function accepts
|
||||||
|
provider and model parameters but ignores them, always using OpenAI.
|
||||||
|
Make it actually use the passed parameters.
|
||||||
|
|
||||||
|
Read each file, understand the bug, fix it, verify the logic is correct.""",
|
||||||
|
agent=TEAM_2_AGENT,
|
||||||
|
expected_output="Fixed agent and workflow code with proper logic"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# TEAM 3: Infrastructure & Config
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TEAM_3_AGENT = create_agent(
|
||||||
|
name="InfrastructureTeam",
|
||||||
|
role="DevOps & Infrastructure Engineer",
|
||||||
|
goal="Improve configuration, error handling, and infrastructure",
|
||||||
|
backstory="""You are a DevOps and infrastructure engineer with expertise in
|
||||||
|
Python application configuration, error handling, and best practices.
|
||||||
|
You believe in fail-fast with clear messages, not silent failures.
|
||||||
|
You understand API rate limiting and cost controls.
|
||||||
|
You make systems robust and production-ready."""
|
||||||
|
)
|
||||||
|
|
||||||
|
TEAM_3_TASK = Task(
|
||||||
|
description="""Fix these infrastructure issues in Opus Orchestrator:
|
||||||
|
|
||||||
|
1. opus_orchestrator/utils/github_ingest.py - GitHubIngestor requires a token
|
||||||
|
for all repos, but public repos don't need one. Make token optional for
|
||||||
|
public repos, required only for private.
|
||||||
|
|
||||||
|
2. opus_orchestrator/config.py + orchestrator.py - When API keys are missing,
|
||||||
|
the system proceeds anyway and fails later with obscure errors.
|
||||||
|
Add validation at startup with clear error messages.
|
||||||
|
|
||||||
|
3. opus_orchestrator/config.py - Add rate limiting and cost controls:
|
||||||
|
- Add max_tokens_per_run to config
|
||||||
|
- Track cumulative token usage
|
||||||
|
- Add cost estimation
|
||||||
|
- Implement early termination when budget exceeded
|
||||||
|
|
||||||
|
Read each file, implement the fixes, ensure proper error handling.""",
|
||||||
|
agent=TEAM_3_AGENT,
|
||||||
|
expected_output="Infrastructure improvements with proper error handling"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# TEAM 4: Architecture & Design
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TEAM_4_AGENT = create_agent(
|
||||||
|
name="ArchitectureSquad",
|
||||||
|
role="Software Architect",
|
||||||
|
goal="Refactor design issues and consolidate duplicate code",
|
||||||
|
backstory="""You are a software architect with expertise in clean code,
|
||||||
|
refactoring, and system design. You specialize in reducing complexity
|
||||||
|
and eliminating duplication. You believe in DRY (Don't Repeat Yourself)
|
||||||
|
and single sources of truth. You make systems maintainable."""
|
||||||
|
)
|
||||||
|
|
||||||
|
TEAM_4_TASK = Task(
|
||||||
|
description="""Fix these architecture/design issues in Opus Orchestrator:
|
||||||
|
|
||||||
|
1. opus_orchestrator/state.py and langgraph_state.py - There are two parallel
|
||||||
|
state models (OpusState and OpusGraphState) that duplicate fields.
|
||||||
|
Create a unified state model that both can use, or create clear adapters.
|
||||||
|
|
||||||
|
2. opus_orchestrator/agents/base.py - Agents return raw text strings,
|
||||||
|
not validated Pydantic models. Add output validation using the existing
|
||||||
|
schemas in schemas/book.py. Make agents return validated output.
|
||||||
|
|
||||||
|
3. opus_orchestrator/frameworks.py and orchestrator.py - There are two
|
||||||
|
different systems for framework prompts. Consolidate into a single
|
||||||
|
source of truth in frameworks.py and import it in orchestrator.py.
|
||||||
|
|
||||||
|
This is refactoring work - preserve existing functionality while improving design.""",
|
||||||
|
agent=TEAM_4_AGENT,
|
||||||
|
expected_output="Refactored code with improved architecture"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# TEAM 5: Features & Polish
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TEAM_5_AGENT = create_agent(
|
||||||
|
name="FeaturesTeam",
|
||||||
|
role="Full-Stack Developer - Features",
|
||||||
|
goal="Implement missing features and polish the application",
|
||||||
|
backstory="""You are a full-stack developer who loves implementing features
|
||||||
|
and making things complete. You have experience with testing, streaming,
|
||||||
|
state persistence, and integrating disconnected components.
|
||||||
|
You make software feature-complete and production-ready."""
|
||||||
|
)
|
||||||
|
|
||||||
|
TEAM_5_TASK = Task(
|
||||||
|
description="""Implement these features in Opus Orchestrator:
|
||||||
|
|
||||||
|
1. tests/test_orchestrator.py - Add basic test coverage:
|
||||||
|
- Test framework prompts
|
||||||
|
- Test CLI commands (mocked)
|
||||||
|
- Test schema validation
|
||||||
|
|
||||||
|
2. opus_orchestrator/langgraph_workflow.py - Enable checkpointing:
|
||||||
|
- Change checkpointer = None to use MemorySaver
|
||||||
|
- Add config option to enable/disable
|
||||||
|
- Store thread_id for resume capability
|
||||||
|
|
||||||
|
3. opus_orchestrator/server.py - Implement streaming:
|
||||||
|
- Add /generate/stream endpoint using Server-Sent Events
|
||||||
|
- Stream progress updates (stage, percentage)
|
||||||
|
|
||||||
|
4. Split large files (if time permits):
|
||||||
|
- Extract CLI commands into separate modules
|
||||||
|
- Target: no file > 400 lines
|
||||||
|
|
||||||
|
Note: For issues #15 (Research Agent) and #16 (Nonfiction), add TODO
|
||||||
|
comments describing what needs to be done for future work.""",
|
||||||
|
agent=TEAM_5_AGENT,
|
||||||
|
expected_output="Implemented features and tests"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# RUN ALL TEAMS
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def run_team(crew: Crew, team_name: str):
|
||||||
|
"""Run a team and return results."""
|
||||||
|
print(f"\n{'='*70}")
|
||||||
|
print(f"🚀 Starting {team_name}...")
|
||||||
|
print(f"{'='*70}")
|
||||||
|
|
||||||
|
result = crew.kickoff()
|
||||||
|
|
||||||
|
print(f"\n✅ {team_name} Complete!")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🎯 Opus Orchestrator AI - CrewAI Development Teams")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
# Create crews
|
||||||
|
crews = [
|
||||||
|
(Crew(agents=[TEAM_1_AGENT], tasks=[TEAM_1_TASK], verbose=True), "Team 1: Critical Bugs"),
|
||||||
|
(Crew(agents=[TEAM_2_AGENT], tasks=[TEAM_2_TASK], verbose=True), "Team 2: Agent/Workflow"),
|
||||||
|
(Crew(agents=[TEAM_3_AGENT], tasks=[TEAM_3_TASK], verbose=True), "Team 3: Infrastructure"),
|
||||||
|
(Crew(agents=[TEAM_4_AGENT], tasks=[TEAM_4_TASK], verbose=True), "Team 4: Architecture"),
|
||||||
|
(Crew(agents=[TEAM_5_AGENT], tasks=[TEAM_5_TASK], verbose=True), "Team 5: Features"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Run sequentially (can be parallelized if needed)
|
||||||
|
results = []
|
||||||
|
for crew, name in crews:
|
||||||
|
try:
|
||||||
|
result = run_team(crew, name)
|
||||||
|
results.append((name, "SUCCESS", result))
|
||||||
|
except Exception as e:
|
||||||
|
results.append((name, "FAILED", str(e)))
|
||||||
|
print(f"❌ {name} failed: {e}")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print("\n" + "=" * 70)
|
||||||
|
print("📊 TEAM SUMMARY")
|
||||||
|
print("=" * 70)
|
||||||
|
for name, status, _ in results:
|
||||||
|
emoji = "✅" if status == "SUCCESS" else "❌"
|
||||||
|
print(f"{emoji} {name}: {status}")
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Opus Orchestrator AI - CrewAI Development Teams
|
||||||
|
================================================
|
||||||
|
Divides 17 issues into 5 specialized teams, creates branches,
|
||||||
|
and assigns work.
|
||||||
|
"""
|
||||||
|
|
||||||
|
TEAMS = {
|
||||||
|
"team-1-critical-bugs": {
|
||||||
|
"name": "Critical Bug Fix Squad",
|
||||||
|
"description": "Fixes blocking bugs that prevent the system from running",
|
||||||
|
"issues": [
|
||||||
|
"#1 - LLM Client self.client undefined (async methods)",
|
||||||
|
"#3 - Server Upload missing UploadFile/File imports",
|
||||||
|
"#17 - LangGraph workflow error recovery (fake fallback)",
|
||||||
|
],
|
||||||
|
"priority": "CRITICAL",
|
||||||
|
"files_to_fix": [
|
||||||
|
"opus_orchestrator/utils/llm.py",
|
||||||
|
"opus_orchestrator/server.py",
|
||||||
|
"opus_orchestrator/langgraph_workflow.py",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"team-2-agent-workflow": {
|
||||||
|
"name": "Agent & Workflow Repair Crew",
|
||||||
|
"description": "Fixes agent behavior and workflow logic issues",
|
||||||
|
"issues": [
|
||||||
|
"#2 - AutoGen critique loop never revises chapters",
|
||||||
|
"#5 - CrewAI LLM factory ignores config parameters",
|
||||||
|
],
|
||||||
|
"priority": "HIGH",
|
||||||
|
"files_to_fix": [
|
||||||
|
"opus_orchestrator/autogen_critique.py",
|
||||||
|
"opus_orchestrator/crews/base_crew.py",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"team-3-infrastructure": {
|
||||||
|
"name": "Infrastructure & Config Team",
|
||||||
|
"description": "Improves configuration, error handling, and infrastructure",
|
||||||
|
"issues": [
|
||||||
|
"#4 - GitHub Ingestor requires token for public repos",
|
||||||
|
"#14 - Silent failures when API keys missing",
|
||||||
|
"#10 - Add rate limiting and cost controls",
|
||||||
|
],
|
||||||
|
"priority": "MEDIUM",
|
||||||
|
"files_to_fix": [
|
||||||
|
"opus_orchestrator/utils/github_ingest.py",
|
||||||
|
"opus_orchestrator/config.py",
|
||||||
|
"opus_orchestrator/orchestrator.py",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"team-4-architecture": {
|
||||||
|
"name": "Architecture & Design Squad",
|
||||||
|
"description": "Refactors design issues and consolidates duplicate code",
|
||||||
|
"issues": [
|
||||||
|
"#6 - Duplicate state management (OpusState vs OpusGraphState)",
|
||||||
|
"#11 - No structured output validation from agents",
|
||||||
|
"#12 - Duplicate framework prompt systems",
|
||||||
|
],
|
||||||
|
"priority": "MEDIUM",
|
||||||
|
"files_to_fix": [
|
||||||
|
"opus_orchestrator/state.py",
|
||||||
|
"opus_orchestrator/langgraph_state.py",
|
||||||
|
"opus_orchestrator/agents/base.py",
|
||||||
|
"opus_orchestrator/frameworks.py",
|
||||||
|
"opus_orchestrator/orchestrator.py",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"team-5-features": {
|
||||||
|
"name": "Features & Polish Team",
|
||||||
|
"description": "Implements missing features and polish items",
|
||||||
|
"issues": [
|
||||||
|
"#7 - Add test suite for core functionality",
|
||||||
|
"#8 - Implement streaming for long-running generations",
|
||||||
|
"#9 - Enable LangGraph state persistence (checkpointing)",
|
||||||
|
"#13 - Giant monolith files need refactoring",
|
||||||
|
"#15 - Research agent disconnected from main flow",
|
||||||
|
"#16 - Nonfiction support underdeveloped",
|
||||||
|
],
|
||||||
|
"priority": "LOW",
|
||||||
|
"files_to_fix": [
|
||||||
|
"tests/",
|
||||||
|
"opus_orchestrator/server.py",
|
||||||
|
"opus_orchestrator/langgraph_workflow.py",
|
||||||
|
"tests/test_orchestrator.py",
|
||||||
|
"opus_orchestrator/cli.py",
|
||||||
|
"opus_orchestrator/orchestrator.py",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for team_id, team in TEAMS.items():
|
||||||
|
print(f"\n{'='*70}")
|
||||||
|
print(f"🚂 TEAM: {team['name']}")
|
||||||
|
print(f" Priority: {team['priority']}")
|
||||||
|
print(f" Description: {team['description']}")
|
||||||
|
print(f"\n Issues:")
|
||||||
|
for issue in team['issues']:
|
||||||
|
print(f" • {issue}")
|
||||||
|
print(f"\n Files to fix:")
|
||||||
|
for f in team['files_to_fix']:
|
||||||
|
print(f" • {f}")
|
||||||
Reference in New Issue
Block a user