mindbomber commited on
Commit
b64b75a
·
verified ·
1 Parent(s): cc31b8b

Add Try AANA two-minute demo

Browse files
Files changed (3) hide show
  1. README.md +15 -5
  2. __pycache__/app.cpython-313.pyc +0 -0
  3. app.py +168 -21
README.md CHANGED
@@ -1,4 +1,4 @@
1
- # AANA Agent Action Contract v1 Space
2
 
3
  This local Hugging Face Space artifact is the repo-owned source for the public
4
  "try AANA" demo. It accepts the frozen Agent Action Contract v1 fields and
@@ -28,10 +28,20 @@ Frozen required fields:
28
  - `proposed_arguments`
29
  - `recommended_route`
30
 
31
- The Space should call `aana.check_tool_call` with these fields and display
32
- `accept`, `ask`, `defer`, or `refuse` along with AIx score, hard blockers,
33
- evidence refs, authorization state, recovery guidance, and an audit-safe log
34
- event.
 
 
 
 
 
 
 
 
 
 
35
 
36
  Public evidence links:
37
 
 
1
+ # Try AANA In 2 Minutes
2
 
3
  This local Hugging Face Space artifact is the repo-owned source for the public
4
  "try AANA" demo. It accepts the frozen Agent Action Contract v1 fields and
 
28
  - `proposed_arguments`
29
  - `recommended_route`
30
 
31
+ The Space calls `aana.check_tool_call` with these fields and displays:
32
+
33
+ - route: `accept`, `ask`, `defer`, or `refuse`
34
+ - AIx score
35
+ - hard blockers
36
+ - missing evidence
37
+ - authorization state
38
+ - recovery guidance
39
+ - audit-safe log event
40
+ - blocked-tool non-execution proof from a synthetic executor
41
+
42
+ The synthetic executor is intentionally safe: it records that it would have run
43
+ only when AANA returns `accept`. It cannot send, delete, purchase, deploy,
44
+ export, or access private data.
45
 
46
  Public evidence links:
47
 
__pycache__/app.cpython-313.pyc CHANGED
Binary files a/__pycache__/app.cpython-313.pyc and b/__pycache__/app.cpython-313.pyc differ
 
app.py CHANGED
@@ -1,4 +1,4 @@
1
- """Minimal Hugging Face Space demo for AANA Agent Action Contract v1.
2
 
3
  The public Space surface must keep accepting these seven frozen fields:
4
  tool_name, tool_category, authorization_state, evidence_refs, risk_domain,
@@ -7,48 +7,195 @@ proposed_arguments, and recommended_route.
7
 
8
  from __future__ import annotations
9
 
 
10
  import json
 
11
 
12
  import aana
13
 
14
 
15
- EXAMPLE_EVENT = {
16
- "tool_name": "send_email",
17
- "tool_category": "write",
18
- "authorization_state": "user_claimed",
19
- "evidence_refs": ["draft_id:123"],
20
- "risk_domain": "customer_support",
21
- "proposed_arguments": {"to": "customer@example.com"},
22
- "recommended_route": "accept",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  def check_json_event(event_json: str) -> str:
27
- """Return a pretty AANA decision for a pasted contract event."""
28
 
29
- payload = json.loads(event_json)
30
- result = aana.check_tool_call(payload)
31
- return json.dumps(result, indent=2, sort_keys=True)
32
 
33
 
34
  def build_demo():
35
- """Build the optional Gradio UI only when the Space runtime imports it."""
36
 
37
  import gradio as gr
38
 
39
  with gr.Blocks(title="Try AANA") as demo:
40
- gr.Markdown("# AANA Agent Action Contract v1")
 
41
  gr.Markdown(
42
- "AANA is a pre-action control layer for AI agents: agents propose actions, "
43
- "AANA checks evidence/auth/risk, and tools execute only when the route is accept."
 
 
 
 
 
 
 
44
  )
45
  event = gr.Code(
46
- value=json.dumps(EXAMPLE_EVENT, indent=2),
47
  language="json",
48
- label="Agent Action Contract v1 event",
49
  )
50
- output = gr.Code(language="json", label="AANA decision")
51
- gr.Button("Check tool call").click(check_json_event, inputs=event, outputs=output)
 
 
 
 
 
 
 
 
52
  return demo
53
 
54
 
 
1
+ """Canonical public "Try AANA in 2 minutes" Hugging Face Space.
2
 
3
  The public Space surface must keep accepting these seven frozen fields:
