Spaces:
Running
Running
RobertoBarrosoLuque
commited on
Commit
Β·
4618b90
1
Parent(s):
d094ea0
Add history and cleanup search functionality
Browse files- configs/prompt_library.yaml +16 -3
- src/app.py +59 -19
- src/modules/fed_tools.py +50 -3
- src/modules/llm_completions.py +11 -13
- src/modules/utils.py +0 -1
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
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
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 |
-
|
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 |
-
|
|
|
170 |
factors_html = "<p><strong>Key Factors:</strong></p><ul>"
|
171 |
-
for factor in
|
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 |
-
π
{
|
179 |
</summary>
|
180 |
<div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e5e7eb;">
|
181 |
-
<p><strong>Meeting:</strong> {
|
182 |
-
<p><strong>Action:</strong> {
|
183 |
-
<p><strong>Rate:</strong> {
|
184 |
-
<p><strong>Magnitude:</strong> {
|
185 |
-
<p><strong>Forward Guidance:</strong> {
|
186 |
{factors_html}
|
187 |
-
<p><strong>Economic Outlook:</strong> {
|
188 |
-
<p><strong>Market Impact:</strong> {
|
189 |
-
{f'<p><strong>Source:</strong> <a href="{
|
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=[
|
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 |
-
|
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 =
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
167 |
|
168 |
return {
|
169 |
"success": True,
|
170 |
"query": query,
|
171 |
-
"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(
|
|
|
|
|
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(
|
|
|
|
|
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 |
-
|
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:
|