Skip to content

Commit 4b06b7c

Browse files
Run agent tools concurrently and fix tool message pairing (#99)
* feat(agent): implement concurrent tool call execution, fix: tool call context * docs: update API usage note, clarify PROCESS_MESSAGE tool, add new metadata types, and fix parameter names in agent strategy examples * resolve: issues
1 parent 05117bf commit 4b06b7c

15 files changed

Lines changed: 318 additions & 206 deletions

File tree

docs/docs/guide/api-reference/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ set_config(config)
5959

6060
**Usage Notes**:
6161

62-
- Must be called after `init()` but before `load_amrita()`
62+
- Should be called before `load_amrita()`
6363
- Configuration affects all subsequent operations
6464

6565
### 7.1.4 get_config() - Getting Configuration

docs/docs/guide/builtins.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,25 @@ Built-in tools are automatically enabled based on the agent configuration:
3838

3939
- **Agent Mode**: When `config.builtin.tool_calling_mode == "agent"`, both `STOP_TOOL` and `REASONING_TOOL` are available.
4040
- **Thought Mode**: The `REASONING_TOOL` is only available when `config.builtin.agent_thought_mode` starts with "reasoning".
41-
- **Process Messages**: The `PROCESS_MESSAGE` tool is enabled when `config.function_config.agent_middle_message` is True.
41+
- **Process Messages**: The `PROCESS_MESSAGE` tool is used internally by the `HybridReActAgentStrategy` to communicate intermediate tool results to the user. It is **not** registered by `ReActAgentStrategy`; the `config.function_config.agent_middle_message` flag controls whether the agent may send intermediate notifications, but does not independently enable the `PROCESS_MESSAGE` tool.
4242

4343
## 9.2 Built-in Metadata Types
4444

4545
> **Since v0.9.1**: A new `amrita_core.builtins.types` module provides typed metadata classes (based on `MessageMetadataPayload`) for structured metadata in agent and hook workflows.
4646
4747
These typed metadata classes replace plain dictionaries, providing type safety and IDE autocompletion:
4848

49-
| Class | Purpose |
50-
| ----------------------------- | ---------------------------------------------------------------------- |
51-
| `AgentReasoningMetadata` | Pre-resolve reasoning summaries (`last_step`, `summary`) |
52-
| `AgentReasoningChunkMetadata` | Streaming reasoning chunks (`content`) |
53-
| `AgentToolCallMetadata` | Tool call notifications (`function_name`, `is_done`, `tool_id`, `err`) |
54-
| `AgentLoopErrorMetadata` | Loop detection errors (`chat_object_id`, `error`) |
55-
| `AgentMiddleMessageMetadata` | LLM middle messages (`content`) |
56-
| `HookErrorMetadata` | Hook-level error responses (`content`) |
49+
| Class | Purpose |
50+
| --------------------------------------- | --------------------------------------------------------------------------------- |
51+
| `AgentReasoningMetadata` | Pre-resolve reasoning summaries (`last_step`, `summary`) |
52+
| `AgentReasoningChunkMetadata` | Streaming reasoning chunks (`content`) |
53+
| `AgentToolCallMetadata` | Tool call notifications (`function_name`, `is_done`, `tool_id`, `err`) |
54+
| `AgentLoopErrorMetadata` | Loop detection errors (`chat_object_id`, `error`) |
55+
| `AgentMiddleMessageMetadata` | LLM middle messages (`content`) |
56+
| `HookErrorMetadata` | Hook-level error responses (`content`) |
57+
| `AgentStructuredReasoningChunkMetadata` | Per-step structured CoT reasoning metadata (`step_index`, `total_steps`, `phase`) |
58+
| `AgentReflectionMetadata` | Post-reasoning self-reflection results (`reflection_type`, `result`, `detail`) |
59+
| `AgentToolPredictionMetadata` | Tool prediction during structured reasoning (`predicted_tools`) |
5760

5861
Base classes in `amrita_core.contents`:
5962

docs/docs/guide/concepts/agent-strategy.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,22 @@ async def use_builtin_strategies():
197197

198198
# Standard ReAct strategy (recommended for most cases)
199199
standard_agent = create_agent(
200-
url="https://api.openai.com",
201-
key="your-api-key",
200+
base_url="https://api.openai.com",
201+
api_key="your-api-key",
202202
strategy=ReActAgentStrategy
203203
)
204204

205205
# Hybrid strategy for MoE models
206206
hybrid_agent = create_agent(
207-
url="https://api.moemodel.com",
208-
key="your-api-key",
207+
base_url="https://api.moemodel.com",
208+
api_key="your-api-key",
209209
strategy=HybridReActAgentStrategy
210210
)
211211

212212
# No-action strategy to skip tool execution
213213
no_action_agent = create_agent(
214-
url="https://api.example.com",
215-
key="your-api-key",
214+
base_url="https://api.example.com",
215+
api_key="your-api-key",
216216
strategy=NoActionAgentStrategy
217217
)
218218

docs/docs/guide/concepts/event.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ async def handle_fallback(event: FallbackContext):
5454

5555
# Switch to a different preset for retry
5656
# The system will automatically use event.preset for the next attempt
57-
if event.term == 1: # First retry
57+
if event.term == 0: # First attempt
5858
event.preset = get_alternative_preset() # Your custom function to get alternative preset
59-
elif event.term == 2: # Second retry
59+
elif event.term == 1: # First retry
6060
event.preset = get_safe_preset() # Your custom function to get a safe/cheaper preset
6161
else:
6262
# Mark as failed if no more fallbacks available
@@ -70,7 +70,7 @@ The `FallbackContext` provides the following properties:
7070
- `exc_info`: The exception that caused the failure
7171
- `config`: The current [AmritaConfig](../api-reference/classes/AmritaConfig.md)
7272
- `context`: The [SendMessageWrap](../api-reference/classes/SendMessageWrap.md) containing the message context
73-
- `term`: The current retry attempt number (starting from 1)
73+
- `term`: The current retry attempt number, counting from **0** (first call) up to `max_retries - 1`.
7474

7575
You can modify the `event.preset` to switch to a different model preset for the next retry attempt. If no suitable fallback is available, call `event.fail(reason)` to terminate the retry process.
7676

docs/docs/guide/extensions-integration/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -612,16 +612,16 @@ Combine AmritaCore with other frameworks:
612612
```python
613613
# Example: Integration with FastAPI for a web service
614614
from fastapi import FastAPI
615-
from amrita_core import ChatObject, init
616-
from amrita_core.config import AmritaConfig
615+
from amrita_core import ChatObject, minimal_init
616+
from amrita_core.config import AmritaConfig, set_config
617617
from amrita_core.types import MemoryModel, Message
618618

619619
app = FastAPI()
620620

621621
# Initialize AmritaCore when the app starts
622-
init()
623-
from amrita_core.config import set_config
624-
set_config(AmritaConfig())
622+
@app.on_event("startup")
623+
async def startup():
624+
await minimal_init(AmritaConfig())
625625

626626
@app.post("/chat/")
627627
async def chat_endpoint(user_input: str, session_id: str):

docs/docs/guide/security-mechanisms.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ The cookie system works by inserting a unique identifier into the conversation c
1212

1313
### 6.1.2 CookieConfig Configuration
1414

15-
The [CookieConfig](../api-reference/classes/CookieConfig.md) class manages cookie-related security settings:
15+
The [CookieConfig](../api-reference/classes/CookieConfig.md) class manages cookie-related security settings. Cookie security is **enabled by default** (`enable_cookie=True`) — no explicit configuration is needed unless you want to customise the cookie string:
1616

1717
```python
1818
from amrita_core.config import CookieConfig
1919

20-
# Enable cookie security detection
20+
# Cookie security is ON by default. These examples show how to change the cookie.
2121
security_config = CookieConfig(
22-
enable_cookie=True, # Enable the cookie leak detection mechanism
22+
enable_cookie=True, # Already the default, shown for clarity
2323
cookie="custom_cookie_string" # Custom cookie string (defaults to random string)
2424
)
2525

26-
# Or let the system generate a random cookie automatically
26+
# Or let the system generate a random cookie automatically (this is the default behaviour)
2727
default_security_config = CookieConfig(enable_cookie=True)
2828
```
2929

docs/docs/zh/guide/api-reference/index.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@
22

33
## 7.1 核心 API 函数
44

5-
### 7.1.1 init() - 初始化
5+
### 7.1.1 init() - 初始化(已废弃)
66

7-
`init()` 函数初始化 AmritaCore 的核心组件,必须在任何其他操作之前调用
7+
> **已废弃**`init()` 函数从 v0.9.0rc1 起已废弃。现在是空操作存根,不再执行任何初始化。请改用 `load_amrita()` 进行异步初始化
88
99
```python
1010
from amrita_core import init
1111

12-
# 初始化 AmritaCore
12+
# 不再必要 — 现在是一个空操作
1313
init()
1414
```
1515

16-
**用途**: 准备 AmritaCore 的内部组件,初始化 Jieba 用于文本处理,加载内置模块并设置核心框架。
17-
18-
**使用注意事项**:
19-
20-
- 必须在任何其他 AmritaCore 函数之前调用
21-
- 线程安全,可以多次调用(后续调用是无操作)
22-
- 设置日志记录和内部状态
16+
**迁移**: 删除代码中所有 `init()` 调用。需要异步初始化时(例如 MCP 客户端设置)使用 `load_amrita()`
2317

2418
### 7.1.2 load_amrita() - 加载框架
2519

@@ -39,7 +33,7 @@ asyncio.run(main())
3933

4034
**使用注意事项**:
4135

42-
- 必须在 `init()``set_config()` 之后调用
36+
- 必须在 `set_config()` 之后调用
4337
- 应该被等待,因为它是一个异步函数
4438

4539
### 7.1.3 set_config() - 设置配置
@@ -61,7 +55,7 @@ set_config(config)
6155

6256
**使用注意事项**:
6357

64-
- 必须在 `init()` 之后但在 `load_amrita()` 之前调用
58+
- 应该在 `load_amrita()` 之前调用
6559
- 配置会影响所有后续操作
6660

6761
### 7.1.4 get_config() - 获取配置
@@ -79,8 +73,8 @@ print(config.function_config.use_minimal_context)
7973

8074
**使用注意事项**:
8175

82-
- 如果 AmritaCore 未初始化则抛出 RuntimeError
83-
- 在初始化后调用是安全的
76+
- 如果尚未调用 `set_config()` 则抛出 RuntimeError
77+
- 初始化后调用是安全的
8478

8579
### 7.1.5 create_agent() - Agent 创建
8680

docs/docs/zh/guide/concepts/agent-strategy.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,22 @@ async def use_builtin_strategies():
197197

198198
# 标准ReAct策略(推荐用于大多数情况)
199199
standard_agent = create_agent(
200-
url="https://api.openai.com",
201-
key="your-api-key",
200+
base_url="https://api.openai.com",
201+
api_key="your-api-key",
202202
strategy=ReActAgentStrategy
203203
)
204204

205205
# MoE模型的混合策略
206206
hybrid_agent = create_agent(
207-
url="https://api.moemodel.com",
208-
key="your-api-key",
207+
base_url="https://api.moemodel.com",
208+
api_key="your-api-key",
209209
strategy=HybridReActAgentStrategy
210210
)
211211

212212
# 跳过工具执行的无操作策略
213213
no_action_agent = create_agent(
214-
url="https://api.example.com",
215-
key="your-api-key",
214+
base_url="https://api.example.com",
215+
api_key="your-api-key",
216216
strategy=NoActionAgentStrategy
217217
)
218218

@@ -254,22 +254,22 @@ async def use_builtin_strategies():
254254
```python
255255
from amrita_core.agent.strategy import StrategyLikedObject
256256

257-
class 限流策略(StrategyLikedObject):
258-
def __init__(self, 最大调用次数: int, api_key: str):
259-
self.最大调用次数 = 最大调用次数
260-
self.调用计数 = 0
257+
class RateLimitedStrategy(StrategyLikedObject):
258+
def __init__(self, max_calls: int, api_key: str):
259+
self.max_calls = max_calls
260+
self.call_count = 0
261261
self.api_key = api_key
262-
self.客户端 = MyAPIClient(api_key) # 预加载资源
262+
self.client = MyAPIClient(api_key) # 预加载资源
263263

264264
@classmethod
265265
def get_category(cls) -> str:
266266
return "agent"
267267

268268
async def single_execute(self) -> bool:
269-
self.调用计数 += 1
270-
if self.调用计数 > self.最大调用次数:
269+
self.call_count += 1
270+
if self.call_count > self.max_calls:
271271
return False # 停止
272-
# 使用 self.客户端 进行 API 调用...
272+
# 使用 self.client 进行 API 调用...
273273
return True
274274

275275
async def on_limited(self) -> None:
@@ -278,13 +278,13 @@ class 限流策略(StrategyLikedObject):
278278
)
279279

