Skip to content

Commit 776d277

Browse files
chore(examples): PR-review fixes for 05/07/09
- 09 tool-use: handle ``ToolCall.arguments is None`` (provider- reported parse error path) and wrap dispatch in a try/except that catches KeyError/ValueError/TypeError from bad args. Errors surface as ToolMessage content so the model can retry or give up gracefully rather than crashing the graph. - 07 multimodal-prompt: add ``prompts_fallback/production/ identify-mission.j2`` so the fallback backend actually covers both prompts. Without it, a primary outage would let the caption call fall through but break the identify call with PromptNotFound. Update the in-code comment that previously said fallback shipped only one prompt. - 05 fan-out-with-retry: fix BatchState docstring that referenced ``branch_errors`` (the parallel-branches-side name) — the actual field is ``instance_errors``.
1 parent 89f13b1 commit 776d277

4 files changed

Lines changed: 36 additions & 7 deletions

File tree

examples/05-fan-out-with-retry/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ async def _chat(system: str, user: str) -> str:
127127

128128
class BatchState(State):
129129
"""Outer graph: list of headlines goes in, parallel lists of summaries
130-
and topic tags come out. ``branch_errors`` only populates under
130+
and topic tags come out. ``instance_errors`` only populates under
131131
``error_policy="collect"`` — each failed instance contributes one
132132
record naming its ``fan_out_index`` and the exception category."""
133133

examples/07-multimodal-prompt/main.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,12 @@ def _get_provider() -> OpenAIProvider:
129129
# Two backends are wired here:
130130
# - primary: ``prompts/`` — ships caption-lunar-image and
131131
# identify-mission.
132-
# - fallback: ``prompts_fallback/`` — ships a backup
133-
# caption-lunar-image only. The fallback path fires when the
134-
# primary raises ``PromptStoreUnavailable`` (e.g., a remote
135-
# primary like Langfuse times out); ``PromptNotFound`` from
136-
# primary stops the chain (the name is legitimately missing).
132+
# - fallback: ``prompts_fallback/`` — ships shorter variants of
133+
# BOTH prompts so the safety net actually covers the whole
134+
# pipeline. The fallback path fires when the primary raises
135+
# ``PromptStoreUnavailable`` (e.g., a remote primary like
136+
# Langfuse times out); ``PromptNotFound`` from primary stops the
137+
# chain (the name is legitimately missing).
137138
#
138139
# In this demo both prompts live in primary, so the fallback path
139140
# isn't exercised at runtime. The construction-time setup is the
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
You are looking at a photograph from a lunar mission. The caption
2+
hint below was written by another system.
3+
4+
Caption hint: {{ caption }}
5+
6+
In ONE short line, name the specific mission shown:
7+
8+
Mission: <name>
9+
10+
No preamble.
11+
12+
(This is the fallback variant. The primary backend ships the
13+
canonical identify-mission prompt and is always tried first; this
14+
file exists so a primary-backend outage doesn't break the demo
15+
pipeline.)

examples/09-tool-use/main.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,20 @@ async def dispatch_tools(s: AgentState) -> Mapping[str, Any]:
289289
raise RuntimeError("dispatch_tools entered without a tool-calling assistant message")
290290
tool_messages: list[Message] = []
291291
for tc in last.tool_calls:
292-
result_text = dispatch(tc.name, tc.arguments or {})
292+
# ToolCall.arguments is None only under provider-reported
293+
# finish_reason="error" (unparseable args). In a real agent the
294+
# model sees the error string and either retries or bails;
295+
# either way the loop doesn't crash.
296+
if tc.arguments is None:
297+
result_text = (
298+
f"Tool {tc.name!r} could not be invoked: arguments were "
299+
f"unparseable. Retry with valid JSON arguments."
300+
)
301+
else:
302+
try:
303+
result_text = dispatch(tc.name, tc.arguments)
304+
except (KeyError, ValueError, TypeError) as exc:
305+
result_text = f"Tool {tc.name!r} failed with {type(exc).__name__}: {exc}"
293306
tool_messages.append(ToolMessage(content=result_text, tool_call_id=tc.id))
294307
return {
295308
"messages": [*s.messages, *tool_messages],

0 commit comments

Comments
 (0)