feat: dynamic subagent loading from SSM
This commit is contained in:
@@ -68,6 +68,7 @@ from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemory
|
|||||||
from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager
|
from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager
|
||||||
# code_interpreter removed — causes [Errno 98] port 8080 conflict on warm container re-init
|
# code_interpreter removed — causes [Errno 98] port 8080 conflict on warm container re-init
|
||||||
from tools.code_interpreter import run_code
|
from tools.code_interpreter import run_code
|
||||||
|
from strands_tools import http_request, file_read
|
||||||
|
|
||||||
app = BedrockAgentCoreApp()
|
app = BedrockAgentCoreApp()
|
||||||
|
|
||||||
@@ -87,6 +88,43 @@ except Exception as _e:
|
|||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
# ── Subagent loading ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TOOL_PRESETS = {
|
||||||
|
"aws": lambda: [MCPClient(lambda: aws_iam_streamablehttp_client(config.AWS_MCP_URL, aws_service="aws-mcp"))],
|
||||||
|
"coding": lambda: [MCPClient(lambda: aws_iam_streamablehttp_client(config.AWS_MCP_URL, aws_service="aws-mcp")), run_code],
|
||||||
|
"documents": lambda: [http_request, file_read],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _load_subagents(ssm_client) -> list:
|
||||||
|
"""Load subagent definitions from SSM and return as tools."""
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
resp = ssm_client.get_parameter(Name='/agent-claw/subagents')
|
||||||
|
defs = json.loads(resp['Parameter']['Value'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f'[main] Failed to load subagents from SSM: {type(e).__name__}: {e}')
|
||||||
|
return []
|
||||||
|
tools = []
|
||||||
|
for cfg in defs:
|
||||||
|
preset = cfg.get('tools', '')
|
||||||
|
if preset not in TOOL_PRESETS:
|
||||||
|
print(f'[main] Unknown tool preset "{preset}" for subagent "{cfg.get("name")}", skipping')
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
sub = Agent(
|
||||||
|
model=BedrockModel(model_id=cfg['model_id'], region_name='us-east-1'),
|
||||||
|
system_prompt=cfg['system_prompt'],
|
||||||
|
tools=TOOL_PRESETS[preset](),
|
||||||
|
)
|
||||||
|
tools.append(sub.as_tool(name=cfg['name'], description=cfg['description']))
|
||||||
|
except Exception as e:
|
||||||
|
print(f'[main] Failed to build subagent "{cfg.get("name")}": {type(e).__name__}: {e}')
|
||||||
|
print(f'[main] Loaded {len(tools)} subagent(s)')
|
||||||
|
return tools
|
||||||
|
|
||||||
|
|
||||||
# ── Tool definitions ──────────────────────────────────────────────────────
|
# ── Tool definitions ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
# NOTE: send_message tool removed — delivery handled by agent-runner streaming consumer
|
# NOTE: send_message tool removed — delivery handled by agent-runner streaming consumer
|
||||||
@@ -497,6 +535,7 @@ async def main(payload: dict, context):
|
|||||||
_time_str = _now.strftime('%A, %B %d, %Y %I:%M %p %Z')
|
_time_str = _now.strftime('%A, %B %d, %Y %I:%M %p %Z')
|
||||||
system_prompt = system_prompt + f'\n\nCurrent date/time: {_time_str}'
|
system_prompt = system_prompt + f'\n\nCurrent date/time: {_time_str}'
|
||||||
system_prompt += 'AWS tools available: call_aws (any AWS API via AWS MCP Server), aws_list_lambda_functions, aws_get_cost_and_usage, aws_describe_service. Use call_aws directly for AWS API calls — do NOT say you lack AWS access.'
|
system_prompt += 'AWS tools available: call_aws (any AWS API via AWS MCP Server), aws_list_lambda_functions, aws_get_cost_and_usage, aws_describe_service. Use call_aws directly for AWS API calls — do NOT say you lack AWS access.'
|
||||||
|
system_prompt += '\n\nSubagents available — use them aggressively to save cost and improve quality:\n- aws_agent: all AWS infrastructure, cost, resource, IAM, CloudWatch queries\n- coding_agent: code writing, builds, deployments, CodeBuild/AppRunner/ECR\n- document_agent: summarize URLs, extract data from documents, process long text\nDefault to delegating; only answer directly for simple conversational responses or tasks that don\'t fit a subagent.'
|
||||||
print(f'[main] System prompt time injection: {_time_str}')
|
print(f'[main] System prompt time injection: {_time_str}')
|
||||||
|
|
||||||
# Model: claude-sonnet-4-6 via cross-region inference
|
# Model: claude-sonnet-4-6 via cross-region inference
|
||||||
@@ -519,7 +558,11 @@ async def main(payload: dict, context):
|
|||||||
mcp_connections = services.get('mcp_connections', [])
|
mcp_connections = services.get('mcp_connections', [])
|
||||||
mcp_clients, _mcp_to_close = mcp_loader.load_mcp_tools(mcp_connections, actor_id)
|
mcp_clients, _mcp_to_close = mcp_loader.load_mcp_tools(mcp_connections, actor_id)
|
||||||
|
|
||||||
all_tools = base_tools + _aws_mcp_tools + mcp_clients
|
# Load subagents from SSM
|
||||||
|
ssm = boto3.client('ssm', region_name='us-east-1')
|
||||||
|
subagent_tools = _load_subagents(ssm)
|
||||||
|
|
||||||
|
all_tools = base_tools + _aws_mcp_tools + mcp_clients + subagent_tools
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
model=model,
|
model=model,
|
||||||
|
|||||||
Reference in New Issue
Block a user