Fix empty tool-use response handling

This commit is contained in:
Haoran
2026-08-15 00:03:45 +08:00
parent 985456f4ad
commit 168fff86dd
90 changed files with 885 additions and 503 deletions

View File

@@ -130,7 +130,7 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
**Stop** はループが終了する直前に発火する`stop_reason != "tool_use"`。以下の hook は終了時の統計を出力する:
**Stop** はループが終了する直前に発火する。以下の hook は終了時の統計を出力する:
```python
def summary_hook(messages: list) -> str | None:
@@ -147,7 +147,10 @@ register_hook("Stop", summary_hook)
agent_loop 内では、終了前に発火:
```python
if response.stop_reason != "tool_use":
tool_calls = [
block for block in response.content if block.type == "tool_use"
]
if not tool_calls:
force = trigger_hooks("Stop", messages) # ← 終了する前に
if force:
# フックがメッセージを返した → 注入して続行
@@ -159,10 +162,7 @@ if response.stop_reason != "tool_use":
**ループ内で変更されたのは一箇所だけ**s03 は直接 `check_permission(block)` を呼び出していたが、s04 は `trigger_hooks("PreToolUse", block)` に置き換えた:
```python
for block in response.content:
if block.type != "tool_use":
continue
for block in tool_calls:
# s03: if not check_permission(block): ...
# s04: フックがハードコードを代替
blocked = trigger_hooks("PreToolUse", block)

View File

@@ -130,7 +130,7 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
**Stop** triggers when the loop is about to exit (`stop_reason != "tool_use"`). The following hook prints a cleanup summary:
**Stop** triggers when the loop is about to exit. The following hook prints a cleanup summary:
```python
def summary_hook(messages: list) -> str | None:
@@ -147,7 +147,10 @@ register_hook("Stop", summary_hook)
In agent_loop, triggered before exit:
```python
if response.stop_reason != "tool_use":
tool_calls = [
block for block in response.content if block.type == "tool_use"
]
if not tool_calls:
force = trigger_hooks("Stop", messages) # ← before exiting
if force:
# hook returned a message → inject it and continue
@@ -159,10 +162,7 @@ if response.stop_reason != "tool_use":
**Only one change in the loop**: s03 directly called `check_permission(block)`, s04 replaces it with `trigger_hooks("PreToolUse", block)`:
```python
for block in response.content:
if block.type != "tool_use":
continue
for block in tool_calls:
# s03: if not check_permission(block): ...
# s04: hooks replace hardcoding
blocked = trigger_hooks("PreToolUse", block)

View File

@@ -130,7 +130,7 @@ register_hook("PreToolUse", log_hook)
register_hook("PostToolUse", large_output_hook)
```
**Stop** 在循环即将退出时触发`stop_reason != "tool_use"`。以下 hook 打印收尾统计:
**Stop** 在循环即将退出时触发。以下 hook 打印收尾统计:
```python
def summary_hook(messages: list) -> str | None:
@@ -147,7 +147,10 @@ register_hook("Stop", summary_hook)
在 agent_loop 中,退出前触发:
```python
if response.stop_reason != "tool_use":
tool_calls = [
block for block in response.content if block.type == "tool_use"
]
if not tool_calls:
force = trigger_hooks("Stop", messages) # ← 退出之前
if force:
# hook returned a message → inject it and continue
@@ -159,10 +162,7 @@ if response.stop_reason != "tool_use":
**循环里只改了一处**s03 直接调用 `check_permission(block)`s04 改为 `trigger_hooks("PreToolUse", block)`
```python
for block in response.content:
if block.type != "tool_use":
continue
for block in tool_calls:
# s03: if not check_permission(block): ...
# s04: hook 替代硬编码
blocked = trigger_hooks("PreToolUse", block)

View File

@@ -205,7 +205,10 @@ def agent_loop(messages: list):
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
tool_calls = [
block for block in response.content if block.type == "tool_use"
]
if not tool_calls:
force = trigger_hooks("Stop", messages)
if force:
messages.append({"role": "user", "content": force})
@@ -213,10 +216,7 @@ def agent_loop(messages: list):
return
results = []
for block in response.content:
if block.type != "tool_use":
continue
for block in tool_calls:
# s04 change: hook replaces hard-coded check_permission()
blocked = trigger_hooks("PreToolUse", block)
if blocked:

View File

@@ -39,7 +39,7 @@
<!-- ② LLM -->
<rect x="200" y="108" width="120" height="64" rx="8" fill="#fff" stroke="#2563eb" stroke-width="1.5"/>
<text x="260" y="134" fill="#1e3a5f" font-size="14" font-weight="700" text-anchor="middle">LLM</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">stop_reason=tool_use?</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">tool_use block?</text>
<!-- LLM No → Return -->
<line x1="260" y1="172" x2="260" y2="200" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -39,7 +39,7 @@
<!-- ② LLM -->
<rect x="200" y="108" width="120" height="64" rx="8" fill="#fff" stroke="#2563eb" stroke-width="1.5"/>
<text x="260" y="134" fill="#1e3a5f" font-size="14" font-weight="700" text-anchor="middle">LLM</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">stop_reason=tool_use?</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">tool_use block?</text>
<!-- LLM No → 返却 -->
<line x1="260" y1="172" x2="260" y2="200" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -39,7 +39,7 @@
<!-- ② LLM -->
<rect x="200" y="108" width="120" height="64" rx="8" fill="#fff" stroke="#2563eb" stroke-width="1.5"/>
<text x="260" y="134" fill="#1e3a5f" font-size="14" font-weight="700" text-anchor="middle">LLM</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">stop_reason=tool_use?</text>
<text x="260" y="154" fill="#64748b" font-size="10" text-anchor="middle">tool_use block?</text>
<!-- LLM 否 → 返回 -->
<line x1="260" y1="172" x2="260" y2="200" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB