ohollo's picture
Adapt fixture and runner
31e6fb5
Raw
History Blame Contribute Delete
3.15 kB
import asyncio
import anthropic
from mcp import ClientSession
from mcp.client.sse import sse_client
from .base import Agent, AgentResult, ToolCall
_DEFAULT_MODEL = "claude-sonnet-4-6"
_SYSTEM = (
"You are a harmonic analysis assistant. After analysing a chord sequence, present only "
"well-known results — songs that are recognisable hits or by widely-known artists. "
"Use your knowledge to filter out obscure tracks. If no well-known matches exist, say so."
)
class ClaudeAgent(Agent):
"""Agent using the Anthropic SDK, connecting to tools via an MCP SSE server."""
def __init__(self, mcp_url: str, model: str = _DEFAULT_MODEL, client: anthropic.Anthropic | None = None):
super().__init__(mcp_url)
self.model = model
self._client = client or anthropic.Anthropic()
def run(self, user_prompt: str) -> AgentResult:
return asyncio.run(self._run(user_prompt))
async def _run(self, user_prompt: str) -> AgentResult:
async with sse_client(self.mcp_url) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = [_to_anthropic(t) for t in (await session.list_tools()).tools]
messages = [{"role": "user", "content": user_prompt}]
tool_calls: list[ToolCall] = []
while True:
response = self._client.messages.create(
model=self.model,
max_tokens=4096,
system=_SYSTEM,
tools=tools,
messages=messages,
)
if response.stop_reason == "end_turn":
text = next(
(b.text for b in response.content if b.type == "text"), ""
)
return AgentResult(response=text, tool_calls=tool_calls)
tool_results = []
for block in response.content:
if block.type == "tool_use":
result_text = await self._invoke_tool(session, block.name, dict(block.input))
tool_calls.append(ToolCall(name=block.name, args=dict(block.input), result=result_text))
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result_text,
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
async def _invoke_tool(self, session: ClientSession, name: str, args: dict) -> str:
mcp_result = await session.call_tool(name, args)
return "\n".join(item.text for item in mcp_result.content if hasattr(item, "text"))
def _to_anthropic(tool) -> dict:
return {
"name": tool.name,
"description": tool.description or "",
"input_schema": tool.inputSchema,
}