Keep flowchart inside right-column bounds; add 3 tools + chained examples
Browse filesSVG geometry:
- Shifted the entire right-column flow 50px right (centre x=580 → 630)
so the 'Final answer' box on the NO branch (at x=410 now, was x=350)
stays inside the card boundary at x=380.
- Loop-back arrow now lives at x=860, still well inside the column's
right edge at x=880.
New tools:
- get_distance(city_a, city_b) — real haversine over a built-in lat/lon
table of 17 cities (IITG-relevant + global hubs).
- get_population(city) — metro-area figures in millions for the same
list.
- get_stock_price(ticker) — mock USD prices for ~12 common tickers.
System prompt now lists the new tools and spells out a three-tool chain
(INR → USD exchange → stock price → share-count calc) as an explicit
example.
Examples overhauled: dropped a couple of weak ones, added
compositional multi-tool questions:
- Delhi–Mumbai distance in miles rounded to the nearest 10
- AAPL shares for 5000 INR (currency → stock → divide)
- Tokyo 9 AM meeting: local time in Delhi + distance between cities
- London–NY km at 900 km/h (distance → convert → divide)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@@ -53,20 +53,26 @@ SYSTEM_PROMPT = """You are a helpful assistant with access to tools.
|
|
| 53 |
Rules you must follow:
|
| 54 |
1. For ANY arithmetic — even simple multiplication like 5 * 7 — call the
|
| 55 |
`calculate` tool. Never compute numbers in your head.
|
| 56 |
-
2. For real-time facts like weather
|
| 57 |
-
tool (`get_weather`, `get_time`).
|
|
|
|
| 58 |
3. For unit conversions, call `convert_units` — don't approximate.
|
| 59 |
4. For currency conversion, call `get_exchange_rate`.
|
| 60 |
-
5. For
|
|
|
|
|
|
|
| 61 |
call `search_notes`.
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
"5 km/day for a week in miles" →
|
| 65 |
-
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
| 67 |
write the final answer? Only answer once you have ALL the numbers.
|
| 68 |
-
|
| 69 |
-
|
| 70 |
|
| 71 |
CRITICAL: when you ARE calling a tool, use the provider's structured
|
| 72 |
tool_calls interface — do NOT write tool calls as Python-style text like
|
|
@@ -207,6 +213,61 @@ def get_exchange_rate(from_currency: str, to_currency: str, amount: float = 1.0)
|
|
| 207 |
})
|
| 208 |
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
def define_word(word: str) -> str:
|
| 211 |
definitions = {
|
| 212 |
"overfitting": "When a model learns training data too well (including noise) and performs poorly on new data.",
|
|
@@ -317,6 +378,45 @@ TOOL_SCHEMAS = [
|
|
| 317 |
},
|
| 318 |
},
|
| 319 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
]
|
| 321 |
|
| 322 |
TOOL_FUNCTIONS = {
|
|
@@ -327,6 +427,9 @@ TOOL_FUNCTIONS = {
|
|
| 327 |
"define_word": define_word,
|
| 328 |
"get_time": get_time,
|
| 329 |
"get_exchange_rate": get_exchange_rate,
|
|
|
|
|
|
|
|
|
|
| 330 |
}
|
| 331 |
|
| 332 |
|
|
@@ -699,44 +802,44 @@ FLOWCHART_HTML = """
|
|
| 699 |
<text x="180" y="330" text-anchor="middle" font-size="10" fill="#5a6070">(may hallucinate)</text>
|
| 700 |
</g>
|
| 701 |
|
| 702 |
-
<!-- ============ RIGHT COLUMN ============ -->
|
| 703 |
<g font-size="13" fill="#1a1a2e">
|
| 704 |
-
<rect x="
|
| 705 |
-
<text x="
|
| 706 |
-
<path d="
|
| 707 |
|
| 708 |
-
<rect x="
|
| 709 |
-
<text x="
|
| 710 |
-
<path d="
|
| 711 |
|
| 712 |
<!-- Diamond decision -->
|
| 713 |
-
<polygon points="
|
| 714 |
-
<text x="
|
| 715 |
-
<text x="
|
| 716 |
|
| 717 |
-
<!-- NO branch: left + down -->
|
| 718 |
-
<path d="
|
| 719 |
-
<text x="
|
| 720 |
-
<rect x="
|
| 721 |
-
<text x="
|
| 722 |
-
<text x="
|
| 723 |
|
| 724 |
<!-- YES branch: right + down -->
|
| 725 |
-
<path d="
|
| 726 |
-
<text x="
|
| 727 |
|
| 728 |
-
<rect x="
|
| 729 |
-
<text x="
|
| 730 |
-
<path d="
|
| 731 |
|
| 732 |
-
<rect x="
|
| 733 |
-
<text x="
|
| 734 |
|
| 735 |
-
<!-- Loop back: dashed red,
|
| 736 |
-
<path d="
|
| 737 |
stroke="#c44536" stroke-width="1.5" fill="none"
|
| 738 |
stroke-dasharray="5 3" marker-end="url(#arrr)"/>
|
| 739 |
-
<text x="
|
| 740 |
</g>
|
| 741 |
</svg>
|
| 742 |
</div>
|
|
@@ -939,21 +1042,28 @@ CUSTOM_CSS = """
|
|
| 939 |
# --- UI ------------------------------------------------------------------
|
| 940 |
|
| 941 |
EXAMPLES = [
|
| 942 |
-
# --- Hard arithmetic
|
| 943 |
"What is 4729 times 8314?",
|
| 944 |
"Compute (127 ** 3) + (49 ** 4).",
|
| 945 |
"What is 31.5% of 128,400?",
|
| 946 |
-
"What is the square root of 987654, to 4 decimals?",
|
| 947 |
"Evaluate 2847 * 9183 - 17^5.",
|
| 948 |
-
# --- Single-tool: real-time data ---
|
| 949 |
"What's the temperature in Gandhinagar in Fahrenheit?",
|
| 950 |
"What time is it in Tokyo right now?",
|
| 951 |
-
|
|
|
|
| 952 |
"How much hotter is Delhi than Bangalore right now, in degrees Celsius?",
|
| 953 |
"If I run 5 km every day for a week, how many miles is that total?",
|
| 954 |
"I have 1000 USD. How much is that in INR, and what time is it in Delhi?",
|
| 955 |
-
|
|
|
|
|
|
|
|
|
|
| 956 |
"I earn 2500 EUR/month. After converting to INR, what is my annual salary?",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
# --- Course knowledge base ---
|
| 958 |
"Which week of CS 203 covered Docker?",
|
| 959 |
"What does 'overfitting' mean?",
|
|
|
|
| 53 |
Rules you must follow:
|
| 54 |
1. For ANY arithmetic — even simple multiplication like 5 * 7 — call the
|
| 55 |
`calculate` tool. Never compute numbers in your head.
|
| 56 |
+
2. For real-time facts like weather, current time, or stock prices,
|
| 57 |
+
call the matching tool (`get_weather`, `get_time`, `get_stock_price`).
|
| 58 |
+
Do not guess or say you don't know.
|
| 59 |
3. For unit conversions, call `convert_units` — don't approximate.
|
| 60 |
4. For currency conversion, call `get_exchange_rate`.
|
| 61 |
+
5. For distances between cities, call `get_distance`. For city
|
| 62 |
+
populations, call `get_population`.
|
| 63 |
+
6. For questions about the CS 203 course ("what week did we cover X?"),
|
| 64 |
call `search_notes`.
|
| 65 |
+
7. For definitions of CS / ML terms, call `define_word`.
|
| 66 |
+
8. Multi-step questions need multiple tool calls in sequence. Examples:
|
| 67 |
+
- "5 km/day for a week in miles" → `convert_units` then `calculate`.
|
| 68 |
+
- "Delhi-Mumbai distance in miles" → `get_distance` then
|
| 69 |
+
`convert_units`.
|
| 70 |
+
- "Shares of AAPL for 5000 INR" → `get_exchange_rate` →
|
| 71 |
+
`get_stock_price` → `calculate`.
|
| 72 |
+
9. After every tool result, decide: do I need another tool, or can I
|
| 73 |
write the final answer? Only answer once you have ALL the numbers.
|
| 74 |
+
10. If the question genuinely doesn't need any tool (e.g. "capital of
|
| 75 |
+
France"), answer directly.
|
| 76 |
|
| 77 |
CRITICAL: when you ARE calling a tool, use the provider's structured
|
| 78 |
tool_calls interface — do NOT write tool calls as Python-style text like
|
|
|
|
| 213 |
})
|
| 214 |
|
| 215 |
|
| 216 |
+
def get_distance(city_a: str, city_b: str) -> str:
|
| 217 |
+
"""Great-circle distance between two cities in kilometres (demo data)."""
|
| 218 |
+
# Stored as city -> (lat, lon) so we can list any pair.
|
| 219 |
+
coords = {
|
| 220 |
+
"gandhinagar": (23.22, 72.65), "mumbai": (19.08, 72.88),
|
| 221 |
+
"delhi": (28.61, 77.21), "bangalore": (12.97, 77.59),
|
| 222 |
+
"chennai": (13.08, 80.27), "kolkata": (22.57, 88.36),
|
| 223 |
+
"hyderabad": (17.38, 78.49), "pune": (18.52, 73.86),
|
| 224 |
+
"tokyo": (35.68, 139.69), "seoul": (37.57, 126.98),
|
| 225 |
+
"singapore": (1.35, 103.82), "hong kong": (22.32, 114.17),
|
| 226 |
+
"london": (51.51, -0.13), "paris": (48.86, 2.35),
|
| 227 |
+
"new york": (40.71, -74.00), "san francisco": (37.77, -122.42),
|
| 228 |
+
"sydney": (-33.87, 151.21),
|
| 229 |
+
}
|
| 230 |
+
a = coords.get(city_a.lower().strip())
|
| 231 |
+
b = coords.get(city_b.lower().strip())
|
| 232 |
+
if a is None or b is None:
|
| 233 |
+
return json.dumps({"error": f"Unknown city. Supported: {sorted(coords.keys())}"})
|
| 234 |
+
import math
|
| 235 |
+
lat1, lon1 = map(math.radians, a)
|
| 236 |
+
lat2, lon2 = map(math.radians, b)
|
| 237 |
+
dlat, dlon = lat2 - lat1, lon2 - lon1
|
| 238 |
+
h = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
|
| 239 |
+
km = 2 * 6371.0 * math.asin(math.sqrt(h))
|
| 240 |
+
return json.dumps({"from": city_a, "to": city_b, "distance_km": round(km, 1)})
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def get_population(city: str) -> str:
|
| 244 |
+
"""Approximate metro-area population (demo data, in millions)."""
|
| 245 |
+
data = {
|
| 246 |
+
"gandhinagar": 0.36, "mumbai": 20.96, "delhi": 32.07, "bangalore": 13.61,
|
| 247 |
+
"chennai": 11.56, "kolkata": 15.33, "hyderabad": 10.53, "pune": 6.81,
|
| 248 |
+
"tokyo": 37.44, "seoul": 9.97, "singapore": 5.94, "hong kong": 7.49,
|
| 249 |
+
"london": 9.54, "paris": 11.21, "new york": 18.87, "san francisco": 3.32,
|
| 250 |
+
"sydney": 5.37,
|
| 251 |
+
}
|
| 252 |
+
v = data.get(city.lower().strip())
|
| 253 |
+
if v is None:
|
| 254 |
+
return json.dumps({"error": f"No population data for {city}"})
|
| 255 |
+
return json.dumps({"city": city, "population_millions": v})
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def get_stock_price(ticker: str) -> str:
|
| 259 |
+
"""Mock share price in USD for a handful of tickers."""
|
| 260 |
+
prices = {
|
| 261 |
+
"aapl": 228.45, "msft": 417.12, "googl": 178.32, "amzn": 212.91,
|
| 262 |
+
"meta": 574.80, "tsla": 249.07, "nvda": 135.60, "amd": 162.33,
|
| 263 |
+
"ibm": 224.18, "intc": 21.40, "nflx": 745.20, "orcl": 176.55,
|
| 264 |
+
}
|
| 265 |
+
p = prices.get(ticker.lower().strip())
|
| 266 |
+
if p is None:
|
| 267 |
+
return json.dumps({"error": f"Unknown ticker '{ticker}'. Try: {sorted(prices.keys())}"})
|
| 268 |
+
return json.dumps({"ticker": ticker.upper(), "price_usd": p, "note": "demo price, not live market data"})
|
| 269 |
+
|
| 270 |
+
|
| 271 |
def define_word(word: str) -> str:
|
| 272 |
definitions = {
|
| 273 |
"overfitting": "When a model learns training data too well (including noise) and performs poorly on new data.",
|
|
|
|
| 378 |
},
|
| 379 |
},
|
| 380 |
},
|
| 381 |
+
{
|
| 382 |
+
"type": "function",
|
| 383 |
+
"function": {
|
| 384 |
+
"name": "get_distance",
|
| 385 |
+
"description": "Great-circle distance in kilometres between two cities. Supports major Indian and global cities (Gandhinagar, Mumbai, Delhi, Bangalore, Chennai, Kolkata, Hyderabad, Pune, Tokyo, Seoul, Singapore, Hong Kong, London, Paris, New York, San Francisco, Sydney).",
|
| 386 |
+
"parameters": {
|
| 387 |
+
"type": "object",
|
| 388 |
+
"properties": {
|
| 389 |
+
"city_a": {"type": "string", "description": "First city, e.g. 'Delhi'"},
|
| 390 |
+
"city_b": {"type": "string", "description": "Second city, e.g. 'Mumbai'"},
|
| 391 |
+
},
|
| 392 |
+
"required": ["city_a", "city_b"],
|
| 393 |
+
},
|
| 394 |
+
},
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"type": "function",
|
| 398 |
+
"function": {
|
| 399 |
+
"name": "get_population",
|
| 400 |
+
"description": "Approximate metro-area population (in millions). Same city list as get_distance.",
|
| 401 |
+
"parameters": {
|
| 402 |
+
"type": "object",
|
| 403 |
+
"properties": {"city": {"type": "string", "description": "City name"}},
|
| 404 |
+
"required": ["city"],
|
| 405 |
+
},
|
| 406 |
+
},
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"type": "function",
|
| 410 |
+
"function": {
|
| 411 |
+
"name": "get_stock_price",
|
| 412 |
+
"description": "Current share price in USD for a handful of tickers (AAPL, MSFT, GOOGL, AMZN, META, TSLA, NVDA, AMD, IBM, INTC, NFLX, ORCL).",
|
| 413 |
+
"parameters": {
|
| 414 |
+
"type": "object",
|
| 415 |
+
"properties": {"ticker": {"type": "string", "description": "Ticker symbol, e.g. 'AAPL'"}},
|
| 416 |
+
"required": ["ticker"],
|
| 417 |
+
},
|
| 418 |
+
},
|
| 419 |
+
},
|
| 420 |
]
|
| 421 |
|
| 422 |
TOOL_FUNCTIONS = {
|
|
|
|
| 427 |
"define_word": define_word,
|
| 428 |
"get_time": get_time,
|
| 429 |
"get_exchange_rate": get_exchange_rate,
|
| 430 |
+
"get_distance": get_distance,
|
| 431 |
+
"get_population": get_population,
|
| 432 |
+
"get_stock_price": get_stock_price,
|
| 433 |
}
|
| 434 |
|
| 435 |
|
|
|
|
| 802 |
<text x="180" y="330" text-anchor="middle" font-size="10" fill="#5a6070">(may hallucinate)</text>
|
| 803 |
</g>
|
| 804 |
|
| 805 |
+
<!-- ============ RIGHT COLUMN (x=380..880) ============ -->
|
| 806 |
<g font-size="13" fill="#1a1a2e">
|
| 807 |
+
<rect x="550" y="90" width="160" height="40" rx="4" fill="#faf7f2" stroke="#ddd"/>
|
| 808 |
+
<text x="630" y="115" text-anchor="middle">User question</text>
|
| 809 |
+
<path d="M630 130 L630 178" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
|
| 810 |
|
| 811 |
+
<rect x="535" y="180" width="190" height="42" rx="4" fill="#fff" stroke="#c44536" stroke-width="1.5"/>
|
| 812 |
+
<text x="630" y="206" text-anchor="middle" fill="#c44536" font-weight="500">LLM + tool menu</text>
|
| 813 |
+
<path d="M630 222 L630 268" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
|
| 814 |
|
| 815 |
<!-- Diamond decision -->
|
| 816 |
+
<polygon points="630,270 720,315 630,360 540,315" fill="#fff" stroke="#c44536" stroke-width="1.5"/>
|
| 817 |
+
<text x="630" y="311" text-anchor="middle" font-size="12" fill="#c44536" font-weight="500">Tool call</text>
|
| 818 |
+
<text x="630" y="327" text-anchor="middle" font-size="12" fill="#c44536" font-weight="500">needed?</text>
|
| 819 |
|
| 820 |
+
<!-- NO branch: left + down. Final-answer box must stay inside the column (x >= 380). -->
|
| 821 |
+
<path d="M540 315 L480 315 L480 405" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
|
| 822 |
+
<text x="495" y="308" font-size="11" fill="#5a6070" font-weight="600">NO</text>
|
| 823 |
+
<rect x="410" y="407" width="140" height="56" rx="4" fill="#fff" stroke="#c44536"/>
|
| 824 |
+
<text x="480" y="430" text-anchor="middle">Final answer</text>
|
| 825 |
+
<text x="480" y="447" text-anchor="middle" font-size="10" fill="#5a6070">(grounded in data)</text>
|
| 826 |
|
| 827 |
<!-- YES branch: right + down -->
|
| 828 |
+
<path d="M720 315 L780 315 L780 397" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
|
| 829 |
+
<text x="737" y="308" font-size="11" fill="#5a6070" font-weight="600">YES</text>
|
| 830 |
|
| 831 |
+
<rect x="710" y="400" width="140" height="38" rx="4" fill="#faf7f2" stroke="#ddd"/>
|
| 832 |
+
<text x="780" y="423" text-anchor="middle">Run tool</text>
|
| 833 |
+
<path d="M780 438 L780 468" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
|
| 834 |
|
| 835 |
+
<rect x="710" y="470" width="140" height="38" rx="4" fill="#faf7f2" stroke="#ddd"/>
|
| 836 |
+
<text x="780" y="493" text-anchor="middle">Append result</text>
|
| 837 |
|
| 838 |
+
<!-- Loop back: dashed red, routed along the right edge (x=860, inside right column x=880). -->
|
| 839 |
+
<path d="M780 508 L780 560 L860 560 L860 155 L630 155 L630 176"
|
| 840 |
stroke="#c44536" stroke-width="1.5" fill="none"
|
| 841 |
stroke-dasharray="5 3" marker-end="url(#arrr)"/>
|
| 842 |
+
<text x="790" y="553" font-size="11" fill="#c44536" font-style="italic">loop back to LLM</text>
|
| 843 |
</g>
|
| 844 |
</svg>
|
| 845 |
</div>
|
|
|
|
| 1042 |
# --- UI ------------------------------------------------------------------
|
| 1043 |
|
| 1044 |
EXAMPLES = [
|
| 1045 |
+
# --- Hard arithmetic (plain LLMs routinely get these wrong) ---
|
| 1046 |
"What is 4729 times 8314?",
|
| 1047 |
"Compute (127 ** 3) + (49 ** 4).",
|
| 1048 |
"What is 31.5% of 128,400?",
|
|
|
|
| 1049 |
"Evaluate 2847 * 9183 - 17^5.",
|
| 1050 |
+
# --- Single-tool: real-time / local data ---
|
| 1051 |
"What's the temperature in Gandhinagar in Fahrenheit?",
|
| 1052 |
"What time is it in Tokyo right now?",
|
| 1053 |
+
"What's the current price of NVDA?",
|
| 1054 |
+
# --- Two-tool chains ---
|
| 1055 |
"How much hotter is Delhi than Bangalore right now, in degrees Celsius?",
|
| 1056 |
"If I run 5 km every day for a week, how many miles is that total?",
|
| 1057 |
"I have 1000 USD. How much is that in INR, and what time is it in Delhi?",
|
| 1058 |
+
# --- Three-tool chains (real compositional reasoning) ---
|
| 1059 |
+
"What's the distance from Delhi to Mumbai in miles, rounded to the nearest 10?",
|
| 1060 |
+
"If Apple stock is $X, how many whole AAPL shares can I buy with 5000 INR? Convert first, then tell me.",
|
| 1061 |
+
"Mumbai's population density if its metro area is 603 sq km — and how does that compare to Delhi's metro at 1484 sq km?",
|
| 1062 |
"I earn 2500 EUR/month. After converting to INR, what is my annual salary?",
|
| 1063 |
+
"Convert the distance from London to New York to kilometres, then tell me how long it would take at 900 km/h.",
|
| 1064 |
+
# --- Four-tool / open-ended chain ---
|
| 1065 |
+
"I want to video-call a colleague in Tokyo at 9 AM their time. What time is that in Delhi, and roughly how far apart are the two cities?",
|
| 1066 |
+
"If Paris is 18 C and New York is 22 C, what's the average in Fahrenheit?",
|
| 1067 |
# --- Course knowledge base ---
|
| 1068 |
"Which week of CS 203 covered Docker?",
|
| 1069 |
"What does 'overfitting' mean?",
|