280280
# 传入实例 — 而非类
281-
策略 = 限流策略(最大调用次数=5, api_key="sk-...")
281+
strategy = RateLimitedStrategy(max_calls=5, api_key="sk-...")
282282
chat_obj = ChatObject(
283283
train={"system": "你是一个有用的助手"},
284284
user_input="你好",
285285
context=None,
286286
session_id="session_123",
287-
agent_strategy=策略, # 实例!
287+
agent_strategy=strategy, # 传入实例
288288
)
289289
```
290290

docs/docs/zh/guide/extensions-integration/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -611,16 +611,16 @@ async def get_weather_data(data: dict) -> str:
611611
```python
612612
# 示例: 与 FastAPI 集成为 Web 服务
613613
from fastapi import FastAPI
614-
from amrita_core import ChatObject, init
615-
from amrita_core.config import AmritaConfig
614+
from amrita_core import ChatObject, minimal_init
615+
from amrita_core.config import AmritaConfig, set_config
616616
from amrita_core.types import MemoryModel, Message
617617

618618
app = FastAPI()
619619

620620
# 启动应用时初始化 AmritaCore
621-
init()
622-
from amrita_core.config import set_config
623-
set_config(AmritaConfig())
621+
@app.on_event("startup")
622+
async def startup():
623+
await minimal_init(AmritaConfig())
624624

