rejig-ai Claude commited on
Commit
0c62277
Β·
1 Parent(s): 50cc7aa

Fix script generation artifact usage and datetime import issues

Browse files

- Fix UnboundLocalError in search_web_tool by removing redundant datetime import
- Fix script generator to handle both artifact key formats:
* Auto-detected: "search_results"
* Explicit artifacts: "search_results_xxxxx"
- Enables proper context passing from search results to video script generation
- Preserves orchestrator intelligence in artifact selection

πŸ€– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

agent_system/agents.py CHANGED
@@ -4,6 +4,7 @@ Agent definitions for the chat system.
4
  from agents import Agent, Runner, TResponseInputItem, WebSearchTool, RunConfig, ModelSettings, function_tool, RunContextWrapper
5
  from typing import AsyncGenerator, Tuple, Dict, List, Any, Optional
6
  from .auth import attempt_login, AuthState
 
7
  import os
8
  import sys
9
  import re
@@ -510,105 +511,159 @@ def get_season(month: int) -> str:
510
  return "Fall"
511
 
512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  # New function tools to replace broken agent.as_tool() calls
514
  @function_tool
515
  async def search_web_tool(
516
  context: RunContextWrapper[ConversationContext],
517
  query: str,
518
- search_type: str = "general",
519
- current_date_context: str = ""
520
  ) -> str:
521
- """
522
- Search the web for current information with temporal context.
523
- PRESERVES: All WebSearchTool functionality, model settings, citations.
524
-
525
- Args:
526
- query: Search query
527
- search_type: Type of search (general, news, financial, etc.)
528
- current_date_context: Current date/time information for temporal searches
529
 
530
- Returns:
531
- Formatted search results with sources
532
- """
533
  try:
534
- logger.info(f"=== SEARCH_WEB_TOOL CALLED ====")
535
- logger.info(f"Query: {query}")
536
- logger.info(f"Search type: {search_type}")
537
- logger.info(f"Date context provided: {bool(current_date_context)}")
538
- logger.info(f"Context type: {type(context)}")
539
 
540
- # Get current date if not provided
541
- if not current_date_context:
542
- from datetime import datetime
543
- now = datetime.now()
544
- current_date_context = f"Current date: {now.strftime('%B %d, %Y')} ({now.strftime('%A')})"
545
- logger.info(f"Generated date context: {current_date_context}")
546
 
547
- # Build temporally-aware search input
548
- search_input = f"""Search for: {query}
549
-
550
- IMPORTANT TEMPORAL CONTEXT:
551
- {current_date_context}
552
-
553
- When searching, prioritize recent and current information. If the query mentions relative time periods like "May", "this month", "recent", "latest", etc., interpret them relative to the current date above.
554
-
555
- For example:
556
- - "May" = May 2025 (current year)
557
- - "this month" = current month from date above
558
- - "recent report" = reports from 2024-2025, not older years
559
- - "latest news" = very recent information
560
-
561
- Focus on {search_type} information."""
562
 
563
- inputs = [{"role": "user", "content": search_input}]
 
 
 
 
 
 
564
 
565
- # Run the sophisticated websearch_agent (preserves WebSearchTool, model settings)
566
- logger.info(f"=== CALLING WEBSEARCH AGENT ====")
567
- logger.info(f"Websearch agent type: {type(websearch_agent)}")
568
- logger.info(f"Inputs: {inputs}")
569
 
570
- try:
571
- result = await Runner.run(websearch_agent, input=inputs)
572
- logger.info(f"βœ… Websearch agent succeeded")
573
- logger.info(f"Result type: {type(result)}")
574
- search_content = str(result.final_output)
575
- logger.info(f"Search content length: {len(search_content)}")
576
- except Exception as e:
577
- logger.error(f"❌ WEBSEARCH AGENT FAILED: {e}")
578
- logger.error(f"Exception type: {type(e)}")
579
- import traceback
580
- logger.error(f"Traceback: {traceback.format_exc()}")
581
- raise
582
 
