Skip to content

feat(agent): M3+M4 — gateway transport + the agent loop#7

Merged
jaredLunde merged 1 commit into
mainfrom
agent-loop
Jun 30, 2026
Merged

feat(agent): M3+M4 — gateway transport + the agent loop#7
jaredLunde merged 1 commit into
mainfrom
agent-loop

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

What — M3 (transport) + M4 (loop)

M3 — transport

  • client::GatewayClient — the harness's only network surface. Picks the dialect by model id, POSTs provider wire to the gateway with an Authorization: Bearer <bai_v1…> (adds anthropic-version for the Anthropic dialect), and frames the chunked SSE body line-by-line into StreamEvents (via async-stream). It never holds a provider key — the gateway swaps the pool key and meters.
  • mock::MockTransport — replays scripted StreamEvent turns and records the requests the loop sends, so the loop and the binaries test with zero network. Ships turn::text / turn::tool_call helpers.
  • dialect::push_sse_line — incremental per-line decode the client drives off the socket; decode_sse now builds on it.

M4 — the loop

  • agent::Agent — Pi's pi-agent-core runtime. One iteration = stream a turn → assemble assistant content blocks from the event stream (dialect-blind) → append → run requested tools → feed tool_results back → repeat until end_turn or max_steps. A tool's own failure becomes an error tool_result, not an aborted run. Streams every event to an on_event callback (for live rendering).

Proven by

  • 21 agent-core unit tests: loop dispatch, tool round-trip (asserts the 2nd request carries the tool_result), unknown tool, failing tool, max_steps enforcement, event streaming.
  • 2 real-socket integration tests: GatewayClient driven against a bare TCP server emitting chunked SSE — success path (decodes TextDelta/Usage/MessageStop) and HTTP-error path (403 surfaces as a stream error). No hyper, no gateway, no keys.

Series: M1 (#5), M2 (#6) merged. Next: M6 tools + M5 binary e2e against a mock model server.

🤖 Generated with Claude Code

… loop

M3 (transport):
- client::GatewayClient — the harness's only network surface. Picks the
  dialect by model, POSTs provider wire to the gateway with a bai_v1 bearer
  (adds anthropic-version for the Anthropic dialect), and frames the chunked
  SSE body line-by-line into StreamEvents via async-stream. No provider keys.
- mock::MockTransport — replays scripted StreamEvent turns and records
  requests, so the loop and the binaries test with no network.
- dialect::push_sse_line — incremental per-line decode the client drives off
  the socket (decode_sse now builds on it).

M4 (loop):
- agent::Agent — Pi's pi-agent-core runtime. One iteration = stream a turn,
  assemble assistant content blocks from the event stream (dialect-blind),
  append, run requested tools, feed results back, repeat until end_turn or
  max_steps. Tool failures become error tool_results, not aborted runs.

Proven: 21 agent-core unit tests (loop dispatch, tool round-trip, unknown/
failing tool, max_steps, event streaming) + 2 real-socket integration tests
driving GatewayClient against a bare TCP SSE server (success + HTTP error).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jaredLunde jaredLunde merged commit 9ec13f7 into main Jun 30, 2026
1 check passed
@jaredLunde jaredLunde deleted the agent-loop branch June 30, 2026 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant