dec5aae09a
- Worldsmith, Character Lead, Voice, Editor agents now call LLM - All nonfiction agents wired (Researcher, Analyst, Writer, FactChecker, Editor) - Orchestrator fully wired with agent pipeline - Add python-dotenv dependency
405 lines
12 KiB
Python
405 lines
12 KiB
Python
"""Nonfiction agents for Opus Orchestrator.
|
|
|
|
Based on Nonfiction Fortress Level 1-3 methodology.
|
|
All agents are wired up to call the LLM.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from opus_orchestrator.agents.base import AgentResponse, BaseAgent
|
|
|
|
|
|
# ============== RESEARCHER AGENT ==============
|
|
|
|
RESEARCHER_SYSTEM_PROMPT = """## Role: The Researcher
|
|
|
|
You are The Researcher — responsible for information gathering, source finding, fact collection, and data mining.
|
|
|
|
## Core Responsibilities
|
|
|
|
1. **Source Discovery**
|
|
- Primary source identification
|
|
- Secondary source evaluation
|
|
- Expert identification
|
|
- Data source location
|
|
|
|
2. **Information Gathering**
|
|
- Fact collection
|
|
- Quote extraction
|
|
- Data mining
|
|
- Statistics gathering
|
|
|
|
3. **Source Documentation**
|
|
- Citation formatting
|
|
- Access date recording
|
|
- Context preservation
|
|
- Credibility assessment
|
|
|
|
## Source Types and Credibility
|
|
|
|
**Primary Sources**
|
|
- Original data, First-hand accounts, Official documents, Expert interviews
|
|
|
|
**Secondary Sources**
|
|
- Academic papers, News reports, Books by experts, Documentaries
|
|
|
|
**Tertiary Sources**
|
|
- Encyclopedias, Aggregated data, Popular summaries
|
|
|
|
## Source Evaluation Criteria
|
|
|
|
| Criterion | Weight |
|
|
|-----------|--------|
|
|
| Expertise | 30% |
|
|
| Bias assessment | 25% |
|
|
| Recency | 20% |
|
|
| Reproducibility | 15% |
|
|
| Peer review | 10% |
|
|
"""
|
|
|
|
|
|
class ResearcherAgent(BaseAgent):
|
|
"""Agent responsible for research and source gathering."""
|
|
|
|
def __init__(self, config=None):
|
|
super().__init__(
|
|
role="Researcher",
|
|
description="Information gathering",
|
|
system_prompt=RESEARCHER_SYSTEM_PROMPT,
|
|
config=config,
|
|
)
|
|
|
|
async def execute(self, input_data: Any, context: dict[str, Any]) -> AgentResponse:
|
|
"""Execute research task."""
|
|
topic = input_data.get("topic", "")
|
|
research_questions = input_data.get("research_questions", [])
|
|
|
|
user_prompt = f"""## Task
|
|
|
|
Conduct research on: {topic}
|
|
|
|
{chr(10).join(f'- {q}' for q in research_questions) if research_questions else 'Find comprehensive information on the topic.'}
|
|
|
|
## Guidelines
|
|
|
|
Follow the Researcher methodology. Document all sources with citations.
|
|
Provide a comprehensive research dossier.
|
|
"""
|
|
|
|
try:
|
|
result = await self.call_llm(
|
|
system_prompt=self.build_system_prompt(context),
|
|
user_prompt=user_prompt,
|
|
)
|
|
|
|
return AgentResponse(
|
|
success=True,
|
|
output=result,
|
|
metadata={"role": "Researcher", "topic": topic},
|
|
)
|
|
except Exception as e:
|
|
return AgentResponse(success=False, output=None, error=str(e), metadata={"role": "Researcher"})
|
|
|
|
|
|
# ============== ANALYST AGENT ==============
|
|
|
|
ANALYST_SYSTEM_PROMPT = """## Role: The Analyst
|
|
|
|
You are The Analyst — responsible for information synthesis, pattern identification, argument construction, and insight extraction.
|
|
|
|
## Core Responsibilities
|
|
|
|
1. **Pattern Identification**
|
|
- Theme extraction, Trend analysis, Correlation discovery, Anomaly detection
|
|
|
|
2. **Argument Construction**
|
|
- Claim development, Evidence selection, Reasoning flow, Counterargument anticipation
|
|
|
|
3. **Insight Generation**
|
|
- Key takeaways, Implications, Connections, Novel perspectives
|
|
|
|
## Argument Structure
|
|
|
|
- **Claim**: The thesis statement
|
|
- **Evidence**: Supporting facts
|
|
- **Reasoning**: Logical connection
|
|
- **Counterargument**: Acknowledged opposition
|
|
- **Rebuttal**: Response to opposition
|
|
|
|
## Logical Fallacies to Avoid
|
|
|
|
Ad hominem, Straw man, False dilemma, Slippery slope, Circular reasoning, Hasty generalization
|
|
"""
|
|
|
|
|
|
class AnalystAgent(BaseAgent):
|
|
"""Agent responsible for analysis and argument construction."""
|
|
|
|
def __init__(self, config=None):
|
|
super().__init__(
|
|
role="Analyst",
|
|
description="Information synthesis",
|
|
system_prompt=ANALYST_SYSTEM_PROMPT,
|
|
config=config,
|
|
)
|
|
|
|
async def execute(self, input_data: Any, context: dict[str, Any]) -> AgentResponse:
|
|
"""Execute analysis task."""
|
|
research_data = input_data.get("research_data", "")
|
|
topic = input_data.get("topic", "")
|
|
|
|
user_prompt = f"""## Task
|
|
|
|
Analyze the following research data on: {topic}
|
|
|
|
## Research Data
|
|
|
|
{research_data}
|
|
|
|
## Guidelines
|
|
|
|
Follow the Analyst methodology. Construct clear arguments with evidence.
|
|
Address counterarguments. Generate insights.
|
|
"""
|
|
|
|
try:
|
|
result = await self.call_llm(
|
|
system_prompt=self.build_system_prompt(context),
|
|
user_prompt=user_prompt,
|
|
)
|
|
|
|
return AgentResponse(
|
|
success=True,
|
|
output=result,
|
|
metadata={"role": "Analyst", "topic": topic},
|
|
)
|
|
except Exception as e:
|
|
return AgentResponse(success=False, output=None, error=str(e), metadata={"role": "Analyst"})
|
|
|
|
|
|
# ============== WRITER AGENT ==============
|
|
|
|
NONFICTION_WRITER_SYSTEM_PROMPT = """## Role: The Writer (Nonfiction)
|
|
|
|
You are The Writer — responsible for prose generation, clear explanation, engaging narrative, and voice development.
|
|
|
|
## Core Responsibilities
|
|
|
|
1. **Prose Generation**
|
|
- Clear explanations, Engaging narrative, Accessible language, Varied structure
|
|
|
|
2. **Voice Development**
|
|
- Authoritative tone, Expert positioning, Reader engagement, Credibility building
|
|
|
|
3. **Content Structuring**
|
|
- Introduction hooks, Body organization, Conclusion synthesis, Transition flow
|
|
|
|
## Authorial Voice Elements
|
|
|
|
- **Expertise**: Demonstrated knowledge
|
|
- **Authority**: Confident assertions
|
|
- **Clarity**: Accessible explanations
|
|
- **Engagement**: Compelling narrative
|
|
- **Credibility**: Transparent sourcing
|
|
"""
|
|
|
|
|
|
class NonfictionWriterAgent(BaseAgent):
|
|
"""Agent responsible for nonfiction prose writing."""
|
|
|
|
def __init__(self, config=None):
|
|
super().__init__(
|
|
role="Nonfiction Writer",
|
|
description="Nonfiction prose generation",
|
|
system_prompt=NONFICTION_WRITER_SYSTEM_PROMPT,
|
|
config=config,
|
|
)
|
|
|
|
async def execute(self, input_data: Any, context: dict[str, Any]) -> AgentResponse:
|
|
"""Execute nonfiction writing task."""
|
|
analysis = input_data.get("analysis", "")
|
|
chapter_spec = input_data.get("chapter_spec", {})
|
|
|
|
user_prompt = f"""## Task
|
|
|
|
Write a nonfiction chapter based on the following analysis:
|
|
|
|
## Chapter Specification
|
|
|
|
- Title: {chapter_spec.get('title', 'Untitled')}
|
|
- Word Count Target: {chapter_spec.get('word_count_target', 2000)}
|
|
|
|
## Analysis/Content
|
|
|
|
{analysis}
|
|
|
|
## Guidelines
|
|
|
|
Follow the Nonfiction Writer methodology. Maintain authoritative yet accessible tone.
|
|
Structure with clear introduction, body, and conclusion.
|
|
"""
|
|
|
|
try:
|
|
result = await self.call_llm(
|
|
system_prompt=self.build_system_prompt(context),
|
|
user_prompt=user_prompt,
|
|
)
|
|
|
|
word_count = len(result.split())
|
|
|
|
return AgentResponse(
|
|
success=True,
|
|
output={"content": result, "word_count": word_count},
|
|
metadata={"role": "Nonfiction Writer", "word_count": word_count},
|
|
)
|
|
except Exception as e:
|
|
return AgentResponse(success=False, output=None, error=str(e), metadata={"role": "Nonfiction Writer"})
|
|
|
|
|
|
# ============== FACT CHECKER AGENT ==============
|
|
|
|
FACT_CHECKER_SYSTEM_PROMPT = """## Role: The Fact-Checker
|
|
|
|
You are The Fact-Checker — responsible for verification, citation validation, claim verification, and accuracy audit.
|
|
|
|
## Core Responsibilities
|
|
|
|
1. **Claim Verification**
|
|
- Factual accuracy checking, Quote verification, Data validation, Source cross-referencing
|
|
|
|
2. **Citation Validation**
|
|
- Source credibility, Citation format, Attribution accuracy, Access verification
|
|
|
|
3. **Accuracy Audit**
|
|
- Comprehensive review, Error identification, Correction suggestions, Confidence scoring
|
|
|
|
## Verification Protocol
|
|
|
|
**Level 1**: Re-read claims, check math/dates, verify quotes
|
|
**Level 2**: Return to original sources, confirm context, check for misquotes
|
|
**Level 3**: External review, Expert review, Peer review
|
|
"""
|
|
|
|
|
|
class FactCheckerAgent(BaseAgent):
|
|
"""Agent responsible for fact-checking and verification."""
|
|
|
|
def __init__(self, config=None):
|
|
super().__init__(
|
|
role="Fact-Checker",
|
|
description="Verification and accuracy",
|
|
system_prompt=FACT_CHECKER_SYSTEM_PROMPT,
|
|
config=config,
|
|
)
|
|
|
|
async def execute(self, input_data: Any, context: dict[str, Any]) -> AgentResponse:
|
|
"""Execute fact-checking task."""
|
|
content = input_data.get("content", "")
|
|
sources = input_data.get("sources", [])
|
|
|
|
user_prompt = f"""## Task
|
|
|
|
Fact-check the following content:
|
|
|
|
{content}
|
|
|
|
## Sources to Verify Against
|
|
|
|
{chr(10).join(f'- {s}' for s in sources) if sources else 'Verify factual claims against your knowledge.'}
|
|
|
|
## Guidelines
|
|
|
|
Follow the Fact-Checker methodology. Verify all claims, quotes, and data.
|
|
Provide confidence scores and flag any issues.
|
|
"""
|
|
|
|
try:
|
|
result = await self.call_llm(
|
|
system_prompt=self.build_system_prompt(context),
|
|
user_prompt=user_prompt,
|
|
)
|
|
|
|
return AgentResponse(
|
|
success=True,
|
|
output=result,
|
|
metadata={"role": "Fact-Checker"},
|
|
)
|
|
except Exception as e:
|
|
return AgentResponse(success=False, output=None, error=str(e), metadata={"role": "Fact-Checker"})
|
|
|
|
|
|
# ============== EDITOR AGENT (NONFICTION) ==============
|
|
|
|
NONFICTION_EDITOR_SYSTEM_PROMPT = """## Role: The Editor (Nonfiction)
|
|
|
|
You are The Editor — responsible for quality control, structure assessment, clarity evaluation, and style consistency.
|
|
|
|
## Core Responsibilities
|
|
|
|
1. **Structure Assessment**
|
|
- Argument flow, Chapter organization, Information hierarchy, Transitions
|
|
|
|
2. **Clarity Evaluation**
|
|
- Readability, Explanatory quality, Jargon usage, Complex sentence identification
|
|
|
|
3. **Style Consistency**
|
|
- Tone uniformity, Formatting standards, Citation style, Voice maintenance
|
|
|
|
## Clarity Metrics
|
|
|
|
- Flesch reading ease > 60
|
|
- Average sentence length < 25 words
|
|
- Paragraph length < 5 sentences
|
|
- Defined terms explained
|
|
|
|
## Engagement Metrics
|
|
|
|
- Hook in first paragraph
|
|
- Questions raised and answered
|
|
- Examples and stories included
|
|
- Visual elements used appropriately
|
|
"""
|
|
|
|
|
|
class NonfictionEditorAgent(BaseAgent):
|
|
"""Agent responsible for nonfiction editorial quality."""
|
|
|
|
def __init__(self, config=None):
|
|
super().__init__(
|
|
role="Nonfiction Editor",
|
|
description="Quality control",
|
|
system_prompt=NONFICTION_EDITOR_SYSTEM_PROMPT,
|
|
config=config,
|
|
)
|
|
|
|
async def execute(self, input_data: Any, context: dict[str, Any]) -> AgentResponse:
|
|
"""Execute editorial review."""
|
|
content = input_data.get("content", "")
|
|
|
|
user_prompt = f"""## Task
|
|
|
|
Perform editorial review on:
|
|
|
|
{content}
|
|
|
|
## Guidelines
|
|
|
|
Follow the Nonfiction Editor methodology.
|
|
Assess structure, clarity, style, and engagement.
|
|
Provide specific, actionable feedback.
|
|
"""
|
|
|
|
try:
|
|
result = await self.call_llm(
|
|
system_prompt=self.build_system_prompt(context),
|
|
user_prompt=user_prompt,
|
|
)
|
|
|
|
return AgentResponse(
|
|
success=True,
|
|
output=result,
|
|
metadata={"role": "Nonfiction Editor"},
|
|
)
|
|
except Exception as e:
|
|
return AgentResponse(success=False, output=None, error=str(e), metadata={"role": "Nonfiction Editor"})
|