Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -483,15 +483,20 @@ You are **GAKR AI**, an expert assistant specializing in depth-calibrated respon
|
|
| 483 |
def normalize_tool_name(name: str) -> str:
|
| 484 |
if not name:
|
| 485 |
return ""
|
|
|
|
| 486 |
normalized = name.strip().lower().replace(" ", "_").replace("-", "_")
|
|
|
|
|
|
|
|
|
|
| 487 |
if normalized == "websearch":
|
| 488 |
return "web_search"
|
| 489 |
return normalized
|
| 490 |
|
| 491 |
def parse_tool_call(text: str) -> Optional[Dict[str, Any]]:
|
| 492 |
-
# ==== ENHANCED DETECTOR: Handle incomplete tool calls ====
|
| 493 |
# When <|tool_call_start|> is detected, it's 100% confirmation of a tool call
|
| 494 |
# The model may not always generate <|tool_call_end|>, so we extract what we can
|
|
|
|
| 495 |
|
| 496 |
if "<|tool_call_start|>" in text:
|
| 497 |
start_pos = text.find("<|tool_call_start|>") + len("<|tool_call_start|>")
|
|
@@ -503,24 +508,27 @@ You are **GAKR AI**, an expert assistant specializing in depth-calibrated respon
|
|
| 503 |
print(f"π [PARSE] Complete token pair detected. Payload: {payload[:80]}")
|
| 504 |
else:
|
| 505 |
# Case 2: Incomplete - only start token, extract what we have
|
| 506 |
-
# Look for the tool call pattern: [web_search(...)] or web_search(...)
|
| 507 |
remaining = text[start_pos:].strip()
|
| 508 |
print(f"π [PARSE] Incomplete token pair. Remaining buffer: {remaining[:80]}")
|
|
|
|
| 509 |
|
| 510 |
-
# Try to extract from brackets first: [web_search(
|
| 511 |
-
|
|
|
|
| 512 |
if bracket_match:
|
| 513 |
-
|
| 514 |
-
|
|
|
|
|
|
|
| 515 |
else:
|
| 516 |
-
# Try bare function call: web_search(
|
| 517 |
-
|
|
|
|
| 518 |
if func_match:
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
print(f"π [PARSE] Extracted bare function: {payload}")
|
| 524 |
else:
|
| 525 |
print(f"β οΈ [PARSE] Could not extract tool call from: {remaining[:50]}")
|
| 526 |
return None
|
|
@@ -543,9 +551,11 @@ You are **GAKR AI**, an expert assistant specializing in depth-calibrated respon
|
|
| 543 |
if clean_payload.startswith("[") and clean_payload.endswith("]"):
|
| 544 |
clean_payload = clean_payload[1:-1].strip()
|
| 545 |
|
| 546 |
-
m = re.match(r"^([a-zA-Z_]\
|
| 547 |
if m:
|
| 548 |
-
name
|
|
|
|
|
|
|
| 549 |
args_str = m.group(2).strip()
|
| 550 |
args: Dict[str, Any] = {}
|
| 551 |
|
|
@@ -576,38 +586,33 @@ You are **GAKR AI**, an expert assistant specializing in depth-calibrated respon
|
|
| 576 |
if isinstance(tc, dict) and "name" in tc and "args" in tc:
|
| 577 |
return {"name": normalize_tool_name(tc.get("name", "")), "args": tc.get("args", {})}
|
| 578 |
|
| 579 |
-
# 3) Bare Pythonic call without special tokens (fallback)
|
| 580 |
stripped = text.strip()
|
| 581 |
raw = stripped
|
| 582 |
if raw.startswith("[") and raw.endswith("]"):
|
| 583 |
raw = raw[1:-1].strip()
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
if mpos:
|
| 607 |
-
pos = mpos.group(1) or mpos.group(2)
|
| 608 |
-
if pos is not None:
|
| 609 |
-
args["query"] = pos
|
| 610 |
-
return {"name": "web_search", "args": args}
|
| 611 |
|
| 612 |
return None
|
| 613 |
|
|
|
|
| 483 |
def normalize_tool_name(name: str) -> str:
|
| 484 |
if not name:
|
| 485 |
return ""
|
| 486 |
+
# Remove spaces, convert to lowercase, normalize underscores
|
| 487 |
normalized = name.strip().lower().replace(" ", "_").replace("-", "_")
|
| 488 |
+
# Handle variations: "web search", "websearch", "web_search" -> "web_search"
|
| 489 |
+
if "web" in normalized and "search" in normalized:
|
| 490 |
+
return "web_search"
|
| 491 |
if normalized == "websearch":
|
| 492 |
return "web_search"
|
| 493 |
return normalized
|
| 494 |
|
| 495 |
def parse_tool_call(text: str) -> Optional[Dict[str, Any]]:
|
| 496 |
+
# ==== ENHANCED DETECTOR: Handle incomplete tool calls & variations ====
|
| 497 |
# When <|tool_call_start|> is detected, it's 100% confirmation of a tool call
|
| 498 |
# The model may not always generate <|tool_call_end|>, so we extract what we can
|
| 499 |
+
# Also handles variations like "web_ Search" (with space/case variations)
|
| 500 |
|
| 501 |
if "<|tool_call_start|>" in text:
|
| 502 |
start_pos = text.find("<|tool_call_start|>") + len("<|tool_call_start|>")
|
|
|
|
| 508 |
print(f"π [PARSE] Complete token pair detected. Payload: {payload[:80]}")
|
| 509 |
else:
|
| 510 |
# Case 2: Incomplete - only start token, extract what we have
|
|
|
|
| 511 |
remaining = text[start_pos:].strip()
|
| 512 |
print(f"π [PARSE] Incomplete token pair. Remaining buffer: {remaining[:80]}")
|
| 513 |
+
payload = None
|
| 514 |
|
| 515 |
+
# Try to extract from brackets first: [web_search(...)] or [web_ Search(...)]
|
| 516 |
+
# Pattern: [word(args)] - allowing for spaces and case variations
|
| 517 |
+
bracket_match = re.search(r'\[([a-zA-Z_\s]+?)\s*\((.*?)\)\s*\]', remaining)
|
| 518 |
if bracket_match:
|
| 519 |
+
func_base = bracket_match.group(1).replace(" ", "_").lower() # Normalize spaces
|
| 520 |
+
func_args = bracket_match.group(2)
|
| 521 |
+
payload = f"{func_base}({func_args})"
|
| 522 |
+
print(f"π [PARSE] Extracted from brackets (normalized): {payload}")
|
| 523 |
else:
|
| 524 |
+
# Try bare function call: web_search(...) or web_ Search(...)
|
| 525 |
+
# Allow for spaces: web_ search, web_search, etc.
|
| 526 |
+
func_match = re.search(r'([a-zA-Z_]+(?:\s+[a-zA-Z_]+)?)\s*\((.*?)\)', remaining)
|
| 527 |
if func_match:
|
| 528 |
+
func_base = func_match.group(1).replace(" ", "_").lower() # Normalize spaces
|
| 529 |
+
func_args = func_match.group(2)
|
| 530 |
+
payload = f"{func_base}({func_args})"
|
| 531 |
+
print(f"π [PARSE] Extracted bare function (normalized): {payload}")
|
|
|
|
| 532 |
else:
|
| 533 |
print(f"β οΈ [PARSE] Could not extract tool call from: {remaining[:50]}")
|
| 534 |
return None
|
|
|
|
| 551 |
if clean_payload.startswith("[") and clean_payload.endswith("]"):
|
| 552 |
clean_payload = clean_payload[1:-1].strip()
|
| 553 |
|
| 554 |
+
m = re.match(r"^([a-zA-Z_]+(?:\s+[a-zA-Z_]+)?)\s*\((.*)\)\s*$", clean_payload)
|
| 555 |
if m:
|
| 556 |
+
# Normalize function name: remove spaces, convert to lowercase
|
| 557 |
+
name_raw = m.group(1)
|
| 558 |
+
name = normalize_tool_name(name_raw)
|
| 559 |
args_str = m.group(2).strip()
|
| 560 |
args: Dict[str, Any] = {}
|
| 561 |
|
|
|
|
| 586 |
if isinstance(tc, dict) and "name" in tc and "args" in tc:
|
| 587 |
return {"name": normalize_tool_name(tc.get("name", "")), "args": tc.get("args", {})}
|
| 588 |
|
| 589 |
+
# 3) Bare Pythonic call without special tokens (fallback) - also handle spacing
|
| 590 |
stripped = text.strip()
|
| 591 |
raw = stripped
|
| 592 |
if raw.startswith("[") and raw.endswith("]"):
|
| 593 |
raw = raw[1:-1].strip()
|
| 594 |
+
|
| 595 |
+
# Handle: web_search(...), web_Search(...), web_ search(...), etc.
|
| 596 |
+
bare_match = re.match(r'([a-zA-Z_]+(?:\s+[a-zA-Z_]+)?)\s*\((.*?)\)\s*$', raw)
|
| 597 |
+
if bare_match:
|
| 598 |
+
func_name_raw = bare_match.group(1)
|
| 599 |
+
func_name = normalize_tool_name(func_name_raw)
|
| 600 |
+
|
| 601 |
+
# Only process if it's a recognized tool (web_search)
|
| 602 |
+
if func_name == "web_search":
|
| 603 |
+
args_str = bare_match.group(2).strip()
|
| 604 |
+
args: Dict[str, Any] = {}
|
| 605 |
+
mq = re.search(r'query\s*=\s*\"(.*?)\"|query\s*=\s*\'(.*?)\'', args_str)
|
| 606 |
+
if mq:
|
| 607 |
+
args["query"] = mq.group(1) or mq.group(2) or ""
|
| 608 |
+
else:
|
| 609 |
+
mpos = re.match(r'^\"(.*)\"$|^\'(.*)\'$', args_str)
|
| 610 |
+
if mpos:
|
| 611 |
+
pos = mpos.group(1) or mpos.group(2)
|
| 612 |
+
if pos is not None:
|
| 613 |
+
args["query"] = pos
|
| 614 |
+
print(f"β
[PARSE] Bare tool call found: {func_name}({args})")
|
| 615 |
+
return {"name": func_name, "args": args}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 616 |
|
| 617 |
return None
|
| 618 |
|