RobertoBarrosoLuque commited on
Commit
4618b90
Β·
1 Parent(s): d094ea0

Add history and cleanup search functionality

Browse files
configs/prompt_library.yaml CHANGED
@@ -67,7 +67,7 @@ fed_savant_chat: |
67
  The date is {date}
68
 
69
  fed_orchestrator: |
70
- You are a Federal Reserve Tool Orchestrator. Analyze user queries about Fed policy and FOMC meetings, then decide which function to call to gather the most relevant information.
71
 
72
  FUNCTION SELECTION STRATEGY:
73
  - Recent/latest/current queries β†’ get_latest_meeting()
@@ -75,6 +75,12 @@ fed_orchestrator: |
75
  - Comparison queries or "changes over time" β†’ compare_meetings(date1, date2)
76
  - Thematic/keyword searches β†’ search_meetings(query, limit)
77
 
 
 
 
 
 
 
78
  DATE HANDLING RULES:
79
  - Convert relative dates to YYYY-MM-DD format
80
  - "December 2024" β†’ "2024-12-18" (typical December FOMC date)
@@ -83,11 +89,12 @@ fed_orchestrator: |
83
  - Recent meeting dates: Jan, Mar, May, Jun, Jul, Sep, Nov, Dec
84
 
85
  FUNCTION CALLING INSTRUCTIONS:
86
- 1. ALWAYS call exactly ONE function per response
87
  2. Use the function that best matches the user's specific information need
88
  3. For date-specific queries, convert dates to proper YYYY-MM-DD format
89
  4. For thematic searches, extract key terms from the user query
90
- 5. If query is ambiguous, prefer the most specific function available
 
91
 
92
  EXAMPLES:
93
 
@@ -107,5 +114,11 @@ fed_orchestrator: |
107
  β†’ Call: search_meetings(query="employment", limit=4)
108
  Reasoning: Thematic search across multiple meetings
109
 
 
 
 
 
 
110
  Current date: {date}
 
111
  User Query: {user_query}
 
67
  The date is {date}
68
 
69
  fed_orchestrator: |
70
+ You are a Federal Reserve Tool Orchestrator. Analyze user queries about Fed policy and FOMC meetings, considering both the current query and conversation history, then decide which function to call to gather the most relevant information.
71
 
72
  FUNCTION SELECTION STRATEGY:
73
  - Recent/latest/current queries β†’ get_latest_meeting()
 
75
  - Comparison queries or "changes over time" β†’ compare_meetings(date1, date2)
76
  - Thematic/keyword searches β†’ search_meetings(query, limit)
77
 
78
+ CONTEXT-AWARE DECISIONS:
79
+ - If user asks for "summary" or "table" and previous context exists, you may not need to call tools
80
+ - If user references "that meeting" or "the data we discussed", check if sufficient context exists
81
+ - For follow-up questions about previously retrieved data, avoid redundant tool calls
82
+ - If user asks to "compare with" something, use previous context as baseline
83
+
84
  DATE HANDLING RULES:
85
  - Convert relative dates to YYYY-MM-DD format
86
  - "December 2024" β†’ "2024-12-18" (typical December FOMC date)
 
89
  - Recent meeting dates: Jan, Mar, May, Jun, Jul, Sep, Nov, Dec
90
 
91
  FUNCTION CALLING INSTRUCTIONS:
92
+ 1. ALWAYS call exactly ONE function per response OR provide analysis if context is sufficient
93
  2. Use the function that best matches the user's specific information need
94
  3. For date-specific queries, convert dates to proper YYYY-MM-DD format
95
  4. For thematic searches, extract key terms from the user query
96
+ 5. If sufficient context exists from conversation history, you may skip tool calls and provide analysis
97
+ 6. If query is ambiguous, prefer the most specific function available
98
 
99
  EXAMPLES:
100
 
 
114
  β†’ Call: search_meetings(query="employment", limit=4)
115
  Reasoning: Thematic search across multiple meetings
116
 
117
+ User: "Can you summarize that in a table?" [when previous context shows FOMC meeting data]
118
+ β†’ No function call needed
119
+ Reasoning: Sufficient context exists to create summary table
120
+
121
+
122
  Current date: {date}
123
+ Conversation History: {conversation_context}
124
  User Query: {user_query}
src/app.py CHANGED
@@ -36,10 +36,16 @@ _EXAMPLES = [
36
  "Give me a table which summarized the last 5 FOMC meetings"
37
  ]
