[P1] ZARA-016 — Correct LLM provider protocols, authentication headers, timeouts, and session reuse #17

Closed
opened 2026-07-18 19:21:14 +00:00 by lost-rob0t · 2 comments
lost-rob0t commented 2026-07-18 19:21:14 +00:00 (Migrated from github.com)

Problem

Zara has two LLM client stacks with provider-specific correctness gaps.

In modules/llm_client.pl:

  • Anthropic history calls include a system role inside messages, instead of the provider’s top-level system field.
  • OpenAI authorization is constructed as the Prolog term "Bearer " + KeyString, not a guaranteed concatenated header value.
  • HTTP calls lack bounded timeouts.
  • Conversation history is unbounded.
  • Manual JSON string helpers do not escape content safely if used.

In zara/llm.py:

  • OpenAI/Ollama create a new aiohttp.ClientSession per request.
  • Error strings are returned as normal assistant responses, losing typed failure semantics.
  • There is no cancellation/streaming contract yet.

Required fix

  • Make provider payloads conform to their APIs through tested serializers.
  • Build authentication headers as literal strings.
  • Add connection/read/total timeouts, cancellation, bounded retries, and reusable clients/sessions.
  • Return typed success/error results to callers; user-facing wording belongs at the boundary.
  • Bound history consistently.
  • Do not change configured providers or model choices.

Required tests

  • Golden request tests for Anthropic, OpenAI, and Ollama in both Python and Prolog paths.
  • Authentication, timeout, malformed response, empty response, rate limit, cancellation, and close tests.
  • Add scripts/test-llm-clients.sh using local fake HTTP servers only.

Acceptance

  • Each provider receives a valid payload/header set.
  • No network call can hang indefinitely.
  • Sessions are reused and closed.
  • Failures cannot masquerade as successful assistant text.

Branch

fix/zara-016-llm-provider-contracts

Dependencies

ZARA-008, ZARA-009, ZARA-015.

## Problem Zara has two LLM client stacks with provider-specific correctness gaps. In `modules/llm_client.pl`: - Anthropic history calls include a `system` role inside `messages`, instead of the provider’s top-level system field. - OpenAI authorization is constructed as the Prolog term `"Bearer " + KeyString`, not a guaranteed concatenated header value. - HTTP calls lack bounded timeouts. - Conversation history is unbounded. - Manual JSON string helpers do not escape content safely if used. In `zara/llm.py`: - OpenAI/Ollama create a new `aiohttp.ClientSession` per request. - Error strings are returned as normal assistant responses, losing typed failure semantics. - There is no cancellation/streaming contract yet. ## Required fix - Make provider payloads conform to their APIs through tested serializers. - Build authentication headers as literal strings. - Add connection/read/total timeouts, cancellation, bounded retries, and reusable clients/sessions. - Return typed success/error results to callers; user-facing wording belongs at the boundary. - Bound history consistently. - Do not change configured providers or model choices. ## Required tests - Golden request tests for Anthropic, OpenAI, and Ollama in both Python and Prolog paths. - Authentication, timeout, malformed response, empty response, rate limit, cancellation, and close tests. - Add `scripts/test-llm-clients.sh` using local fake HTTP servers only. ## Acceptance - Each provider receives a valid payload/header set. - No network call can hang indefinitely. - Sessions are reused and closed. - Failures cannot masquerade as successful assistant text. ## Branch `fix/zara-016-llm-provider-contracts` ## Dependencies ZARA-008, ZARA-009, ZARA-015.
lost-rob0t commented 2026-08-16 02:41:27 +00:00 (Migrated from github.com)

Reopened after manual testing on 2026-08-15 reproduced a provider error-contract regression from current master.

Observed CLI:

zara what is the weather?
DEBUG: Resolved - Intent: ask, Args: [what,is,weather]
LLM Error: error(llm_error(malformed_response,error(socket_error(eai_noname,'Name or service not known'),...),none),...)

The current modules/llm_client.pl retry/error classifier recognizes error(socket_error(_), _), but SWI-Prolog emitted error(socket_error(eai_noname, 'Name or service not known'), _). That arity mismatch means DNS/name-resolution failures fall through to the generic malformed_response branch instead of the typed connection failure required by this issue.

This is a tracker sync only; no code has been changed yet.

Regression coverage for the repair should include at least DNS resolution failure (socket_error/2), refused connection, timeout, malformed JSON/body, and provider HTTP errors, and should prove each maps to the correct stable error category.

Reopened after manual testing on 2026-08-15 reproduced a provider error-contract regression from current `master`. Observed CLI: ```text zara what is the weather? DEBUG: Resolved - Intent: ask, Args: [what,is,weather] LLM Error: error(llm_error(malformed_response,error(socket_error(eai_noname,'Name or service not known'),...),none),...) ``` The current `modules/llm_client.pl` retry/error classifier recognizes `error(socket_error(_), _)`, but SWI-Prolog emitted `error(socket_error(eai_noname, 'Name or service not known'), _)`. That arity mismatch means DNS/name-resolution failures fall through to the generic `malformed_response` branch instead of the typed connection failure required by this issue. This is a tracker sync only; no code has been changed yet. Regression coverage for the repair should include at least DNS resolution failure (`socket_error/2`), refused connection, timeout, malformed JSON/body, and provider HTTP errors, and should prove each maps to the correct stable error category.
Owner

Fixed in #224 (merge 634b105).

Reopened regression resolved: SWI-Prolog arity-2 socket_error(eai_noname, ...) DNS failures now classify as llm_error(connection, ...) via the extended retryable_exception/1, instead of falling through to malformed_response.

Evidence: iteration log rage/17-zara016-provider-contracts.org; full local gate 10/10 phases at 7985353; exact-head Actions green on fe43c9e. Research confirmed the remaining ZARA-016 contract work (serializers, literal auth, timeouts, retries, session reuse, typed results, bounded history) was already landed with green tests on both stacks; required-but-missing auth/close coverage added for both.

Fixed in #224 (merge 634b105). Reopened regression resolved: SWI-Prolog arity-2 `socket_error(eai_noname, ...)` DNS failures now classify as `llm_error(connection, ...)` via the extended `retryable_exception/1`, instead of falling through to `malformed_response`. Evidence: iteration log `rage/17-zara016-provider-contracts.org`; full local gate 10/10 phases at 7985353; exact-head Actions green on fe43c9e. Research confirmed the remaining ZARA-016 contract work (serializers, literal auth, timeouts, retries, session reuse, typed results, bounded history) was already landed with green tests on both stacks; required-but-missing auth/close coverage added for both.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/zara#17
No description provided.