Chatty coding agents burn tokens and stall CI. Bedrock Converse toolConfig.toolChoice is how you force progress: auto for interactive IDE copilots, any when a tool call is mandatory, tool when a named tool must run now.
⚡ TL;DR: Use
toolChoice: {tool:{name}}for mechanical steps (apply_patch, run_tests);anywhen the agent must act but pick among tools;autoonly for human-in-the-loop chat. Cap iterations, validate tool schemas, and sandbox side effects. Deep companions: Bedrock Agents guardrails, Lambda sandboxes, prompt caching.
The three modes in practice
| Mode | When | Failure mode if wrong |
|---|---|---|
auto |
IDE chat, planning | Agent narrates instead of patching in CI |
any |
Must call some tool | Still may pick a weak tool |
tool + name |
Deterministic step | Wrong name → API error (good — fail loud) |
import boto3
brt = boto3.client("bedrock-runtime")
TOOLS = [
{"toolSpec": {"name": "search_repo", "description": "ripgrep", "inputSchema": {"json": {
"type": "object", "required": ["pattern"], "properties": {
"pattern": {"type": "string"}, "path": {"type": "string"}
}, "additionalProperties": False
}}}},
{"toolSpec": {"name": "apply_patch", "description": "Apply unified diff", "inputSchema": {"json": {
"type": "object", "required": ["diff"], "properties": {"diff": {"type": "string"}},
"additionalProperties": False
}}}},
{"toolSpec": {"name": "run_tests", "description": "Run targeted tests", "inputSchema": {"json": {
"type": "object", "required": ["filter"], "properties": {"filter": {"type": "string"}},
"additionalProperties": False
}}}},
]
def converse(messages, choice):
return brt.converse(
modelId="anthropic.claude-sonnet-4-20250514-v1:0",
messages=messages,
toolConfig={"tools": TOOLS, "toolChoice": choice},
inferenceConfig={"maxTokens": 4096, "temperature": 0},
)
Orchestrate a PR agent with forced tools
def pr_fix_loop(issue: str, max_iters: int = 8):
messages = [{"role": "user", "content": [{"text": issue}]}]
# 1) Force search first
r = converse(messages, {"tool": {"name": "search_repo"}})
messages = append_tool_results(messages, r, execute)
# 2) Force patch
r = converse(messages, {"tool": {"name": "apply_patch"}})
messages = append_tool_results(messages, r, execute)
# 3) Force tests
r = converse(messages, {"tool": {"name": "run_tests"}})
messages = append_tool_results(messages, r, execute)
# 4) Allow auto only for the final summary to humans
return converse(messages, {"auto": {}})
✅ State machine owns toolChoice per step.
❌ Single auto loop hoping the model “decides to run tests.”
Guardrails around tool execution
Even with perfect toolChoice, apply_patch must run in a sandbox — see LLM Coding Agents on AWS. Validate diffs (path allowlist, no .env, no lockfile unless intended).
function assertPatchSafe(diff: string) {
if (/^\+\+\+ b\/\.env/m.test(diff)) throw new Error("forbid_env");
if (/^\+\+\+ b\/pnpm-lock\.yaml/m.test(diff)) throw new Error("forbid_lockfile");
// ✅ only packages/** and apps/**
if (!/^\+\+\+ b\/(packages|apps)\//m.test(diff)) throw new Error("path_not_allowed");
}
Cost and latency notes
Forcing tools cuts wasted assistant tokens (illustrative: 30–50% fewer chat tokens on mechanical PR fixes). Combine with Bedrock prompt caching for large system + tool schemas. Keep temperature: 0 for CI agents.
Closing checklist
✅ Dos
– ✅ Drive toolChoice from an explicit state machine
– ✅ Use tool name for apply_patch / run_tests / search_repo
– ✅ Keep auto for human-facing summaries only
– ✅ Validate tool args against JSON Schema again in the executor
– ✅ Cap iterations and wall-clock time
❌ Don’ts
– ❌ Don’t run unattended CI agents on auto alone
– ❌ Don’t expose aws/kubectl as tools without allowlists
– ❌ Don’t ignore tool errors — feed them back as toolResult status
– ❌ Don’t raise temperature for deterministic codegen
– ❌ Don’t skip path allowlists on apply_patch
Related reading
- Amazon Bedrock Agents: Tool Use, Memory, and Production Guardrails
- LLM Coding Agents on AWS: Safe Tool Sandboxes with Lambda
- Bedrock Prompt Caching and Batch Inference: Cut Latency and Cost
- AI Code Review Bots: IAM, Secrets, and Least-Privilege Pipelines
Last updated on September 11, 2026
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
