Feats: Works mostly end to end and now prints full paper content as first step in the paper_review stage

This commit is contained in:
2025-12-09 18:26:04 -05:00
parent 666b70f9be
commit d9d00dc7bd
2 changed files with 59 additions and 118 deletions
+59 -102
View File
@@ -1079,9 +1079,14 @@ agents:
- Work with the user to refine the content based on their feedback
- If the user asks for changes, make them and present the revised content
IMPORTANT: When the user is satisfied with the section content, tell them to type !proofread to proceed to proofreading.
RESPONSE FORMAT (MANDATORY):
SECTION_CONTENT:
<final section text>
Example ending: "Let me know if you'd like any changes. When you're satisfied, type !proofread to proceed to proofreading."
NEXT_ACTION:
Type !proofread when you are satisfied with this section.
Do NOT include any other commentary, explanations, or conversational text. The SECTION_CONTENT block must contain only the section prose that will be stored in the paper.
section_writer_saver:
type: tool
@@ -1092,9 +1097,20 @@ agents:
path = context.get('current_section_path', 'unknown')
# Only save actual content, not routing commands
if input_data and not input_data.startswith('GOTO_'):
context.setdefault('section_content', {})[path] = input_data
context.setdefault('section_drafts', {})[path] = input_data
context['last_written_section_content'] = input_data
text = input_data.strip()
section_text = text
marker = 'SECTION_CONTENT:'
if marker in text:
remainder = text.split(marker, 1)[1]
next_marker = 'NEXT_ACTION:'
if next_marker in remainder:
section_text = remainder.split(next_marker, 1)[0].strip()
else:
section_text = remainder.strip()
if section_text:
context.setdefault('section_content', {})[path] = section_text
context.setdefault('section_drafts', {})[path] = section_text
context['last_written_section_content'] = section_text
result = input_data
section_accept_handler:
@@ -1191,95 +1207,26 @@ agents:
import sys
print(f"DEBUG paper_review_controller", file=sys.stderr)
def looks_like_feedback(text: str) -> bool:
if not isinstance(text, str):
return False
lowered = text.lower()
markers = [
"proofread",
"proofreading",
"grammatical errors",
"type !accept",
"command_output:",
"review feedback",
]
return any(marker in lowered for marker in markers)
history_messages = None
for key in ("__messages", "history", "conversation_history", "messages"):
value = context.get(key)
if isinstance(value, list):
history_messages = value
break
if history_messages is None:
graph_state = context.get('graph_state', {})
if isinstance(graph_state, dict):
msgs = graph_state.get('messages')
if isinstance(msgs, list):
history_messages = msgs
if history_messages is None:
history_messages = []
writer_history = {}
current_section = None
pending_writer_output = False
for message in history_messages:
if not isinstance(message, dict):
continue
role = (message.get('role') or '').lower()
content = message.get('content')
if not isinstance(content, str):
continue
stripped = content.strip()
if role == 'assistant':
if stripped.lower().startswith('now working on section:'):
section_name = stripped.split(':', 1)[1].strip()
if section_name:
section_name = section_name.splitlines()[0].strip()
current_section = section_name or current_section
pending_writer_output = False
elif pending_writer_output and current_section:
writer_history[current_section] = content
pending_writer_output = False
elif role == 'user':
if stripped.lower().startswith('!write'):
pending_writer_output = True
else:
pending_writer_output = False
section_content = context.get('section_content', {})
if not section_content:
result = "ERROR: No sections found. Please complete section writing stage first."
else:
section_drafts = context.get('section_drafts', {})
# Build full paper text
paper_topic = context.get('paper_details', {}).get('topic', 'Scientific Paper')
full_text = f"# {paper_topic}\n\n"
# Add sections in order, repairing content when necessary
section_paths = context.get('section_paths', [])
for path in section_paths:
text = section_content.get(path)
if not text:
replacement = section_drafts.get(path) or writer_history.get(path)
if replacement:
section_content[path] = replacement
text = replacement
elif looks_like_feedback(text):
replacement = section_drafts.get(path) or writer_history.get(path)
if replacement:
section_content[path] = replacement
text = replacement
if text:
full_text += f"## {path}\n\n{text}\n\n"
if isinstance(text, str) and text.strip():
full_text += f"## {path}\n\n{text.strip()}\n\n"
context['assembled_paper'] = full_text
assembled = full_text.strip()
context['assembled_paper'] = assembled
# Display the complete paper to the user before invoking the reviewer LLM
preview_header = "# Full Paper\n"
preview_body = full_text.strip()
preview_output = f"{preview_header}\n{preview_body}" if preview_body else preview_header
preview_output = (
f"# Full Paper\n\n{assembled}" if assembled else "# Full Paper\n\n(No content available.)"
)
print(preview_output, flush=True)
instruction = (
@@ -1298,28 +1245,27 @@ agents:
max_history: 20
system_prompt: |
You are reviewing the complete assembled paper.
Here is the full paper content:
{{ context.get('assembled_paper', '') }}
Here is the full paper content:
{{ context.get('assembled_paper', '') }}
The system already displayed the full paper verbatim before your turn.
DO NOT repeat or summarize the paper content. Focus solely on analysis.
Structure your response under a single top-level heading "Review Feedback" with clear bullets or subheadings.
When providing feedback, review the paper for:
- Consistency and logical flow between sections
- Grammar, spelling, and style
- Proper citation format and usage
- Logical coherence and argument strength
- Transitions between sections
Provide specific, actionable feedback tied to the relevant sections. The user can:
- Discuss refinements to specific sections
- Make changes across the document
- Use !accept or !next when satisfied to proceed to LaTeX generation
When providing feedback, review the paper for:
- Consistency and logical flow between sections
- Grammar, spelling, and style
- Proper citation format and usage
- Logical coherence and argument strength
- Transitions between sections
Provide specific, actionable feedback tied to the relevant sections. The user can:
- Discuss refinements to specific sections
- Make changes across the document
- Use !accept or !next when satisfied to proceed to LaTeX generation
paper_review_saver:
type: tool
@@ -1330,6 +1276,7 @@ agents:
context['reviewed_paper'] = input_data
result = input_data
# ============================================
# LATEX GENERATION STAGE
# ============================================
@@ -1699,10 +1646,11 @@ routes:
target: paper_review
extract_message: true
separator: ":"
- match_type: prefix
pattern: "GOTO_LATEX_GENERATION"
target: latex_generation
extract_message: true
separator: ":"
@@ -1985,18 +1933,19 @@ routes:
paper_review:
type: AGENT
agent: paper_review_controller
paper_review_agent:
type: AGENT
agent: paper_review_agent
metadata:
max_history_messages: 10
max_history_chars: 6000
paper_review_saver:
type: AGENT
agent: paper_review_saver
latex_generation:
type: AGENT
agent: latex_controller
@@ -2208,6 +2157,13 @@ routes:
value: section_accept_handler
# Paper review sub-routing
- source: router
target: paper_review
condition:
type: context_value
key: next_node
value: paper_review
- source: router
target: paper_review_agent
condition:
@@ -2215,6 +2171,7 @@ routes:
key: next_node
value: paper_review_agent
# LaTeX generation sub-routing
- source: router
target: latex_structure_gen
-16
View File
@@ -141,9 +141,6 @@ def run(
context_manager = ContextManager(context, context_dir)
context_manager.import_context(load_context)
if app.config:
app.config.global_context["__messages"] = list(context_manager.messages)
# Restore the global context to the app
saved_global_context = context_manager.get_global_context()
if saved_global_context and app.config:
@@ -173,11 +170,6 @@ def run(
with open(load_context, "r", encoding="utf-8") as f:
context_data = json.load(f)
if app.config:
app.config.global_context["__messages"] = list(
context_data.get("messages", [])
)
# Apply global context to app if present
if context_data.get("global_context") and app.config:
app.config.global_context.update(context_data["global_context"])
@@ -189,9 +181,6 @@ def run(
# Use named context (existing behavior)
context_manager = ContextManager(context, context_dir)
if app.config:
app.config.global_context["__messages"] = list(context_manager.messages)
# If context exists, restore the global context to the app
if context_manager.exists():
saved_global_context = context_manager.get_global_context()
@@ -312,11 +301,6 @@ def interactive(
# Import the context from file
temp_ctx_manager.import_context(load_context)
if app.config:
app.config.global_context["__messages"] = list(
temp_ctx_manager.messages
)
# Apply global context to app if present
saved_global_context = temp_ctx_manager.get_global_context()
if saved_global_context and app.config: