Spaces:
Sleeping
Sleeping
Riley Claude commited on
Commit ·
ff0b7db
1
Parent(s): 9e7adc5
fix: Improve UX - text comparisons, remove preset bloat, fix tool message errors
Browse files- Convert grant comparison from markdown table to cleaner text-based format
- Remove past winners preset questions (not needed)
- Fix tool message error by implementing safe message trimming that preserves tool_call/tool pairs
- Add system prompt instruction to eliminate verbose "I'm going to..." announcements
- Assistant now just calls tools and presents results directly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- src/analyzer/chat/chat_tools.py +10 -6
- src/analyzer/chat/demo_app.py +54 -5
src/analyzer/chat/chat_tools.py
CHANGED
|
@@ -550,9 +550,14 @@ class ChatTools:
|
|
| 550 |
),
|
| 551 |
]
|
| 552 |
|
| 553 |
-
|
|
|
|
| 554 |
for name, va, vb in fields:
|
| 555 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
|
| 557 |
# ---------------- optional insight ----------------
|
| 558 |
context_text = ""
|
|
@@ -565,10 +570,10 @@ class ChatTools:
|
|
| 565 |
if self.client and self.client.is_ready() and context_text.strip():
|
| 566 |
try:
|
| 567 |
prompt = (
|
| 568 |
-
"Given the factual
|
| 569 |
"highlighting *meaningful differences* that matter to SMEs (funding size, "
|
| 570 |
"duration, eligibility, etc.). Do not restate identical facts.\n\n"
|
| 571 |
-
+ "\n".join(
|
| 572 |
+ "\n\n"
|
| 573 |
+ context_text
|
| 574 |
)
|
|
@@ -578,8 +583,7 @@ class ChatTools:
|
|
| 578 |
|
| 579 |
md = [
|
| 580 |
"### Comparison",
|
| 581 |
-
|
| 582 |
-
"\n".join(table),
|
| 583 |
]
|
| 584 |
if insight:
|
| 585 |
md += ["\n### Key differences", insight]
|
|
|
|
| 550 |
),
|
| 551 |
]
|
| 552 |
|
| 553 |
+
# Build text-based comparison instead of table
|
| 554 |
+
comparison_lines = ["### Grant A: " + getf(A, "title")]
|
| 555 |
for name, va, vb in fields:
|
| 556 |
+
comparison_lines.append(f"**{name}:** {va}")
|
| 557 |
+
|
| 558 |
+
comparison_lines.append("\n### Grant B: " + getf(B, "title"))
|
| 559 |
+
for name, va, vb in fields:
|
| 560 |
+
comparison_lines.append(f"**{name}:** {vb}")
|
| 561 |
|
| 562 |
# ---------------- optional insight ----------------
|
| 563 |
context_text = ""
|
|
|
|
| 570 |
if self.client and self.client.is_ready() and context_text.strip():
|
| 571 |
try:
|
| 572 |
prompt = (
|
| 573 |
+
"Given the factual comparison and context below, write 3-5 bullet points "
|
| 574 |
"highlighting *meaningful differences* that matter to SMEs (funding size, "
|
| 575 |
"duration, eligibility, etc.). Do not restate identical facts.\n\n"
|
| 576 |
+
+ "\n".join(comparison_lines)
|
| 577 |
+ "\n\n"
|
| 578 |
+ context_text
|
| 579 |
)
|
|
|
|
| 583 |
|
| 584 |
md = [
|
| 585 |
"### Comparison",
|
| 586 |
+
"\n".join(comparison_lines),
|
|
|
|
| 587 |
]
|
| 588 |
if insight:
|
| 589 |
md += ["\n### Key differences", insight]
|
src/analyzer/chat/demo_app.py
CHANGED
|
@@ -42,8 +42,6 @@ PRESET_QUESTIONS = {
|
|
| 42 |
"Compare two grants": "Compare competition-2313 and competition-2314",
|
| 43 |
"Grant details": "Tell me about competition-2317 in detail",
|
| 44 |
"SME funding options": "What grants are available for SMEs with funding over £100k?",
|
| 45 |
-
"Past winners of open grants": "Of the grants that are currently open, are there any past winners listed as reference?",
|
| 46 |
-
"Past AI winners": "Show me past winners related to AI projects",
|
| 47 |
}
|
| 48 |
|
| 49 |
|
|
@@ -169,7 +167,9 @@ class GrantAnalystDemo:
|
|
| 169 |
"- Avoid fluff, filler, or over-formality\n"
|
| 170 |
"- Skip headings, bullet points, or 'as an AI' disclaimers\n"
|
| 171 |
"- Prefer short, active sentences\n"
|
| 172 |
-
"- Be bold, human, and efficient\n
|
|
|
|
|
|
|
| 173 |
),
|
| 174 |
}
|
| 175 |
]
|
|
@@ -394,6 +394,53 @@ class GrantAnalystDemo:
|
|
| 394 |
logging.error(f"Tool {tool_name} failed: {e}", exc_info=True)
|
| 395 |
return {"error": str(e)}
|
| 396 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 397 |
def chat(self, user_message: str, history: List) -> Tuple[str, List]:
|
| 398 |
"""
|
| 399 |
Process a chat message.
|
|
@@ -422,7 +469,8 @@ class GrantAnalystDemo:
|
|
| 422 |
llm_start = time.time()
|
| 423 |
|
| 424 |
# Limit conversation history (keep system + last 10 messages)
|
| 425 |
-
|
|
|
|
| 426 |
if len(self.messages) > len(messages_to_send):
|
| 427 |
logger.debug(
|
| 428 |
f"Trimmed conversation from {len(self.messages)} to {len(messages_to_send)} messages"
|
|
@@ -491,7 +539,8 @@ class GrantAnalystDemo:
|
|
| 491 |
final_start = time.time()
|
| 492 |
|
| 493 |
# Limit conversation history to prevent bloat (keep system + last 10 messages)
|
| 494 |
-
|
|
|
|
| 495 |
if len(self.messages) > len(messages_to_send):
|
| 496 |
logger.debug(
|
| 497 |
f"Trimmed conversation from {len(self.messages)} to {len(messages_to_send)} messages"
|
|
|
|
| 42 |
"Compare two grants": "Compare competition-2313 and competition-2314",
|
| 43 |
"Grant details": "Tell me about competition-2317 in detail",
|
| 44 |
"SME funding options": "What grants are available for SMEs with funding over £100k?",
|
|
|
|
|
|
|
| 45 |
}
|
| 46 |
|
| 47 |
|
|
|
|
| 167 |
"- Avoid fluff, filler, or over-formality\n"
|
| 168 |
"- Skip headings, bullet points, or 'as an AI' disclaimers\n"
|
| 169 |
"- Prefer short, active sentences\n"
|
| 170 |
+
"- Be bold, human, and efficient\n"
|
| 171 |
+
"- NEVER announce what you're going to do - just do it and present the results\n"
|
| 172 |
+
"- NO phrases like 'I'll search for', 'Let me find', 'Calling the tool' - just call it\n\n"
|
| 173 |
),
|
| 174 |
}
|
| 175 |
]
|
|
|
|
| 394 |
logging.error(f"Tool {tool_name} failed: {e}", exc_info=True)
|
| 395 |
return {"error": str(e)}
|
| 396 |
|
| 397 |
+
def _trim_messages_safely(self, messages: List, max_recent: int = 10) -> List:
|
| 398 |
+
"""
|
| 399 |
+
Trim messages to reduce context size while preserving tool_call/tool pairs.
|
| 400 |
+
|
| 401 |
+
Args:
|
| 402 |
+
messages: Full message history
|
| 403 |
+
max_recent: Max number of recent messages to keep (excluding system)
|
| 404 |
+
|
| 405 |
+
Returns:
|
| 406 |
+
Trimmed messages list with system message + recent messages
|
| 407 |
+
"""
|
| 408 |
+
if len(messages) <= max_recent + 1: # +1 for system message
|
| 409 |
+
return messages
|
| 410 |
+
|
| 411 |
+
# Always keep system message (index 0)
|
| 412 |
+
system_msg = messages[0] if messages and messages[0].get("role") == "system" else None
|
| 413 |
+
|
| 414 |
+
# Get recent messages
|
| 415 |
+
recent = messages[-(max_recent):]
|
| 416 |
+
|
| 417 |
+
# Check if the first recent message is a tool response without its tool_call
|
| 418 |
+
# If so, find the corresponding assistant message with tool_calls and include it
|
| 419 |
+
if recent and recent[0].get("role") == "tool":
|
| 420 |
+
# Find the preceding assistant message with tool_calls
|
| 421 |
+
tool_call_id = recent[0].get("tool_call_id")
|
| 422 |
+
if tool_call_id:
|
| 423 |
+
# Search backwards from the cutoff point
|
| 424 |
+
cutoff_idx = len(messages) - max_recent
|
| 425 |
+
for i in range(cutoff_idx - 1, 0, -1):
|
| 426 |
+
msg = messages[i]
|
| 427 |
+
if msg.get("role") == "assistant" and hasattr(msg, "tool_calls"):
|
| 428 |
+
# Found the assistant message with tool_calls, include it
|
| 429 |
+
recent = [msg] + recent
|
| 430 |
+
break
|
| 431 |
+
# Check if it's a dict with tool_calls key
|
| 432 |
+
elif msg.get("role") == "assistant" and "tool_calls" in str(msg):
|
| 433 |
+
recent = [msg] + recent
|
| 434 |
+
break
|
| 435 |
+
|
| 436 |
+
# Build final message list
|
| 437 |
+
result = []
|
| 438 |
+
if system_msg:
|
| 439 |
+
result.append(system_msg)
|
| 440 |
+
result.extend(recent)
|
| 441 |
+
|
| 442 |
+
return result
|
| 443 |
+
|
| 444 |
def chat(self, user_message: str, history: List) -> Tuple[str, List]:
|
| 445 |
"""
|
| 446 |
Process a chat message.
|
|
|
|
| 469 |
llm_start = time.time()
|
| 470 |
|
| 471 |
# Limit conversation history (keep system + last 10 messages)
|
| 472 |
+
# BUT preserve tool_call/tool pairs to avoid OpenAI API errors
|
| 473 |
+
messages_to_send = self._trim_messages_safely(self.messages, max_recent=10)
|
| 474 |
if len(self.messages) > len(messages_to_send):
|
| 475 |
logger.debug(
|
| 476 |
f"Trimmed conversation from {len(self.messages)} to {len(messages_to_send)} messages"
|
|
|
|
| 539 |
final_start = time.time()
|
| 540 |
|
| 541 |
# Limit conversation history to prevent bloat (keep system + last 10 messages)
|
| 542 |
+
# BUT preserve tool_call/tool pairs to avoid OpenAI API errors
|
| 543 |
+
messages_to_send = self._trim_messages_safely(self.messages, max_recent=10)
|
| 544 |
if len(self.messages) > len(messages_to_send):
|
| 545 |
logger.debug(
|
| 546 |
f"Trimmed conversation from {len(self.messages)} to {len(messages_to_send)} messages"
|