FlyingNunchucks commited on
Commit
c47cb60
·
verified ·
1 Parent(s): ff6ead7

Sync from GitHub via hub-sync

Browse files
Files changed (1) hide show
  1. app.py +201 -96
app.py CHANGED
@@ -2,9 +2,21 @@ from typing import Any, Dict, List
2
 
3
  import gradio as gr
4
 
5
- from src.agent import run_agent
6
  from src.audit import read_audit_records
7
- from src.tool_registry import list_tools
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
 
10
  def get_run_audit_records(
@@ -29,12 +41,8 @@ def get_run_audit_records(
29
  ]
30
 
31
 
32
- def handle_request(
33
- user_request: str,
34
- ):
35
- """
36
- Run the agent and return user-facing execution details.
37
- """
38
 
39
  if not user_request or not user_request.strip():
40
  return (
@@ -45,34 +53,26 @@ def handle_request(
45
  )
46
 
47
  try:
48
- result = run_agent(
49
- user_request.strip()
50
- )
51
 
52
  tool_calls = [
53
  call.model_dump(mode="json")
54
  for call in result.tool_calls
55
  ]
56
-
57
  tool_results = [
58
  tool_result.model_dump(mode="json")
59
  for tool_result in result.tool_results
60
  ]
61
-
62
  call_ids = [
63
  call.call_id
64
  for call in result.tool_calls
65
  ]
66
 
67
- audit_records = get_run_audit_records(
68
- call_ids
69
- )
70
-
71
  return (
72
  result.final_answer,
73
  tool_calls,
74
  tool_results,
75
- audit_records,
76
  )
77
 
78
  except Exception:
@@ -87,106 +87,211 @@ def handle_request(
87
  )
88
 
89
 
90
- APP_DESCRIPTION = """
91
- # Tool-Using Operations Agent
92
 
93
- A controlled AI agent that selects and executes approved tools through a
94
- validated execution layer.
 
95
 
96
- The language model **proposes** tool calls. Application code decides what
97
- tools exist, validates their arguments, executes them, captures failures,
98
- and records an audit trail.
99
 
100
- ### Available tools
101
 
102
- - **calculator** — deterministic arithmetic
103
- - **search_inventory** — constrained SQLite inventory search
104
- - **lookup_country** — structured World Bank country lookup
105
 
106
- Try a single-tool request or a request that requires multiple tools.
107
- """
 
108
 
 
109
 
110
- with gr.Blocks(
111
- title="Tool-Using Operations Agent",
112
- ) as demo:
113
-
114
- gr.Markdown(APP_DESCRIPTION)
115
 
116
- with gr.Row():
117
- request_box = gr.Textbox(
118
- label="Request",
119
- placeholder=(
120
- "Example: How many Electronics items are "
121
- "in inventory, and what is 347 multiplied "
122
- "by that number?"
123
- ),
124
- lines=3,
125
- )
 
 
 
 
 
 
 
126
 
127
- run_button = gr.Button(
128
- "Run Agent",
129
- variant="primary",
 
130
  )
131
 
132
- gr.Examples(
133
- examples=[
134
- [
135
- "What is 347 multiplied by 29?"
136
- ],
137
- [
138
- "What electronics are currently in inventory?"
139
- ],
140
- [
141
- "What is the capital, region, and income level of Japan?"
142
- ],
143
- [
144
- (
145
- "How many Electronics items are in inventory, "
146
- "and what is 347 multiplied by that number?"
147
- )
148
- ],
149
- ],
150
- inputs=request_box,
151
  )
152
 
153
- gr.Markdown("## Agent Response")
154
 
155
- final_answer = gr.Textbox(
156
- label="Final Answer",
157
- lines=5,
158
- interactive=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  )
160
 
161
- with gr.Row():
162
- tool_calls_output = gr.JSON(
163
- label="Tool Calls",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  )
 
165
 
166
- tool_results_output = gr.JSON(
167
- label="Tool Results",
 
 
 
 
 
 
 
168
  )
169
 
170
- gr.Markdown(
171
- "## Current Run Audit Trail\n"
172
- "Only tool executions generated by this request are shown."
173
- )
174
 
175
- audit_output = gr.JSON(
176
- label="Audit Records",
177
- )
 
 
178
 
179
- run_button.click(
180
- fn=handle_request,
181
- inputs=request_box,
182
- outputs=[
183
- final_answer,
184
- tool_calls_output,
185
- tool_results_output,
186
- audit_output,
187
- ],
188
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
 
191
  if __name__ == "__main__":
192
- demo.launch()
 
2
 
3
  import gradio as gr
4
 
5
+ from src.agent import run_agent, run_agent_iter
6
  from src.audit import read_audit_records
7
+ from src.demo_presentation import (
8
+ APP_CSS,
9
+ ARCHITECTURE_MARKDOWN,
10
+ AUTHORITY_HTML,
11
+ BUSINESS_CASE_HTML,
12
+ HERO_HTML,
13
+ SECURITY_MARKDOWN,
14
+ TOOL_BELT_HTML,
15
+ render_activity,
16
+ render_summary,
17
+ starting_activity_html,
18
+ )
19
+ from src.schemas import AgentRunEvent, AgentRunResult
20
 
21
 
22
  def get_run_audit_records(
 
41
  ]
42
 
43
 
44
+ def handle_request(user_request: str):
45
+ """Preserve the original programmatic callback contract."""
 
 
 
 
46
 
47
  if not user_request or not user_request.strip():
48
  return (
 
53
  )
54
 
55
  try:
56
+ result = run_agent(user_request.strip())
 
 
57
 
58
  tool_calls = [
59
  call.model_dump(mode="json")
60
  for call in result.tool_calls
61
  ]
 
62
  tool_results = [
63
  tool_result.model_dump(mode="json")
64
  for tool_result in result.tool_results
65
  ]
 
66
  call_ids = [
67
  call.call_id
68
  for call in result.tool_calls
69
  ]
70
 
 
 
 
 
71
  return (
72
  result.final_answer,
73
  tool_calls,
74
  tool_results,
75
+ get_run_audit_records(call_ids),
76
  )
77
 
78
  except Exception:
 
87
  )
88
 
89
 
90
+ def _current_calls(events: list[AgentRunEvent]) -> list[Dict[str, Any]]:
91
+ calls: dict[str, Dict[str, Any]] = {}
92
 
93
+ for event in events:
94
+ if event.call is not None:
95
+ calls[event.call.call_id] = event.call.model_dump(mode="json")
96
 
97
+ return list(calls.values())
 
 
98
 
 
99
 
100
+ def _current_results(events: list[AgentRunEvent]) -> list[Dict[str, Any]]:
101
+ results: dict[str, Dict[str, Any]] = {}
 
102
 
103
+ for event in events:
104
+ if event.result is not None:
105
+ results[event.result.call_id] = event.result.model_dump(mode="json")
106
 
107
+ return list(results.values())
108
 
 
 
 
 
 
109
 
110
+ def _stream_outputs(
111
+ events: list[AgentRunEvent],
112
+ final_result: AgentRunResult | None = None,
113
+ complete: bool = False,
114
+ ):
115
+ calls = (
116
+ [call.model_dump(mode="json") for call in final_result.tool_calls]
117
+ if final_result is not None
118
+ else _current_calls(events)
119
+ )
120
+ results = (
121
+ [result.model_dump(mode="json") for result in final_result.tool_results]
122
+ if final_result is not None
123
+ else _current_results(events)
124
+ )
125
+ call_ids = [call["call_id"] for call in calls]
126
+ audits = get_run_audit_records(call_ids) if complete else []
127
 
128
+ answer = (
129
+ final_result.final_answer
130
+ if final_result is not None
131
+ else "*The final business answer will appear after controlled execution completes.*"
132
  )
133
 
134
+ return (
135
+ render_activity(events, complete=complete),
136
+ answer,
137
+ render_summary(final_result),
138
+ calls,
139
+ results,
140
+ audits,
 
 
 
 
 
 
 
 
 
 
 
 
141
  )
142
 
 
143
 
144
+ def stream_request(user_request: str):
145
+ """Stream real model/application boundary events into the Gradio demo."""
146
+
147
+ if not user_request or not user_request.strip():
148
+ yield (
149
+ render_activity([], complete=True),
150
+ "Please enter a request.",
151
+ render_summary(None),
152
+ [],
153
+ [],
154
+ [],
155
+ )
156
+ return
157
+
158
+ events: list[AgentRunEvent] = []
159
+
160
+ yield (
161
+ starting_activity_html(),
162
+ "*The final business answer will appear after controlled execution completes.*",
163
+ render_summary(None),
164
+ [],
165
+ [],
166
+ [],
167
  )
168
 
169
+ try:
170
+ for event in run_agent_iter(user_request.strip()):
171
+ events.append(event)
172
+ final_result = event.final_result
173
+ complete = final_result is not None
174
+
175
+ yield _stream_outputs(
176
+ events=events,
177
+ final_result=final_result,
178
+ complete=complete,
179
+ )
180
+
181
+ except Exception:
182
+ error_event = AgentRunEvent(
183
+ event="max_rounds_reached",
184
+ message=(
185
+ "The request could not complete. The application stopped the run "
186
+ "without exposing internal server details."
187
+ ),
188
  )
189
+ events.append(error_event)
190
 
191
+ yield (
192
+ render_activity(events, complete=True),
193
+ (
194
+ "Agent execution failed. Please review the server logs for details."
195
+ ),
196
+ render_summary(None),
197
+ _current_calls(events),
198
+ _current_results(events),
199
+ [],
200
  )
201
 
 
 
 
 
202
 
203
+ FLAGSHIP_REQUEST = (
204
+ "We may ship equipment to Japan. Find the Electronics items currently in "
205
+ "inventory, calculate an accessory budget of $347 per matching item, and "
206
+ "give me Japan's capital, region, and income classification."
207
+ )
208
 
209
+
210
+ with gr.Blocks(
211
+ title="Governed Tool-Using Agent",
212
+ css=APP_CSS,
213
+ ) as demo:
214
+ with gr.Column(elem_classes=["agent-shell"]):
215
+ gr.HTML(HERO_HTML)
216
+ gr.HTML(BUSINESS_CASE_HTML)
217
+
218
+ gr.Markdown("## The approved tool belt")
219
+ gr.HTML(TOOL_BELT_HTML)
220
+
221
+ gr.Markdown("## Who controls what?")
222
+ gr.HTML(AUTHORITY_HTML)
223
+
224
+ gr.Markdown("## Try a controlled business request")
225
+ request_box = gr.Textbox(
226
+ label="Operations request",
227
+ value=FLAGSHIP_REQUEST,
228
+ placeholder="Ask for work that may require one or more approved tools.",
229
+ lines=4,
230
+ )
231
+
232
+ gr.Examples(
233
+ examples=[
234
+ [FLAGSHIP_REQUEST],
235
+ ["What is 347 multiplied by 29?"],
236
+ ["What electronics are currently in inventory?"],
237
+ ["What is the capital, region, and income level of Japan?"],
238
+ [
239
+ (
240
+ "How many Electronics items are in inventory, "
241
+ "and what is 347 multiplied by that number?"
242
+ )
243
+ ],
244
+ ],
245
+ inputs=request_box,
246
+ )
247
+
248
+ run_button = gr.Button(
249
+ "Run controlled request",
250
+ variant="primary",
251
+ )
252
+
253
+ activity_output = gr.HTML(starting_activity_html())
254
+
255
+ with gr.Tabs():
256
+ with gr.Tab("Business Result"):
257
+ gr.Markdown(
258
+ "The answer below is produced only after requested capabilities "
259
+ "pass through the application-controlled boundary."
260
+ )
261
+ final_answer = gr.Markdown(
262
+ "*Run a request to produce a business answer.*"
263
+ )
264
+ summary_output = gr.HTML(render_summary(None))
265
+
266
+ with gr.Tab("Engineering Audit"):
267
+ gr.Markdown(
268
+ "These are the structured requests, normalized results, and "
269
+ "current-run audit records behind the business-facing view."
270
+ )
271
+ tool_calls_output = gr.JSON(label="Model-proposed Tool Calls")
272
+ tool_results_output = gr.JSON(label="Controlled Tool Results")
273
+ audit_output = gr.JSON(label="Current Run Audit Records")
274
+
275
+ with gr.Tab("Security & Failure Semantics"):
276
+ gr.Markdown(SECURITY_MARKDOWN)
277
+
278
+ with gr.Tab("Architecture"):
279
+ gr.Markdown(ARCHITECTURE_MARKDOWN)
280
+
281
+ run_button.click(
282
+ fn=stream_request,
283
+ inputs=request_box,
284
+ outputs=[
285
+ activity_output,
286
+ final_answer,
287
+ summary_output,
288
+ tool_calls_output,
289
+ tool_results_output,
290
+ audit_output,
291
+ ],
292
+ show_progress="hidden",
293
+ )
294
 
295
 
296
  if __name__ == "__main__":
297
+ demo.launch()