2 Commits

Author SHA1 Message Date
e5ca677113 feat(translate): handle canonical.ImageBlock → Anthropic image content
Picks the most efficient source shape available:

  URL set        → {"type":"url", "url":...}
  DataBase64 set → {"type":"base64", "media_type":..., "data":...}
  Path set       → read file → base64 → {"type":"base64", ...}

MIME defaults to application/octet-stream when ImageBlock.MediaType is
empty (some servers accept that, some don't — operator's responsibility
to fill it in upstream).

File read failure → emits a "[image %q unavailable]" text block in its
place so the message still goes through with provenance preserved.

Verified live against Kimi K2.6 via Fabric channel: alice uploads
blue 32x32 PNG → Fabric plugin downloads + emits Media in inbound →
host turncore builds canonical.Message with ImageBlock → translator
reads file + base64s → Kimi responds "Blue".
2026-05-31 21:03:04 +01:00
94f33a003a feat: initial extract of shared anthropic-compat client + translator
Extracted from Plexum-minimax-provider and Plexum-kimi-provider (both
had near-identical copies under internal/anthropic + internal/translate).
Future provider plugins (Qwen, Doubao, …) import these two packages
instead of re-implementing the protocol.

anthropic/ (~220 LOC + 6 tests):
- minimal HTTP+SSE Anthropic Messages client (POST /v1/messages,
  stream:true, parses event:/data: SSE)
- Client.UserAgent + Client.ExtraHeaders fields for per-backend
  customization (Kimi needs "claude-code/0.1.0"; MiniMax is flexible)
- non-2xx surfaces as Go error; mid-stream errors as final
  Event{Type:"error"}

translate/ (~220 LOC):
- CanonicalToAnthropic: TurnRequest → MessagesRequest
- blockToAnthropic: TextBlock / ToolUseBlock / ToolResultBlock /
  ThinkingBlock → loose ContentBlock map; preserves signatures
- Translator: per-turn state machine; anthropic.Event stream →
  canonical.TurnEvent stream (text + thinking + tool_use deltas;
  signature_delta capture; message_delta stop_reason + usage)

Both MiniMax and Kimi now import from here; their internal/* dirs are
gone. Live verified after refactor — both still answer "ready" via
plexum say.
2026-05-31 20:34:57 +01:00