Skip to content

feat(agent): M2 — OpenAI + Anthropic wire dialects#6

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

feat(agent): M2 — OpenAI + Anthropic wire dialects#6
jaredLunde merged 1 commit into
mainfrom
agent-harness

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

What — M2

Adds agent_core::dialect: per-provider request building and streaming SSE decoding, normalizing both providers onto the dialect-agnostic StreamEvent sequence the agent loop will consume. This is the one piece of pi-ai worth porting (the gateway owns provider keys/routing; the harness owns the wire).

  • Dialect::for_model — Claude → Anthropic (/v1/messages), everything else → OpenAI wire (/v1/chat/completions).
  • anthropic — near-identity request mapping (the internal model is Anthropic-shaped); decoder translates content_block_* / message_* into TextDelta / ToolUseStart / InputJsonDelta / ContentBlockStop / Usage / MessageStop.
  • openai — real translation: system→message, ToolUsetool_calls (arguments as a JSON string), ToolResultrole:"tool" messages; decoder synthesizes the block-stop boundaries OpenAI omits and defers MessageStop past the trailing usage chunk. Both dialects emit identical event shapes so the loop is dialect-blind.

Proven by

Recorded text + tool_use SSE fixtures for each dialect decoded to an exact StreamEvent sequence, plus golden request-body assertions (system hoisting, tool-call arg stringification, tool-result fan-out). 15 agent-core unit tests, no network.

Part of the agent-harness series (M1 scaffold merged in #5). Next: M3 transport + M4 loop.

🤖 Generated with Claude Code

Add `agent_core::dialect`: per-provider request building and streaming SSE
decoding, normalizing both providers onto the dialect-agnostic StreamEvent
sequence the loop will consume.

- Dialect::for_model picks Anthropic for Claude, OpenAI wire otherwise.
- anthropic: near-identity mapping (internal model is Anthropic-shaped);
  decodes content_block_*/message_* into TextDelta/ToolUseStart/
  InputJsonDelta/ContentBlockStop/Usage/MessageStop.
- openai: translates system→message, ToolUse→tool_calls (args as JSON
  string), ToolResult→role:"tool" messages; decoder synthesizes the
  block-stop boundaries OpenAI omits and defers MessageStop past the
  trailing usage chunk. Both dialects emit identical event shapes.

Proven against recorded text+tool_use SSE fixtures for each dialect, plus
golden request-body assertions. 15 agent-core unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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