Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions src/dashboard/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,15 +553,30 @@ async def api_update_agent_config(agent_id: str, request: Request) -> dict:
budget_val = body["budget"]
if isinstance(budget_val, dict):
daily = budget_val.get("daily_usd")
if daily is not None:
try:
daily = float(daily)
if daily <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="Budget must be a positive number")
_update_agent_field(agent_id, "budget", {"daily_usd": daily})
cost_tracker.set_budget(agent_id, daily_usd=daily)
monthly = budget_val.get("monthly_usd")
if daily is not None or monthly is not None:
# Read current budget so we don't reset the other limit
current_budget = cost_tracker.check_budget(agent_id)
if daily is not None:
try:
daily = float(daily)
if daily <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="Budget daily_usd must be a positive number")
else:
daily = current_budget.get("daily_limit", 10.0)
if monthly is not None:
try:
monthly = float(monthly)
if monthly <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="Budget monthly_usd must be a positive number")
else:
monthly = current_budget.get("monthly_limit", 200.0)
_update_agent_field(agent_id, "budget", {"daily_usd": daily, "monthly_usd": monthly})
cost_tracker.set_budget(agent_id, daily_usd=daily, monthly_usd=monthly)
updated.append("budget")

if "thinking" in body:
Expand Down Expand Up @@ -634,16 +649,35 @@ async def api_update_budget(agent_id: str, request: Request) -> dict:
raise HTTPException(status_code=404, detail="Agent not found")
body = await request.json()
daily_usd = body.get("daily_usd")
try:
daily_usd = float(daily_usd)
if daily_usd <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="daily_usd must be a positive number")
cost_tracker.set_budget(agent_id, daily_usd=daily_usd)
monthly_usd = body.get("monthly_usd")
if daily_usd is None and monthly_usd is None:
raise HTTPException(status_code=400, detail="Provide daily_usd and/or monthly_usd")
# Read current budget so we don't reset the other limit
current = cost_tracker.check_budget(agent_id)
current_daily = current.get("daily_limit", 10.0)
current_monthly = current.get("monthly_limit", 200.0)
if daily_usd is not None:
try:
daily_usd = float(daily_usd)
if daily_usd <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="daily_usd must be a positive number")
else:
daily_usd = current_daily
if monthly_usd is not None:
try:
monthly_usd = float(monthly_usd)
if monthly_usd <= 0:
raise ValueError
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail="monthly_usd must be a positive number")
else:
monthly_usd = current_monthly
cost_tracker.set_budget(agent_id, daily_usd=daily_usd, monthly_usd=monthly_usd)
from src.cli.config import _update_agent_field
_update_agent_field(agent_id, "budget", {"daily_usd": daily_usd})
return {"updated": True, "agent": agent_id, "daily_usd": daily_usd}
_update_agent_field(agent_id, "budget", {"daily_usd": daily_usd, "monthly_usd": monthly_usd})
return {"updated": True, "agent": agent_id, "daily_usd": daily_usd, "monthly_usd": monthly_usd}

@api_router.get("/api/agents/{agent_id}/permissions")
async def api_agent_permissions(agent_id: str) -> dict:
Expand Down
18 changes: 14 additions & 4 deletions src/dashboard/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,7 @@ function dashboard() {
avatar: cfg.avatar || 1,
_showAvatarPicker: false,
budget_daily: cfg.budget?.daily_usd || '',
budget_monthly: cfg.budget?.monthly_usd || '',
allowed_credentials: credsStr,
_credMode: credMode,
};
Expand Down Expand Up @@ -1515,8 +1516,14 @@ function dashboard() {
if (this.editForm.model && this.editForm.model !== cfg.model) body.model = this.editForm.model;
if (this.editForm.role !== undefined && this.editForm.role !== cfg.role) body.role = this.editForm.role;
if (this.editForm.avatar && this.editForm.avatar !== (cfg.avatar || 1)) body.avatar = this.editForm.avatar;
if (this.editForm.budget_daily && parseFloat(this.editForm.budget_daily) > 0) {
body.budget = { daily_usd: parseFloat(this.editForm.budget_daily) };
if ((this.editForm.budget_daily && parseFloat(this.editForm.budget_daily) > 0) ||
(this.editForm.budget_monthly && parseFloat(this.editForm.budget_monthly) > 0)) {
const budget = {};
if (this.editForm.budget_daily && parseFloat(this.editForm.budget_daily) > 0)
budget.daily_usd = parseFloat(this.editForm.budget_daily);
if (this.editForm.budget_monthly && parseFloat(this.editForm.budget_monthly) > 0)
budget.monthly_usd = parseFloat(this.editForm.budget_monthly);
body.budget = budget;
}
// Handle allowed_credentials via the permissions endpoint
const newCreds = (this.editForm.allowed_credentials || '').split(',').map(s => s.trim()).filter(Boolean);
Expand Down Expand Up @@ -1596,11 +1603,14 @@ function dashboard() {
}, true);
},

async updateBudget(agentId, dailyUsd) {
async updateBudget(agentId, dailyUsd, monthlyUsd) {
try {
const body = {};
if (dailyUsd != null) body.daily_usd = parseFloat(dailyUsd);
if (monthlyUsd != null) body.monthly_usd = parseFloat(monthlyUsd);
const resp = await fetch(`${window.__config.apiBase}/agents/${agentId}/budget`, {
method: 'PUT', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ daily_usd: parseFloat(dailyUsd) }),
body: JSON.stringify(body),
});
if (resp.ok) this.showToast(`Budget updated for ${agentId}`);
} catch (e) { console.warn('updateBudget failed:', e); }
Expand Down
4 changes: 4 additions & 0 deletions src/dashboard/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,10 @@ <h2 class="text-xl font-bold" x-text="agentDetail.id"></h2>
<label class="text-xs text-gray-500 mb-1 block">Budget ($/day)</label>
<input type="number" step="0.5" min="0.1" x-model="editForm.budget_daily" class="dash-input w-full" placeholder="10.0">
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block">Budget ($/month)</label>
<input type="number" step="1" min="1" x-model="editForm.budget_monthly" class="dash-input w-full" placeholder="200.0">
</div>
<div class="md:col-span-2">
<label class="text-xs text-gray-500 mb-1.5 block">Credential Access</label>
<div class="flex items-center gap-3 mb-2">
Expand Down
Loading