38
 
39
- def respond_for_chat_interface(message: str, history: str, api_key_input: str = ""):
 
 
 
 
 
 
 
40
  """Enhanced response function for gr.ChatInterface with Fed AI Savant capabilities"""
41
 
42
- # Priority: frontend API key input > environment variable
43
  api_key = api_key_input.strip() if api_key_input else os.getenv("FIREWORKS_API_KEY", "")
44
 
45
  if not api_key:
@@ -53,9 +59,16 @@ def respond_for_chat_interface(message: str, history: str, api_key_input: str =
53
  "compare_meetings": compare_meetings
54
  }
55
 
 
 
56
  try:
57
- # Use the compact version
58
- for messages in stream_fed_agent_response(message, api_key, PROMPT_LIBRARY, fed_tools):
 
 
 
 
 
59
  if isinstance(messages, list) and len(messages) > 0:
60
  formatted_content = ""
61
 
@@ -70,11 +83,15 @@ def respond_for_chat_interface(message: str, history: str, api_key_input: str =
70
  else:
71
  formatted_content += str(msg)
72
 
 
73
  yield formatted_content
74
  else:
 
75
  yield str(messages)
 
76
  except Exception as e:
77
- yield f"❌ Error: {str(e)}"
 
78
 
79
 
80
  # Function to create searchable FOMC meetings accordion
@@ -128,7 +145,7 @@ with gr.Blocks(css=_CUSTOM_CSS, title="Fed AI Savant", theme=gr.themes.Soft()) a
128
 
129
  val = os.getenv("FIREWORKS_API_KEY", "")
130
 
131
- api_key = gr.Textbox(
132
  label="Fireworks AI API Key",
133
  type="password",
134
  placeholder="Enter your Fireworks AI API key",
@@ -164,29 +181,41 @@ with gr.Blocks(css=_CUSTOM_CSS, title="Fed AI Savant", theme=gr.themes.Soft()) a
164
 
165
  html_content = '<div style="space-y: 8px;">'
166
  for meeting in meetings_list:
 
 
 
 
 
 
 
 
 
 
 
167
  # Format key economic factors for display (show all factors)
168
  factors_html = ""
169
- if meeting.get('key_economic_factors') and len(meeting['key_economic_factors']) > 0:
 
170
  factors_html = "<p><strong>Key Factors:</strong></p><ul>"
171
- for factor in meeting['key_economic_factors']: # Show all factors
172
  factors_html += f"<li>{factor}</li>"
173
  factors_html += "</ul>"
174
 
175
  html_content += f"""
176
  <details style="border: 1px solid #e5e7eb; border-radius: 6px; padding: 12px; margin-bottom: 8px;">
177
  <summary style="font-weight: 600; cursor: pointer; color: #1f2937;">
178
- πŸ“… {meeting['date']} - Rate: {meeting['rate_decision']}
179
  </summary>
180
  <div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e5e7eb;">
181
- <p><strong>Meeting:</strong> {meeting['title']}</p>
182
- <p><strong>Action:</strong> {meeting.get('action', 'N/A')}</p>
183
- <p><strong>Rate:</strong> {meeting['rate_decision']}</p>
184
- <p><strong>Magnitude:</strong> {meeting.get('magnitude', 'N/A')}</p>
185
- <p><strong>Forward Guidance:</strong> {meeting['summary']}</p>
186
  {factors_html}
187
- <p><strong>Economic Outlook:</strong> {meeting.get('economic_outlook', 'N/A')}</p>
188
- <p><strong>Market Impact:</strong> {meeting.get('market_impact', 'N/A')}</p>
189
- {f'<p><strong>Source:</strong> <a href="{meeting["url"]}" target="_blank">Fed Minutes PDF</a></p>' if meeting.get('url') else ''}
190
  </div>
191
  </details>
192
  """
@@ -195,6 +224,17 @@ with gr.Blocks(css=_CUSTOM_CSS, title="Fed AI Savant", theme=gr.themes.Soft()) a
195
 
196
  meetings_accordion = gr.HTML(generate_meetings_html(FOMC_MEETINGS))
197
 
 
 
 
 
 
 
 
 
 
 
 
198
  with gr.Row():
199
  with gr.Column():
200
  gr.Markdown("### πŸ’¬ Fed AI Assistant")
@@ -206,7 +246,7 @@ with gr.Blocks(css=_CUSTOM_CSS, title="Fed AI Savant", theme=gr.themes.Soft()) a
206
  textbox=gr.Textbox(
207
  placeholder="Ask about Fed policy, rate decisions, or FOMC meetings...", scale=10
208
  ),
209
- additional_inputs=[api_key],
210
  cache_examples=False,
211
  submit_btn="Send",
212
  )
@@ -222,7 +262,7 @@ with gr.Blocks(css=_CUSTOM_CSS, title="Fed AI Savant", theme=gr.themes.Soft()) a
222
 
223
 
224
  date_search.change(
225
- search_meetings,
226
  inputs=date_search,
227
  outputs=meetings_accordion
228
  )
 
36
  "Give me a table which summarized the last 5 FOMC meetings"
37
  ]
