refactor(agent-run-limits): centralize agent run limit configuration

- Removed hardcoded maximum parallel agent runs and replaced with a configurable property in the Configuration class.
- Updated API and agent limit checks to utilize the new configuration property.
- Simplified error handling by removing limit from error details in the frontend components.
- Adjusted UI components to reflect changes in agent limit data structure.
This commit is contained in:
mykonos-ibiza 2025-08-05 18:15:52 +05:30
parent 43bc71779e
commit ddef5fab19
8 changed files with 42 additions and 37 deletions

View File

@ -25,7 +25,7 @@ from utils.constants import MODEL_NAME_ALIASES
from flags.flags import is_enabled
from .config_helper import extract_agent_config, build_unified_config, extract_tools_for_agent_run, get_mcp_configs
from .utils import check_agent_run_limit, MAX_PARALLEL_AGENT_RUNS
from .utils import check_agent_run_limit
from .versioning.version_service import get_version_service
from .versioning.api import router as version_router, initialize as initialize_versioning
@ -442,10 +442,10 @@ async def start_agent(
limit_check = await check_agent_run_limit(client, account_id)
if not limit_check['can_start']:
error_detail = {
"message": f"Maximum of {MAX_PARALLEL_AGENT_RUNS} parallel agent runs allowed within 24 hours. You currently have {limit_check['running_count']} running.",
"message": f"Maximum of {config.MAX_PARALLEL_AGENT_RUNS} parallel agent runs allowed within 24 hours. You currently have {limit_check['running_count']} running.",
"running_thread_ids": limit_check['running_thread_ids'],
"running_count": limit_check['running_count'],
"limit": MAX_PARALLEL_AGENT_RUNS
"limit": config.MAX_PARALLEL_AGENT_RUNS
}
logger.warning(f"Agent run limit exceeded for account {account_id}: {limit_check['running_count']} running agents")
raise HTTPException(status_code=429, detail=error_detail)
@ -1066,10 +1066,10 @@ async def initiate_agent_with_files(
limit_check = await check_agent_run_limit(client, account_id)
if not limit_check['can_start']:
error_detail = {
"message": f"Maximum of {MAX_PARALLEL_AGENT_RUNS} parallel agent runs allowed within 24 hours. You currently have {limit_check['running_count']} running.",
"message": f"Maximum of {config.MAX_PARALLEL_AGENT_RUNS} parallel agent runs allowed within 24 hours. You currently have {limit_check['running_count']} running.",
"running_thread_ids": limit_check['running_thread_ids'],
"running_count": limit_check['running_count'],
"limit": MAX_PARALLEL_AGENT_RUNS
"limit": config.MAX_PARALLEL_AGENT_RUNS
}
logger.warning(f"Agent run limit exceeded for account {account_id}: {limit_check['running_count']} running agents")
raise HTTPException(status_code=429, detail=error_detail)

View File

@ -2,12 +2,10 @@ import json
from typing import Optional, List, Dict, Any
from datetime import datetime, timezone, timedelta
from utils.logger import logger
from utils.config import config
from services import redis
from run_agent_background import update_agent_run_status
# Agent run limits
MAX_PARALLEL_AGENT_RUNS = 3
async def _cleanup_redis_response_list(agent_run_id: str):
try:
@ -120,7 +118,7 @@ async def check_agent_run_limit(client, account_id: str) -> Dict[str, Any]:
logger.info(f"Account {account_id} has {running_count} running agent runs in the past 24 hours")
return {
'can_start': running_count < MAX_PARALLEL_AGENT_RUNS,
'can_start': running_count < config.MAX_PARALLEL_AGENT_RUNS,
'running_count': running_count,
'running_thread_ids': running_thread_ids
}

View File

@ -267,7 +267,34 @@ class Configuration:
# API Keys system configuration
API_KEY_SECRET: str = "default-secret-key-change-in-production"
API_KEY_LAST_USED_THROTTLE_SECONDS: int = 900
# Agent execution limits (can be overridden via environment variable)
_MAX_PARALLEL_AGENT_RUNS_ENV: Optional[str] = None
@property
def MAX_PARALLEL_AGENT_RUNS(self) -> int:
"""
Get the maximum parallel agent runs limit.
Can be overridden via MAX_PARALLEL_AGENT_RUNS environment variable.
Defaults:
- Production: 3
- Local/Staging: 999999 (effectively infinite)
"""
# Check for environment variable override first
if self._MAX_PARALLEL_AGENT_RUNS_ENV is not None:
try:
return int(self._MAX_PARALLEL_AGENT_RUNS_ENV)
except ValueError:
logger.warning(f"Invalid MAX_PARALLEL_AGENT_RUNS value: {self._MAX_PARALLEL_AGENT_RUNS_ENV}, using default")
# Environment-based defaults
if self.ENV_MODE == EnvMode.PRODUCTION:
return 3
else:
# Local and staging: effectively infinite
return 999999
@property
def STRIPE_PRODUCT_ID(self) -> str:
if self.ENV_MODE == EnvMode.STAGING:
@ -317,6 +344,11 @@ class Configuration:
else:
# String or other type
setattr(self, key, env_val)
# Custom handling for environment-dependent properties
max_parallel_runs_env = os.getenv("MAX_PARALLEL_AGENT_RUNS")
if max_parallel_runs_env is not None:
self._MAX_PARALLEL_AGENT_RUNS_ENV = max_parallel_runs_env
def _validate(self):
"""Validate configuration based on type hints."""

View File

@ -59,7 +59,6 @@ export default function ThreadPage({
const [showAgentLimitDialog, setShowAgentLimitDialog] = useState(false);
const [agentLimitData, setAgentLimitData] = useState<{
runningCount: number;
limit: number;
runningThreadIds: string[];
} | null>(null);
@ -329,12 +328,11 @@ export default function ThreadPage({
if (error instanceof AgentRunLimitError) {
console.log("Caught AgentRunLimitError:", error.detail);
const { running_thread_ids, running_count, limit } = error.detail;
const { running_thread_ids, running_count } = error.detail;
// Show the dialog with limit information
setAgentLimitData({
runningCount: running_count,
limit: limit,
runningThreadIds: running_thread_ids,
});
setShowAgentLimitDialog(true);
@ -764,7 +762,6 @@ export default function ThreadPage({
open={showAgentLimitDialog}
onOpenChange={setShowAgentLimitDialog}
runningCount={agentLimitData.runningCount}
limit={agentLimitData.limit}
runningThreadIds={agentLimitData.runningThreadIds}
projectId={projectId}
/>

View File

@ -48,7 +48,6 @@ export function DashboardContent() {
const [showAgentLimitDialog, setShowAgentLimitDialog] = useState(false);
const [agentLimitData, setAgentLimitData] = useState<{
runningCount: number;
limit: number;
runningThreadIds: string[];
} | null>(null);
const router = useRouter();
@ -163,12 +162,11 @@ export function DashboardContent() {
onOpen("paymentRequiredDialog");
} else if (error instanceof AgentRunLimitError) {
console.log('Handling AgentRunLimitError:', error.detail);
const { running_thread_ids, running_count, limit } = error.detail;
const { running_thread_ids, running_count } = error.detail;
// Show the dialog with limit information
setAgentLimitData({
runningCount: running_count,
limit: limit,
runningThreadIds: running_thread_ids,
});
setShowAgentLimitDialog(true);
@ -282,7 +280,6 @@ export function DashboardContent() {
open={showAgentLimitDialog}
onOpenChange={setShowAgentLimitDialog}
runningCount={agentLimitData.runningCount}
limit={agentLimitData.limit}
runningThreadIds={agentLimitData.runningThreadIds}
projectId={undefined} // Dashboard doesn't have a specific project context
/>

View File

@ -72,7 +72,6 @@ export function HeroSection() {
const [showAgentLimitDialog, setShowAgentLimitDialog] = useState(false);
const [agentLimitData, setAgentLimitData] = useState<{
runningCount: number;
limit: number;
runningThreadIds: string[];
} | null>(null);
@ -209,12 +208,11 @@ export function HeroSection() {
onOpen("paymentRequiredDialog");
} else if (error instanceof AgentRunLimitError) {
console.log('Handling AgentRunLimitError:', error.detail);
const { running_thread_ids, running_count, limit } = error.detail;
const { running_thread_ids, running_count } = error.detail;
// Show the dialog with limit information
setAgentLimitData({
runningCount: running_count,
limit: limit,
runningThreadIds: running_thread_ids,
});
setShowAgentLimitDialog(true);
@ -439,7 +437,6 @@ export function HeroSection() {
open={showAgentLimitDialog}
onOpenChange={setShowAgentLimitDialog}
runningCount={agentLimitData.runningCount}
limit={agentLimitData.limit}
runningThreadIds={agentLimitData.runningThreadIds}
projectId={undefined} // Hero section doesn't have a specific project context
/>

View File

@ -148,7 +148,6 @@ interface AgentRunLimitDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
runningCount: number;
limit: number;
runningThreadIds: string[];
projectId?: string;
}
@ -157,7 +156,6 @@ export const AgentRunLimitDialog: React.FC<AgentRunLimitDialogProps> = ({
open,
onOpenChange,
runningCount,
limit,
runningThreadIds,
projectId,
}) => {

View File

@ -4,9 +4,6 @@ import { handleApiError } from './error-handler';
// Get backend URL from environment variables
const API_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '';
// Agent run limits
const MAX_PARALLEL_AGENT_RUNS = 3;
// Set to keep track of agent runs that are known to be non-running
const nonRunningAgentRuns = new Set<string>();
// Map to keep track of active EventSource streams
@ -39,8 +36,6 @@ export class AgentRunLimitError extends Error {
message: string;
running_thread_ids: string[];
running_count: number;
limit: number;
[key: string]: any;
};
constructor(
@ -49,7 +44,6 @@ export class AgentRunLimitError extends Error {
message: string;
running_thread_ids: string[];
running_count: number;
limit: number;
[key: string]: any;
},
message?: string,
@ -751,7 +745,6 @@ export const startAgent = async (
message: 'Too many agent runs running',
running_thread_ids: [],
running_count: 0,
limit: MAX_PARALLEL_AGENT_RUNS
};
if (typeof detail.message !== 'string') {
detail.message = 'Too many agent runs running';
@ -762,9 +755,6 @@ export const startAgent = async (
if (typeof detail.running_count !== 'number') {
detail.running_count = 0;
}
if (typeof detail.limit !== 'number') {
detail.limit = MAX_PARALLEL_AGENT_RUNS;
}
throw new AgentRunLimitError(response.status, detail);
}
@ -1608,7 +1598,6 @@ export const initiateAgent = async (
message: 'Too many agent runs running',
running_thread_ids: [],
running_count: 0,
limit: MAX_PARALLEL_AGENT_RUNS
};
if (typeof detail.message !== 'string') {
detail.message = 'Too many agent runs running';
@ -1619,9 +1608,6 @@ export const initiateAgent = async (
if (typeof detail.running_count !== 'number') {
detail.running_count = 0;
}
if (typeof detail.limit !== 'number') {
detail.limit = MAX_PARALLEL_AGENT_RUNS;
}
throw new AgentRunLimitError(response.status, detail);
}