Providers and agents
A provider wraps an LLM SDK behind a stable interface. An agent is a configured provider instance — a model, a system prompt, limits, and a tool set — held as a module-level singleton.
The runtime’s provider modules are thin re-exports; the implementations live in
morpheus-llm so the Lambda functions share them.
# agentcore/providers/claude_service.py
from morpheus_llm.providers.claude_service import ClaudeAgentService
# agentcore/providers/base_service.py
from morpheus_llm.providers.base_service import BaseAgentService
ClaudeAgentService
Claude on Bedrock via the Strands SDK. Authenticates through the runtime’s IAM role — no API key.
ClaudeAgentService(
config: AgentConfig,
tools: list[Any] | Callable[[], list[Any]],
memory_id: str | None = None,
)
| Argument | Purpose |
|---|---|
|
|
|
A static list, or a zero-argument factory callable |
|
Overrides the |
run() versus new_session()
| Method | Behaviour |
|---|---|
|
Builds a fresh |
|
Returns a fresh |
|
Both return a fresh |
Static versus factory tools
# Static — stateless tools
svc = ClaudeAgentService(config, [add_numbers, shell])
# Factory — required when any tool holds a stateful transport
svc = ClaudeAgentService(config, lambda: [add_numbers, create_hubspot_mcp(...)])
MCPClient holds an open HTTP session and cannot be shared across agent
invocations. Any tool set containing one must be a factory. See
Tools.
Pre-wired agents
Module-level singletons in agentcore/providers/agents/. Constructed once at import,
so no per-request setup cost beyond building the Agent.
dialler_agent
agentcore/providers/agents/dialler_agent.py:
config: AppConfig = load_config()
dialler_agent = ClaudeAgentService(
config=AgentConfig(
model_id=AgentModelIds.CLAUDE_SONNET_4,
system_prompt="You are a helpful assistant that can help with dialling tasks.",
max_tokens=1000,
max_turns=10,
),
tools=lambda: [
editor,
shell,
http_request,
python_repl,
add_numbers,
create_hubspot_mcp(
client_id=config.hubspot_client_id,
client_secret=config.hubspot_client_secret,
refresh_token=config.hubspot_refresh_token,
),
],
)
Two things to note:
-
load_config()is called at module import, which is whymain.pymust call it before importing the registry. It hits the cache. -
Credentials are passed explicitly into
create_hubspot_mcp(). The library never readsos.environitself.
|
This agent has |
Types
@dataclass
class AgentConfig:
model_id: str
system_prompt: str
max_tokens: int
max_turns: int
structured_output_model: type | None = None
@dataclass
class AgentResult:
output: str
stop_reason: str = "end_turn" # "end_turn" | "max_turns"
usage: dict[str, int] | None = None
structured_output: Any = None
@dataclass
class RunOptions:
system_prompt: str | None = None # per-call system prompt override
max_turns: int | None = None
metadata: dict | None = None
session_id: str | None = None # required for memory
actor_id: str | None = None # memory namespace key
session_id and actor_id are what wire an invocation to AgentCore Memory — see
AgentCore Memory.
Model ids
Always from morpheus_llm.utils.AgentModelIds:
| Member | Model id |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Do not strip the us. prefix — it selects the cross-region inference profile that
newer models require.
Adding an agent
-
Create
agentcore/providers/agents/<name>_agent.pyexporting a module-level singleton. -
Take model ids from
AgentModelIds. -
Use a
lambdafortoolsif any tool is stateful. -
Pass credentials explicitly from
load_config(). -
Reference it from a workflow — see Workflows.
# agentcore/providers/agents/research_agent.py
from agentcore.config.loader import AppConfig, load_config
from morpheus_llm.providers import ClaudeAgentService
from morpheus_llm.tools import create_tavily_mcp
from morpheus_llm.types import AgentConfig
from morpheus_llm.utils import AgentModelIds
config: AppConfig = load_config()
research_agent = ClaudeAgentService(
config=AgentConfig(
model_id=AgentModelIds.CLAUDE_HAIKU_4_5,
system_prompt="You are a research assistant with real-time web access.",
max_tokens=4096,
max_turns=15,
),
tools=lambda: [create_tavily_mcp(api_key=config.tavily_api_key)],
)
Adding a provider
BaseAgentService (in morpheus-llm) already owns tool resolution, memory session
management, and the run / new_session API. A new provider implements one method:
class MyProviderService(BaseAgentService):
def _make_agent(self, options: RunOptions | None = None) -> Any:
return SomeAgent(
model=...,
system_prompt=(options.system_prompt if options and options.system_prompt
else self._config.system_prompt),
tools=self._resolve_tools(),
session_manager=self._make_session_manager(options) if options else None,
)
The provider belongs in libs/morpheus-llm/morpheus_llm/providers/, not in
agentcore/, so the Lambdas can use it too.