You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Analysis**: Stream thinking process, then replace with final conclusion
267
267
-**Tool integration**: Stream partial results, then override with tool-enhanced content
268
268
269
+
## Unified Harness Surface (Framework Agents)
270
+
271
+
!!! tip "Recommended for framework-based agents"
272
+
If your agent is built on an agent framework (LangGraph, Pydantic AI, OpenAI Agents SDK) or a coding CLI (Claude Code, Codex), the **unified harness surface** is the recommended way to stream. You write nothing ACP-specific: wrap the framework's native event stream in a `HarnessTurn` and hand it to a `UnifiedEmitter`. The emitter delivers the same canonical `StreamTaskMessage*` stream over either channel **and derives tracing spans from it automatically** — no separate tracing handler.
273
+
274
+
The canonical event stream (`StreamTaskMessageStart/Delta/Full/Done`) is produced **once** by a per-framework *tap* (`convert_<framework>_to_agentex_events`). The emitter consumes it and handles delivery + tracing uniformly, so the same `turn` object works for Sync, Async, and Temporal — only the delivery call changes.
275
+
276
+
Per-framework `HarnessTurn` wrappers ship today, all re-exported from `agentex.lib.adk` (requires `agentex-sdk >= 0.14.0`):
277
+
278
+
| Framework | Turn class | Tap function |
279
+
|---|---|---|
280
+
| Pydantic AI |`PydanticAITurn`|`convert_pydantic_ai_to_agentex_events`|
parent_span_id=turn_span.id if turn_span elseNone,
317
+
)
318
+
turn = LangGraphTurn(graph.astream(...))
319
+
result =await emitter.auto_send_turn(turn) # auto_send_turn replaces yield_turn
320
+
# result.final_text, result.usage
321
+
```
322
+
323
+
In a **Temporal** workflow the body is the same — construct the `UnifiedEmitter`, build the `turn`, and `await emitter.auto_send_turn(turn, created_at=workflow.now())` (pass `created_at` so events carry deterministic workflow time).
324
+
325
+
**Why use it:**
326
+
327
+
-**One mental model** for Sync, Async, and Temporal — `yield_turn` vs `auto_send_turn`, same `turn`.
328
+
-**Tracing for free** — tool and reasoning spans are derived from the canonical stream (tool spans paired by `tool_call_id`) and fan out to every registered processor. No `create_<framework>_tracing_handler` to wire (those per-framework tracing handlers have been removed).
329
+
-**Usage + final text** — `auto_send_turn` returns a `TurnResult` (`final_text`, `usage`) with normalized token/cost numbers.
330
+
-**Streamed tool args survive async** — the emitter honors streamed `ToolRequestDelta`s on the Redis channel, not just sync.
331
+
332
+
To add a framework that doesn't have a `HarnessTurn` yet, follow the `agentex-add-agent-framework` workflow: write a tap + a `<Fw>Turn`, export both from `agentex.lib.adk`. There is no per-framework async streamer or tracing handler to author.
333
+
269
334
## OpenAI Agents SDK Streaming
270
335
271
-
!!! note "More Modular Approach"
272
-
The **OpenAI Agents SDK** provides a more modular alternative to `auto_send`. Instead of black-box logic, you write custom **providers** (for sync agents) and/or**hooks + providers** (for agentic ACPs) by inheriting classes and overriding methods. This Pythonic approach gives you full control over streaming behavior while working with **any LiteLLM model** (GPT-4, Claude, Gemini, etc.).
336
+
!!! note "Lower-level alternative for fine-grained OpenAI SDK control"
337
+
The unified harness `OpenAITurn` above covers most OpenAI Agents SDK agents. The custom **provider** (sync) and **hooks + provider** (agentic) approach below is the lower-level path when you need to override streaming behavior directly — it works with **any LiteLLM model** (GPT-4, Claude, Gemini, etc.).
273
338
274
339
The OpenAI Agents SDK supports [any LiteLLM model](https://openai.github.io/openai-agents-python/models/litellm/) and provides a cleaner architecture than `auto_send`:
- Wrap the framework's stream in a `HarnessTurn` (`LangGraphTurn`, `PydanticAITurn`, `OpenAITurn`, `ClaudeCodeTurn`, `CodexTurn`) and deliver via `UnifiedEmitter`.
586
+
- `yield_turn` for Sync, `auto_send_turn` for Async/Temporal — same `turn`, tracing derived automatically.
587
+
519
588
**Standard LiteLLM Providers (via ADK):**
520
589
- **Sync ACP**: Manual delta accumulation, full control
521
590
- **Async Auto Send**: Automatic but black-box (easiest, least flexible)
-**[Multiturn](https://github.com/scaleapi/scale-agentex-python/tree/main/examples/tutorials/00_sync/010_multiturn){target="_blank"}**: Conversation history and memory
Framework starters (the `agentex init` Sync ACP options, each on the [unified harness](streaming_patterns.md#unified-harness-surface-framework-agents)):
-**[Multi-Agent Assembly Line](https://github.com/scaleapi/scale-agentex-python/tree/main/examples/tutorials/10_async/00_base/090_multi_agent_non_temporal){target="_blank"}**: Multi-agent coordination without Temporal
28
36
37
+
Framework starters (the `agentex init` Async - ACP Only options, each on the [unified harness](streaming_patterns.md#unified-harness-surface-framework-agents)):
Enterprise-ready patterns with durable execution for production deployments requiring reliability and fault tolerance.
@@ -40,6 +56,14 @@ Enterprise-ready patterns with durable execution for production deployments requ
40
56
-[OpenAI Agents SDK: Tools](https://github.com/scaleapi/scale-agentex-python/tree/main/examples/tutorials/10_async/10_temporal/070_open_ai_agents_sdk_tools){target="_blank"}: Single and multi-activity tool patterns
41
57
-[OpenAI Agents SDK: Human-in-the-Loop](https://github.com/scaleapi/scale-agentex-python/tree/main/examples/tutorials/10_async/10_temporal/080_open_ai_agents_sdk_human_in_the_loop){target="_blank"}: Human approval workflows
42
58
59
+
Framework starters (the `agentex init` Async - Temporal options, each on the [unified harness](streaming_patterns.md#unified-harness-surface-framework-agents)):
Copy file name to clipboardExpand all lines: agentex/docs/docs/getting_started/choose_your_agent_type.md
+28Lines changed: 28 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,6 +21,34 @@ Agentex supports three agent types with different execution models and capabilit
21
21
22
22
---
23
23
24
+
## Pick a Framework (Harness)
25
+
26
+
Choosing an agent type is only the **first** prompt in `agentex init`. After you pick Sync / Async-base / Temporal, the CLI asks which **agent framework** to scaffold. This is independent of the agent type — each type offers the same framework starters:
27
+
28
+
|`agentex init` prompt | Framework options |
29
+
|---|---|
30
+
|**Sync ACP**| Basic · OpenAI Agents SDK (Recommended) · OpenAI Agents SDK + Local Sandbox · LangGraph · Pydantic AI · Claude Code · Codex |
31
+
|**Async - ACP Only**| Basic · OpenAI Agents SDK · LangGraph · Pydantic AI · Claude Code · Codex |
32
+
|**Async - Temporal**| Basic · OpenAI Agents SDK (Recommended) · Pydantic AI · LangGraph · Claude Code · Codex |
33
+
34
+
!!! note "OpenAI Agents SDK + Local Sandbox"
35
+
The **Local Sandbox** variant is the OpenAI Agents SDK starter wired to run tools inside a local sandbox. It shares the same harness wiring and tutorial base as the plain [OpenAI Agents SDK](../development_guides/tutorials.md#sync-acp-simple-agents) starter — there is no separate tutorial for it.
36
+
37
+
**What "Basic" gives you:** a blank handler that you fill in yourself (the examples in the [Project Structure Guide](project_structure.md) show this variant). Pick it when you're writing your agent loop by hand or calling an LLM through LiteLLM directly.
38
+
39
+
**What a framework template gives you:** the same project layout **plus** the [unified harness](../development_guides/streaming_patterns.md#unified-harness-surface-framework-agents) wiring already in place — the framework's stream wrapped in a `HarnessTurn` and delivered by `UnifiedEmitter`, so streaming and tracing work out of the box. Some frameworks also add helper files (e.g. `agent.py` + `tools.py` for Pydantic AI / OpenAI Agents, `graph.py` + `tools.py` for LangGraph).
40
+
41
+
How to choose:
42
+
43
+
-**Writing the loop yourself / LiteLLM only** → Basic.
44
+
-**Already standardized on a framework** → pick it directly (LangGraph, Pydantic AI, OpenAI Agents SDK).
45
+
-**Wrapping a coding CLI** → Claude Code (spawns the `claude` CLI) or Codex (spawns the `codex` CLI) as a local subprocess, streamed through the harness.
46
+
-**Want tools + good defaults and unsure** → OpenAI Agents SDK (the Recommended option for Sync and Temporal).
47
+
48
+
To add a framework that isn't in the list, see the `agentex-add-agent-framework` workflow.
49
+
50
+
---
51
+
24
52
## Upgrade Path
25
53
26
54
| Current Type | When to Upgrade | Upgrade To | Key Benefit |
`agentex init` then asks which **agent framework** to scaffold (Basic, OpenAI Agents SDK, LangGraph, Pydantic AI, Claude Code, or Codex) — see [Pick a Framework (Harness)](choose_your_agent_type.md#pick-a-framework-harness).
14
+
15
+
!!! note "These examples are the **Basic** variant"
16
+
The `project/acp.py` shown for each agent type below is the **Basic** (blank-slate) template. If you pick a framework instead, the handler comes pre-wired with the [unified harness](../development_guides/streaming_patterns.md#unified-harness-surface-framework-agents) (the framework's stream wrapped in a `HarnessTurn`, delivered by `UnifiedEmitter`, with streaming + tracing handled), and some frameworks add helper files: `agent.py` + `tools.py` (Pydantic AI, OpenAI Agents) or `graph.py` + `tools.py` (LangGraph). For **Sync** and **Async-base** agents this wiring lives in `acp.py`; for **Temporal** agents it lives in `workflow.py` / `activities.py` instead. The rest of the layout is identical.
17
+
13
18
This guide is organized by agent type. Jump to your section:
0 commit comments