Skip to content

Commit e783502

Browse files
authored
Dev 0.3.0 (#366) - Remove "augmented llm" pattern, migrate code, improved human_input
* improve handling of mixed Multipart vs. Standard loads * harmonize send, generate, structured methods; deduplicate handling * template method for generate to standardize message normalization * bump SDK, add LlmStopReason * interim commit * interim commit * interim commit * interim commit * interim commit * move MCPApp to fast_agent namespace * move mcp_agent.* to fast_agent, tests (except orchestrator) pass * rename MCPApp to Core, remove unused properties * interim commit (laptop-ws) * interim commit (ws->laptop) * interim commit before breaking tool loop * anthropic basics done (structured output empty message handling needs updating) * linting * remove reverse dependency in console_display * migrate agent namespace * simple tool call loop * sync * add logging * simple tool calls * interim commit * fix logger, add comment on tool call * Merge branch 'main' into dev-0.3.0 * break inheritance between agent and llm * stop reason handling; need to tidy up console_display! * stop sequence display * tool calling agent * simplify structured output, augmented_llm_anthropic * local * prepare for mcp re-integration * mcp working, checkpoint before renaming/interface checks * standardize tool use counting * typo * reinstate structured * interim commit * partial openai support * fix multimodal * interim commit * interim commit * update internal interfaces etc. * test update * fix orchestrator iterations * test updates * linter * update docstrings * elicitation handlers * resource link handling * update build * tool counting per turn * max iterations for tool loop. needs to be merge request params * fix test, openai unused reset tool counter * interim commit * linter! * revert sampling converter * fix anthropic empty system prompt (don't send block if None) * stop test collector complaining * rename BaseAgent to McpAgent * migrate from mcp_agent to fast_agent, use lower types * parameterise llm test * tidy up initialize flag * update last_text method to return None rather than "<no text>" * interim commit * interim commit * fix history/planner issues * update display etc. * fix tool loop display * improve display * suppress usage display output in quiet mode * reinstate tool display * standardize logging * tweak test suite, kimi to json object mode * partial update of gemini provider. todo: inbound tool response conversion todo: history approach check (be more like oai) todo: call structured correctly * new human input tool, mcp/tool agent tidyup * move code to fast_agent * empty file remove * improve url parser * migrate google native provider to use tool_agent etc. * rename llm classes (no longer augmented) * migrate llm code to fast_agent package * remove unused class * code/interface migration * consolidate ui code * move items to fast_agent.types * migrate human input etc. * complete e2e suite for multimodal * move progress display to ui * migrate cli commands to fast_agent * fix lint * lint (2) * anthropic api bump, docs in tool results, slow llm fix
1 parent 5ddd934 commit e783502

File tree

248 files changed

+9432
-8149
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

248 files changed

+9432
-8149
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ project_contents.md
179179

180180
# example logs
181181
examples/**/*.jsonl
182-
mcp_agent.config.yaml
183-
mcp_agent.secrets.yaml
184182
fastagent.secrets.yaml
185183
CLAUDE.md
186184
example-outputs/

examples/custom-agents/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import asyncio
22

3-
from mcp_agent.agents.base_agent import BaseAgent
3+
from fast_agent.agents.mcp_agent import McpAgent
44
from mcp_agent.core.fastagent import FastAgent
55

66
# Create the application
77
fast = FastAgent("fast-agent example")
88

99

10-
class MyAgent(BaseAgent):
10+
class MyAgent(McpAgent):
1111
async def initialize(self):
1212
await super().initialize()
1313
print("it's a-me!...Mario!")

examples/data-analysis/analysis-campaign.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22

3+
from fast_agent.llm.fastagent_llm import RequestParams
34
from mcp_agent.core.fastagent import FastAgent
4-
from mcp_agent.llm.augmented_llm import RequestParams
55

66
# Create the application
77
fast = FastAgent("Data Analysis & Campaign Generator")
@@ -179,8 +179,9 @@ async def main() -> None:
179179
)
180180

181181
async with fast.run() as agent:
182-
await agent.research_campaign_creator.prompt(
183-
default_prompt="Analyze the CSV file in the current directory and create a comprehensive multi-lingual social media campaign based on the findings. Save all campaign elements as separate files."
182+
await agent.interactive(
183+
"research_campaign_creator",
184+
default_prompt="Analyze the CSV file in the current directory and create a comprehensive multi-lingual social media campaign based on the findings. Save all campaign elements as separate files.",
184185
)
185186

186187

examples/mcp/elicitations/forms_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
from rich.console import Console
1414
from rich.panel import Panel
1515

16+
from fast_agent.mcp.helpers.content_helpers import get_resource_text
1617
from mcp_agent.core.fastagent import FastAgent
17-
from mcp_agent.mcp.helpers.content_helpers import get_resource_text
1818

1919
fast = FastAgent("Elicitation Forms Demo", quiet=True)
2020
console = Console()

examples/mcp/elicitations/game_character.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from rich.console import Console
1515
from rich.panel import Panel
1616

17+
from fast_agent.mcp.helpers.content_helpers import get_resource_text
1718
from mcp_agent.core.fastagent import FastAgent
18-
from mcp_agent.mcp.helpers.content_helpers import get_resource_text
1919

2020
fast = FastAgent("Game Character Creator", quiet=True)
2121
console = Console()

examples/new-api/display_check.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import asyncio
2+
3+
from fast_agent.agents.agent_types import AgentConfig
4+
from fast_agent.agents.llm_agent import LlmAgent
5+
from fast_agent.core import Core
6+
from fast_agent.llm.model_factory import ModelFactory
7+
from fast_agent.llm.request_params import RequestParams
8+
9+
10+
async def main():
11+
core: Core = Core()
12+
await core.initialize()
13+
test: AgentConfig = AgentConfig("hello", model="kimi")
14+
agent: LlmAgent = LlmAgent(test, context=core.context)
15+
await agent.attach_llm(ModelFactory.create_factory("haiku"))
16+
await agent.send("hello world, render some xml tags both inside and outside of code fences")
17+
await agent.generate("write a 200 word story", RequestParams(maxTokens=50))
18+
await agent.generate(
19+
"repeat after me: `one, two, three, four`",
20+
RequestParams(stopSequences=[" two,"]),
21+
)
22+
23+
24+
if __name__ == "__main__":
25+
asyncio.run(main())

examples/new-api/simple_llm.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import asyncio
2+
3+
from mcp.server.fastmcp import FastMCP
4+
5+
from fast_agent.agents.agent_types import AgentConfig
6+
from fast_agent.agents.tool_agent import ToolAgent
7+
from fast_agent.core import Core
8+
from fast_agent.llm.model_factory import ModelFactory
9+
10+
# Initialize FastMCP instance for decorator-based tools
11+
# Set log_level to WARNING or ERROR to avoid httpx INFO logs
12+
mcp = FastMCP("Weather Bot", log_level="WARNING")
13+
14+
15+
# Option 1: Using @mcp.tool decorator
16+
@mcp.tool()
17+
async def check_weather(city: str) -> str:
18+
"""Check the weather in a given city.
19+
20+
Args:
21+
city: The city to check the weather for
22+
23+
Returns:
24+
Weather information for the city
25+
"""
26+
return f"The weather in {city} is sunny."
27+
28+
29+
# Option 2: Simple function-based tool (without decorator)
30+
async def check_weather_function(city: str) -> str:
31+
"""Check the weather in a given city (function version).
32+
33+
Args:
34+
city: The city to check the weather for
35+
36+
Returns:
37+
Weather information for the city
38+
"""
39+
return f"The weather in {city} is sunny."
40+
41+
42+
# Alternative: Regular (non-async) function also works
43+
def get_temperature(city: str) -> int:
44+
"""Get the temperature in a city.
45+
46+
Args:
47+
city: The city to get temperature for
48+
49+
Returns:
50+
Temperature in degrees Celsius
51+
"""
52+
return 22
53+
54+
55+
async def main():
56+
core: Core = Core()
57+
await core.initialize()
58+
59+
# Create agent configuration
60+
config = AgentConfig(name="weather_bot", model="haiku")
61+
62+
tool_agent = ToolAgent(
63+
config,
64+
tools=[
65+
check_weather,
66+
get_temperature,
67+
],
68+
context=core.context,
69+
)
70+
71+
# Attach the LLM
72+
await tool_agent.attach_llm(ModelFactory.create_factory("haiku"))
73+
74+
# Test the agent
75+
await tool_agent.send("What's the weather like in San Francisco and what's the temperature?")
76+
await core.cleanup()
77+
78+
79+
if __name__ == "__main__":
80+
asyncio.run(main())
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import asyncio
2+
from typing import Any, Dict
3+
4+
from mcp.server.fastmcp.tools.base import Tool as FastMCPTool
5+
6+
from fast_agent.agents.agent_types import AgentConfig
7+
from fast_agent.agents.tool_agent_sync import ToolAgentSynchronous
8+
from fast_agent.core import Core
9+
from fast_agent.llm.model_factory import ModelFactory
10+
11+
12+
# Example 1: Simple function that will be wrapped
13+
async def search_web(query: str, max_results: int = 5) -> str:
14+
"""Search the web for information.
15+
16+
Args:
17+
query: The search query
18+
max_results: Maximum number of results to return
19+
20+
Returns:
21+
Search results as a formatted string
22+
"""
23+
# Mock implementation
24+
return f"Found {max_results} results for '{query}': [Result 1, Result 2, ...]"
25+
26+
27+
# Example 2: Create a FastMCP Tool directly for more control
28+
def create_calculator_tool() -> FastMCPTool:
29+
"""Create a calculator tool with explicit schema."""
30+
31+
def calculate(operation: str, a: float, b: float) -> float:
32+
"""Perform a calculation."""
33+
operations = {
34+
"add": lambda x, y: x + y,
35+
"subtract": lambda x, y: x - y,
36+
"multiply": lambda x, y: x * y,
37+
"divide": lambda x, y: x / y if y != 0 else float("inf"),
38+
}
39+
40+
if operation not in operations:
41+
raise ValueError(f"Unknown operation: {operation}")
42+
43+
return operations[operation](a, b)
44+
45+
# Create the tool with explicit configuration
46+
return FastMCPTool.from_function(
47+
fn=calculate,
48+
name="calculator",
49+
description="Perform basic arithmetic operations",
50+
# FastMCP will still generate the schema, but we could override if needed
51+
)
52+
53+
54+
# Example 3: Complex async tool with side effects
55+
async def send_email(to: str, subject: str, body: str) -> Dict[str, Any]:
56+
"""Send an email (mock implementation).
57+
58+
Args:
59+
to: Recipient email address
60+
subject: Email subject
61+
body: Email body content
62+
63+
Returns:
64+
Dictionary with send status and message ID
65+
"""
66+
# Mock async operation
67+
await asyncio.sleep(0.1)
68+
69+
return {
70+
"status": "sent",
71+
"message_id": f"msg_{hash((to, subject))}",
72+
"timestamp": "2024-01-01T12:00:00Z",
73+
}
74+
75+
76+
async def main():
77+
core: Core = Core()
78+
await core.initialize()
79+
80+
# Create agent configuration
81+
config = AgentConfig(name="assistant", model="haiku")
82+
83+
# Mix different tool types
84+
tools = [
85+
search_web, # Async function
86+
create_calculator_tool(), # Pre-configured FastMCP Tool
87+
send_email, # Complex async function
88+
]
89+
90+
# Create tool agent
91+
tool_agent = ToolAgentSynchronous(config, tools=tools, context=core.context)
92+
93+
# Attach the LLM
94+
await tool_agent.attach_llm(ModelFactory.create_factory("haiku"))
95+
96+
# Test various tools
97+
print("Testing search:")
98+
await tool_agent.send("Search for information about Python FastMCP")
99+
100+
print("\nTesting calculator:")
101+
await tool_agent.send("What is 42 multiplied by 17?")
102+
103+
print("\nTesting email:")
104+
await tool_agent.send(
105+
"Send an email to [email protected] with subject 'Hello' and body 'Test message'"
106+
)
107+
108+
109+
if __name__ == "__main__":
110+
asyncio.run(main())

examples/new-api/simple_mcp.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import asyncio
2+
3+
from fast_agent.core import Core
4+
5+
6+
async def main():
7+
core: Core = Core()
8+
await core.initialize()
9+
10+
# # Create agent configuration
11+
# config = AgentConfig(name="weather_bot", model="haiku")
12+
13+
# tool_agent = McpAgent(
14+
# config,
15+
# context=core.context,
16+
# )
17+
18+
# # Attach the LLM
19+
# await tool_agent.attach_llm(ModelFactory.create_factory("haiku"))
20+
21+
# # Test the agent
22+
# await tool_agent.send("What's the weather like in San Francisco and what's the temperature?")
23+
# await core.cleanup()
24+
25+
26+
if __name__ == "__main__":
27+
asyncio.run(main())

examples/otel/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
from pydantic import BaseModel, Field
55

6+
from fast_agent.llm.request_params import RequestParams
67
from mcp_agent.core.fastagent import FastAgent
78
from mcp_agent.core.prompt import Prompt
8-
from mcp_agent.core.request_params import RequestParams
99

1010
# Create the application
1111
fast = FastAgent("fast-agent example")

0 commit comments

Comments
 (0)