583
- # CREATE NEW: Store search results as artifact
584
- from datetime import datetime
585
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
  artifact = Artifact(
587
  type=ArtifactType.SEARCH_RESULTS,
588
  content={
589
  "query": query,
590
- "search_type": search_type,
591
  "results": search_content,
 
592
  "timestamp": datetime.now().isoformat()
593
  },
594
  created_by="search_web_tool",
595
- metadata={"summary": f"Search results for '{query}'"}
596
  )
597
 
598
- # Add artifact to conversation context
599
  context.context.add_artifact(artifact)
600
-
601
  logger.info(f"Search results stored as artifact {artifact.id}")
602
 
603
- # Return enhanced response with artifact reference
604
  return f"""Search Results for "{query}":
605
 
606
  {search_content}
607
 
608
- [Results saved as artifact {artifact.id} for use in script generation]"""
609
 
610
  except Exception as e:
611
- logger.error(f"Search error: {e}", exc_info=True)
612
  return f"Search failed: {str(e)}"
613
 
614
 
@@ -807,10 +862,10 @@ def format_script_response(script_data: Dict[str, Any], artifact_id: str) -> str
807
 
808
  {script_text}
809
 
810
- Key points:
811
  {key_points_text}
812
 
813
- Sources:
814
  {sources_text}
815
 
816
  [Script saved as artifact {artifact_id}]"""
@@ -884,18 +939,18 @@ orchestrator_agent = Agent(
884
  instructions="""
885
  You are an intelligent orchestrator that plans and executes multi-step workflows.
886
 
887
- 🚨 MANDATORY FIRST STEP - GET DATE/TIME:
888
- Before doing ANYTHING else, you MUST IMMEDIATELY call get_current_datetime().
889
  DO NOT skip this step. DO NOT proceed without it.
890
- This is REQUIRED for:
891
- - Providing accurate greetings (Good morning/afternoon/evening, Happy weekend, etc.)
892
- - Understanding time-sensitive requests
893
- - Contextualizing any date/time references in conversations
894
- - Ensuring all responses are temporally appropriate
895
- - CRITICAL: Interpreting relative dates like "May", "this month", "recent" relative to the CURRENT date
896
 
897
  ⚠️ TEMPORAL INTERPRETATION RULE:
898
- When the user mentions relative time periods (like "May", "this quarter", "recent report"), you MUST interpret them relative to the CURRENT DATE from get_current_datetime(), NOT any old cached dates.
899
 
900
  Examples using current date context:
901
  - If current date is June 2025 and user says "May report" β†’ interpret as "May 2025"
