forked from adamwlarson/ai-book-writer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathagents.py
254 lines (208 loc) · 10.4 KB
/
agents.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
"""Define the agents used in the book generation system with improved context management"""
import autogen
from typing import Dict, List, Optional
class BookAgents:
def __init__(self, agent_config: Dict, outline: Optional[List[Dict]] = None):
"""Initialize agents with book outline context"""
self.agent_config = agent_config
self.outline = outline
self.world_elements = {} # Track described locations/elements
self.character_developments = {} # Track character arcs
def _format_outline_context(self) -> str:
"""Format the book outline into a readable context"""
if not self.outline:
return ""
context_parts = ["Complete Book Outline:"]
for chapter in self.outline:
context_parts.extend([
f"\nChapter {chapter['chapter_number']}: {chapter['title']}",
chapter['prompt']
])
return "\n".join(context_parts)
def create_agents(self, initial_prompt, num_chapters) -> Dict:
"""Create and return all agents needed for book generation"""
outline_context = self._format_outline_context()
# Memory Keeper: Maintains story continuity and context
memory_keeper = autogen.AssistantAgent(
name="memory_keeper",
system_message=f"""You are the keeper of the story's continuity and context.
Your responsibilities:
1. Track and summarize each chapter's key events
2. Monitor character development and relationships
3. Maintain world-building consistency
4. Flag any continuity issues
Book Overview:
{outline_context}
Format your responses as follows:
- Start updates with 'MEMORY UPDATE:'
- List key events with 'EVENT:'
- List character developments with 'CHARACTER:'
- List world details with 'WORLD:'
- Flag issues with 'CONTINUITY ALERT:'""",
llm_config=self.agent_config,
)
# Story Planner - Focuses on high-level story structure
story_planner = autogen.AssistantAgent(
name="story_planner",
system_message=f"""You are an expert story arc planner focused on overall narrative structure.
Your sole responsibility is creating the high-level story arc.
When given an initial story premise:
1. Identify major plot points and story beats
2. Map character arcs and development
3. Note major story transitions
4. Plan narrative pacing
Format your output EXACTLY as:
STORY_ARC:
- Major Plot Points:
[List each major event that drives the story]
- Character Arcs:
[For each main character, describe their development path]
- Story Beats:
[List key emotional and narrative moments in sequence]
- Key Transitions:
[Describe major shifts in story direction or tone]
Always provide specific, detailed content - never use placeholders.""",
llm_config=self.agent_config,
)
# Outline Creator - Creates detailed chapter outlines
outline_creator = autogen.AssistantAgent(
name="outline_creator",
system_message=f"""Generate a detailed {num_chapters}-chapter outline.
YOU MUST USE EXACTLY THIS FORMAT FOR EACH CHAPTER - NO DEVIATIONS:
Chapter 1: [Title]
Chapter Title: [Same title as above]
Key Events:
- [Event 1]
- [Event 2]
- [Event 3]
Character Developments: [Specific character moments and changes]
Setting: [Specific location and atmosphere]
Tone: [Specific emotional and narrative tone]
[REPEAT THIS EXACT FORMAT FOR ALL {num_chapters} CHAPTERS]
Requirements:
1. EVERY field must be present for EVERY chapter
2. EVERY chapter must have AT LEAST 3 specific Key Events
3. ALL chapters must be detailed - no placeholders
4. Format must match EXACTLY - including all headings and bullet points
Initial Premise:
{initial_prompt}
START WITH 'OUTLINE:' AND END WITH 'END OF OUTLINE'
""",
llm_config=self.agent_config,
)
# World Builder: Creates and maintains the story setting
world_builder = autogen.AssistantAgent(
name="world_builder",
system_message=f"""You are an expert in world-building who creates rich, consistent settings.
Your role is to establish ALL settings and locations needed for the entire story based on a provided story arc.
Book Overview:
{outline_context}
Your responsibilities:
1. Review the story arc to identify every location and setting needed
2. Create detailed descriptions for each setting, including:
- Physical layout and appearance
- Atmosphere and environmental details
- Important objects or features
- Sensory details (sights, sounds, smells)
3. Identify recurring locations that appear multiple times
4. Note how settings might change over time
5. Create a cohesive world that supports the story's themes
Format your response as:
WORLD_ELEMENTS:
[LOCATION NAME]:
- Physical Description: [detailed description]
- Atmosphere: [mood, time of day, lighting, etc.]
- Key Features: [important objects, layout elements]
- Sensory Details: [what characters would experience]
[RECURRING ELEMENTS]:
- List any settings that appear multiple times
- Note any changes to settings over time
[TRANSITIONS]:
- How settings connect to each other
- How characters move between locations""",
llm_config=self.agent_config,
)
# Writer: Generates the actual prose
writer = autogen.AssistantAgent(
name="writer",
system_message=f"""You are an expert creative writer who brings scenes to life.
Book Context:
{outline_context}
Your focus:
1. Write according to the outlined plot points
2. Maintain consistent character voices
3. Incorporate world-building details
4. Create engaging prose
5. Please make sure that you write the complete scene, do not leave it incomplete
6. Each chapter MUST be at least 5000 words (approximately 30,000 characters). Consider this a hard requirement. If your output is shorter, continue writing until you reach this minimum length
7. Ensure transitions are smooth and logical
8. Do not cut off the scene, make sure it has a proper ending
9. Add a lot of details, and describe the environment and characters where it makes sense
Always reference the outline and previous content.
Mark drafts with 'SCENE:' and final versions with 'SCENE FINAL:'""",
llm_config=self.agent_config,
)
# Editor: Reviews and improves content
editor = autogen.AssistantAgent(
name="editor",
system_message=f"""You are an expert editor ensuring quality and consistency.
Book Overview:
{outline_context}
Your focus:
1. Check alignment with outline
2. Verify character consistency
3. Maintain world-building rules
4. Improve prose quality
5. Return complete edited chapter
6. Never ask to start the next chapter, as the next step is finalizing this chapter
7. Each chapter MUST be at least 5000 words. If the content is shorter, return it to the writer for expansion. This is a hard requirement - do not approve chapters shorter than 5000 words
Format your responses:
1. Start critiques with 'FEEDBACK:'
2. Provide suggestions with 'SUGGEST:'
3. Return full edited chapter with 'EDITED_SCENE:'
Reference specific outline elements in your feedback.""",
llm_config=self.agent_config,
)
# User Proxy: Manages the interaction
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
human_input_mode="TERMINATE",
code_execution_config={
"work_dir": "book_output",
"use_docker": False
}
)
return {
"story_planner": story_planner,
"world_builder": world_builder,
"memory_keeper": memory_keeper,
"writer": writer,
"editor": editor,
"user_proxy": user_proxy,
"outline_creator": outline_creator
}
def update_world_element(self, element_name: str, description: str) -> None:
"""Track a new or updated world element"""
self.world_elements[element_name] = description
def update_character_development(self, character_name: str, development: str) -> None:
"""Track character development"""
if character_name not in self.character_developments:
self.character_developments[character_name] = []
self.character_developments[character_name].append(development)
def get_world_context(self) -> str:
"""Get formatted world-building context"""
if not self.world_elements:
return "No established world elements yet."
return "\n".join([
"Established World Elements:",
*[f"- {name}: {desc}" for name, desc in self.world_elements.items()]
])
def get_character_context(self) -> str:
"""Get formatted character development context"""
if not self.character_developments:
return "No character developments tracked yet."
return "\n".join([
"Character Development History:",
*[f"- {name}:\n " + "\n ".join(devs)
for name, devs in self.character_developments.items()]
])