soprano-sdk 0.2.16__tar.gz → 0.2.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/PKG-INFO +1 -1
  2. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/concert_booking/concert_ticket_booking.yaml +30 -6
  3. soprano_sdk-0.2.17/examples/concert_booking/concert_tools.py +253 -0
  4. soprano_sdk-0.2.17/examples/concert_booking/example_runner.py +602 -0
  5. soprano_sdk-0.2.17/examples/concert_booking/tool.py +330 -0
  6. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/pyproject.toml +1 -1
  7. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/agents/adaptor.py +56 -10
  8. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/authenticators/mfa.py +42 -39
  9. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/validation/schema.py +1 -1
  10. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/validation/validator.py +0 -4
  11. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/.github/workflows/test_build_and_publish.yaml +0 -0
  12. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/.gitignore +0 -0
  13. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/.python-version +0 -0
  14. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/CLAUDE.md +0 -0
  15. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/LICENSE +0 -0
  16. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/README.md +0 -0
  17. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/concert_booking/__init__.py +0 -0
  18. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/concert_booking/booking_helpers.py +0 -0
  19. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/framework_example.yaml +0 -0
  20. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/greeting_functions.py +0 -0
  21. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/greeting_workflow.yaml +0 -0
  22. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/main.py +0 -0
  23. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/payment_async_functions.py +0 -0
  24. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/payment_async_workflow.yaml +0 -0
  25. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/persistence/README.md +0 -0
  26. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/persistence/conversation_based.py +0 -0
  27. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/persistence/entity_based.py +0 -0
  28. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/persistence/mongodb_demo.py +0 -0
  29. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/return_functions.py +0 -0
  30. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/return_workflow.yaml +0 -0
  31. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/structured_output_example.yaml +0 -0
  32. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/README.md +0 -0
  33. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/crewai_supervisor_ui.py +0 -0
  34. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/langgraph_supervisor_ui.py +0 -0
  35. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/tools/__init__.py +0 -0
  36. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/tools/crewai_tools.py +0 -0
  37. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/tools/langgraph_tools.py +0 -0
  38. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/supervisors/workflow_tools.py +0 -0
  39. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/test_payment_async.py +0 -0
  40. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/tools/__init__.py +0 -0
  41. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/tools/address.py +0 -0
  42. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/examples/validator.py +0 -0
  43. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/langgraph_demo.py +0 -0
  44. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/langgraph_selfloop_demo.py +0 -0
  45. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/langgraph_v.py +0 -0
  46. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/main.py +0 -0
  47. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/return_fsm.excalidraw +0 -0
  48. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/return_state_machine.png +0 -0
  49. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/legacy/ui.py +0 -0
  50. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/scripts/visualize_workflow.py +0 -0
  51. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/scripts/workflow_demo.py +0 -0
  52. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/scripts/workflow_demo_ui.py +0 -0
  53. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/__init__.py +0 -0
  54. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/agents/__init__.py +0 -0
  55. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/agents/factory.py +0 -0
  56. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/agents/structured_output.py +0 -0
  57. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/authenticators/__init__.py +0 -0
  58. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/core/__init__.py +0 -0
  59. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/core/constants.py +0 -0
  60. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/core/engine.py +0 -0
  61. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/core/rollback_strategies.py +0 -0
  62. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/core/state.py +0 -0
  63. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/engine.py +0 -0
  64. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/__init__.py +0 -0
  65. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/async_function.py +0 -0
  66. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/base.py +0 -0
  67. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/call_function.py +0 -0
  68. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/collect_input.py +0 -0
  69. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/nodes/factory.py +0 -0
  70. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/routing/__init__.py +0 -0
  71. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/routing/router.py +0 -0
  72. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/tools.py +0 -0
  73. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/__init__.py +0 -0
  74. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/function.py +0 -0
  75. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/logger.py +0 -0
  76. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/template.py +0 -0
  77. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/tool.py +0 -0
  78. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/utils/tracing.py +0 -0
  79. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/soprano_sdk/validation/__init__.py +0 -0
  80. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/debug_jinja2.py +0 -0
  81. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_adaptor_logging.py +0 -0
  82. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_agent_factory.py +0 -0
  83. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_async_function.py +0 -0
  84. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_collect_input_refactor.py +0 -0
  85. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_external_values.py +0 -0
  86. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_inputs_validation.py +0 -0
  87. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_jinja2_path.py +0 -0
  88. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_jinja2_standalone.py +0 -0
  89. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_mfa_scenarios.py +0 -0
  90. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_persistence.py +0 -0
  91. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_structured_output.py +0 -0
  92. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_transition_routing.py +0 -0
  93. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/tests/test_workflow_tool_context_update.py +0 -0
  94. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/todo.md +0 -0
  95. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/.eslintrc.cjs +0 -0
  96. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/.gitignore +0 -0
  97. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/README.md +0 -0
  98. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/index.html +0 -0
  99. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/package-lock.json +0 -0
  100. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/package.json +0 -0
  101. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/App.jsx +0 -0
  102. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/CustomNode.jsx +0 -0
  103. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/StepDetailsModal.jsx +0 -0
  104. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/WorkflowGraph.jsx +0 -0
  105. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/WorkflowInfoPanel.jsx +0 -0
  106. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/assets/react.svg +0 -0
  107. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/src/main.jsx +0 -0
  108. {soprano_sdk-0.2.16 → soprano_sdk-0.2.17}/workflow-visualizer/vite.config.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soprano-sdk