@@ -986,8 +1041,8 @@ orchestrator_agent = Agent(
986
  TOOL USAGE EXAMPLES:
987
 
988
  1. "Create a video about today's weather in San Francisco"
989
- β†’ get_current_datetime() [get date_info]
990
- β†’ search_web_tool(query="today's weather San Francisco", current_date_context=date_info)
991
  β†’ create_or_modify_script(topic="weather in San Francisco", context_artifacts=[search_result_id])
992
  β†’ Present script for review before video creation
993
 
@@ -1017,8 +1072,8 @@ orchestrator_agent = Agent(
1017
  β†’ create_or_modify_script(topic="topic from context", context_artifacts=[relevant_artifact_id])
1018
 
1019
  9. User: "things to do this weekend in Maui"
1020
- β†’ get_current_datetime() [get date_info]
1021
- β†’ search_web_tool(query="things to do this weekend Maui June 2025", current_date_context=date_info)
1022
  β†’ Provide current events and activities for the specific weekend dates
1023
 
1024
  CRITICAL: Always use search_web_tool for location-based, time-sensitive queries like:
@@ -1028,41 +1083,46 @@ orchestrator_agent = Agent(
1028
  - "restaurants open today in [location]"
1029
  These require fresh, up-to-date information, not cached knowledge.
1030
 
1031
- TEMPORAL CONTEXT USAGE:
1032
- Always use the current date/time information from get_current_datetime for:
1033
- - Appropriate greetings based on time of day
1034
- - Weekend vs weekday context ("Happy Friday!", "Hope you're enjoying your weekend!")
1035
- - Seasonal references when relevant
1036
- - Time-sensitive content (news, events, deadlines)
1037
- - CRITICAL: Pass date context to search_web_tool for temporal searches
1038
 
1039
- TEMPORAL SEARCH REQUIREMENTS:
1040
- When calling search_web_tool, ALWAYS include the current_date_context parameter with the date/time information from get_current_datetime. This ensures searches for relative terms like "May", "this month", "recent", "latest" are interpreted correctly relative to the current date.
 
 
 
1041
 
1042
- Example: search_web_tool(query="May market report", current_date_context=date_info)
 
 
 
1043
 
1044
  REMEMBER THE WORKFLOW:
1045
- 1. FIRST: Call get_current_datetime() - NO EXCEPTIONS
1046
  2. SECOND: Check/handle authentication
1047
- 3. THIRD: Process the user's request using the FRESH date context from step 1
1048
 
1049
  CRITICAL WORKFLOW FOR TIME-SENSITIVE REQUESTS:
1050
  When user mentions relative dates (May, this month, recent, etc.):
1051
- 1. Call get_current_datetime() to get fresh date context
1052
- 2. Use that date context to properly interpret the user's relative time references
1053
- 3. Pass the correct interpreted query and current_date_context to search_web_tool
1054
  4. NEVER use old timestamps or cached date information
1055
 
1056
  For requests involving current data, always search first.
1057
  For creative content (jokes, poems), use the appropriate tools (tell_joke, write_poem).
1058
 
1059
- ⚠️ CRITICAL: Never provide greetings or responses without first getting the current date/time!
1060
  ⚠️ CRITICAL: Never interpret relative dates using old cached date information!
1061
  """,
1062
  handoffs=[], # Removed - using pure agents-as-tools pattern
1063
  tools=[
1064
- # Date/time information tool - should be called first for temporal context
1065
- get_current_datetime,
1066
 
1067
  # Authentication status checking tool - checks if user is authenticated
1068
  check_authentication_status,
@@ -1251,7 +1311,7 @@ async def handle_video_request(message):
1251
 
1252
  **{video_title}**
1253
 
1254
- Key points:
1255
  {key_points}
1256
 
1257
  You can view it here: {video_url}""",
 
4
  from agents import Agent, Runner, TResponseInputItem, WebSearchTool, RunConfig, ModelSettings, function_tool, RunContextWrapper
5
  from typing import AsyncGenerator, Tuple, Dict, List, Any, Optional
6
  from .auth import attempt_login, AuthState
7
+ from .user_store import get_user_profile
8
  import os
9
  import sys
10
  import re
 
511
  return "Fall"
512
 
513
 
514
+ @function_tool
515
+ async def get_personalized_temporal_context(
516
+ context: RunContextWrapper[ConversationContext]
517
+ ) -> Dict[str, Any]:
518
+ """Get current date/time with user's location and timezone."""
519
+ from datetime import datetime
520
+
521
+ # Get user info
522
+ auth_state = context.context.auth_state
523
+ user_location = "New York"
524
+ user_timezone = "America/New_York"
525
+ service_areas = []
526
+
527
+ if auth_state.is_authenticated and auth_state.user_profile:
528
+ location_data = auth_state.user_profile.get("location", {})
529
+ user_location = location_data.get("city", "New York")
530
+ user_timezone = location_data.get("timezone", "America/New_York")
531
+ service_areas = auth_state.user_profile.get("service_areas", [])
532
+
533
+ # Get current time in user's timezone
534
+ try:
535
+ from zoneinfo import ZoneInfo
536
+ now_user = datetime.now(ZoneInfo(user_timezone))
537
+ except ImportError:
538
+ now_user = datetime.now()
539
+
540
+ return {
541
+ "user_location": user_location,
542
+ "user_timezone": user_timezone,
543
+ "service_areas": service_areas,
544
+ "current_time": now_user.strftime('%A, %B %d, %Y at %I:%M %p'),
545
+ "time_of_day": get_time_of_day(now_user.hour),
546
+ "is_weekend": now_user.weekday() >= 5
547
+ }
548
+
549
+
550
+ def get_time_of_day(hour: int) -> str:
551
+ """Get time period based on hour."""
552
+ if 5 <= hour < 12:
553
+ return "morning"
554
+ elif 12 <= hour < 17:
555
+ return "afternoon"
556
+ elif 17 <= hour < 21:
557
+ return "evening"
558
+ else:
559
+ return "night"
560
+
561
+
562
  # New function tools to replace broken agent.as_tool() calls
563
  @function_tool
564
  async def search_web_tool(
565
  context: RunContextWrapper[ConversationContext],
566
  query: str,
567
+ search_type: str = "general"
 
568
  ) -> str:
569
+ """Search with user's location and time context."""
 
 
 
 
 
 
 
570
 
 
 
 
571
  try:
572
+ logger.info(f"=== PERSONALIZED SEARCH_WEB_TOOL CALLED ====")
573
+ logger.info(f"Query: '{query}'")
574
+ logger.info(f"Search type: '{search_type}'")
 
 
575
 
576
+ # Get user's personalized context directly
577
+ logger.info("Getting personalized temporal context...")
578
+ user_email = context.context.auth_state.user_email if context.context.auth_state.is_authenticated else None
579
+ user_profile = get_user_profile(user_email) if user_email else {}
 
 
580
 
581
+ # Build temporal context with user's timezone
582
+ current_time = datetime.now()
583
+ user_timezone = "UTC"
584
+ user_location = "Unknown"
 
 
 
 
 
 
 
 
 
 
 
585
 
586
+ if user_profile.get('location', {}).get('timezone'):
587
+ try:
588
+ tz = pytz.timezone(user_profile['location']['timezone'])
589
+ current_time = current_time.astimezone(tz)
590
+ user_timezone = user_profile['location']['timezone']
591
+ except:
592
+ pass # Fallback to system time if timezone is invalid
593
 
594
+ if user_profile.get('location'):
595
+ user_location = f"{user_profile['location']['city']}, {user_profile['location']['state']}"
 
 
596
 
597
+ current_time = current_time.strftime('%A, %B %d, %Y at %I:%M %p %Z')
 
 
 
 
 
 
 
 
 
 
 
598
 
599
+ logger.info(f"User context retrieved: {user_location} ({user_timezone}) at {current_time}")
 
600
 
601
+ # Create personalized websearch agent
602
+ logger.info("Creating personalized websearch agent...")
603
+ personalized_websearch_agent = Agent(
604
+ name="websearch_agent",
605
+ instructions=f"""
606
+ You are a context-aware web search specialist.
607
+
608
+ USER'S CONTEXT:
609
+ - Location: {user_location}
610
+ - Current Time: {current_time}
611
+ - Timezone: {user_timezone}
612
+
613
+ SMART LOCATION USAGE:
614
+ - If query is location-dependent ("weather", "restaurants", "events") and has no specified location β†’ add user's location
615
+ - If query specifies location ("weather in Paris") β†’ use that location
616
+ - If query is general knowledge ("how to code") β†’ don't add location
617
+
618
+ Examples:
619
+ - "weather" β†’ search "weather in {user_location}"
620
+ - "weather in London" β†’ search "weather in London"
621
+ - "restaurants" β†’ search "restaurants in {user_location}"
622
+ - "how to cook pasta" β†’ search "how to cook pasta"
623
+ """,
624
+ tools=[
625
+ WebSearchTool(
626
+ user_location={"type": "approximate", "city": user_location},
627
+ search_context_size="high"
628
+ )
629
+ ],
630
+ model_settings=ModelSettings(tool_choice="required", temperature=0.2)
631
+ )
632
+
633
+ # Execute search
634
+ logger.info("Executing search with personalized agent...")
635
+ result = await Runner.run(
636
+ personalized_websearch_agent,
637
+ input=[{"role": "user", "content": f"Search for: {query}"}]
638
+ )
639
+
640
+ search_content = str(result.final_output)
641
+ logger.info(f"Search completed, result length: {len(search_content)}")
642
+
643
+ # Store as artifact
644
  artifact = Artifact(
645
  type=ArtifactType.SEARCH_RESULTS,
646
  content={
647
  "query": query,
 
648
  "results": search_content,
649
+ "user_location": user_location,
650
  "timestamp": datetime.now().isoformat()
651
  },
652
  created_by="search_web_tool",
653
+ metadata={"summary": f"Search for '{query}' (from {user_location})"}
654
  )
655
 
 
656
  context.context.add_artifact(artifact)
 
657
  logger.info(f"Search results stored as artifact {artifact.id}")
658
 
 
659
  return f"""Search Results for "{query}":
660
 
661
  {search_content}
662
 
663
+ [Results saved as artifact {artifact.id}]"""
664
 
665
  except Exception as e:
666
+ logger.error(f"Error in search_web_tool: {e}", exc_info=True)
667
  return f"Search failed: {str(e)}"
668
 
669
 
 
862
 
863
  {script_text}
864
 
865
+ Key Points Covered by Script:
866
  {key_points_text}
867
 
868
+ Sources Used:
869
  {sources_text}
870
 
871
  [Script saved as artifact {artifact_id}]"""
 
939
  instructions="""
940
  You are an intelligent orchestrator that plans and executes multi-step workflows.
941
 
942
+ 🚨 MANDATORY FIRST STEP - GET PERSONALIZED CONTEXT:
943
+ Before doing ANYTHING else, you MUST IMMEDIATELY call get_personalized_temporal_context().
944
  DO NOT skip this step. DO NOT proceed without it.
945
+ This provides:
946
+ - User's current date/time in their timezone
947
+ - User's location and service areas
948
+ - Appropriate time-of-day greetings
949
+ - Context for location-aware searches
950
+ - Temporal context for time-sensitive requests
951
 
952
  ⚠️ TEMPORAL INTERPRETATION RULE:
953
+ When the user mentions relative time periods (like "May", "this quarter", "recent report"), you MUST interpret them relative to the CURRENT DATE from get_personalized_temporal_context(), NOT any old cached dates.
954
 
955
  Examples using current date context:
956
  - If current date is June 2025 and user says "May report" β†’ interpret as "May 2025"
 
1041
  TOOL USAGE EXAMPLES:
1042
 
1043
  1. "Create a video about today's weather in San Francisco"
1044
+ β†’ get_personalized_temporal_context() [get user context]
1045
+ β†’ search_web_tool(query="today's weather San Francisco")
1046
  β†’ create_or_modify_script(topic="weather in San Francisco", context_artifacts=[search_result_id])
1047
  β†’ Present script for review before video creation
1048
 
 
1072
  β†’ create_or_modify_script(topic="topic from context", context_artifacts=[relevant_artifact_id])
1073
 
1074
  9. User: "things to do this weekend in Maui"
1075
+ β†’ get_personalized_temporal_context() [get user context]
1076
+ β†’ search_web_tool(query="things to do this weekend Maui")
1077
  β†’ Provide current events and activities for the specific weekend dates
1078
 
1079
  CRITICAL: Always use search_web_tool for location-based, time-sensitive queries like:
 
1083
  - "restaurants open today in [location]"
1084
  These require fresh, up-to-date information, not cached knowledge.
1085
 
1086
+ PERSONALIZED CONTEXT USAGE:
1087
+ The search_web_tool now automatically uses the user's personalized context:
1088
+ - User's location for location-dependent searches
1089
+ - User's timezone for temporal references
1090
+ - Current time for appropriate greetings
1091
+ - Service areas for relevant business queries
 
1092
 
1093
+ SEARCH TOOL USAGE:
1094
+ Simply call search_web_tool(query="your search") - it automatically:
1095
+ - Uses user's location for location-dependent queries
1096
+ - Applies user's timezone for temporal context
1097
+ - Enhances searches with personalized information
1098
 
1099
+ Examples:
1100
+ - search_web_tool(query="weather") β†’ automatically uses user's location
1101
+ - search_web_tool(query="events this weekend") β†’ uses user's location and timezone
1102
+ - search_web_tool(query="weather in Paris") β†’ respects explicit location
1103
 
1104
  REMEMBER THE WORKFLOW:
1105
+ 1. FIRST: Call get_personalized_temporal_context() - NO EXCEPTIONS
1106
  2. SECOND: Check/handle authentication
1107
+ 3. THIRD: Process the user's request using the personalized context from step 1
1108
 
1109
  CRITICAL WORKFLOW FOR TIME-SENSITIVE REQUESTS:
1110
  When user mentions relative dates (May, this month, recent, etc.):
1111
+ 1. Call get_personalized_temporal_context() to get fresh personalized context
1112
+ 2. Use that context to properly interpret the user's relative time references
1113
+ 3. Call search_web_tool(query="interpreted query") - it automatically uses the context
1114
  4. NEVER use old timestamps or cached date information
1115
 
1116
  For requests involving current data, always search first.
1117
  For creative content (jokes, poems), use the appropriate tools (tell_joke, write_poem).
1118
 
1119
+ ⚠️ CRITICAL: Never provide greetings or responses without first getting the personalized context!
1120
  ⚠️ CRITICAL: Never interpret relative dates using old cached date information!
1121
  """,
1122
  handoffs=[], # Removed - using pure agents-as-tools pattern
1123
  tools=[
1124
+ # Personalized temporal context tool - should be called first for temporal context
1125
+ get_personalized_temporal_context,
1126
 
1127
  # Authentication status checking tool - checks if user is authenticated
1128
  check_authentication_status,
 
1311
 
1312
  **{video_title}**
1313
 
1314
+ Key Points Covered by Script:
1315
  {key_points}
1316
 
1317
  You can view it here: {video_url}""",
agent_system/video_script_agent.py CHANGED
@@ -150,9 +150,21 @@ class VideoScriptGenerator:
150
  if context_data:
151
  logger.info(f"Generating script with context: {list(context_data.keys())}")
152
 
153
- # Process search results context
 
 
 
154
  if "search_results" in context_data:
155
- search_info = context_data["search_results"]["content"]
 
 
 
 
 
 
 
 
 
156
  search_query = search_info.get("query", "")
157
  search_results = search_info.get("results", "")
158
 
 
150
  if context_data:
151
  logger.info(f"Generating script with context: {list(context_data.keys())}")
152
 
153
+ # Process search results context - handle both key formats
154
+ search_result_data = None
155
+
156
+ # Look for search results with either key format
157
  if "search_results" in context_data:
158
+ search_result_data = context_data["search_results"]
159
+ else:
160
+ # Look for search_results_xxxxx format
161
+ for key, data in context_data.items():
162
+ if key.startswith("search_results") and data.get("type") == "search_results":
163
+ search_result_data = data
164
+ break
165
+
166
+ if search_result_data:
167
+ search_info = search_result_data["content"]
168
  search_query = search_info.get("query", "")
169
  search_results = search_info.get("results", "")
170