4
  tool_name, tool_category, authorization_state, evidence_refs, risk_domain,
 
7
 
8
  from __future__ import annotations
9
 
10
+ import copy
11
  import json
12
+ from typing import Any
13
 
14
  import aana
15
 
16
 
17
+ PUBLIC_MESSAGE = (
18
+ "AANA is a pre-action control layer for AI agents: agents propose actions, "
19
+ "AANA checks evidence/auth/risk, and tools execute only when the route is accept."
20
+ )
21
+
22
+ EXAMPLE_EVENTS: dict[str, dict[str, Any]] = {
23
+ "Accept: confirmed support email": {
24
+ "tool_name": "send_email",
25
+ "tool_category": "write",
26
+ "authorization_state": "confirmed",
27
+ "evidence_refs": ["user_confirmed_send_email", "draft_id:123"],
28
+ "risk_domain": "customer_support",
29
+ "proposed_arguments": {"to": "customer@example.com"},
30
+ "recommended_route": "accept",
31
+ },
32
+ "Ask: write missing confirmation": {
33
+ "tool_name": "send_email",
34
+ "tool_category": "write",
35
+ "authorization_state": "user_claimed",
36
+ "evidence_refs": ["draft_id:123"],
37
+ "risk_domain": "customer_support",
38
+ "proposed_arguments": {"to": "customer@example.com"},
39
+ "recommended_route": "accept",
40
+ },
41
+ "Defer: private read missing auth": {
42
+ "tool_name": "get_recent_transactions",
43
+ "tool_category": "private_read",
44
+ "authorization_state": "none",
45
+ "evidence_refs": [],
46
+ "risk_domain": "finance",
47
+ "proposed_arguments": {"account_id": "acct_redacted", "limit": 5},
48
+ "recommended_route": "accept",
49
+ },
50
+ "Refuse: unknown destructive tool": {
51
+ "tool_name": "delete_database",
52
+ "tool_category": "unknown",
53
+ "authorization_state": "none",
54
+ "evidence_refs": [],
55
+ "risk_domain": "unknown",
56
+ "proposed_arguments": {"database": "prod"},
57
+ "recommended_route": "refuse",
58
+ },
59
  }
60
 
61
 