3
- Version: 0.2.16
3
+ Version: 0.2.17
4
4
  Summary: YAML-driven workflow engine with AI agent integration for building conversational SOPs
5
5
  Author: Arvind Thangamani
6
6
  License: MIT
@@ -1,6 +1,7 @@
1
1
  name: Concert Ticket Booking
2
2
  description: Manages concert ticket booking with seat selection, payment processing, and confirmation
3
3
  version: '1.0.0'
4
+ agent_framework: "crewai"
4
5
 
5
6
  data:
6
7
  - name: bearer_token
@@ -58,7 +59,6 @@ steps:
58
59
  max_attempts: 3
59
60
  agent:
60
61
  name: Customer Name Collector
61
- model: gpt-4o-mini
62
62
  initial_message: "Welcome to Concert Ticket Booking! Please provide your full name."
63
63
  instructions: >
64
64
  Extract the customer's full name from their message.
@@ -76,11 +76,19 @@ steps:
76
76
  max_attempts: 3
77
77
  agent:
78
78
  name: Concert Details Collector
79
- model: gpt-4o-mini
80
79
  initial_message: "Hi {{customer_name}}! Which concert would you like to attend? Please specify the concert name."
81
80
  instructions: >
82
81
  Extract concert name from the user's message.
82
+
83
+ IMPORTANT: Use the available tools to help the user:
84
+ - check_concert_availability: Check if a concert is available and get details
85
+ - search_venue_info: Get venue information
86
+
87
+ When user mentions a concert, check its availability first before proceeding.
83
88
  Return: CONCERT_CAPTURED: [concert_name] or CANCEL_REQUEST:
89
+ tools:
90
+ - check_concert_availability
91
+ - search_venue_info
84
92
  transitions:
85
93
  - next: collect_seat_preference
86
94
  pattern: "CONCERT_CAPTURED:"
@@ -116,11 +124,16 @@ steps:
116
124
  max_attempts: 3
117
125
  agent:
118
126
  name: Ticket Quantity Collector
119
- model: gpt-4o-mini
120
127
  initial_message: "How many {{seat_preference}} tickets would you like to book? (Maximum 8 per booking)"
121
128
  instructions: >
122
129
  Extract the number of tickets (1-8).
130
+
131
+ IMPORTANT: Use the calculate_total_price tool to show the user the total cost
132
+ when they specify a quantity. This helps them make an informed decision.
133
+
123
134
  Return: QUANTITY_CAPTURED: [ticket_quantity] or INVALID_QUANTITY:
135
+ tools:
136
+ - calculate_total_price
124
137
  transitions:
125
138
  - next: check_seat_availability
