Skip to content

Commit 1c256d0

Browse files
committed
fix example and pipeline execution
1 parent bbd07eb commit 1c256d0

20 files changed

Lines changed: 446 additions & 894 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pip install trpc-agent-py
8484
Install optional capabilities as needed:
8585

8686
```bash
87-
pip install "trpc-agent-py[a2a,ag-ui,knowledge,agent-claude,mem0,mempalace,langfuse]"
87+
pip install trpc-agent-py[a2a,ag-ui,knowledge,agent-claude,mem0, Mempalace, langfuse]
8888
```
8989

9090
### Develop Weather Agent

README.zh_CN.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ pip install trpc-agent-py
8484
按需安装扩展能力:
8585

8686
```bash
87-
pip install "trpc-agent-py[a2a,ag-ui,knowledge,agent-claude,mem0,mempalace,langfuse]"
87+
pip install trpc-agent-py[a2a,ag-ui,knowledge,agent-claude,mem0, Mempalace, langfuse]
8888
```
8989

90+
9091
### 开发天气查询Agent
9192

9293
```python

docs/mkdocs/en/sub_agent.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,6 @@ A **short-lived sub-agent** is a natural fit for these problems: a fresh context
2121

2222
The difference is *who defines the role*: the developer (Spawn) or the LLM (Dynamic).
2323

24-
### How this differs from other multi-agent mechanisms
25-
26-
The framework already offers several ways to compose agents (see [Multi Agents](multi_agents.md)). Spawned Sub-Agents solve a different problem:
27-
28-
| Mechanism | Agents involved | Who decides when to invoke | Context | Typical use |
29-
| --- | --- | --- | --- | --- |
30-
| **Chain / Parallel / Cycle Agent** | **Pre-built** fixed agent instances | **Deterministic** orchestration — run in list order / in parallel / in a loop, regardless of input | Each agent independent | Fixed multi-step workflows |
31-
| **Sub Agents (transfer)** | Pre-registered agents | Parent **transfers control** at runtime; the sub-agent then takes over the conversation | Shared session | **Hand off** the whole conversation to a better-suited agent |
32-
| **AgentTool** | Wraps **an existing agent instance** as a tool | Parent LLM calls it on demand | Shares/syncs state & artifacts back to parent | Reuse a **specific, already-built** agent |
33-
| **Spawned Sub-Agents** | **Created on the fly** per call, destroyed after | Parent LLM calls it on demand | **Strictly isolated**: fresh ephemeral session, history/state not shared by default | Delegate a **one-off** subtask while keeping the parent context clean |
34-
35-
In one line: **Chain/Parallel/Cycle** deterministically orchestrate a fixed set of agents; **transfer** hands the conversation off; **AgentTool** reuses one existing agent as a tool; while **Spawned Sub-Agents** create an **isolated, short-lived** sub-agent on the spot for a single task and discard it afterward — the emphasis is on **on-demand runtime creation** and **context isolation**, not reusing an existing agent or transferring control.
36-
3724
## Quick Start
3825

3926
```python
@@ -186,19 +173,8 @@ class SubAgentConfig:
186173

187174
max_turns: int | None = None
188175
"""Max LLM calls the sub-agent may make. None = unlimited."""
189-
190-
forward_events: bool = False
191-
"""Whether to forward the sub-agent's execution events to the parent
192-
runner's consumer as progress updates.
193-
194-
True: the orchestrator can display the sub-agent's execution live (model
195-
output, tool calls, tool results); the parent agent's LLM still receives
196-
only the sub-agent's final result. False (default): the sub-agent runs
197-
silently and only its final result is returned."""
198176
```
199177

200-
Forwarded events reach the consumer as progress events; they are **not** written to the parent session and **never** enter the parent agent's LLM context. Consumers identify them via `tool_progress=True` on `event.custom_metadata` and read the execution from `payload` (`author` / `partial` / `content`, plus optional `error` / `usage`).
201-
202178
## Usage
203179

204180
### SpawnSubAgentTool
@@ -294,4 +270,3 @@ orchestrator = LlmAgent(
294270
- **Session isolation**: sub-agents run in a fresh ephemeral session. Parent history is not shared by default; opt in via `include_parent_history=True`.
295271
- **Nesting**: 1-level hard cap. Sub-agents cannot spawn further sub-agents.
296272
- **Result shape**: the sub-agent's final text is returned as the tool result string.
297-
- **Live execution (`forward_events`)**: set `SubAgentConfig(forward_events=True)` to stream the sub-agent's execution to the parent runner's consumer for display. Forwarded events are progress events — they never enter the parent LLM's context, which still receives only the final result. Consumers detect them via `tool_progress=True` on `event.custom_metadata` and read `payload`. See `examples/dynamic_subagent` and `examples/spawn_subagent` for a working consumer.

docs/mkdocs/zh/sub_agent.md

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,6 @@
2121

2222
区别在于**谁定义角色**:开发者(Spawn)还是 LLM(Dynamic)。
2323

24-
### 与框架其他多 agent 机制的区别
25-
26-
框架已有几种组合 agent 的方式(详见 [Multi Agents](multi_agents.md))。Spawned Sub-Agents 与它们解决的是不同问题:
27-
28-
| 机制 | 参与的 agent | 谁决定何时调用 | 上下文 | 典型用途 |
29-
| --- | --- | --- | --- | --- |
30-
| **Chain / Parallel / Cycle Agent** | **预先构建**的固定 agent 实例 | **确定性**编排——按列表顺序/并行/循环执行,与输入无关 | 各 agent 独立 | 固定的多步工作流 |
31-
| **Sub Agents(transfer)** | 预先注册的 agent | 父 agent 运行时**转移控制权**,之后由子 agent 接管对话 | 共享同一会话 | 把整段对话**移交**给更合适的 agent |
32-
| **AgentTool** |**某个已有 agent 实例**包成工具 | 父 LLM 按需调用 | 会共享/同步 state 与 artifact 回父 | 复用一个**具体的、已存在的** agent |
33-
| **Spawned Sub-Agents** | **调用时临时创建**、用完即销毁 | 父 LLM 按需调用 | **严格隔离**:全新临时会话,默认不共享历史/state | 委派**一次性**子任务,保持父上下文干净 |
34-
35-
一句话概括:**Chain/Parallel/Cycle** 是"确定性编排一组固定 agent";**transfer** 是"把对话交出去";**AgentTool** 是"把一个已有 agent 当工具复用";而 **Spawned Sub-Agents** 是"为单次任务**现场造一个隔离的、短命的**子 agent,跑完就丢"——强调的是**运行时按需创建****上下文隔离**,而非复用既有 agent 或转移控制。
36-
3724
## Quick Start
3825

3926
```python
@@ -186,17 +173,8 @@ class SubAgentConfig:
186173

