Skip to content

Commit 0c0be07

Browse files
author
Anthony Bernabeu
authored
Merge pull request #349 from rjesh-git/feat/ant-thinking
Thinking feature for Anthropic and Bedrock LLM Agents
2 parents 75a1e82 + 14a0618 commit 0c0be07

File tree

17 files changed

+867
-265
lines changed

17 files changed

+867
-265
lines changed

docs/src/content/docs/agents/built-in/anthropic-agent.mdx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,52 @@ agent = AnthropicAgent(AnthropicAgentOptions(
339339
</Tabs>
340340
<hr/>
341341

342-
**9. Complete Example with All Options**
342+
**9. With Reasoning enabled**
343+
344+
<Tabs syncKey="runtime">
345+
<TabItem label="TypeScript" icon="seti:typescript" color="blue">
346+
```typescript
347+
import { AnthropicAgent } from 'agent-squad';
348+
349+
const agent = new AnthropicAgent({
350+
name: "Tech Agent",
351+
description: "Specializes in technology areas including software development, hardware, AI, cybersecurity, blockchain, cloud computing, emerging tech innovations, and pricing/costs related to technology products and services.",
352+
inferenceConfig: {
353+
maxTokens: 2500,
354+
temperature: 1, // 1 for thinking
355+
topP: 0.96 // 0.95 or above
356+
},
357+
modelId: "claude-3-7-sonnet-20250219", // Claude 3.7 or above
358+
thinking: {type: "enabled", budget_tokens: 1024},
359+
streaming: true,
360+
apiKey: 'your-anthropic-api-key',
361+
});
362+
```
363+
</TabItem>
364+
<TabItem label="Python" icon="seti:python">
365+
```python
366+
367+
agent = AnthropicAgent(
368+
AnthropicAgentOptions(
369+
name="Tech Agent",
370+
api_key='your-anthropic-api-key',
371+
streaming=True,
372+
description="Specializes in technology areas including software development, hardware, AI, \
373+
cybersecurity, blockchain, cloud computing, emerging tech innovations, and pricing/costs \
374+
related to technology products and services.",
375+
model_id="claude-3-7-sonnet-20250219",
376+
callbacks=LLMAgentCallbacks(),
377+
inference_config={"maxTokens": 2500, "temperature": 1, "topP": 0.95}, # temperature set to 1 and topP 0.95 or above
378+
thinking={"type": "enabled", "budget_tokens": 2000},
379+
)
380+
)
381+
```
382+
</TabItem>
383+
</Tabs>
384+
385+
<hr/>
386+
387+
**10. Complete Example with All Options**
343388

344389
<Tabs syncKey="runtime">
345390
<TabItem label="TypeScript" icon="seti:typescript" color="blue">

docs/src/content/docs/agents/built-in/bedrock-llm-agent.mdx

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,48 @@ agent = BedrockLLMAgent(BedrockLLMAgentOptions(
301301

302302
<hr/>
303303

304-
**9. Complete Example with All Options**
304+
**9. With Thinking enabled**
305+
306+
<Tabs syncKey="runtime">
307+
<TabItem label="TypeScript" icon="seti:typescript" color="blue">
308+
```typescript
309+
const agent = new BedrockLLMAgent({
310+
name: "Tech Agent",
311+
modelId: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
312+
description:"Specializes in technology areas including software development, hardware, AI, cybersecurity, \
313+
blockchain, cloud computing, emerging tech innovations, and pricing/costs related to technology products and services.",
314+
inferenceConfig: {
315+
maxTokens: 2500,
316+
temperature: 1, // 1 for thinking and unset topP
317+
},
318+
additional_model_request_fields: {
319+
thinking: {type: "enabled", budget_tokens: 1024},
320+
},
321+
streaming: true,
322+
});
323+
```
324+
</TabItem>
325+
<TabItem label="Python" icon="seti:python">
326+
```python
327+
agent = BedrockLLMAgent(
328+
BedrockLLMAgentOptions(
329+
name="Tech Agent",
330+
streaming=False,
331+
description="Specializes in technology areas including software development, hardware, AI, \
332+
cybersecurity, blockchain, cloud computing, emerging tech innovations, and pricing/costs \
333+
related to technology products and services.",
334+
model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
335+
callbacks=LLMAgentCallbacks(),
336+
inference_config={"maxTokens": 2500, "temperature": 1},
337+
additional_model_request_fields={"thinking": {"type": "enabled", "budget_tokens": 2000}},
338+
)
339+
)
340+
```
341+
</TabItem>
342+
</Tabs>
343+
<hr/>
344+
345+
**10. Complete Example with All Options**
305346

306347
<Tabs syncKey="runtime">
307348
<TabItem label="TypeScript" icon="seti:typescript" color="blue">
@@ -444,7 +485,7 @@ agent = BedrockLLMAgent(BedrockLLMAgentOptions(
444485

445486
The `BedrockLLMAgent` provides multiple ways to set custom prompts. You can set them either during initialization or after the agent is created, and you can use prompts with or without variables.
446487

447-
**10. Setting Custom Prompt After Initialization (Without Variables)**
488+
**11. Setting Custom Prompt After Initialization (Without Variables)**
448489

449490
<Tabs syncKey="runtime">
450491
<TabItem label="TypeScript" icon="seti:typescript" color="blue">
@@ -495,7 +536,7 @@ When providing business advice:
495536

496537
<hr/>
497538

498-
**11. Setting Custom Prompt After Initialization (With Variables)**
539+
**12. Setting Custom Prompt After Initialization (With Variables)**
499540

500541
<Tabs syncKey="runtime">
501542
<TabItem label="TypeScript" icon="seti:typescript" color="blue">
@@ -616,6 +657,7 @@ Choose the approach that best fits your needs:
616657
| `streaming` | Enables streaming responses for real-time output | Optional |
617658
| `inferenceConfig` | Fine-tunes the model's output characteristics | Optional |
618659
| `guardrailConfig` | Applies predefined guardrails to the model's responses | Optional |
660+
| `reasoningConfig` | Enables thinking and configuration for budget_tokens | Optional |
619661
| `retriever` | Integrates a retrieval system for enhanced context | Optional |
620662
| `toolConfig` | Defines tools the agent can use and how to handle their responses | Optional |
621663
| `customSystemPrompt` | Defines the agent's system prompt and behavior, with optional variables for dynamic content | Optional |
@@ -632,6 +674,7 @@ Choose the approach that best fits your needs:
632674
| `streaming` | Enables streaming responses for real-time output | Optional |
633675
| `inference_config` | Fine-tunes the model's output characteristics | Optional |
634676
| `guardrail_config` | Applies predefined guardrails to the model's responses | Optional |
677+
| `additional_model_request_fields` | Additional fields to send to the model, including thinking capability | Optional |
635678
| `retriever` | Integrates a retrieval system for enhanced context | Optional |
636679
| `tool_config` | Defines tools the agent can use and how to handle their responses | Optional |
637680
| `custom_system_prompt` | Defines the agent's system prompt and behavior, with optional variables for dynamic content | Optional |

examples/local-demo/local-orchestrator.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,25 @@ function createOrchestrator(): AgentSquad {
5151
// Add weahter agent with tool
5252
const weatherAgent = new BedrockLLMAgent({
5353
name: "Weather Agent",
54+
modelId:"us.anthropic.claude-3-7-sonnet-20250219-v1:0",
5455
description:
5556
"Specialized agent for giving weather condition from a city.",
56-
streaming: true,
57-
inferenceConfig: {
58-
temperature: 0.1,
59-
},
57+
streaming: false,
6058
toolConfig: {
6159
tool: weatherToolDescription,
6260
useToolHandler: weatherToolHanlder,
6361
toolMaxRecursions: 5,
64-
}
62+
},
63+
inferenceConfig: {
64+
temperature: 1.0,
65+
maxTokens:4096,
66+
},
67+
reasoningConfig:{
68+
thinking:{
69+
type:'enabled',
70+
budget_tokens: 4000,
71+
}
72+
}
6573
});
6674
weatherAgent.setSystemPrompt(WEATHER_PROMPT);
6775
orchestrator.addAgent(weatherAgent);
@@ -174,6 +182,10 @@ async function runLocalConversation(): Promise<void> {
174182
for await (const chunk of response.output) {
175183
if (typeof chunk === "string") {
176184
process.stdout.write(chunk);
185+
}
186+
else if (typeof chunk === "object" && chunk.hasOwnProperty("thinking")) {
187+
// Print thinking content in cyan color
188+
process.stdout.write('\x1b[36m' + chunk.content + '\x1b[0m');
177189
} else {
178190
Logger.logger.error("Received unexpected chunk type:", typeof chunk);
179191
}

examples/python-demo/main-stream.py

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
AgentStreamResponse,
1616
AgentCallbacks)
1717
from agent_squad.types import ConversationMessage, ParticipantRole
18-
from agent_squad.utils import AgentTool, AgentTools, AgentToolCallbacks
18+
from agent_squad.utils import AgentToolCallbacks
19+
from dotenv import load_dotenv
1920

21+
load_dotenv()
2022
class LLMAgentCallbacks(AgentCallbacks):
2123
async def on_agent_start(
2224
self,
@@ -105,10 +107,23 @@ async def handle_request(_orchestrator: AgentSquad, _user_input:str, _user_id:st
105107
async for chunk in response.output:
106108
if isinstance(chunk, AgentStreamResponse):
107109
if response.streaming:
108-
print(chunk.text, end='', flush=True)
110+
if (chunk.thinking):
111+
print(f"\033[34m{chunk.thinking}\033[0m", end='', flush=True)
112+
elif (chunk.text):
113+
print(chunk.text, end='', flush=True)
109114
else:
110115
if isinstance(response.output, ConversationMessage):
111116
print(response.output.content[0]['text'])
117+
118+
# Safely extract thinking content from response
119+
thinking_content = None
120+
for content_item in response.output.content:
121+
if isinstance(content_item, dict) and 'reasoningContent' in content_item:
122+
thinking_content = content_item['reasoningContent']
123+
break
124+
125+
if thinking_content:
126+
print(f"\nThinking: {thinking_content}")
112127
elif isinstance(response.output, str):
113128
print(response.output)
114129
else:
@@ -159,26 +174,50 @@ def custom_output_payload_decoder(response: dict[str, Any]) -> Any:
159174
))
160175
orchestrator.add_agent(tech_agent)
161176

177+
162178
# Add some agents
163179
tech_agent = BedrockLLMAgent(BedrockLLMAgentOptions(
164180
name="Health Agent",
165-
streaming=False,
181+
streaming=True,
182+
inference_config={
183+
"maxTokens": 4096,
184+
"temperature":1.0
185+
},
166186
description="Specializes in health and well being.",
167-
model_id="anthropic.claude-3-sonnet-20240229-v1:0",
187+
model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
188+
additional_model_request_fields={
189+
"thinking": {
190+
"type": "enabled",
191+
"budget_tokens": 4000
192+
}
193+
}
168194
))
169195
orchestrator.add_agent(tech_agent)
170196

171197
# Add a Anthropic weather agent with a tool in anthropic's tool format
172198
# weather_agent = AnthropicAgent(AnthropicAgentOptions(
173-
# api_key='api-key',
199+
# api_key=os.getenv('ANTHROPIC_API_KEY', None),
174200
# name="Weather Agent",
175-
# streaming=False,
201+
# streaming=True,
202+
# model_id="claude-3-7-sonnet-20250219",
176203
# description="Specialized agent for giving weather condition from a city.",
177204
# tool_config={
178205
# 'tool': [tool.to_claude_format() for tool in weather_tool.weather_tools.tools],
179206
# 'toolMaxRecursions': 5,
180207
# 'useToolHandler': weather_tool.anthropic_weather_tool_handler
181208
# },
209+
# inference_config={
210+
# "maxTokens": 4096,
211+
# "temperature":1.0,
212+
# "topP":1.0
213+
# }
214+
# ,
215+
# additional_model_request_fields = {
216+
# "thinking": {
217+
# "type": "enabled",
218+
# "budget_tokens": 4000
219+
# }
220+
# },
182221
# callbacks=LLMAgentCallbacks()
183222
# ))
184223

@@ -210,13 +249,24 @@ def custom_output_payload_decoder(response: dict[str, Any]) -> Any:
210249
# Add a Bedrock weather agent with custom handler and bedrock's tool format
211250
weather_agent = BedrockLLMAgent(BedrockLLMAgentOptions(
212251
name="Weather Agent",
213-
streaming=False,
252+
streaming=True,
253+
model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
214254
description="Specialized agent for giving weather condition from a city.",
215255
tool_config={
216256
'tool': [tool.to_bedrock_format() for tool in weather_tool.weather_tools.tools],
217257
'toolMaxRecursions': 5,
218258
'useToolHandler': weather_tool.bedrock_weather_tool_handler
219-
}
259+
},
260+
additional_model_request_fields={
261+
"thinking": {
262+
"type": "enabled",
263+
"budget_tokens": 4000
264+
}
265+
},
266+
inference_config={
267+
"maxTokens": 4096,
268+
"temperature":1.0
269+
},
220270
))
221271

222272

@@ -236,5 +286,6 @@ def custom_output_payload_decoder(response: dict[str, Any]) -> Any:
236286
print("Exiting the program. Goodbye!")
237287
sys.exit()
238288

239-
# Run the async function
240-
asyncio.run(handle_request(orchestrator, user_input, USER_ID, SESSION_ID))
289+
if user_input != '':
290+
# Run the async function
291+
asyncio.run(handle_request(orchestrator, user_input, USER_ID, SESSION_ID))

0 commit comments

Comments
 (0)