126
139
  pattern: "QUANTITY_CAPTURED:"
@@ -145,7 +158,6 @@ steps:
145
158
  max_attempts: 3
146
159
  agent:
147
160
  name: Alternative Seat Offer
148
- model: gpt-4o-mini
149
161
  initial_message: >
150
162
  Sorry {{customer_name}}, {{seat_preference}} seats are not available for {{concert_name}}.
151
163
  Would you like to try a different section?
@@ -187,7 +199,6 @@ steps:
187
199
  function: booking_helpers.send_confirmation
188
200
  output: confirmation_sent
189
201
  mfa:
190
- model: gpt-4o-mini
191
202
  type: REST
192
203
  payload:
193
204
  transactionType: SEND_TICKET_CONFIRMATION
@@ -203,7 +214,6 @@ steps:
203
214
  max_attempts: 3
204
215
  agent:
205
216
  name: Modification Request Collector
206
- model: gpt-4o-mini
207
217
  initial_message: >
208
218
  Booking confirmed for {{concert_name}}, {{customer_name}}!
209
219
  Reference: {{booking_reference}}
@@ -242,3 +252,17 @@ outcomes:
242
252
  - id: payment_failed
243
253
  type: failure
244
254
  message: "Payment failed. Please check your payment method and try again."
255
+
256
+ tool_config:
257
+ tools:
258
+ - name: check_concert_availability
259
+ description: Check if a concert is available for booking with dates and pricing
260
+ callable: concert_tools.check_concert_availability
261
+
262
+ - name: calculate_total_price
263
+ description: Calculate the total price for concert tickets with discounts
264
+ callable: concert_tools.calculate_total_price
265
+
266
+ - name: search_venue_info
267
+ description: Get detailed information about a concert venue
268
+ callable: concert_tools.search_venue_info
@@ -0,0 +1,253 @@
1
+ """
2
+ Concert booking tool functions for agent use
3
+ These functions are exposed as tools to AI agents in the workflow
4
+ """
5
+ from typing import Annotated, Any
6
+
7
+
8
+ def check_concert_availability(
9
+ concert_name: Annotated[str, "Name of the concert to check availability for"],
10
+ **state: Any
11
+ ) -> str:
12
+ """
13
+ Check if a concert is available for booking with dates and pricing.
14
+
15
+ Args:
16
+ concert_name: Name of the concert to check
17
+
18
+ Returns:
19
+ String with concert availability details including dates and venue
20
+ """
21
+ # Mock concert database
22
+ concerts = {
23
+ "Coldplay": {
24
+ "available": True,
25
+ "venue": "DY Patil Stadium, Mumbai",
26
+ "date": "2026-03-15",
27
+ "seats_left": 5000,
28
+ "genres": ["Rock", "Pop"]
29
+ },
30
+ "AR Rahman": {
31
+ "available": True,
32
+ "venue": "Jawaharlal Nehru Stadium, Delhi",
33
+ "date": "2026-04-20",
34
+ "seats_left": 3500,
35
+ "genres": ["Classical", "Bollywood"]
36
+ },
37
+ "Ed Sheeran": {
38
+ "available": True,
39
+ "venue": "Phoenix Marketcity, Chennai",
40
+ "date": "2026-05-10",
41
+ "seats_left": 2000,
42
+ "genres": ["Pop", "Folk"]
43
+ },
44
+ "Arijit Singh": {
45
+ "available": True,
46
+ "venue": "MMRDA Grounds, Mumbai",
47
+ "date": "2026-06-05",
48
+ "seats_left": 8000,
49
+ "genres": ["Bollywood", "Romantic"]
50
+ },
51
+ "Imagine Dragons": {
52
+ "available": False,
53
+ "venue": "Bangalore Palace Grounds",
54
+ "date": "2026-02-28",
55
+ "seats_left": 0,
56
+ "genres": ["Rock", "Alternative"]
57
+ }
58
+ }
59
+
60
+ # Check if concert exists
61
+ concert_name_normalized = concert_name.strip()
62
+
63
+ # Try exact match first
64
+ concert_info = concerts.get(concert_name_normalized)
65
+
66
+ # Try case-insensitive match
67
+ if not concert_info:
68
+ for name, info in concerts.items():
69
+ if name.lower() == concert_name_normalized.lower():
70
+ concert_info = info
71
+ concert_name_normalized = name
72
+ break
73
+
74
+ if not concert_info:
75
+ # Concert not found
76
+ available_concerts = ", ".join(concerts.keys())
77
+ return f"Sorry, '{concert_name}' is not in our system. Available concerts: {available_concerts}"
78
+
79
+ # Return availability information
80
+ if concert_info["available"]:
81
+ return (
82
+ f"✓ {concert_name_normalized} is AVAILABLE!\n"
83
+ f"Venue: {concert_info['venue']}\n"
84
+ f"Date: {concert_info['date']}\n"
85
+ f"Seats Available: {concert_info['seats_left']}\n"
86
+ f"Genres: {', '.join(concert_info['genres'])}"
87
+ )
88
+ else:
89
+ return (
90
+ f"✗ {concert_name_normalized} is SOLD OUT\n"
91
+ f"Venue: {concert_info['venue']}\n"
92
+ f"Original Date: {concert_info['date']}\n"
93
+ f"Check back later for additional dates!"
94
+ )
95
+
96
+
97
+ def calculate_total_price(
98
+ seat_preference: Annotated[str, "Seating section (VIP, Premium, or General)"],
99
+ ticket_quantity: Annotated[int, "Number of tickets to purchase"],
100
+ vip_price: Annotated[float, "Price per VIP ticket"],
101
+ premium_price: Annotated[float, "Price per Premium ticket"],
102
+ general_price: Annotated[float, "Price per General ticket"],
103
+ **state: Any
104
+
105
+ ) -> str:
106
+ """
107
+ Calculate the total price for concert tickets with discounts.
108
+
109
+ Args:
110
+ seat_preference: Seating section (VIP, Premium, General)
111
+ ticket_quantity: Number of tickets
112
+ vip_price: Price per VIP ticket
113
+ premium_price: Price per Premium ticket
114
+ general_price: Price per General ticket
115
+
116
+ Returns:
117
+ String with price breakdown and total
118
+ """
119
+ # Normalize seat preference
120
+ seat_preference = seat_preference.strip().title()
121
+
122
+ # Map seat preference to price
123
+ prices = {
124
+ 'VIP': vip_price,
125
+ 'Vip': vip_price,
126
+ 'Premium': premium_price,
127
+ 'General': general_price
128
+ }
129
+
130
+ price_per_ticket = prices.get(seat_preference, general_price)
131
+ subtotal = price_per_ticket * ticket_quantity
132
+
133
+ # Apply discounts based on quantity
134
+ discount = 0
135
+ discount_percent = 0
136
+
137
+ if ticket_quantity >= 5:
138
+ discount_percent = 10
139
+ discount = subtotal * 0.10
140
+ elif ticket_quantity >= 3:
141
+ discount_percent = 5
142
+ discount = subtotal * 0.05
143
+
144
+ total = subtotal - discount
145
+
146
+ # Build response
147
+ response = "💰 Price Breakdown:\n"
148
+ response += f" Seat Type: {seat_preference}\n"
149
+ response += f" Price per ticket: ₹{price_per_ticket:,.0f}\n"
150
+ response += f" Quantity: {ticket_quantity}\n"
151
+ response += f" Subtotal: ₹{subtotal:,.0f}\n"
152
+
153
+ if discount > 0:
154
+ response += f" Discount ({discount_percent}%): -₹{discount:,.0f}\n"
155
+ response += " ──────────────────\n"
156
+ response += f" TOTAL: ₹{total:,.0f} ✨"
157
+ else:
158
+ response += " ──────────────────\n"
159
+ response += f" TOTAL: ₹{total:,.0f}"
160
+
161
+ # Add discount tip if applicable
162
+ if ticket_quantity < 3:
163
+ response += "\n\n💡 Tip: Book 3+ tickets for 5% off, or 5+ for 10% off!"
164
+
165
+ return response
166
+
167
+
168
+ def search_venue_info(
169
+ venue_name: Annotated[str, "Name of the venue to search for"],
170
+ **state: Any
171
+ ) -> str:
172
+ """
173
+ Get detailed information about a concert venue.
174
+
175
+ Args:
176
+ venue_name: Name or partial name of the venue
177
+
178
+ Returns:
179
+ String with venue details including capacity, location, and facilities
180
+ """
181
+ # Mock venue database
182
+ venues = {
183
+ "DY Patil Stadium": {
184
+ "full_name": "DY Patil Stadium",
185
+ "location": "Navi Mumbai, Maharashtra",
186
+ "capacity": 55000,
187
+ "facilities": ["Parking", "Food Courts", "VIP Lounges", "Wheelchair Access"],
188
+ "transport": "Metro: Nerul Station (3km), Bus routes available",
189
+ "website": "www.dypstadium.com"
190
+ },
191
+ "Jawaharlal Nehru Stadium": {
192
+ "full_name": "Jawaharlal Nehru Stadium",
193
+ "location": "Delhi",
194
+ "capacity": 60000,
195
+ "facilities": ["Parking", "Metro Connectivity", "Multiple Entry Gates", "Food Stalls"],
196
+ "transport": "Metro: Jawaharlal Nehru Stadium (direct), Well connected by roads",
197
+ "website": "www.jnstadium.in"
198
+ },
199
+ "Phoenix Marketcity": {
200
+ "full_name": "Phoenix Marketcity Arena",
201
+ "location": "Chennai, Tamil Nadu",
202
+ "capacity": 15000,
203
+ "facilities": ["Mall Complex", "Restaurants", "Parking", "AC Indoor Arena"],
204
+ "transport": "Bus: Multiple routes, Taxi/App cabs recommended",
205
+ "website": "www.phoenixmarketcity.com"
206
+ },
207
+ "MMRDA Grounds": {
208
+ "full_name": "MMRDA Grounds (Bandra-Kurla Complex)",
209
+ "location": "Mumbai, Maharashtra",
210
+ "capacity": 45000,
211
+ "facilities": ["Open Air Venue", "Multiple Stages", "Food Trucks", "Parking"],
212
+ "transport": "Metro: BKC Station (walkable), Well connected by roads",
213
+ "website": "www.mmrdagrounds.com"
214
+ },
215
+ "Bangalore Palace Grounds": {
216
+ "full_name": "Bangalore Palace Grounds",
217
+ "location": "Bangalore, Karnataka",
218
+ "capacity": 50000,
219
+ "facilities": ["Historic Venue", "Spacious Grounds", "Parking", "Food Courts"],
220
+ "transport": "Metro: Sampige Road (2km), Easily accessible by cab",
221
+ "website": "www.bangalorepalace.gov.in"
222
+ }
223
+ }
224
+
225
+ # Normalize search query
226
+ venue_name_normalized = venue_name.strip()
227
+
228
+ # Try exact match
229
+ venue_info = venues.get(venue_name_normalized)
230
+
231
+ # Try case-insensitive partial match
232
+ if not venue_info:
233
+ for name, info in venues.items():
234
+ if venue_name_normalized.lower() in name.lower():
235
+ venue_info = info
236
+ break
237
+
238
+ if not venue_info:
239
+ # Venue not found
240
+ available_venues = ", ".join(venues.keys())
241
+ return f"Venue '{venue_name}' not found. Available venues: {available_venues}"
242
+
243
+ # Build detailed response
244
+ response = f"📍 {venue_info['full_name']}\n\n"
245
+ response += f"Location: {venue_info['location']}\n"
246
+ response += f"Capacity: {venue_info['capacity']:,} people\n\n"
247
+ response += "Facilities:\n"
248
+ for facility in venue_info['facilities']:
249
+ response += f" • {facility}\n"
250
+ response += f"\nTransport: {venue_info['transport']}\n"
251
+ response += f"Website: {venue_info['website']}"
252
+
253
+ return response