Add rigorous nonfiction frameworks
NEW frameworks: - Diátaxis Tutorial - Learn by doing a project - Diátaxis How-To - Accomplish a specific task - Diátaxis Explanation - Clarify and deepen understanding - Diátaxis Reference - Complete information lookup - Technical Manual - From foundations to mastery - Codebase Tour - Document code systematically - API Documentation - Complete API reference NonfictionGenerator class to use these frameworks. CLI integration with --framework flag. Example: opus generate --framework codebase-tour --concept 'Linux Kernel'
This commit is contained in:
@@ -41,6 +41,11 @@ from opus_orchestrator.utils.github_ingest import GitHubIngestor, create_github_
|
|||||||
from opus_orchestrator.utils.s3_ingest import S3Ingestor, create_s3_ingestor
|
from opus_orchestrator.utils.s3_ingest import S3Ingestor, create_s3_ingestor
|
||||||
from opus_orchestrator.utils.local_ingest import LocalIngestor, create_local_ingestor
|
from opus_orchestrator.utils.local_ingest import LocalIngestor, create_local_ingestor
|
||||||
from opus_orchestrator.frameworks import StoryFramework
|
from opus_orchestrator.frameworks import StoryFramework
|
||||||
|
from opus_orchestrator.nonfiction_frameworks import (
|
||||||
|
NonfictionFramework,
|
||||||
|
get_nonfiction_framework,
|
||||||
|
list_nonfiction_frameworks,
|
||||||
|
)
|
||||||
from opus_orchestrator.crews import (
|
from opus_orchestrator.crews import (
|
||||||
OpusCrew,
|
OpusCrew,
|
||||||
FictionCrew,
|
FictionCrew,
|
||||||
@@ -97,6 +102,10 @@ __all__ = [
|
|||||||
"OpusGraphState",
|
"OpusGraphState",
|
||||||
"run_opus",
|
"run_opus",
|
||||||
"StoryFramework",
|
"StoryFramework",
|
||||||
|
# Nonfiction Frameworks (NEW!)
|
||||||
|
"NonfictionFramework",
|
||||||
|
"get_nonfiction_framework",
|
||||||
|
"list_nonfiction_frameworks",
|
||||||
# Crews
|
# Crews
|
||||||
"OpusCrew",
|
"OpusCrew",
|
||||||
"FictionCrew",
|
"FictionCrew",
|
||||||
|
|||||||
@@ -211,9 +211,16 @@ Examples:
|
|||||||
gen_parser.add_argument(
|
gen_parser.add_argument(
|
||||||
"--framework", "-f",
|
"--framework", "-f",
|
||||||
default="snowflake",
|
default="snowflake",
|
||||||
choices=["snowflake", "three-act", "save-the-cat", "hero-journey",
|
choices=[
|
||||||
"story-circle", "seven-point", "fichtean"],
|
# Story frameworks
|
||||||
help="Story framework to use",
|
"snowflake", "three-act", "save-the-cat", "hero-journey",
|
||||||
|
"story-circle", "seven-point", "fichtean",
|
||||||
|
# Nonfiction frameworks (NEW!)
|
||||||
|
"technical-manual", "codebase-tour", "diataxis-tutorial",
|
||||||
|
"diataxis-howto", "diataxis-explanation", "diataxis-reference",
|
||||||
|
"api-documentation",
|
||||||
|
],
|
||||||
|
help="Framework to use (story or nonfiction)",
|
||||||
)
|
)
|
||||||
gen_parser.add_argument(
|
gen_parser.add_argument(
|
||||||
"--genre", "-g",
|
"--genre", "-g",
|
||||||
@@ -612,7 +619,44 @@ async def run_generate(args: argparse.Namespace) -> int:
|
|||||||
|
|
||||||
use_autogen = not args.no_autogen
|
use_autogen = not args.no_autogen
|
||||||
|
|
||||||
if args.use_crewai:
|
# Check for nonfiction frameworks (NEW!)
|
||||||
|
nonfiction_frameworks = [
|
||||||
|
"technical-manual", "codebase-tour", "diataxis-tutorial",
|
||||||
|
"diataxis-howto", "diataxis-explanation", "diataxis-reference",
|
||||||
|
"api-documentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
if args.framework in nonfiction_frameworks:
|
||||||
|
# Use NonfictionGenerator for rigorous technical frameworks
|
||||||
|
from opus_orchestrator.nonfiction_generator import NonfictionGenerator
|
||||||
|
from opus_orchestrator.nonfiction_frameworks import NonfictionFramework
|
||||||
|
|
||||||
|
print("📚 Using Nonfiction Framework...\n")
|
||||||
|
|
||||||
|
# Map framework string to enum
|
||||||
|
framework_map = {
|
||||||
|
"technical-manual": NonfictionFramework.TECHNICAL_MANUAL,
|
||||||
|
"codebase-tour": NonfictionFramework.CODEBASE_TOUR,
|
||||||
|
"diataxis-tutorial": NonfictionFramework.DIAXIS_TUTORIAL,
|
||||||
|
"diataxis-howto": NonfictionFramework.DIAXIS_HOWTO,
|
||||||
|
"diataxis-explanation": NonfictionFramework.DIAXIS_EXPLANATION,
|
||||||
|
"diataxis-reference": NonfictionFramework.DIAXIS_REFERENCE,
|
||||||
|
"api-documentation": NonfictionFramework.API_DOCUMENTATION,
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_framework = framework_map.get(args.framework, NonfictionFramework.TECHNICAL_MANUAL)
|
||||||
|
|
||||||
|
gen = NonfictionGenerator(
|
||||||
|
framework=nf_framework,
|
||||||
|
topic=args.concept or "Technical Topic",
|
||||||
|
source_content=seed_concept[:50000], # Limit for context
|
||||||
|
)
|
||||||
|
|
||||||
|
manuscript = gen.generate(target_word_count=args.words)
|
||||||
|
|
||||||
|
print(f" ✅ Generated {len(manuscript.split())} words using {nf_framework.value}")
|
||||||
|
|
||||||
|
elif args.use_crewai:
|
||||||
# Use CrewAI crews
|
# Use CrewAI crews
|
||||||
print("🛠️ Using CrewAI crews...\n")
|
print("🛠️ Using CrewAI crews...\n")
|
||||||
|
|
||||||
@@ -649,7 +693,6 @@ async def run_generate(args: argparse.Namespace) -> int:
|
|||||||
framework=args.framework,
|
framework=args.framework,
|
||||||
genre=args.genre,
|
genre=args.genre,
|
||||||
target_word_count=args.words,
|
target_word_count=args.words,
|
||||||
use_autogen=use_autogen,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
manuscript = result.get("manuscript", str(result))
|
manuscript = result.get("manuscript", str(result))
|
||||||
|
|||||||
@@ -0,0 +1,290 @@
|
|||||||
|
"""Nonfiction frameworks for Opus Orchestrator.
|
||||||
|
|
||||||
|
Rigorous nonfiction structures: Diátaxis, Technical Manual, Codebase Tour.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class NonfictionFramework(str, Enum):
|
||||||
|
"""Nonfiction book frameworks."""
|
||||||
|
|
||||||
|
DIAXIS_TUTORIAL = "diataxis-tutorial"
|
||||||
|
DIAXIS_HOWTO = "diataxis-howto"
|
||||||
|
DIAXIS_EXPLANATION = "diataxis-explanation"
|
||||||
|
DIAXIS_REFERENCE = "diataxis-reference"
|
||||||
|
TECHNICAL_MANUAL = "technical-manual"
|
||||||
|
CODEBASE_TOUR = "codebase-tour"
|
||||||
|
API_DOCUMENTATION = "api-documentation"
|
||||||
|
|
||||||
|
|
||||||
|
# Diátaxis Framework Definitions
|
||||||
|
# Based on Daniele Procida's work - the gold standard for technical documentation
|
||||||
|
|
||||||
|
DIAXIS_TUTORIAL = {
|
||||||
|
"name": "Diátaxis Tutorial",
|
||||||
|
"description": "A tutorial is a lesson that leads the learner through a series of steps to complete a project. The learner learns by doing.",
|
||||||
|
"stages": [
|
||||||
|
"Introduction - What will we build and why?",
|
||||||
|
"Prerequisites - What do you need before starting?",
|
||||||
|
"Step 1: Setup - Getting the environment ready",
|
||||||
|
"Step 2: First Steps - Your initial actions",
|
||||||
|
"Step 3: Building - Creating something concrete",
|
||||||
|
"Step 4: Enhancement - Adding features",
|
||||||
|
"Step 5: Completion - Finishing the project",
|
||||||
|
"Summary - What you learned",
|
||||||
|
"Next Steps - Where to go from here",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Learners who need guided, hands-on experience",
|
||||||
|
"goal": "Complete a concrete project through step-by-step instruction",
|
||||||
|
"approach": "Progressive disclosure - reveal complexity gradually",
|
||||||
|
"tone": "Encouraging, clear, patient",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
DIAXIS_HOWTO = {
|
||||||
|
"name": "Diátaxis How-To Guide",
|
||||||
|
"description": "A how-to guide leads the reader through a series of steps to accomplish a goal. They already know what they want to do.",
|
||||||
|
"stages": [
|
||||||
|
"Goal Statement - What problem does this solve?",
|
||||||
|
"Prerequisites - What's needed?",
|
||||||
|
"Step 1 - First action",
|
||||||
|
"Step 2 - Second action",
|
||||||
|
"Step N - Final step",
|
||||||
|
"Troubleshooting - Common issues",
|
||||||
|
"Related Tasks - See also",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Practitioners who know what they want to achieve",
|
||||||
|
"goal": "Accomplish a specific, practical task",
|
||||||
|
"approach": "Direct, efficient steps toward a goal",
|
||||||
|
"tone": "Direct, authoritative, no fluff",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
DIAXIS_EXPLANATION = {
|
||||||
|
"name": "Diátaxis Explanation",
|
||||||
|
"description": "An explanation clarifies and deepens understanding of a topic. It provides context and connects concepts.",
|
||||||
|
"stages": [
|
||||||
|
"Overview - What are we exploring?",
|
||||||
|
"Background - What do you need to know first?",
|
||||||
|
"Core Concepts - The key ideas",
|
||||||
|
"How It Works - Under the hood",
|
||||||
|
"Different Approaches - Alternative perspectives",
|
||||||
|
"Why It Matters - Significance",
|
||||||
|
"Common Misconceptions - What people get wrong",
|
||||||
|
"Further Reading - Deepen knowledge",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Readers who want to understand, not just do",
|
||||||
|
"goal": "Build mental models and deepen comprehension",
|
||||||
|
"approach": "Multiple perspectives, rich context",
|
||||||
|
"tone": "Thoughtful, explanatory, nuanced",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
DIAXIS_REFERENCE = {
|
||||||
|
"name": "Diátaxis Reference",
|
||||||
|
"description": "Reference documentation provides authoritative information about a system. Accurate, complete, findable.",
|
||||||
|
"stages": [
|
||||||
|
"Overview - What is this?",
|
||||||
|
"Syntax - How to use it",
|
||||||
|
"Parameters - What it accepts",
|
||||||
|
"Returns - What it produces",
|
||||||
|
"Examples - Usage patterns",
|
||||||
|
"Errors - What can go wrong",
|
||||||
|
"Notes - Important details",
|
||||||
|
"See Also - Related topics",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Users who need precise, detailed information",
|
||||||
|
"goal": "Accurate, comprehensive information lookup",
|
||||||
|
"approach": "Complete, organized, searchable",
|
||||||
|
"tone": "Precise, technical, complete",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Technical Manual Framework
|
||||||
|
# Structured for learning technical subjects deeply
|
||||||
|
|
||||||
|
TECHNICAL_MANUAL = {
|
||||||
|
"name": "Technical Manual",
|
||||||
|
"description": "A comprehensive technical manual that takes readers from foundations to mastery with practical examples.",
|
||||||
|
"stages": [
|
||||||
|
"Part 1: Foundations",
|
||||||
|
" 1. Introduction - Why this matters",
|
||||||
|
" 2. Core Concepts - Essential background",
|
||||||
|
" 3. Architecture - High-level design",
|
||||||
|
" 4. Getting Started - First steps",
|
||||||
|
"",
|
||||||
|
"Part 2: Deep Dive",
|
||||||
|
" 5. [Topic A] - In-depth exploration",
|
||||||
|
" 6. [Topic B] - Implementation details",
|
||||||
|
" 7. [Topic C] - Advanced features",
|
||||||
|
" 8. [Topic D] - Edge cases",
|
||||||
|
"",
|
||||||
|
"Part 3: Practical Application",
|
||||||
|
" 9. Hands-On Project - Build something",
|
||||||
|
" 10. Best Practices - How experts do it",
|
||||||
|
" 11. Debugging - When things go wrong",
|
||||||
|
" 12. Performance - Optimization",
|
||||||
|
"",
|
||||||
|
"Part 4: Reference",
|
||||||
|
" 13. API Reference - Complete API",
|
||||||
|
" 14. Command Reference - All commands",
|
||||||
|
" 15. Configuration - All options",
|
||||||
|
" 16. Troubleshooting Guide - Common problems",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Professionals needing comprehensive, practical knowledge",
|
||||||
|
"goal": "Build expertise from ground up to mastery",
|
||||||
|
"approach": "Theory → Practice → Reference spiral",
|
||||||
|
"tone": "Professional, thorough, practical",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Codebase Tour Framework
|
||||||
|
# For documenting code directly
|
||||||
|
|
||||||
|
CODEBASE_TOUR = {
|
||||||
|
"name": "Codebase Tour",
|
||||||
|
"description": "Document a codebase systematically: structure → components → relationships → implementation → usage.",
|
||||||
|
"stages": [
|
||||||
|
"1. Repository Overview",
|
||||||
|
" - What is this project?",
|
||||||
|
" - What problem does it solve?",
|
||||||
|
" - Key technologies",
|
||||||
|
" - Directory structure",
|
||||||
|
"",
|
||||||
|
"2. High-Level Architecture",
|
||||||
|
" - System components",
|
||||||
|
" - Data flow",
|
||||||
|
" - Key abstractions",
|
||||||
|
"",
|
||||||
|
"3. Core Components",
|
||||||
|
" - Component A: Purpose, public API, key structs",
|
||||||
|
" - Component B: Purpose, public API, key structs",
|
||||||
|
" - Component C: Purpose, public API, key structs",
|
||||||
|
"",
|
||||||
|
"4. Data Structures",
|
||||||
|
" - Key structs and their fields",
|
||||||
|
" - Relationships between data types",
|
||||||
|
" - Memory layout if relevant",
|
||||||
|
"",
|
||||||
|
"5. Core Functions",
|
||||||
|
" - Main entry points",
|
||||||
|
" - Critical paths",
|
||||||
|
" - Algorithm implementations",
|
||||||
|
"",
|
||||||
|
"6. Interfaces",
|
||||||
|
" - How components communicate",
|
||||||
|
" - Public APIs",
|
||||||
|
" - Event/message systems",
|
||||||
|
"",
|
||||||
|
"7. Configuration",
|
||||||
|
" - Config files",
|
||||||
|
" - Environment variables",
|
||||||
|
" - Runtime parameters",
|
||||||
|
"",
|
||||||
|
"8. Testing",
|
||||||
|
" - Test strategies",
|
||||||
|
" - Key test files",
|
||||||
|
" - How to run tests",
|
||||||
|
"",
|
||||||
|
"9. Contributing",
|
||||||
|
" - Development setup",
|
||||||
|
" - Code style",
|
||||||
|
" - Pull request process",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Developers who need to understand, use, or contribute to the codebase",
|
||||||
|
"goal": "Map code to mental model accurately",
|
||||||
|
"approach": "Top-down from architecture to implementation",
|
||||||
|
"tone": "Technical, precise, code-focused",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# API Documentation Framework
|
||||||
|
# For generating API docs from code
|
||||||
|
|
||||||
|
API_DOCUMENTATION = {
|
||||||
|
"name": "API Documentation",
|
||||||
|
"description": "Complete API reference documentation: endpoints, parameters, responses, examples, errors.",
|
||||||
|
"stages": [
|
||||||
|
"API Overview",
|
||||||
|
" - Introduction",
|
||||||
|
" - Authentication",
|
||||||
|
" - Rate Limiting",
|
||||||
|
" - Base URL",
|
||||||
|
"",
|
||||||
|
"Resources",
|
||||||
|
" - Each endpoint documented:",
|
||||||
|
" - Endpoint URL and method",
|
||||||
|
" - Description",
|
||||||
|
" - Path parameters",
|
||||||
|
" - Query parameters",
|
||||||
|
" - Request body schema",
|
||||||
|
" - Response schema",
|
||||||
|
" - Success codes",
|
||||||
|
" - Error codes",
|
||||||
|
" - Example request",
|
||||||
|
" - Example response",
|
||||||
|
"",
|
||||||
|
"Models",
|
||||||
|
" - Data models used",
|
||||||
|
" - Field definitions",
|
||||||
|
" - Type specifications",
|
||||||
|
"",
|
||||||
|
"Errors",
|
||||||
|
" - Error code reference",
|
||||||
|
" - Error message meanings",
|
||||||
|
" - Troubleshooting",
|
||||||
|
"",
|
||||||
|
"SDKs/Libraries",
|
||||||
|
" - Official libraries",
|
||||||
|
" - Community libraries",
|
||||||
|
"",
|
||||||
|
"Changelog",
|
||||||
|
" - Version history",
|
||||||
|
" - Breaking changes",
|
||||||
|
],
|
||||||
|
"structure": {
|
||||||
|
"audience": "Developers integrating with the API",
|
||||||
|
"goal": "Complete, accurate reference for implementation",
|
||||||
|
"approach": "Complete enumeration of all capabilities",
|
||||||
|
"tone": "Technical, complete, unambiguous",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Registry of all nonfiction frameworks
|
||||||
|
NONFICTION_FRAMEWORKS = {
|
||||||
|
NonfictionFramework.DIAXIS_TUTORIAL: DIAXIS_TUTORIAL,
|
||||||
|
NonfictionFramework.DIAXIS_HOWTO: DIAXIS_HOWTO,
|
||||||
|
NonfictionFramework.DIAXIS_EXPLANATION: DIAXIS_EXPLANATION,
|
||||||
|
NonfictionFramework.DIAXIS_REFERENCE: DIAXIS_REFERENCE,
|
||||||
|
NonfictionFramework.TECHNICAL_MANUAL: TECHNICAL_MANUAL,
|
||||||
|
NonfictionFramework.CODEBASE_TOUR: CODEBASE_TOUR,
|
||||||
|
NonfictionFramework.API_DOCUMENTATION: API_DOCUMENTATION,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_nonfiction_framework(framework: NonfictionFramework) -> dict[str, Any]:
|
||||||
|
"""Get a nonfiction framework by type."""
|
||||||
|
return NONFICTION_FRAMEWORKS.get(framework, {})
|
||||||
|
|
||||||
|
|
||||||
|
def list_nonfiction_frameworks() -> dict[str, dict]:
|
||||||
|
"""List all available nonfiction frameworks."""
|
||||||
|
return {
|
||||||
|
k.value: {
|
||||||
|
"name": v.get("name", k.value),
|
||||||
|
"description": v.get("description", ""),
|
||||||
|
}
|
||||||
|
for k, v in NONFICTION_FRAMEWORKS.items()
|
||||||
|
}
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
"""Nonfiction generator using rigorous frameworks.
|
||||||
|
|
||||||
|
Generate technical documentation using Diátaxis, Technical Manual, and Codebase Tour frameworks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
from opus_orchestrator.nonfiction_frameworks import (
|
||||||
|
NonfictionFramework,
|
||||||
|
get_nonfiction_framework,
|
||||||
|
)
|
||||||
|
from opus_orchestrator.utils.llm import LLMClient
|
||||||
|
from opus_orchestrator.config import get_config
|
||||||
|
|
||||||
|
|
||||||
|
class NonfictionGenerator:
|
||||||
|
"""Generate nonfiction using rigorous frameworks."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
framework: NonfictionFramework = NonfictionFramework.TECHNICAL_MANUAL,
|
||||||
|
topic: str = "",
|
||||||
|
source_content: str = "",
|
||||||
|
model: Optional[str] = None,
|
||||||
|
):
|
||||||
|
"""Initialize nonfiction generator.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
framework: Nonfiction framework to use
|
||||||
|
topic: Topic to document
|
||||||
|
source_content: Source code/content to document
|
||||||
|
model: Override model name
|
||||||
|
"""
|
||||||
|
self.framework = framework
|
||||||
|
self.topic = topic
|
||||||
|
self.source_content = source_content
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
self.llm = LLMClient(
|
||||||
|
provider=config.agent.provider,
|
||||||
|
model=model or config.agent.model,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.framework_info = get_nonfiction_framework(framework)
|
||||||
|
|
||||||
|
def generate(self, target_word_count: int = 5000) -> str:
|
||||||
|
"""Generate nonfiction document.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
target_word_count: Target word count
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Generated document
|
||||||
|
"""
|
||||||
|
if self.framework == NonfictionFramework.CODEBASE_TOUR:
|
||||||
|
return self._generate_codebase_tour(target_word_count)
|
||||||
|
elif self.framework == NonfictionFramework.TECHNICAL_MANUAL:
|
||||||
|
return self._generate_technical_manual(target_word_count)
|
||||||
|
elif self.framework == NonfictionFramework.DIAXIS_TUTORIAL:
|
||||||
|
return self._generate_diataxis_tutorial(target_word_count)
|
||||||
|
elif self.framework == NonfictionFramework.DIAXIS_HOWTO:
|
||||||
|
return self._generate_diataxis_howto(target_word_count)
|
||||||
|
elif self.framework == NonfictionFramework.DIAXIS_EXPLANATION:
|
||||||
|
return self._generate_diataxis_explanation(target_word_count)
|
||||||
|
elif self.framework == NonfictionFramework.DIAXIS_REFERENCE:
|
||||||
|
return self._generate_diataxis_reference(target_word_count)
|
||||||
|
else:
|
||||||
|
return self._generate_technical_manual(target_word_count)
|
||||||
|
|
||||||
|
def _generate_codebase_tour(self, target_word_count: int) -> str:
|
||||||
|
"""Generate codebase tour documentation."""
|
||||||
|
source_summary = self.source_content[:10000] if self.source_content else "No source content provided"
|
||||||
|
|
||||||
|
prompt = f"""Generate comprehensive CODEBASE TOUR documentation.
|
||||||
|
|
||||||
|
FRAMEWORK: Codebase Tour - Document a codebase systematically
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
SOURCE CODE/CONTENT:
|
||||||
|
{source_summary}
|
||||||
|
|
||||||
|
Generate the following sections:
|
||||||
|
1. Repository Overview - What is this project, what problem does it solve?
|
||||||
|
2. High-Level Architecture - System components and data flow
|
||||||
|
3. Core Components - Purpose and API of main components
|
||||||
|
4. Data Structures - Key structs and relationships
|
||||||
|
5. Core Functions - Main entry points and algorithms
|
||||||
|
6. Interfaces - How components communicate
|
||||||
|
7. Configuration - Config files and options
|
||||||
|
8. Testing - Test strategies and key files
|
||||||
|
9. Contributing - Development setup and PR process
|
||||||
|
|
||||||
|
Write in a technical, precise tone. Be specific and use code examples.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert technical writer specializing in codebase documentation.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_technical_manual(self, target_word_count: int) -> str:
|
||||||
|
"""Generate technical manual."""
|
||||||
|
source_summary = self.source_content[:10000] if self.source_content else "No source content provided"
|
||||||
|
|
||||||
|
prompt = f"""Generate a comprehensive TECHNICAL MANUAL.
|
||||||
|
|
||||||
|
FRAMEWORK: Technical Manual - From foundations to mastery
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
SOURCE CONTENT:
|
||||||
|
{source_summary}
|
||||||
|
|
||||||
|
Generate a technical manual with:
|
||||||
|
1. Introduction - Why this topic matters
|
||||||
|
2. Core Concepts - Essential background knowledge
|
||||||
|
3. Architecture - High-level system design
|
||||||
|
4. Getting Started - First steps for beginners
|
||||||
|
5. Deep Dive Sections - Detailed exploration of key topics
|
||||||
|
6. Practical Examples - Hands-on code examples
|
||||||
|
7. Best Practices - How experts do it
|
||||||
|
8. Troubleshooting - Common problems and solutions
|
||||||
|
9. Reference - API/command reference
|
||||||
|
|
||||||
|
Write in a professional, thorough, practical tone.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert technical writer specializing in technical manuals and educational content.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_diataxis_tutorial(self, target_word_count: int) -> str:
|
||||||
|
"""Generate Diátaxis tutorial."""
|
||||||
|
prompt = f"""Generate a DIÁTEXIS TUTORIAL.
|
||||||
|
|
||||||
|
FRAMEWORK: Tutorial - Learn by doing a concrete project
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
Generate a tutorial that leads the learner through a complete project:
|
||||||
|
1. Introduction - What will we build and why?
|
||||||
|
2. Prerequisites - What do you need before starting?
|
||||||
|
3. Step 1: Setup - Getting the environment ready
|
||||||
|
4. Step 2: First Steps - Your initial actions
|
||||||
|
5. Step 3: Building - Creating something concrete
|
||||||
|
6. Step 4: Enhancement - Adding features
|
||||||
|
7. Step 5: Completion - Finishing the project
|
||||||
|
8. Summary - What you learned
|
||||||
|
9. Next Steps - Where to go from here
|
||||||
|
|
||||||
|
Write in an encouraging, clear, patient tone.
|
||||||
|
Use numbered steps. Make it achievable for beginners.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert technical educator specializing in tutorials.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_diataxis_howto(self, target_word_count: int) -> str:
|
||||||
|
"""Generate Diátaxis how-to guide."""
|
||||||
|
prompt = f"""Generate a DIÁTEXIS HOW-TO GUIDE.
|
||||||
|
|
||||||
|
FRAMEWORK: How-To Guide - Accomplish a specific task
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
Generate a practical how-to guide:
|
||||||
|
1. Goal Statement - What problem does this solve?
|
||||||
|
2. Prerequisites - What's needed?
|
||||||
|
3. Step 1 - First action
|
||||||
|
4. Step 2 - Second action
|
||||||
|
5. Step N - Final step
|
||||||
|
6. Troubleshooting - Common issues
|
||||||
|
7. Related Tasks - See also
|
||||||
|
|
||||||
|
Write in a direct, authoritative tone. No fluff.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert technical writer specializing in how-to guides.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_diataxis_explanation(self, target_word_count: int) -> str:
|
||||||
|
"""Generate Diátaxis explanation."""
|
||||||
|
prompt = f"""Generate a DIÁTEXIS EXPLANATION.
|
||||||
|
|
||||||
|
FRAMEWORK: Explanation - Clarify and deepen understanding
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
Generate an explanatory document:
|
||||||
|
1. Overview - What are we exploring?
|
||||||
|
2. Background - What do you need to know first?
|
||||||
|
3. Core Concepts - The key ideas
|
||||||
|
4. How It Works - Under the hood
|
||||||
|
5. Different Approaches - Alternative perspectives
|
||||||
|
6. Why It Matters - Significance
|
||||||
|
7. Common Misconceptions - What people get wrong
|
||||||
|
8. Further Reading - Deepen knowledge
|
||||||
|
|
||||||
|
Write in a thoughtful, explanatory tone. Build mental models.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert educator specializing in explanatory writing.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_diataxis_reference(self, target_word_count: int) -> str:
|
||||||
|
"""Generate Diátaxis reference."""
|
||||||
|
prompt = f"""Generate DIÁTEXIS REFERENCE documentation.
|
||||||
|
|
||||||
|
FRAMEWORK: Reference - Accurate, complete information lookup
|
||||||
|
|
||||||
|
TOPIC: {self.topic}
|
||||||
|
|
||||||
|
Generate reference documentation:
|
||||||
|
1. Overview - What is this?
|
||||||
|
2. Syntax - How to use it
|
||||||
|
3. Parameters - What it accepts
|
||||||
|
4. Returns - What it produces
|
||||||
|
5. Examples - Usage patterns
|
||||||
|
6. Errors - What can go wrong
|
||||||
|
7. Notes - Important details
|
||||||
|
8. See Also - Related topics
|
||||||
|
|
||||||
|
Write in a precise, technical, complete tone.
|
||||||
|
Target approximately {target_word_count} words.
|
||||||
|
"""
|
||||||
|
return self.llm.complete(
|
||||||
|
system_prompt="You are an expert technical writer specializing in reference documentation.",
|
||||||
|
user_prompt=prompt,
|
||||||
|
temperature=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nonfiction_generator(
|
||||||
|
framework: NonfictionFramework = NonfictionFramework.TECHNICAL_MANUAL,
|
||||||
|
topic: str = "",
|
||||||
|
source_content: str = "",
|
||||||
|
) -> NonfictionGenerator:
|
||||||
|
"""Factory function to create a nonfiction generator."""
|
||||||
|
return NonfictionGenerator(
|
||||||
|
framework=framework,
|
||||||
|
topic=topic,
|
||||||
|
source_content=source_content,
|
||||||
|
)
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
"""LLM client for Opus Orchestrator.
|
"""LLM client for Opus Orchestrator.
|
||||||
|
|
||||||
Supports MiniMax and OpenAI providers.
|
Supports MiniMax and OpenAI providers - both async and sync.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
class LLMClient:
|
class LLMClient:
|
||||||
"""Simple LLM client for making API calls."""
|
"""Simple LLM client for making API calls - supports both sync and async."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -26,7 +28,6 @@ class LLMClient:
|
|||||||
|
|
||||||
# Normalize model name for MiniMax
|
# Normalize model name for MiniMax
|
||||||
if provider == "minimax":
|
if provider == "minimax":
|
||||||
# MiniMax uses model names like "abab6.5s-chat" or "MiniMax-M2.1"
|
|
||||||
self.minimax_model = model.split("/")[-1] if "/" in model else model
|
self.minimax_model = model.split("/")[-1] if "/" in model else model
|
||||||
|
|
||||||
# Set base URL based on provider
|
# Set base URL based on provider
|
||||||
@@ -39,27 +40,52 @@ class LLMClient:
|
|||||||
else:
|
else:
|
||||||
self.base_url = "https://api.openai.com/v1"
|
self.base_url = "https://api.openai.com/v1"
|
||||||
|
|
||||||
self.client = httpx.AsyncClient(timeout=120.0)
|
# Async client
|
||||||
|
self._async_client = httpx.AsyncClient(timeout=120.0)
|
||||||
|
|
||||||
async def complete(
|
def complete(
|
||||||
self,
|
self,
|
||||||
system_prompt: str,
|
system_prompt: str,
|
||||||
user_prompt: str,
|
user_prompt: str,
|
||||||
temperature: float = 0.7,
|
temperature: float = 0.7,
|
||||||
max_tokens: Optional[int] = None,
|
max_tokens: Optional[int] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Make a completion request."""
|
"""Make a completion request (SYNC - for LangGraph compatibility)."""
|
||||||
headers = {
|
headers = {
|
||||||
"Authorization": f"Bearer {self.api_key}",
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.provider == "minimax":
|
if self.provider == "minimax":
|
||||||
return await self._complete_minimax(
|
return self._complete_minimax_sync(
|
||||||
system_prompt, user_prompt, temperature, max_tokens, headers
|
system_prompt, user_prompt, temperature, max_tokens, headers
|
||||||
)
|
)
|
||||||
elif self.provider == "openai":
|
elif self.provider == "openai":
|
||||||
return await self._complete_openai(
|
return self._complete_openai_sync(
|
||||||
|
system_prompt, user_prompt, temperature, max_tokens, headers
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported provider: {self.provider}")
|
||||||
|
|
||||||
|
async def complete_async(
|
||||||
|
self,
|
||||||
|
system_prompt: str,
|
||||||
|
user_prompt: str,
|
||||||
|
temperature: float = 0.7,
|
||||||
|
max_tokens: Optional[int] = None,
|
||||||
|
) -> str:
|
||||||
|
"""Make a completion request (ASYNC)."""
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.provider == "minimax":
|
||||||
|
return await self._complete_minimax_async(
|
||||||
|
system_prompt, user_prompt, temperature, max_tokens, headers
|
||||||
|
)
|
||||||
|
elif self.provider == "openai":
|
||||||
|
return await self._complete_openai_async(
|
||||||
system_prompt, user_prompt, temperature, max_tokens, headers
|
system_prompt, user_prompt, temperature, max_tokens, headers
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -143,7 +169,85 @@ class LLMClient:
|
|||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
"""Close the HTTP client."""
|
"""Close the HTTP client."""
|
||||||
await self.client.aclose()
|
await self._async_client.aclose()
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# SYNC VERSIONS (for LangGraph compatibility)
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
def _complete_minimax_sync(
|
||||||
|
self,
|
||||||
|
system_prompt: str,
|
||||||
|
user_prompt: str,
|
||||||
|
temperature: float,
|
||||||
|
max_tokens: Optional[int],
|
||||||
|
headers: dict,
|
||||||
|
) -> str:
|
||||||
|
"""Call MiniMax API (sync)."""
|
||||||
|
payload = {
|
||||||
|
"model": self.minimax_model,
|
||||||
|
"messages": [
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_prompt},
|
||||||
|
],
|
||||||
|
"temperature": temperature,
|
||||||
|
}
|
||||||
|
|
||||||
|
if max_tokens:
|
||||||
|
payload["max_tokens"] = max_tokens
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{self.base_url}/text/chatcompletion_v2",
|
||||||
|
headers=headers,
|
||||||
|
json=payload,
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
print(f"MiniMax API error: {response.status_code}")
|
||||||
|
print(f"Response: {response.text[:500]}")
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
if "choices" in data:
|
||||||
|
return data["choices"][0]["message"]["content"]
|
||||||
|
elif "choices" in data.get("data", {}):
|
||||||
|
return data["data"]["choices"][0]["message"]["content"]
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unexpected MiniMax response: {data}")
|
||||||
|
|
||||||
|
def _complete_openai_sync(
|
||||||
|
self,
|
||||||
|
system_prompt: str,
|
||||||
|
user_prompt: str,
|
||||||
|
temperature: float,
|
||||||
|
max_tokens: Optional[int],
|
||||||
|
headers: dict,
|
||||||
|
) -> str:
|
||||||
|
"""Call OpenAI API (sync)."""
|
||||||
|
payload = {
|
||||||
|
"model": self.model,
|
||||||
|
"messages": [
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_prompt},
|
||||||
|
],
|
||||||
|
"temperature": temperature,
|
||||||
|
}
|
||||||
|
|
||||||
|
if max_tokens:
|
||||||
|
payload["max_tokens"] = max_tokens
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{self.base_url}/chat/completions",
|
||||||
|
headers=headers,
|
||||||
|
json=payload,
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
return data["choices"][0]["message"]["content"]
|
||||||
|
|
||||||
|
|
||||||
# Convenience function
|
# Convenience function
|
||||||
|
|||||||
Reference in New Issue
Block a user