Skip to content

Commit f458eb7

Browse files
feat: add logfire to agent sandbox, expand example questions
1 parent 5a93004 commit f458eb7

2 files changed

Lines changed: 58 additions & 28 deletions

File tree

docs/src/components/policy-chat.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,20 @@ export function PolicyChat() {
272272
};
273273

274274
const exampleQuestions = [
275+
// UK tax questions
275276
"How much would it cost to set the UK basic income tax rate to 19p?",
276277
"What would happen if we doubled child benefit?",
277278
"How would a £15,000 personal allowance affect different income groups?",
279+
"What is the budgetary impact of abolishing the higher rate of income tax?",
280+
"How much does universal credit cost the government?",
281+
// US tax questions
282+
"What would a $2,000 child tax credit cost in the US?",
283+
"How would doubling SNAP benefits affect poverty rates?",
284+
"What is the revenue impact of a 25% top marginal tax rate?",
285+
// Household calculations
286+
"Calculate tax for a UK household earning £50,000",
287+
"What benefits would a single parent with two children receive in California?",
288+
"How much income tax does someone earning $100,000 in New York pay?",
278289
];
279290

280291
const formatToolName = (name: string) => {

src/policyengine_api/agent_sandbox.py

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
sandbox_image = (
1111
modal.Image.debian_slim(python_version="3.12")
1212
.apt_install("curl", "git", "unzip")
13+
.pip_install("logfire")
1314
.run_commands(
1415
# Install Bun
1516
"curl -fsSL https://bun.sh/install | bash",
@@ -28,6 +29,7 @@
2829

2930
# Secrets
3031
anthropic_secret = modal.Secret.from_name("anthropic-api-key")
32+
logfire_secret = modal.Secret.from_name("logfire-token")
3133

3234

3335
def run_claude_code_in_sandbox(
@@ -50,7 +52,7 @@ def run_claude_code_in_sandbox(
5052

5153
sb = modal.Sandbox.create(
5254
image=sandbox_image,
53-
secrets=[anthropic_secret],
55+
secrets=[anthropic_secret, logfire_secret],
5456
timeout=600,
5557
workdir="/tmp",
5658
)
@@ -74,7 +76,7 @@ def run_claude_code_in_sandbox(
7476
return sb, process
7577

7678

77-
@app.function(image=sandbox_image, secrets=[anthropic_secret], timeout=600)
79+
@app.function(image=sandbox_image, secrets=[anthropic_secret, logfire_secret], timeout=600)
7880
def run_policy_analysis(
7981
question: str, api_base_url: str = "https://v2.api.policyengine.org"
8082
) -> dict:
@@ -86,33 +88,50 @@ def run_policy_analysis(
8688
import os
8789
import subprocess
8890

89-
# Write MCP config
90-
os.makedirs("/root/.claude", exist_ok=True)
91-
mcp_config = {
92-
"mcpServers": {"policyengine": {"type": "sse", "url": f"{api_base_url}/mcp"}}
93-
}
94-
with open("/root/.claude/mcp_servers.json", "w") as f:
95-
json.dump(mcp_config, f)
96-
97-
# Run Claude Code
98-
result = subprocess.run(
99-
[
100-
"claude",
101-
"-p",
102-
question,
103-
"--allowedTools",
104-
"mcp__policyengine__*,Bash,Read,Grep,Glob,Write,Edit",
105-
],
106-
capture_output=True,
107-
text=True,
108-
timeout=540,
109-
)
91+
import logfire
92+
93+
logfire.configure(service_name="policyengine-agent-sandbox")
11094

111-
return {
112-
"status": "completed" if result.returncode == 0 else "failed",
113-
"report": result.stdout,
114-
"error": result.stderr if result.returncode != 0 else None,
115-
}
95+
with logfire.span("run_policy_analysis", question=question[:100], api_base_url=api_base_url):
96+
# Write MCP config
97+
os.makedirs("/root/.claude", exist_ok=True)
98+
mcp_config = {
99+
"mcpServers": {"policyengine": {"type": "sse", "url": f"{api_base_url}/mcp"}}
100+
}
101+
with open("/root/.claude/mcp_servers.json", "w") as f:
102+
json.dump(mcp_config, f)
103+
104+
logfire.info("Starting Claude Code", question=question[:100])
105+
106+
# Run Claude Code
107+
result = subprocess.run(
108+
[
109+
"claude",
110+
"-p",
111+
question,
112+
"--allowedTools",
113+
"mcp__policyengine__*,Bash,Read,Grep,Glob,Write,Edit",
114+
],
115+
capture_output=True,
116+
text=True,
117+
timeout=540,
118+
)
119+
120+
logfire.info(
121+
"Claude Code finished",
122+
returncode=result.returncode,
123+
stdout_len=len(result.stdout),
124+
stderr_len=len(result.stderr),
125+
)
126+
127+
if result.returncode != 0:
128+
logfire.error("Claude Code failed", stderr=result.stderr[:500])
129+
130+
return {
131+
"status": "completed" if result.returncode == 0 else "failed",
132+
"report": result.stdout,
133+
"error": result.stderr if result.returncode != 0 else None,
134+
}
116135

117136

118137
# For local testing

0 commit comments

Comments
 (0)