support concurrency

This commit is contained in:
2026-01-03 15:58:54 +08:00
parent 59ed6a5457
commit 65fef78f45

View File

@@ -1,5 +1,6 @@
import math import math
import random import random
import asyncio
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Type, List from typing import Type, List
import tyro import tyro
@@ -8,6 +9,19 @@ import time
from lang_agent.config import ToolConfig from lang_agent.config import ToolConfig
from lang_agent.base import LangToolBase from lang_agent.base import LangToolBase
# Concurrency control: limit max concurrent calculations
MAX_CONCURRENT_CALCULATIONS = 10
_semaphore: asyncio.Semaphore | None = None
def get_semaphore() -> asyncio.Semaphore:
"""Lazy initialization of semaphore (must be created within an event loop)."""
global _semaphore
if _semaphore is None:
_semaphore = asyncio.Semaphore(MAX_CONCURRENT_CALCULATIONS)
return _semaphore
@tyro.conf.configure(tyro.conf.SuppressFixed) @tyro.conf.configure(tyro.conf.SuppressFixed)
@dataclass @dataclass
class CalculatorConfig(ToolConfig): class CalculatorConfig(ToolConfig):
@@ -20,10 +34,18 @@ class Calculator(LangToolBase):
def calculator(self, python_expression: str) -> dict: def calculator(self, python_expression: str) -> dict:
"""For mathamatical calculation, always use this tool to calculate the result of a python expression. You can use 'math' or 'random' directly, without 'import'.""" """For mathamatical calculation, always use this tool to calculate the result of a python expression. You can use 'math' or 'random' directly, without 'import'."""
# time.sleep(2)
result = eval(python_expression, {"math": math, "random": random}) result = eval(python_expression, {"math": math, "random": random})
return {"success": True, "result": result} return {"success": True, "result": result}
async def calculator_async(self, python_expression: str) -> dict:
"""Async version: runs eval in a thread pool to avoid blocking the event loop."""
async with get_semaphore():
await asyncio.sleep(5) # Simulate delay for testing
result = await asyncio.to_thread(
eval, python_expression, {"math": math, "random": random}
)
return {"success": True, "result": result}
def get_tool_fnc(self): def get_tool_fnc(self):
return [self.calculator] return [self.calculator]
@@ -38,9 +60,9 @@ mcp = FastMCP("Calculator Server")
@mcp.tool() @mcp.tool()
def calculate(python_expression: str) -> dict: async def calculate(python_expression: str) -> dict:
"""For mathematical calculation, always use this tool to calculate the result of a python expression. You can use 'math' or 'random' directly, without 'import'.""" """For mathematical calculation, always use this tool to calculate the result of a python expression. You can use 'math' or 'random' directly, without 'import'."""
return calculator.calculator(python_expression) return await calculator.calculator_async(python_expression)
if __name__ == "__main__": if __name__ == "__main__":