Problem
`clm_agent_compact()` (lib/agent.c, ~line 820) builds its summarization
request by hand in the canonical OpenAI chat-completions shape
(`{model, messages, stream}`) and POSTs it directly via `agent_http_post`.
Its response is parsed by `compact_success_cb` via
`extract_message_content()` -> `response_message()`, which looks for
`choices[0].message.content`.
This is the one remaining codepath that never goes through the provider
ops vtable added in 365f3d2 (`clm/provider.h`) -- `clm_agent_start_turn`
calls `ops->build_request(...)` and `clm_http_success_cb_wrapper` calls
`ops->normalize_response(...)`, but `clm_agent_compact`/`compact_success_cb`
do neither.
For `CLM_PROVIDER_ANTHROPIC`, this means:
- The request sent to `/v1/messages` is OpenAI-shaped, not Anthropic's
Messages API shape (no `max_tokens`, wrong message/content shape, system
prompt left inline instead of pulled into a top-level `system` field).
- Even if the server tolerated that, the response has no `choices` array
(`response_message()` returns NULL), so `extract_message_content()`
returns NULL and compaction fails with "compaction produced no summary"
every single time.
Net effect: `/compact` (explicit) and autocompaction (mid-chain, triggered
from `clm_agent_tools_done`) are completely broken for any
Anthropic-configured agent -- exactly the scenario that most needs
compaction to work, since a long agentic Anthropic session will eventually
cross the autocompact threshold with no way to recover.
Fix direction
Route `clm_agent_compact`'s request building through
`ops->build_request()` (or a compaction-specific variant of it) and its
response parsing through `ops->normalize_response()`, the same way
`clm_agent_start_turn`/`clm_http_success_cb_wrapper` already do.
Found during a manual code review pass on commit 365f3d2 (the Anthropic
provider PR).
Problem
`clm_agent_compact()` (lib/agent.c, ~line 820) builds its summarization
request by hand in the canonical OpenAI chat-completions shape
(`{model, messages, stream}`) and POSTs it directly via `agent_http_post`.
Its response is parsed by `compact_success_cb` via
`extract_message_content()` -> `response_message()`, which looks for
`choices[0].message.content`.
This is the one remaining codepath that never goes through the provider
ops vtable added in 365f3d2 (`clm/provider.h`) -- `clm_agent_start_turn`
calls `ops->build_request(...)` and `clm_http_success_cb_wrapper` calls
`ops->normalize_response(...)`, but `clm_agent_compact`/`compact_success_cb`
do neither.
For `CLM_PROVIDER_ANTHROPIC`, this means:
Messages API shape (no `max_tokens`, wrong message/content shape, system
prompt left inline instead of pulled into a top-level `system` field).
(`response_message()` returns NULL), so `extract_message_content()`
returns NULL and compaction fails with "compaction produced no summary"
every single time.
Net effect: `/compact` (explicit) and autocompaction (mid-chain, triggered
from `clm_agent_tools_done`) are completely broken for any
Anthropic-configured agent -- exactly the scenario that most needs
compaction to work, since a long agentic Anthropic session will eventually
cross the autocompact threshold with no way to recover.
Fix direction
Route `clm_agent_compact`'s request building through
`ops->build_request()` (or a compaction-specific variant of it) and its
response parsing through `ops->normalize_response()`, the same way
`clm_agent_start_turn`/`clm_http_success_cb_wrapper` already do.
Found during a manual code review pass on commit 365f3d2 (the Anthropic
provider PR).