Skip to content

Commit abf053b

Browse files
declan-scaleclaude
andcommitted
test(harness): conformance scaffold + CI integration job skeleton
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c256383 commit abf053b

4 files changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Harness Integration
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "src/agentex/lib/core/harness/**"
7+
- "src/agentex/lib/adk/_modules/**"
8+
- ".github/workflows/harness-integration.yml"
9+
10+
jobs:
11+
conformance:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
15+
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
18+
with:
19+
version: '0.10.2'
20+
21+
- name: Bootstrap
22+
run: ./scripts/bootstrap
23+
24+
- name: Conformance suite
25+
run: uv run pytest tests/lib/core/harness/ -v
26+
27+
# Live integration matrix (harness x {sync, async, temporal}) is added per-harness
28+
# in the migration plans. Placeholder job keeps the workflow valid until then.
29+
live-matrix:
30+
runs-on: ubuntu-latest
31+
if: false # enabled once the first harness's test agents land
32+
steps:
33+
- run: echo "populated by migration PRs"

tests/lib/core/harness/conformance/__init__.py

Whitespace-only changes.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Shared conformance engine: every harness tap registers fixtures here.
2+
3+
A fixture is (name, list[StreamTaskMessage]). The runner asserts that span
4+
derivation over the events is identical regardless of delivery channel, which is
5+
the cross-channel guarantee from the spec.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from dataclasses import dataclass
11+
12+
from agentex.lib.core.harness.span_derivation import SpanDeriver
13+
from agentex.lib.core.harness.types import SpanSignal, StreamTaskMessage
14+
15+
16+
@dataclass
17+
class Fixture:
18+
name: str
19+
events: list[StreamTaskMessage]
20+
21+
22+
_REGISTRY: list[Fixture] = []
23+
24+
25+
def register(fixture: Fixture) -> None:
26+
_REGISTRY.append(fixture)
27+
28+
29+
def all_fixtures() -> list[Fixture]:
30+
return list(_REGISTRY)
31+
32+
33+
def derive_all(events: list[StreamTaskMessage]) -> list[SpanSignal]:
34+
d = SpanDeriver()
35+
out: list[SpanSignal] = []
36+
for e in events:
37+
out.extend(d.observe(e))
38+
out.extend(d.flush())
39+
return out
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import pytest
2+
3+
from tests.lib.core.harness.conformance.runner import Fixture, derive_all, register, all_fixtures
4+
from agentex.types.task_message_update import (
5+
StreamTaskMessageStart, StreamTaskMessageDone, StreamTaskMessageFull,
6+
)
7+
from agentex.types.tool_request_content import ToolRequestContent
8+
from agentex.types.tool_response_content import ToolResponseContent
9+
10+
register(Fixture(
11+
name="builtin-single-tool",
12+
events=[
13+
StreamTaskMessageStart(type="start", index=0,
14+
content=ToolRequestContent(type="tool_request", author="agent",
15+
tool_call_id="c", name="Bash", arguments={})),
16+
StreamTaskMessageDone(type="done", index=0),
17+
StreamTaskMessageFull(type="full", index=1,
18+
content=ToolResponseContent(type="tool_response", author="agent",
19+
tool_call_id="c", name="Bash", content="ok")),
20+
],
21+
))
22+
23+
24+
@pytest.mark.parametrize("fixture", all_fixtures(), ids=lambda f: f.name)
25+
def test_span_derivation_is_deterministic(fixture):
26+
# Deriving twice over the same events yields identical signals (the property
27+
# that makes yield vs auto-send equivalent, since both observe the same stream).
28+
assert derive_all(fixture.events) == derive_all(fixture.events)

0 commit comments

Comments
 (0)