187174
max_turns: int | None = None
188175
"""子 agent 最多可发起的 LLM 调用次数。None = 不限制。"""
189-
190-
forward_events: bool = False
191-
"""是否将子 agent 的执行事件转发给父 runner 的消费者,作为进度更新。
192-
193-
True:编排层可实时展示子 agent 的执行(模型输出、工具调用、工具结果),
194-
父 agent 的 LLM 仍只收到子 agent 的最终结果。
195-
False(默认):子 agent 静默执行,只回传最终结果。"""
196176
```
197177

198-
转发的事件以进度事件形式到达消费者,**不会**写入父会话、也**不会**进入父 agent 的 LLM 上下文;消费者通过 `event.custom_metadata` 上的 `tool_progress=True` 识别它们,并从 `payload` 读取执行内容(`author` / `partial` / `content` / 可选 `error` / `usage`)。
199-
200178
## 使用方式
201179

202180
### SpawnSubAgentTool
@@ -292,4 +270,3 @@ orchestrator = LlmAgent(
292270
- **会话隔离**:子 agent 在全新临时会话中运行,默认不共享父会话历史。通过 `include_parent_history=True` 可注入。
293271
- **嵌套限制**:1 层硬限,子 agent 无法再次 spawn。
294272
- **结果形态**:子 agent 的最终文本作为 tool result 字符串返回。
295-
- **实时执行(`forward_events`**:设置 `SubAgentConfig(forward_events=True)` 可将子 agent 的执行流转发给父 runner 的消费者用于展示。转发事件为进度事件——它们不会进入父 agent 的 LLM 上下文(父仍只收到最终结果)。消费者通过 `event.custom_metadata` 上的 `tool_progress=True` 识别它们并读取 `payload`。可运行示例见 `examples/dynamic_subagent``examples/spawn_subagent`

examples/dynamic_subagent/agent/agent.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,7 @@ def create_minimal_agent() -> LlmAgent:
4545
temperature=0.7,
4646
max_output_tokens=2000,
4747
),
48-
tools=workspace_tools + [
49-
DynamicSubAgentTool(
50-
# Stream the sub-agent's execution to the parent consumer.
51-
agent_config=SubAgentConfig(forward_events=True),
52-
),
53-
],
48+
tools=workspace_tools + [DynamicSubAgentTool()],
5449
)
5550

5651

@@ -74,8 +69,6 @@ def create_bounded_agent() -> LlmAgent:
7469
temperature=0.3,
7570
max_output_tokens=1000,
7671
),
77-
# Stream the sub-agent's execution to the parent consumer.
78-
forward_events=True,
7972
),
8073
),
8174
],

examples/dynamic_subagent/run_agent.py

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,45 +33,14 @@
3333

3434
def _truncate(text: str, max_len: int = 200) -> str:
3535
"""Truncate long tool output for display."""
36+
return text
3637
if not isinstance(text, str):
3738
text = str(text)
3839
if len(text) <= max_len:
3940
return text
4041
return text[:max_len] + f"\n... (truncated, total {len(text)} chars)"
4142

4243

43-
def _print_subagent_progress(payload: dict) -> None:
44-
"""Render one forwarded sub-agent execution event.
45-
46-
``payload`` is a :class:`SubAgentProgress` dict: ``author`` / ``partial``,
47-
the framework-native ``content`` dump (``parts`` with ``function_call`` /
48-
``function_response`` / ``text`` / ``thought``), and optional ``error`` /
49-
``usage``. Indented under the parent output so the sub-agent's steps are
50-
visually distinct from the orchestrator's.
51-
"""
52-
name = payload.get("author") or "subagent"
53-
# Errors first — always surface them, even on an otherwise-partial event.
54-
err = payload.get("error")
55-
if err:
56-
print(f"\n \U0001F9E9 [{name}] !! error {err.get('code')}: {err.get('message')}")
57-
if payload.get("partial"):
58-
# Skip streaming text deltas to keep the demo output readable; the
59-
# non-partial steps below already summarize the sub-agent's work.
60-
return
61-
parts = (payload.get("content") or {}).get("parts") or []
62-
has_calls = any(p.get("function_call") or p.get("function_response") for p in parts)
63-
for p in parts:
64-
fc = p.get("function_call")
65-
if fc:
66-
print(f"\n \U0001F9E9 [{name}] -> tool {fc.get('name')}({_truncate(fc.get('args'))})")
67-
fr = p.get("function_response")
68-
if fr:
69-
print(f" \U0001F9E9 [{name}] <- {_truncate(fr.get('response'))}")
70-
text = p.get("text")
71-
if text and not p.get("thought") and not has_calls:
72-
print(f"\n \U0001F9E9 [{name}] {_truncate(text)}")
73-
74-
7544
_QUERIES = {
7645
"minimal": [
7746
# Simple task: orchestrator may call word_count directly.
@@ -124,18 +93,6 @@ async def run_demo(mode: str):
12493
session_id=current_session_id,
12594
new_message=user_content,
12695
):
127-
# Forwarded sub-agent execution events (SubAgentConfig
128-
# forward_events=True). These are partial progress events carrying
129-
# the sub-agent's own steps under custom_metadata.payload; they
130-
# never reach the parent LLM's context. This demo registers only the
131-
# sub-agent tool, so tool_progress alone identifies them; an app with
132-
# several progress tools would also branch on meta["tool_name"].
133-
meta = event.custom_metadata or {}
134-
payload = meta.get("payload")
135-
if meta.get("tool_progress") and isinstance(payload, dict):
136-
_print_subagent_progress(payload)
137-
continue
138-
13996
if event.content and event.content.parts and event.author != "user":
14097
if event.partial:
14198
for part in event.content.parts:

examples/langgraph_agent/agent/agent.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ def build_calculator_subgraph():
3939
api_key, url, model_name = get_model_config()
4040
model = init_chat_model(
4141
model_name,
42+
model_provider="openai",
4243
api_key=api_key,
43-
api_base=url,
44+
base_url=url,
4445
)
4546

4647
tools = [calculate]
@@ -79,8 +80,9 @@ def build_graph_with_subgraph():
7980
api_key, url, model_name = get_model_config()
8081
model = init_chat_model(
8182
model_name,
83+
model_provider="openai",
8284
api_key=api_key,
83-
api_base=url,
85+
base_url=url,
8486
)
8587

8688
# Build calculator subgraph
@@ -126,8 +128,9 @@ def build_graph():
126128
api_key, url, model_name = get_model_config()
127129
model = init_chat_model(
128130
model_name,
131+
model_provider="openai",
129132
api_key=api_key,
130-
api_base=url,
133+
base_url=url,
131134
)
132135

133136
tools = [calculate]

examples/langgraph_agent_with_cancel/agent/agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ def build_graph():
4444
api_key, url, model_name = get_model_config()
4545
model = init_chat_model(
4646
model_name,
47+
model_provider="openai",
4748
api_key=api_key,
48-
api_base=url,
49+
base_url=url,
4950
)
5051

5152
tools = [calculate, analyze_data]

examples/langgraphagent_with_human_in_the_loop/agent/agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ def _build_graph():
5353
api_key, url, model_name = get_model_config()
5454
model = init_chat_model(
5555
model_name,
56+
model_provider="openai",
5657
api_key=api_key,
57-
api_base=url,
58+
base_url=url,
5859
)
5960
tools = [execute_database_operation]
6061
llm_with_tools = model.bind_tools(tools)

examples/mem0_tools/agent/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
from trpc_agent_sdk.agents import LlmAgent
1111
from trpc_agent_sdk.models import LLMModel
1212
from trpc_agent_sdk.models import OpenAIModel
13-
from trpc_agent_sdk.tools.mem0_tools import SaveMemoryTool
14-
from trpc_agent_sdk.tools.mem0_tools import SearchMemoryTool
13+
from trpc_agent_sdk.tools.mem0_tool import SaveMemoryTool
14+
from trpc_agent_sdk.tools.mem0_tool import SearchMemoryTool
1515

1616
from .config import get_mem0_platform_config
1717
from .config import get_memory_config

0 commit comments

Comments
 (0)