38
 
39
+ def convert_history_to_string(history: list) -> str:
40
+ previous_messages = ""
41
+ for msg in history:
42
+ previous_messages += f"{msg['role'].capitalize()}: {msg['content']}\n\n"
43
+ return previous_messages
44
+
45
+
46
+ def respond_for_chat_interface(message: str, history: list, api_key_input: str = ""):
47
  """Enhanced response function for gr.ChatInterface with Fed AI Savant capabilities"""
48
 
 
49
  api_key = api_key_input.strip() if api_key_input else os.getenv("FIREWORKS_API_KEY", "")
50
 
51
  if not api_key:
 
59
  "compare_meetings": compare_meetings
60
  }
61
 
62
+ message_with_history = convert_history_to_string(history)
63
+
64
  try:
65
+ for messages in stream_fed_agent_response(
66
+ message=message,
67
+ api_key=api_key,
68
+ prompt_library=PROMPT_LIBRARY,
69
+ fed_tools=fed_tools,
70
+ history=message_with_history
71
+ ):
72
  if isinstance(messages, list) and len(messages) > 0:
73
  formatted_content = ""
74
 
 
83
  else:
84
  formatted_content += str(msg)
85
 
86
+ final_response = formatted_content
87
  yield formatted_content
88
  else:
89
+ final_response = str(messages)
90
  yield str(messages)
91
+
92
  except Exception as e:
93
+ error_msg = f"❌ Error: {str(e)}"
94
+ yield error_msg
95
 
96
 
97
  # Function to create searchable FOMC meetings accordion
 
145
 
146
  val = os.getenv("FIREWORKS_API_KEY", "")
147
 
148
+ api_key_value = gr.Textbox(
149
  label="Fireworks AI API Key",
150
  type="password",
151
  placeholder="Enter your Fireworks AI API key",
 
181
 
182
  html_content = '<div style="space-y: 8px;">'
183
  for meeting in meetings_list:
184
+ # Safely get meeting data with defaults
185
+ date = meeting.get('date', 'Unknown Date')
186
+ rate_decision = meeting.get('rate_decision', 'N/A')
187
+ title = meeting.get('title', 'FOMC Meeting')
188
+ action = meeting.get('action', 'N/A')
189
+ magnitude = meeting.get('magnitude', 'N/A')
190
+ summary = meeting.get('summary', 'No summary available')
191
+ economic_outlook = meeting.get('economic_outlook', 'N/A')
192
+ market_impact = meeting.get('market_impact', 'N/A')
193
+ url = meeting.get('url', '')
194
+
195
  # Format key economic factors for display (show all factors)
196
  factors_html = ""
197
+ key_factors = meeting.get('key_economic_factors', [])
198
+ if key_factors and len(key_factors) > 0:
199
  factors_html = "<p><strong>Key Factors:</strong></p><ul>"
200
+ for factor in key_factors:
201
  factors_html += f"<li>{factor}</li>"
202
  factors_html += "</ul>"
203
 
204
  html_content += f"""
205
  <details style="border: 1px solid #e5e7eb; border-radius: 6px; padding: 12px; margin-bottom: 8px;">
206
  <summary style="font-weight: 600; cursor: pointer; color: #1f2937;">
207
+ πŸ“… {date} - Rate: {rate_decision}
208
  </summary>
209
  <div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e5e7eb;">
210
+ <p><strong>Meeting:</strong> {title}</p>
211
+ <p><strong>Action:</strong> {action}</p>
212
+ <p><strong>Rate:</strong> {rate_decision}</p>
213
+ <p><strong>Magnitude:</strong> {magnitude}</p>
214
+ <p><strong>Forward Guidance:</strong> {summary}</p>
215
  {factors_html}
216
+ <p><strong>Economic Outlook:</strong> {economic_outlook}</p>
217
+ <p><strong>Market Impact:</strong> {market_impact}</p>
218
+ {f'<p><strong>Source:</strong> <a href="{url}" target="_blank">Fed Minutes PDF</a></p>' if url else ''}
219
  </div>
220
  </details>
221
  """
 
224
 
225
  meetings_accordion = gr.HTML(generate_meetings_html(FOMC_MEETINGS))
226
 
227
+ def search_and_format_meetings(query: str):
228
+ """Search meetings and format them for HTML display"""
229
+ if not query.strip():
230
+ return generate_meetings_html(FOMC_MEETINGS)
231
+
232
+ search_result = search_meetings(query)
233
+ if search_result.get("success") and search_result.get("results"):
234
+ return generate_meetings_html(search_result["results"])
235
+ else:
236
+ return '<p style="color: #ef4444; text-align: center; padding: 20px;">No meetings found matching your search.</p>'
237
+
238
  with gr.Row():
239
  with gr.Column():
240
  gr.Markdown("### πŸ’¬ Fed AI Assistant")
 
246
  textbox=gr.Textbox(
247
  placeholder="Ask about Fed policy, rate decisions, or FOMC meetings...", scale=10
248
  ),
249
+ additional_inputs=[api_key_value],
250
  cache_examples=False,
251
  submit_btn="Send",
252
  )
 
