Skip to content

Commit 90182cb

Browse files
declan-scaleclaude
andcommitted
docs(migration): add guide for moving off the legacy claude_agents plugin
Document migrating from the original Temporal `claude_agents` plugin (`run_claude_agent_activity` + bespoke streaming/tracing) to the unified harness tap (`ClaudeCodeTurn` over the CLI stream-json stdout, delivered via UnifiedEmitter), which gets central span derivation — tool AND reasoning spans — and the shared delivery path. Also records the two Claude Code defect fixes (reasoning span text, duplicate-text dedup) in the guide, and adds a deprecation note to the plugin module docstring pointing at the tap. No code removal — the plugin still has consumers (090 tutorial, eval_dashboard_agent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 01fbc84 commit 90182cb

2 files changed

Lines changed: 82 additions & 1 deletion

File tree

adk/docs/migration-0.16.0.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,76 @@ path. No API change — behavior only.
197197
function-tool response path (`on_tool_end`) so hosted and function tools
198198
render identically within the same flow.
199199

200+
5. **Reasoning text now appears in derived spans.** `SpanDeriver` opened reasoning
201+
spans with empty input and closed them with `output=None`, so reasoning/thinking
202+
text never reached the trace (spans showed blank — read as "0 reasoning traces").
203+
It now accumulates the `ReasoningContentDelta` / `ReasoningSummaryDelta` text (and
204+
any text seeded on the Start content) and records it as the span output. Affects
205+
every harness that streams reasoning, including the Claude Code tap.
206+
207+
6. **Claude Code: no more duplicate text messages.** The `stream-json` converter
208+
deduped streamed-vs-materialized blocks by numeric block index and reset that
209+
state after every materialized `assistant` envelope. A single streamed message
210+
that materializes as several envelopes (thinking, then text) lost the dedup
211+
marker between envelopes and re-emitted the text. Dedup is now **content-based**
212+
(match the streamed block's text, consume once), which a numeric index cannot do
213+
reliably.
214+
200215
> Action: if you adopted `OpenAITurn` for **reasoning models** (o1/o3/gpt-5) on
201216
> the sync path before these fixes, upgrade — fixes 2 and 3 are required for
202-
> correct reasoning rendering.
217+
> correct reasoning rendering. Claude Code agents on the unified harness tap should
218+
> upgrade for fixes 5 and 6.
219+
220+
---
221+
222+
## 6. Legacy Temporal `claude_agents` plugin → unified harness tap
223+
224+
`agentex.lib.core.temporal.plugins.claude_agents` (`run_claude_agent_activity`,
225+
`create_streaming_hooks`, `TemporalStreamingHooks`, `ClaudeMessageHandler`) is the
226+
**original** Claude Code integration: it drives the Python `claude-agent-sdk`
227+
directly and hand-rolls its own streaming + tracing. It is **superseded** by the
228+
unified harness tap and slated for removal in a future release. It still works
229+
today, so this migration is **recommended, not yet required** — but new Claude Code
230+
agents should use the tap, and existing ones should plan to move.
231+
232+
Why migrate: the tap routes Claude Code through the same canonical
233+
`StreamTaskMessage*` stream as every other harness, so it gets central span
234+
derivation (tool **and** reasoning spans), the single delivery path
235+
(`UnifiedEmitter`), and fixes like the two above for free. The legacy plugin does
236+
not derive reasoning spans at all and duplicates the streaming/tracing logic.
237+
238+
**Before — legacy plugin activity:**
239+
240+
```python
241+
from agentex.lib.core.temporal.plugins.claude_agents import run_claude_agent_activity
242+
243+
# In the workflow:
244+
result = await workflow.execute_activity(
245+
run_claude_agent_activity,
246+
args=[prompt, workspace_path, allowed_tools, ...],
247+
start_to_close_timeout=...,
248+
)
249+
```
250+
251+
**After — unified harness tap.** Run the CLI yourself (`claude -p --output-format
252+
stream-json --include-partial-messages`), wrap its stdout in `ClaudeCodeTurn`, and
253+
deliver through `UnifiedEmitter`:
254+
255+
```python
256+
from agentex.lib.adk import ClaudeCodeTurn, UnifiedEmitter
257+
258+
# `stdout_lines` is an async iterator of the CLI's stdout lines (raw JSON strings
259+
# or pre-parsed dicts) — e.g. read from sandbox.exec() / a subprocess.
260+
turn = ClaudeCodeTurn(stdout_lines)
261+
262+
emitter = UnifiedEmitter(task_id=task_id, trace_id=trace_id, parent_span_id=parent_span_id)
263+
result = await emitter.auto_send_turn(turn, created_at=workflow.now())
264+
# result.final_text — last text segment
265+
# result.usage — TurnUsage (tokens, cost, num_reasoning_blocks, ...)
266+
```
267+
268+
The golden agent is the reference implementation
269+
(`teams/sgp/agents/golden_agent/project/harness/`): it spawns the CLI in a sandbox,
270+
yields stdout lines into `ClaudeCodeTurn`, and drives `auto_send_turn`. Known
271+
remaining consumers to migrate: the `090_claude_agents_sdk_mvp` tutorial and the
272+
`eval_dashboard_agent`.

src/agentex/lib/core/temporal/plugins/claude_agents/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
"""Claude Agents SDK integration with Temporal.
22
3+
.. deprecated::
4+
This is the original Claude Code integration: it drives the Python
5+
``claude-agent-sdk`` directly and hand-rolls its own streaming + tracing
6+
(and does not derive reasoning spans). It is superseded by the unified
7+
harness tap (``agentex.lib.adk.ClaudeCodeTurn`` over the ``claude -p
8+
--output-format stream-json`` CLI stdout, delivered via ``UnifiedEmitter``),
9+
which routes Claude Code through the same canonical ``StreamTaskMessage*``
10+
stream as every other harness. It still works, but new agents should use the
11+
tap and existing ones should plan to migrate; see
12+
``adk/docs/migration-0.16.0.md`` for the before/after.
13+
314
This plugin provides integration between Claude Agents SDK and AgentEx's
415
Temporal-based orchestration platform.
516

0 commit comments

Comments
 (0)