Nipun Claude Opus 4.6 (1M context) commited on
Commit
6af85e6
·
1 Parent(s): d3be733

Keep flowchart inside right-column bounds; add 3 tools + chained examples

Browse files

SVG 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>

Files changed (1) hide show
  1. app.py +151 -41
app.py CHANGED
@@ -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 or current time, call the matching
57
- tool (`get_weather`, `get_time`). Do not guess or say you don't know.
 
58
  3. For unit conversions, call `convert_units` — don't approximate.
59
  4. For currency conversion, call `get_exchange_rate`.
60
- 5. For questions about the CS 203 course ("what week did we cover X?"),
 
 
61
  call `search_notes`.
62
- 6. For definitions of CS / ML terms, call `define_word`.
63
- 7. Multi-step questions need multiple tool calls. Example:
64
- "5 km/day for a week in miles" → first `convert_units`, then
65
- `calculate` to multiply by 7.
66
- 8. After every tool result, decide: do I need another tool, or can I
 
 
 
67
  write the final answer? Only answer once you have ALL the numbers.
68
- 9. If the question genuinely doesn't need any tool (e.g. "capital of
69
- France"), answer directly.
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="500" y="90" width="160" height="40" rx="4" fill="#faf7f2" stroke="#ddd"/>
705
- <text x="580" y="115" text-anchor="middle">User question</text>
706
- <path d="M580 130 L580 178" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
707
 
708
- <rect x="485" y="180" width="190" height="42" rx="4" fill="#fff" stroke="#c44536" stroke-width="1.5"/>
709
- <text x="580" y="206" text-anchor="middle" fill="#c44536" font-weight="500">LLM + tool menu</text>
710
- <path d="M580 222 L580 268" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
711
 
712
  <!-- Diamond decision -->
713
- <polygon points="580,270 670,315 580,360 490,315" fill="#fff" stroke="#c44536" stroke-width="1.5"/>
714
- <text x="580" y="311" text-anchor="middle" font-size="12" fill="#c44536" font-weight="500">Tool call</text>
715
- <text x="580" y="327" text-anchor="middle" font-size="12" fill="#c44536" font-weight="500">needed?</text>
716
 
717
- <!-- NO branch: left + down -->
718
- <path d="M490 315 L430 315 L430 405" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
719
- <text x="445" y="308" font-size="11" fill="#5a6070" font-weight="600">NO</text>
720
- <rect x="350" y="407" width="160" height="56" rx="4" fill="#fff" stroke="#c44536"/>
721
- <text x="430" y="430" text-anchor="middle">Final answer</text>
722
- <text x="430" y="447" text-anchor="middle" font-size="10" fill="#5a6070">(grounded in data)</text>
723
 
724
  <!-- YES branch: right + down -->
725
- <path d="M670 315 L730 315 L730 397" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
726
- <text x="687" y="308" font-size="11" fill="#5a6070" font-weight="600">YES</text>
727
 
728
- <rect x="660" y="400" width="140" height="38" rx="4" fill="#faf7f2" stroke="#ddd"/>
729
- <text x="730" y="423" text-anchor="middle">Run tool</text>
730
- <path d="M730 438 L730 468" stroke="#5a6070" stroke-width="1.5" fill="none" marker-end="url(#arr)"/>
731
 
732
- <rect x="660" y="470" width="140" height="38" rx="4" fill="#faf7f2" stroke="#ddd"/>
733
- <text x="730" y="493" text-anchor="middle">Append result</text>
734
 
735
- <!-- Loop back: dashed red, around the right side -->
736
- <path d="M730 508 L730 560 L860 560 L860 155 L580 155 L580 176"
737
  stroke="#c44536" stroke-width="1.5" fill="none"
738
  stroke-dasharray="5 3" marker-end="url(#arrr)"/>
739
- <text x="745" y="553" font-size="11" fill="#c44536" font-style="italic">loop back to LLM</text>
740
  </g>
741
  </svg>
742
  </div>
@@ -939,21 +1042,28 @@ CUSTOM_CSS = """
939
  # --- UI ------------------------------------------------------------------
940
 
941
  EXAMPLES = [
942
- # --- Hard arithmetic plain LLMs routinely get these wrong ---
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
- # --- Multi-tool chains ---
 
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
- "If Paris is 18 C and New York is 22 C, what's the average in Fahrenheit?",
 
 
 
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?",