Skip to content

Commit 3f61c7f

Browse files
Implement bug fixes, and style changes
1 parent 3709034 commit 3f61c7f

File tree

8 files changed

+121
-67
lines changed

8 files changed

+121
-67
lines changed

docker/worker.dockerfile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ RUN poetry config virtualenvs.create false && poetry install --no-root --no-inte
2626
# Copy application code
2727
COPY mxgo ./mxgo
2828

29-
# Copy test code into the container
30-
COPY ./tests /app/tests
31-
3229
# Create directories
3330
RUN mkdir -p /app/attachments
3431

mxgo/api.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
send_email_reply,
2626
)
2727
from mxgo.models import TaskStatus
28+
from mxgo.prompts.template_prompts import NEWSLETTER_TEMPLATE
2829
from mxgo.reply_generation import generate_replies
2930
from mxgo.scheduling.scheduled_task_executor import execute_scheduled_task
3031
from mxgo.scheduling.scheduler import Scheduler, is_one_time_task
@@ -880,17 +881,34 @@ async def generate_email_replies(
880881

881882
# Helper functions for create_newsletter
882883
def _build_newsletter_instructions(request: CreateNewsletterRequest) -> str:
883-
"""Builds the full instruction string from the request."""
884-
full_instructions = [f"PROMPT: {request.prompt}"]
884+
"""Builds the full instruction string from the request using the NEWSLETTER template."""
885+
user_instructions = []
885886
if request.estimated_read_time:
886-
full_instructions.append(f"ESTIMATED READ TIME: {request.estimated_read_time} minutes")
887+
user_instructions.append(
888+
f"- **Target Read Time**: The newsletter should be concise enough to be read in approximately {request.estimated_read_time} minutes."
889+
)
887890
if request.sources:
888-
full_instructions.append(f"SOURCES: {', '.join(request.sources)}")
891+
user_instructions.append(
892+
f"- **Prioritize Sources**: When researching, give priority to information from the following sources: {', '.join(request.sources)}."
893+
)
889894
if request.geographic_locations:
890-
full_instructions.append(f"GEOGRAPHIC FOCUS: {', '.join(request.geographic_locations)}")
895+
user_instructions.append(
896+
f"- **Geographic Focus**: The content should be primarily relevant to the following locations: {', '.join(request.geographic_locations)}."
897+
)
891898
if request.formatting_instructions:
892-
full_instructions.append(f"FORMATTING INSTRUCTIONS: {request.formatting_instructions}")
893-
return "\n\n".join(full_instructions)
899+
user_instructions.append(
900+
f"- **Formatting Rules**: Strictly follow these formatting instructions: {request.formatting_instructions}."
901+
)
902+
903+
if user_instructions:
904+
user_instructions_section = "\n".join(user_instructions)
905+
else:
906+
user_instructions_section = (
907+
"No specific user instructions were provided. Use your best judgment to create a high-quality newsletter."
908+
)
909+
910+
# This becomes the detailed, distilled instructions for the agent.
911+
return NEWSLETTER_TEMPLATE.format(prompt=request.prompt, user_instructions_section=user_instructions_section)
894912

895913

896914
async def _validate_newsletter_limits(user_email: str, cron_expressions: list[str]):
@@ -953,7 +971,16 @@ def _create_and_schedule_task(user_email: str, cron_expr: str, distilled_instruc
953971
)
954972

955973
scheduler = Scheduler()
956-
scheduler.add_job(job_id=scheduler_job_id, cron_expression=cron_expr, func=execute_scheduled_task, args=[task_id])
974+
try:
975+
scheduler.add_job(
976+
job_id=scheduler_job_id, cron_expression=cron_expr, func=execute_scheduled_task, args=[task_id]
977+
)
978+
except Exception as e:
979+
logger.error(f"Failed to schedule task {task_id}: {e}")
980+
981+
with db_connection.get_session() as session:
982+
crud.delete_task(session, task_id)
983+
raise
957984

958985
with db_connection.get_session() as session:
959986
crud.update_task_status(session, task_id, TaskStatus.ACTIVE)
@@ -980,10 +1007,10 @@ async def _handle_post_creation_action(
9801007
distilled_processing_instructions=distilled_instructions,
9811008
distilled_alias=HandlerAlias.ASK,
9821009
messageId=f"<newsletter-sample-{first_task_id}-{datetime.now(timezone.utc).isoformat()}@mxgo.ai>",
983-
parent_message_id=f"<newsletter-parent-{first_task_id}@mxgo.ai>",
1010+
parent_message_id=f"<newsletter-parent-{first_task_id}@mx go.ai>",
9841011
)
9851012
process_email_task.send(
986-
sample_email_request.model_dump(),
1013+
sample_email_request.model_dump(by_alias=True),
9871014
email_attachments_dir="",
9881015
attachment_info=[],
9891016
scheduled_task_id=first_task_id,
@@ -1018,17 +1045,14 @@ async def create_newsletter(
10181045
f"Duplicate request_id {request.request_id} detected for {user_email}, returning existing tasks from Redis"
10191046
)
10201047
existing_task_ids = json.loads(existing_task_ids_json)
1021-
return Response(
1022-
content=json.dumps(
1023-
{
1024-
"message": "This request has already been processed.",
1025-
"status": "duplicate",
1026-
"request_id": request.request_id,
1027-
"scheduled_task_ids": existing_task_ids,
1028-
}
1029-
),
1048+
raise HTTPException(
10301049
status_code=status.HTTP_409_CONFLICT,
1031-
media_type="application/json",
1050+
detail={
1051+
"message": "This request has already been processed.",
1052+
"status": "duplicate",
1053+
"request_id": request.request_id,
1054+
"scheduled_task_ids": existing_task_ids,
1055+
},
10321056
)
10331057

10341058
distilled_instructions = _build_newsletter_instructions(request)
@@ -1064,7 +1088,10 @@ async def create_newsletter(
10641088
except Exception as scheduler_e:
10651089
logger.error(f"Failed to remove scheduler job for task {tid}: {scheduler_e}")
10661090

1067-
raise HTTPException(status_code=500, detail="Failed to schedule one or more newsletter tasks.") from e
1091+
raise HTTPException(
1092+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
1093+
detail="Failed to schedule one or more newsletter tasks.",
1094+
) from e
10681095

10691096
sample_email_sent = False
10701097
if created_task_ids:

mxgo/config.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,35 @@
5858
},
5959
},
6060
}
61+
62+
# System capabilities - extracted from email handles and their templates
63+
SYSTEM_CAPABILITIES = """## Available Email Processing Handles
64+
65+
- **summarize**: Systematically analyze and summarize content from all sources with clear structure and action focus. Processes email content, attachments, and external references to provide executive summaries, main points, action items, and additional context.
66+
67+
- **research**: Conduct comprehensive research and provide detailed analysis with proper sections and citations. Uses deep research tools to gather current information, analyze findings, and provide supporting evidence with academic tone.
68+
69+
- **simplify**: Transform complex content into clear, accessible explanations using simple language and relatable examples. Breaks down technical jargon, adds helpful analogies, and makes content understandable to general audiences.
70+
71+
- **ask**: Execute custom tasks and workflows systematically with research, analysis, and professional presentation. Handles any custom request, research needs, content creation, and provides comprehensive solutions with proper formatting.
72+
73+
- **fact-check**: Systematically verify claims and statements with comprehensive source validation and transparent uncertainty handling. Extracts all verifiable claims, searches for evidence, cross-references multiple sources, and provides clear verification status.
74+
75+
- **background-research**: Conduct comprehensive business intelligence research on individuals and organizations. Provides strategic insights for business decisions, company analysis, professional profiles, and competitive context.
76+
77+
- **translate**: Provide accurate translations with cultural context preservation and clear explanation of translation decisions. Detects source language, chooses appropriate translation approach, and provides cultural adaptations.
78+
79+
- **meeting**: Intelligently extract, research, and schedule meetings or appointments with proper validation. Handles participant research, time resolution, and generates calendar invitations with comprehensive meeting details.
80+
81+
- **pdf**: Intelligently analyze email content and create professional PDF document exports. Removes email metadata, preserves content structure, and generates clean, formatted documents for sharing or archiving.
82+
83+
- **schedule**: Analyze email content to extract scheduling requirements for future or recurring task processing. Creates appropriate cron expressions for reminders, recurring tasks, and future email processing.
84+
85+
- **delete**: Analyze email content to identify and delete scheduled tasks. Handles task ID extraction and provides clear confirmation of task removal.
86+
87+
- **news**: Search for current news and breaking stories with comprehensive analysis and grouping. Provides structured news summaries with source citations, grouped by themes to avoid repetition.
88+
"""
89+
6190
RATE_LIMIT_PER_DOMAIN_HOUR = { # Consistent structure for domain limits
6291
"hour": {"limit": 50, "period_seconds": 3600, "expiry_seconds": 3600 * 2}
6392
}

mxgo/instruction_resolver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def register_handles(self, instructions_list: list[ProcessingInstructions], *, o
4848
for name in all_names:
4949
if name in self.handle_map and not overwrite:
5050
msg = f"Handle or alias '{name}' already registered. Use `overwrite=True` to replace."
51-
raise exceptions.HandleAlreadyExistsException(msg)
51+
raise exceptions.HandleAlreadyExistsError(msg)
5252
self.handle_map[name] = instructions
5353

5454
def add_custom_handle(self, custom_instruction: ProcessingInstructions, *, overwrite: bool = False):

mxgo/prompts/template_prompts.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
Template prompts for different email processing handlers.
33
"""
44

5+
from mxgo.config import SYSTEM_CAPABILITIES
6+
57
# Summarize email handler template
68
SUMMARIZE_TEMPLATE = """
79
Systematically analyze and summarize content from all available sources with clear structure and action focus.
@@ -1108,7 +1110,7 @@
11081110
"""
11091111

11101112
# Future handler template
1111-
FUTURE_TEMPLATE = """
1113+
FUTURE_TEMPLATE = f"""
11121114
Analyze email content to extract scheduling requirements for future or recurring task processing and create appropriate cron expressions.
11131115
11141116
# Future Task Scheduling Process
@@ -1177,14 +1179,8 @@
11771179
- **distilled_future_task_instructions**: Clear, detailed instructions about how the task should be processed when executed in the future. This should include the processing approach, any specific requirements, and what the expected outcome should be. **CRITICAL: If the original email contains attachments, you MUST include detailed context about the attachments in these instructions since attachments will not be available during scheduled execution. Include attachment names, types, sizes, and any relevant content or context from the attachments.**
11781180
- **start_time**: (Optional) Start time for the task in ISO 8601 format - task will not execute before this time (e.g., "2024-09-01T00:00:00Z")
11791181
- **end_time**: (Optional) End time for the task in ISO 8601 format - task will not execute after this time (e.g., "2024-12-31T23:59:59Z")
1180-
- **future_handle_alias**: The specific email handle to use for the future task. Select one of the following based on the user's instructions:
1181-
- **`ask`**: (Default) For general questions, custom tasks, or when no other handle fits.
1182-
- **`news`**: For fetching the latest news on a specific topic (e.g., "send me the news on AI every Friday").
1183-
- **`research`**: For conducting in-depth research on a topic at a later time.
1184-
- **`summarize`**: For summarizing the content of the email at a future date.
1185-
- **`fact-check`**: For verifying claims in the email content later.
1186-
- **`simplify`**: For explaining the content of the email in simple terms at a scheduled time.
1187-
- **`translate`**: For translating the email content at a future time.
1182+
- **future_handle_alias**: The specific email handle to use for the future task. Select one of the available email processing handles based on the user's instructions:
1183+
{SYSTEM_CAPABILITIES}
11881184
11891185
**Response (Successful Scheduling):**
11901186
1. Confirmation message with:
@@ -1441,7 +1437,7 @@
14411437
3. **Detailed processing instructions** - create comprehensive distilled_future_task_instructions
14421438
4. **User-friendly confirmation** - explain what was scheduled and when it will happen
14431439
5. **Error handling** - validate timing requests and provide alternatives if invalid
1444-
"""
1440+
""" # noqa: S608
14451441

14461442
# Delete handler template
14471443
DELETE_TEMPLATE = """
@@ -1835,3 +1831,34 @@
18351831
- Focus on **actionable insights** and current developments
18361832
- Maintain **professional news analysis** tone
18371833
"""
1834+
1835+
NEWSLETTER_TEMPLATE = """
1836+
## Primary Goal: Generate a high-quality, engaging, and well-researched newsletter.
1837+
1838+
## STEP 1: Deconstruct the Request & Plan the Outline
1839+
- **Analyze the Core Topic**: Identify the central theme from the user's prompt: **"{prompt}"**.
1840+
- **Review Specific Instructions**: Carefully read all user-provided instructions below regarding sources, formatting, and geographic focus.
1841+
- **Create a Research Outline**: Based on the topic, generate a logical 3-5 section outline for the newsletter. This will be your plan for research. The outline should be more than just keywords; it should represent the narrative flow of the newsletter.
1842+
1843+
## STEP 2: Conduct Comprehensive Research (Per Section)
1844+
- For EACH section in your outline, use the `web_search` tool to gather detailed, current, and authoritative information.
1845+
- **Prioritize Sources**: If the user has specified sources, you MUST prioritize them in your search.
1846+
- **Data & Evidence**: Focus on finding specific data, statistics, expert quotes, and verifiable facts. Avoid vague generalizations.
1847+
1848+
## STEP 3: Synthesize and Draft the Newsletter
1849+
- **Introduction**: Write a compelling opening that introduces the topic and hooks the reader.
1850+
- **Body**: Draft each section from your outline, synthesizing the research findings into a coherent narrative. Do not simply list facts. Weave them together to tell a story or build an argument.
1851+
- **Conclusion**: Write a concise summary or a forward-looking statement to conclude the newsletter.
1852+
- **Adhere to User Instructions**: Ensure the draft meets all specific user instructions.
1853+
1854+
## STEP 4: Final Review and Formatting
1855+
- **Apply Markdown**: Format the entire newsletter using professional Markdown, including headings (`###`), bullet points, and bold/italic text for emphasis.
1856+
- **Check for Quality**: Review the draft for clarity, accuracy, and engagement. Ensure it directly addresses the user's core prompt.
1857+
- **Source Attribution**: The system will handle the final "References" section. You do not need to add manual citations in the text.
1858+
1859+
---
1860+
1861+
## Specific Instructions for This Newsletter
1862+
You MUST adhere to the following user-provided instructions:
1863+
{user_instructions_section}
1864+
"""

mxgo/schemas.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,9 @@ class ScheduleType(str, Enum):
503503

504504

505505
class RecurringWeekly(BaseModel):
506-
days: list[int] = Field(..., description="List of weekdays as integers (0=Sunday, 1=Monday, ..., 6=Saturday)")
506+
days: list[int] = Field(
507+
..., min_length=1, description="List of weekdays as integers (0=Sunday, 1=Monday, ..., 6=Saturday)"
508+
)
507509
time: str = Field(..., description="Time in HH:MM format, e.g., '09:30'")
508510

509511
@field_validator("days")
@@ -531,7 +533,7 @@ def validate_time(cls, v):
531533
class ScheduleOptions(BaseModel):
532534
type: ScheduleType
533535
specific_datetime: str | None = Field(
534-
None, description="List of ISO 8601 datetime string for a specific, non-recurring schedules."
536+
None, description="ISO 8601 datetime string for a specific, non-recurring schedule."
535537
)
536538
weekly_schedule: RecurringWeekly | None = Field(None, description="Configuration for a recurring weekly schedule.")
537539

mxgo/suggestions.py

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import TYPE_CHECKING
66

77
from mxgo._logging import get_logger
8+
from mxgo.config import SYSTEM_CAPABILITIES
89
from mxgo.email_handles import DEFAULT_EMAIL_HANDLES
910
from mxgo.routed_litellm_model import RoutedLiteLLMModel
1011
from mxgo.schemas import EmailSuggestionRequest, EmailSuggestionResponse, RiskAnalysisResponse, SuggestionDetail
@@ -18,34 +19,6 @@
1819
MIN_SUGGESTIONS = 3
1920
MAX_SUGGESTIONS = 7
2021

21-
# System capabilities - extracted from email handles and their templates
22-
SYSTEM_CAPABILITIES = """## Available Email Processing Handles
23-
24-
- **summarize**: Systematically analyze and summarize content from all sources with clear structure and action focus. Processes email content, attachments, and external references to provide executive summaries, main points, action items, and additional context.
25-
26-
- **research**: Conduct comprehensive research and provide detailed analysis with proper sections and citations. Uses deep research tools to gather current information, analyze findings, and provide supporting evidence with academic tone.
27-
28-
- **simplify**: Transform complex content into clear, accessible explanations using simple language and relatable examples. Breaks down technical jargon, adds helpful analogies, and makes content understandable to general audiences.
29-
30-
- **ask**: Execute custom tasks and workflows systematically with research, analysis, and professional presentation. Handles any custom request, research needs, content creation, and provides comprehensive solutions with proper formatting.
31-
32-
- **fact-check**: Systematically verify claims and statements with comprehensive source validation and transparent uncertainty handling. Extracts all verifiable claims, searches for evidence, cross-references multiple sources, and provides clear verification status.
33-
34-
- **background-research**: Conduct comprehensive business intelligence research on individuals and organizations. Provides strategic insights for business decisions, company analysis, professional profiles, and competitive context.
35-
36-
- **translate**: Provide accurate translations with cultural context preservation and clear explanation of translation decisions. Detects source language, chooses appropriate translation approach, and provides cultural adaptations.
37-
38-
- **meeting**: Intelligently extract, research, and schedule meetings or appointments with proper validation. Handles participant research, time resolution, and generates calendar invitations with comprehensive meeting details.
39-
40-
- **pdf**: Intelligently analyze email content and create professional PDF document exports. Removes email metadata, preserves content structure, and generates clean, formatted documents for sharing or archiving.
41-
42-
- **schedule**: Analyze email content to extract scheduling requirements for future or recurring task processing. Creates appropriate cron expressions for reminders, recurring tasks, and future email processing.
43-
44-
- **delete**: Analyze email content to identify and delete scheduled tasks. Handles task ID extraction and provides clear confirmation of task removal.
45-
46-
- **news**: Search for current news and breaking stories with comprehensive analysis and grouping. Provides structured news summaries with source citations, grouped by themes to avoid repetition.
47-
"""
48-
4922
SUGGESTION_INSTRUCTIONS = f"""## Email Analysis and Suggestion Guidelines
5023
5124
You are an intelligent email assistant that analyzes email content to provide a crisp overview and suggest appropriate processing handles.

mxgo/tools/scheduled_tasks_tool.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def _parse_and_validate_times(
175175
logger.warning(f"Could not parse start_time: {e}")
176176

177177
# Validate that start_time is before end_time if both are provided
178-
if parsed_start_time and parsed_end_time and parsed_start_time >= parsed_end_time:
178+
if parsed_start_time and parsed_end_time and parsed_start_time > parsed_end_time:
179179
return (
180180
None,
181181
None,
@@ -250,7 +250,6 @@ def forward(
250250

251251
try:
252252
# Resolve the handle alias before validation
253-
resolved_handle_alias = future_handle_alias
254253
if future_handle_alias:
255254
try:
256255
# Resolve the provided alias (e.g., 'remind') to its canonical handle (e.g., 'schedule')

0 commit comments

Comments
 (0)