625625
@app.post("/chat/")
626626
async def chat_endpoint(user_input: str, session_id: str):

docs/docs/zh/guide/function-implementation.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22

33
## 4.1 初始化和加载
44

5-
### 4.1.1 init() 初始化函数
5+
### 4.1.1 init() 初始化函数(已废弃)
66

7-
`init()` 函数初始化AmritaCore的核心组件,在执行任何其他操作之前必须调用:
7+
> **从 v0.9.0rc1 起已废弃**`init()` 函数现在是空操作存根,不再执行任何初始化。请改用 `minimal_init()``load_amrita()` 进行异步初始化。
88
99
```python
1010
from amrita_core import init
1111

12-
# 初始化AmritaCore
12+
# 不再必要 — 现在是一个空操作
1313
init()
1414
```
1515

16-
此函数执行几项关键任务
16+
此函数以前执行几项关键任务
1717

1818
- 设置内部日志记录
19-
- 初始化Jieba进行文本处理(如果可用)
19+
- 初始化Jieba进行文本处理
2020
- 加载内置模块
21-
- 准备核心框架以供使用
21+
22+
这些任务现在由框架自动处理,或通过 `amrita-sense` 完成。
2223

2324
### 4.1.2 load_amrita() 异步加载
2425

@@ -35,9 +36,21 @@ async def main():
3536
asyncio.run(main())
3637
```
3738

38-
### 4.1.3 配置设置和检索
39+
### 4.1.3 minimal_init() 最小化初始化
40+
41+
`minimal_init()` 结合了配置设置和异步加载,是推荐的初始化方式:
42+
43+
```python
44+
from amrita_core import minimal_init
45+
from amrita_core.config import AmritaConfig
46+
47+
# 一行完成初始化和配置
48+
await minimal_init(AmritaConfig())
49+
```
50+
51+
### 4.1.4 配置设置和检索
3952

40-
#### 4.1.3.1 set_config() 设置配置
53+
#### 4.1.4.1 set_config() 设置配置
4154

4255
`set_config()` 函数将配置应用到AmritaCore:
4356

0 commit comments

Comments
 (0)