262
 
263
 
264
  date_search.change(
265
+ search_and_format_meetings,
266
  inputs=date_search,
267
  outputs=meetings_accordion
268
  )
src/modules/fed_tools.py CHANGED
@@ -101,7 +101,7 @@ def load_meetings_data() -> List[Dict[str, Any]]:
101
  except Exception as e:
102
  return []
103
 
104
- def search_meetings(query: str, limit: int = 3) -> Dict[str, Any]:
105
  """
106
  Search across all FOMC meeting data for relevant information.
107
 
@@ -127,6 +127,33 @@ def search_meetings(query: str, limit: int = 3) -> Dict[str, Any]:
127
  "count": 0
128
  }
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  query_lower = query.lower()
131
  scored_meetings = []
132
 
@@ -163,12 +190,32 @@ def search_meetings(query: str, limit: int = 3) -> Dict[str, Any]:
163
  })
164
 
165
  scored_meetings.sort(key=lambda x: x['score'], reverse=True)
166
- top_results = scored_meetings[:limit]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
  return {
169
  "success": True,
170
  "query": query,
171
- "results": [result['meeting'] for result in top_results],
172
  "match_details": [{'score': r['score'], 'matched_fields': r['matched_fields']} for r in top_results],
173
  "count": len(top_results),
174
  "total_matches": len(scored_meetings)
 
101
  except Exception as e:
102
  return []
103
 
104
+ def search_meetings(query: str, limit: int = 10) -> Dict[str, Any]:
105
  """
106
  Search across all FOMC meeting data for relevant information.
107
 
 
127
  "count": 0
128
  }
129
 
130
+ # If query is empty, return all meetings with transformation
131
+ if not query.strip():
132
+ transformed_results = []
133
+ for meeting in meetings_data:
134
+ transformed_results.append({
135
+ "date": meeting.get("date", ""),
136
+ "title": meeting.get("title", ""),
137
+ "rate_decision": meeting.get("rate", ""), # Transform rate -> rate_decision
138
+ "summary": meeting.get("forward_guidance", ""),
139
+ "action": meeting.get("action", ""),
140
+ "magnitude": meeting.get("magnitude", ""),
141
+ "key_economic_factors": meeting.get("key_economic_factors", []),
142
+ "economic_outlook": meeting.get("economic_outlook", ""),
143
+ "market_impact": meeting.get("market_impact", ""),
144
+ "full_text": meeting.get("full_text", "")[:500] + "..." if meeting.get("full_text") else "",
145
+ "url": meeting.get("url", "")
146
+ })
147
+
148
+ return {
149
+ "success": True,
150
+ "query": query,
151
+ "results": transformed_results,
152
+ "match_details": [{"score": 0, "matched_fields": []} for _ in meetings_data],
153
+ "count": len(transformed_results),
154
+ "total_matches": len(meetings_data)
155
+ }
156
+
157
  query_lower = query.lower()
158
  scored_meetings = []
159
 
 
190
  })
191
 
192
  scored_meetings.sort(key=lambda x: x['score'], reverse=True)
