Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 6 additions & 6 deletions .github/workflows/harness-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ on:
paths:
- "src/agentex/lib/core/harness/**"
- "src/agentex/lib/adk/_modules/**"
- "tests/lib/core/harness/test_harness_pydantic_ai_*.py"
- "tests/lib/core/harness/test_harness_langgraph_*.py"
- "tests/lib/core/harness/test_harness_*.py"
- ".github/workflows/harness-integration.yml"

jobs:
Expand All @@ -34,14 +33,15 @@ jobs:
run: ./scripts/test tests/lib/core/harness/ -v

# Offline harness integration tests (sync / async / temporal channels) for each
# migrated harness. These use fake streams / TestModel + fake streaming/tracing
# and require no live infrastructure. Future harness migration PRs (6-8) add
# their harness to the matrix below and their test paths to the triggers above.
# harness. These use fake streams / TestModel + fake streaming/tracing and
# require no live infrastructure. All five harnesses are now covered; the
# trigger above uses a `test_harness_*.py` glob so new suites are picked up
# automatically.
live-matrix:
runs-on: ubuntu-latest
strategy:
matrix:
harness: [pydantic_ai, langgraph]
harness: [pydantic_ai, langgraph, openai, claude_code, codex]
channel: [sync, async, temporal]
fail-fast: false
name: ${{ matrix.harness }}-${{ matrix.channel }}
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

### ⚠ BREAKING CHANGES

* **harness:** removed the deprecated bespoke tracing handlers `create_langgraph_tracing_handler` / `create_pydantic_ai_tracing_handler` (and their `AgentexLangGraphTracingHandler` / `AgentexPydanticAITracingHandler` classes) from the public `agentex.lib.adk` surface. Span tracing is now derived from the canonical `StreamTaskMessage*` stream by `UnifiedEmitter` — wrap your run in the harness `*Turn` and drive `UnifiedEmitter.yield_turn` / `auto_send_turn`. The `agentex init` templates were migrated accordingly.
* **harness:** each harness now exposes exactly `_<harness>_sync.py` + `_<harness>_turn.py` under `agentex.lib.adk._modules`. The OpenAI harness `OpenAITurn` and `convert_openai_to_agentex_events` moved to `agentex.lib.adk._modules._openai_turn` / `_openai_sync`; back-compat shims remain at `agentex.lib.adk.providers._modules.{openai_turn,sync_provider}` for one release. Public facade names (`stream_pydantic_ai_events`, `stream_langgraph_events`, `emit_langgraph_messages`, etc.) are unchanged.

### Features

* **tracing:** emit OTel metrics for async span queue depth, batch drain, and SGP export success/failure (HTTP status labels). Disable SDK-side recording with ``AGENTEX_TRACING_METRICS=0``.
Expand Down
20 changes: 12 additions & 8 deletions adk/docs/harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ Every harness tap produces a sequence of these. Everything downstream (delivery,

## Per-harness taps: `convert_<harness>_to_agentex_events`

A tap is an async generator that translates the harness's native event stream into `StreamTaskMessage*` events. The currently shipped taps are:
A tap is an async generator that translates the harness's native event stream into `StreamTaskMessage*` events. The shipped taps are:

| Harness | Tap function | Exported from |
|---|---|---|
| pydantic-ai | `convert_pydantic_ai_to_agentex_events` | `agentex.lib.adk` |
| LangGraph | `convert_langgraph_to_agentex_events` | `agentex.lib.adk` |
| claude-code | `convert_claude_code_to_agentex_events` | `agentex.lib.adk` |
| codex | `convert_codex_to_agentex_events` | `agentex.lib.adk` |
| OpenAI Agents | `convert_openai_to_agentex_events` | `agentex.lib.adk.providers._modules.sync_provider` |

Taps for claude-code and codex will be added in subsequent PRs (AGX1-420, AGX1-421) and exported from `agentex.lib.adk` in the same way.
Each harness also provides a `HarnessTurn` wrapper that pairs its tap's event stream with usage extraction: `PydanticAITurn`, `LangGraphTurn`, `ClaudeCodeTurn`, `CodexTurn`, and `OpenAITurn`.

---

Expand Down Expand Up @@ -157,11 +160,13 @@ Spans are derived from the canonical stream by `SpanDeriver` (pure, no `adk` dep

## Usage examples by channel

### Sync ACP (pydantic-ai tap)
### Sync ACP (`yield_turn`)

Build the harness's `HarnessTurn` wrapper and iterate `emitter.yield_turn(turn)` — the emitter forwards each event to the caller and traces spans as a side effect:

```python
import agentex.lib.adk as adk
from agentex.lib.adk import UnifiedEmitter, convert_pydantic_ai_to_agentex_events
from agentex.lib.adk import UnifiedEmitter, ClaudeCodeTurn

@acp.on_message_send
async def handle(params):
Expand All @@ -172,13 +177,12 @@ async def handle(params):
trace_id=task_id,
parent_span_id=turn_span.id if turn_span else None,
)
tap = convert_pydantic_ai_to_agentex_events(pydantic_stream)
# wrap tap in a HarnessTurn then yield_turn, or yield directly:
async for event in tap:
turn = ClaudeCodeTurn(claude_code_stream) # any HarnessTurn
async for event in emitter.yield_turn(turn):
yield event
```

For the pre-unified sync path the tap is still yielded directly; `UnifiedEmitter.yield_turn` is the forward-looking integration point when a `HarnessTurn` wrapper is available.
Every harness follows the same shape — swap `ClaudeCodeTurn` for `PydanticAITurn`, `LangGraphTurn`, `CodexTurn`, or `OpenAITurn` and feed it that harness's native stream.

### Async Temporal (auto-send)

Expand Down
Loading
Loading