62
+ def example_event(name: str) -> str:
63
+ """Return a formatted example event for a scenario button/dropdown."""
64
+
65
+ return json.dumps(copy.deepcopy(EXAMPLE_EVENTS[name]), indent=2, sort_keys=True)
66
+
67
+
68
+ def _decision(result: dict[str, Any]) -> dict[str, Any]:
69
+ architecture = result.get("architecture_decision")
70
+ return architecture if isinstance(architecture, dict) else result
71
+
72
+
73
+ def _route(result: dict[str, Any]) -> str:
74
+ decision = _decision(result)
75
+ return str(decision.get("route") or result.get("route") or result.get("recommended_action") or "defer")
76
+
77
+
78
+ def _synthetic_tool(event: dict[str, Any]) -> dict[str, Any]:
79
+ """Synthetic-only executor used to prove blocked tools do not run."""
80
+
81
+ return {
82
+ "synthetic_tool_executed": True,
83
+ "tool_name": event.get("tool_name"),
84
+ "argument_keys": sorted((event.get("proposed_arguments") or {}).keys()),
85
+ "side_effects": "none_public_demo_only",
86
+ }
87
+
88
+
89
+ def guarded_synthetic_execution(event: dict[str, Any], result: dict[str, Any]) -> dict[str, Any]:
90
+ """Run the synthetic tool only when AANA returns accept."""
91
+
92
+ route = _route(result)
93
+ proof = {
94
+ "required_route": "accept",
95
+ "aana_route": route,
96
+ "blocked_tool_non_execution_proven": route != "accept",
97
+ "synthetic_executor_call_count_before": 0,
98
+ "synthetic_executor_call_count_after": 0,
99
+ "synthetic_executor_result": None,
100
+ }
101
+ if route == "accept":
102
+ proof["synthetic_executor_result"] = _synthetic_tool(event)
103
+ proof["synthetic_executor_call_count_after"] = 1
104
+ proof["blocked_tool_non_execution_proven"] = False
105
+ return proof
106
+
107
+
108
+ def summarize_decision(event: dict[str, Any], result: dict[str, Any], execution_proof: dict[str, Any]) -> dict[str, Any]:
109
+ """Extract the reviewer-facing fields from the full AANA result."""
110
+
111
+ decision = _decision(result)
112
+ evidence_refs = decision.get("evidence_refs") if isinstance(decision.get("evidence_refs"), dict) else {}
113
+ audit_event = decision.get("audit_safe_log_event") or decision.get("audit_event") or {}
114
+ return {
115
+ "route": decision.get("route") or result.get("route"),
116
+ "aix_score": decision.get("aix_score") or (result.get("aix") or {}).get("score"),
117
+ "hard_blockers": decision.get("hard_blockers") or result.get("hard_blockers") or [],
118
+ "missing_evidence": decision.get("missing_evidence") or evidence_refs.get("missing") or [],
119
+ "authorization_state": decision.get("authorization_state") or event.get("authorization_state"),
120
+ "recovery_suggestion": decision.get("correction_recovery_suggestion") or decision.get("recovery_suggestion"),
121
+ "audit_safe_log_event": audit_event,
122
+ "execution_allowed": _route(result) == "accept",
123
+ "synthetic_executor_call_count_after": execution_proof["synthetic_executor_call_count_after"],
124
+ "blocked_tool_non_execution_proven": execution_proof["blocked_tool_non_execution_proven"],
125
+ }
126
+
127
+
128
+ def check_event(event_json: str) -> tuple[str, str, str, str]:
129
+ """Check a pasted tool-call event and return Gradio-friendly outputs."""
130
+
131
+ event = json.loads(event_json)
132
+ result = aana.check_tool_call(event)
133
+ execution_proof = guarded_synthetic_execution(event, result)
134
+ summary = summarize_decision(event, result, execution_proof)
135
+ route = str(summary["route"])
136
+ proof_line = (
137
+ "Synthetic executor did not run because AANA did not return accept."
138
+ if route != "accept"
139
+ else "Synthetic executor ran because AANA returned accept."
140
+ )
141
+ markdown = "\n".join(
142
+ [
143
+ f"## Route: `{route}`",
144
+ f"- AIx score: `{summary['aix_score']}`",
145
+ f"- Authorization state: `{summary['authorization_state']}`",
146
+ f"- Hard blockers: `{summary['hard_blockers'] or ['none']}`",
147
+ f"- Missing evidence: `{summary['missing_evidence'] or ['none']}`",
148
+ f"- Execution proof: {proof_line}",
149
+ ]
150
+ )
151
+ return (
152
+ markdown,
153
+ json.dumps(summary, indent=2, sort_keys=True),
154
+ json.dumps(execution_proof, indent=2, sort_keys=True),
155
+ json.dumps(result, indent=2, sort_keys=True),
156
+ )
157
+
158
+
159
  def check_json_event(event_json: str) -> str:
160
+ """Backward-compatible helper returning the full AANA decision as JSON."""
161
 
162
+ return check_event(event_json)[3]
 
 
163
 
164
 
165
  def build_demo():
166
+ """Build the Gradio UI only when the Space runtime imports it."""
167
 
168
  import gradio as gr
169
 
170
  with gr.Blocks(title="Try AANA") as demo:
171
+ gr.Markdown("# Try AANA in 2 minutes")
172
+ gr.Markdown(PUBLIC_MESSAGE)
173
  gr.Markdown(
174
+ "Paste a proposed tool call or load an example. AANA returns a route, AIx score, "
175
+ "hard blockers, missing evidence, authorization state, and an audit-safe event. "
176
+ "The synthetic executor only runs when the route is `accept`."
177
+ )
178
+ scenario = gr.Dropdown(
179
+ choices=list(EXAMPLE_EVENTS),
180
+ value="Ask: write missing confirmation",
181
+ label="Load example",
182
+ interactive=True,
183
  )
184
  event = gr.Code(
185
+ value=example_event("Ask: write missing confirmation"),
186
  language="json",
187
+ label="Paste Agent Action Contract v1 tool call",
188
  )
189
+ with gr.Row():
190
+ load = gr.Button("Load Example")
191
+ check = gr.Button("Check With AANA", variant="primary")
192
+ summary = gr.Markdown(label="Decision summary")
193
+ compact = gr.Code(language="json", label="Route, AIx, blockers, missing evidence, auth state")
194
+ proof = gr.Code(language="json", label="Blocked-tool non-execution proof")
195
+ full = gr.Code(language="json", label="Full AANA decision")
196
+
197
+ load.click(example_event, inputs=scenario, outputs=event)
198
+ check.click(check_event, inputs=event, outputs=[summary, compact, proof, full])
199
  return demo
200
 
201