193
+
194
+ _limit = min(limit, len(scored_meetings))
195
+ top_results = scored_meetings[:_limit]
196
+
197
+ # Transform meetings to match frontend format (same as utils.py)
198
+ transformed_results = []
199
+ for result in top_results:
200
+ meeting = result['meeting']
201
+ transformed_results.append({
202
+ "date": meeting.get("date", ""),
203
+ "title": meeting.get("title", ""),
204
+ "rate_decision": meeting.get("rate", ""), # Transform rate -> rate_decision
205
+ "summary": meeting.get("forward_guidance", ""),
206
+ "action": meeting.get("action", ""),
207
+ "magnitude": meeting.get("magnitude", ""),
208
+ "key_economic_factors": meeting.get("key_economic_factors", []),
209
+ "economic_outlook": meeting.get("economic_outlook", ""),
210
+ "market_impact": meeting.get("market_impact", ""),
211
+ "full_text": meeting.get("full_text", "")[:500] + "..." if meeting.get("full_text") else "",
212
+ "url": meeting.get("url", "")
213
+ })
214
 
215
  return {
216
  "success": True,
217
  "query": query,
218
+ "results": transformed_results,
219
  "match_details": [{'score': r['score'], 'matched_fields': r['matched_fields']} for r in top_results],
220
  "count": len(top_results),
221
  "total_matches": len(scored_meetings)
src/modules/llm_completions.py CHANGED
@@ -73,10 +73,12 @@ async def run_multi_llm_completions(llm: LLM, prompts: list[str], output_class:
73
  return await asyncio.gather(*tasks)
74
 
75
 
76
- def get_orchestrator_decision(user_query: str, api_key: str, prompt_library: Dict[str, str]) -> Dict[str, Any]:
 
 
77
  """Use orchestrator LLM to decide which tools to use"""
78
  orchestrator_prompt = prompt_library.get('fed_orchestrator')
79
- formatted_prompt = orchestrator_prompt.format(user_query=user_query, date=TODAY)
80
 
81
  print("Running function orchestrator")
82
  llm = get_llm("large", api_key)
@@ -276,13 +278,14 @@ def stream_final_response(message: str, system_prompt: str, api_key: str, citati
276
 
277
 
278
  def stream_fed_agent_response(
 
279
  message: str,
280
  api_key: str,
281
  prompt_library: Dict[str, str],
282
- fed_tools: Dict[str, callable]
 
283
  ):
284
  """Main orchestrator function that coordinates tools and generates responses with ChatMessage objects"""
285
- # Input validation
286
  if not message.strip():
287
  yield [ChatMessage(role="assistant",
288
  content="Please enter a question about Federal Reserve policy or FOMC meetings.")]
@@ -295,9 +298,10 @@ def stream_fed_agent_response(
295
  messages = []
296
 
297
  try:
298
- # Get orchestrator decision
299
  print("Getting orchestrator decision...")
300
- orchestrator_result = get_orchestrator_decision(message, api_key, prompt_library)
 
 
301
 
302
  if not orchestrator_result["success"]:
303
  yield [ChatMessage(role="assistant", content="❌ Error in planning phase")]
@@ -307,18 +311,15 @@ def stream_fed_agent_response(
307
 
308
  # Execute tools if any were called
309
  if orchestrator_result["has_tool_calls"]:
310
- # Show single summary message for tools
311
  tool_names = [tc.function.name for tc in orchestrator_result["tool_calls"]]
312
  tools_summary = f"πŸ”§ **Tools Used:** {', '.join(tool_names)}"
313
 
314
  messages.append(ChatMessage(role="assistant", content=tools_summary))
315
  yield messages
316
 
317
- # Execute the tools
318
  print("Executing tools...")
319
  tool_results = execute_tool_calls(orchestrator_result["tool_calls"], fed_tools)
320
 
321
- # Update the tools summary with results
322
  successful_tools = sum(1 for tr in tool_results if tr["success"])
323
  total_time = sum(tr["execution_time"] for tr in tool_results)
324
 
@@ -326,7 +327,6 @@ def stream_fed_agent_response(
326
  messages[0] = ChatMessage(role="assistant", content=updated_summary)
327
  yield messages
328
 
329
- # Build context and start streaming final response
330
  combined_context = build_context_from_tool_results(tool_results)
331
  citations = extract_citations_from_tool_results(tool_results)
332
 
@@ -337,7 +337,6 @@ def stream_fed_agent_response(
337
  date=TODAY
338
  )
339
 
340
- # Add separator and final response
341
  messages.append(ChatMessage(role="assistant", content=""))
342
 
343
  for response_chunk in stream_final_response(message, system_prompt, api_key, citations):
@@ -345,12 +344,11 @@ def stream_fed_agent_response(
345
  yield messages
346
 
347
  else:
348
- # No tools used - direct response
349
  if orchestrator_message.content:
350
  messages.append(ChatMessage(role="assistant", content=orchestrator_message.content))
351
  yield messages
352
  else:
353
- # Fallback response
354
  system_prompt_template = prompt_library.get('fed_savant_chat', '')
355
  system_prompt = system_prompt_template.format(
356
  fed_data_context="No specific tool data available.",
 
73
  return await asyncio.gather(*tasks)
74
 
75
 
76
+ def get_orchestrator_decision(
77
+ *, user_query: str, history: str, api_key: str, prompt_library: Dict[str, str]
78
+ ) -> Dict[str, Any]:
79
  """Use orchestrator LLM to decide which tools to use"""
80
  orchestrator_prompt = prompt_library.get('fed_orchestrator')
81
+ formatted_prompt = orchestrator_prompt.format(user_query=user_query, date=TODAY, conversation_context=history)
82
 
83
  print("Running function orchestrator")
84
  llm = get_llm("large", api_key)
 
278
 
279
 
280
  def stream_fed_agent_response(
281
+ *,
282
  message: str,
283
  api_key: str,
284
  prompt_library: Dict[str, str],
285
+ fed_tools: Dict[str, callable],
286
+ history: str = "",
287
  ):
288
  """Main orchestrator function that coordinates tools and generates responses with ChatMessage objects"""
 
289
  if not message.strip():
290
  yield [ChatMessage(role="assistant",
291
  content="Please enter a question about Federal Reserve policy or FOMC meetings.")]
 
298
  messages = []
299
 
300
  try:
 
301
  print("Getting orchestrator decision...")
302
+ orchestrator_result = get_orchestrator_decision(
303
+ user_query=message, api_key=api_key, history=history, prompt_library=prompt_library
304
+ )
305
 
306
  if not orchestrator_result["success"]:
307
  yield [ChatMessage(role="assistant", content="❌ Error in planning phase")]
 
311
 
312
  # Execute tools if any were called
313
  if orchestrator_result["has_tool_calls"]:
 
314
  tool_names = [tc.function.name for tc in orchestrator_result["tool_calls"]]
315
  tools_summary = f"πŸ”§ **Tools Used:** {', '.join(tool_names)}"
316
 
317
  messages.append(ChatMessage(role="assistant", content=tools_summary))
318
  yield messages
319
 
 
320
  print("Executing tools...")
321
  tool_results = execute_tool_calls(orchestrator_result["tool_calls"], fed_tools)
322
 
 
323
  successful_tools = sum(1 for tr in tool_results if tr["success"])
324
  total_time = sum(tr["execution_time"] for tr in tool_results)
325
 
 
327
  messages[0] = ChatMessage(role="assistant", content=updated_summary)
328
  yield messages
329
 
 
330
  combined_context = build_context_from_tool_results(tool_results)
331
  citations = extract_citations_from_tool_results(tool_results)
332
 
 
337
  date=TODAY
338
  )
339
 
 
340
  messages.append(ChatMessage(role="assistant", content=""))
341
 
342
  for response_chunk in stream_final_response(message, system_prompt, api_key, citations):
 
344
  yield messages
345
 
346
  else:
 
347
  if orchestrator_message.content:
348
  messages.append(ChatMessage(role="assistant", content=orchestrator_message.content))
349
  yield messages
350
  else:
351
+
352
  system_prompt_template = prompt_library.get('fed_savant_chat', '')
353
  system_prompt = system_prompt_template.format(
354
  fed_data_context="No specific tool data available.",
src/modules/utils.py CHANGED
@@ -4,7 +4,6 @@ from pathlib import Path
4
 
5
  _FILE_PATH = Path(__file__).parents[2]
6
 
7
-
8
  def load_processed_meetings():
9
  """Load processed FOMC meetings from JSON file"""
10
  try:
 
4
 
5
  _FILE_PATH = Path(__file__).parents[2]
6
 
 
7
  def load_processed_meetings():
8
  """Load processed FOMC meetings from JSON file"""
9
  try: