* fix: harden openai-compatible tool flow and local defaults
* fix: close approval replay gaps and harden openai-compatible flow
* fix: address review feedback and code improvements (takeover #112)
- Make ChatCompletionResponse.id Optional<String> to handle providers
that omit or null the field
- Propagate HTTP client builder errors instead of silently dropping
timeout configuration (openai_compatible_chat, nearai_chat)
- Add EMBEDDING_DIMENSION env var with smart per-model defaults instead
of hardcoding 768/1536 everywhere
- Remove duplicated dimension inference logic from main.rs
Co-Authored-By: panosAthDBX <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix: harden src/llm/ module from crate audit findings
- Replace 9x .expect() on RwLock with graceful poison recovery
(nearai.rs: 7, nearai_chat.rs: 2) — eliminates production panics
- Propagate HTTP client builder errors in nearai.rs instead of
silently dropping timeout config (NearAiProvider::new now returns Result)
- Make nearai_chat ChatCompletionResponse.id Optional<String>
(mirrors openai_compatible_chat.rs fix for providers that omit id)
- Make nearai_chat usage fields optional with defensive parse_usage()
helper (was required u32 fields that crash on null/missing)
- Truncate error responses to 512 chars in nearai_chat.rs error
messages to prevent log bloat and potential data leakage
- Delegate 4 missing LlmProvider methods in FailoverProvider
(model_metadata, seed_response_chain, get_response_chain_id,
calculate_cost) to last-used provider instead of trait defaults
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* refactor(llm): add RetryProvider, remove openai_compatible_chat, harden decorators
- Add composable RetryProvider decorator wrapping any LlmProvider with
exponential backoff + jitter, respecting RateLimited retry_after hints
- Remove openai_compatible_chat.rs — replaced by rig adapter + RetryProvider
- Remove internal retry loop from nearai.rs (was causing double-retry
with external RetryProvider, up to 16 attempts instead of 4)
- Remove internal retry loop from nearai_chat.rs (same issue)
- Wire RetryProvider into main.rs composition chain: each provider gets
its own retry wrapper before failover
- Move normalize_tool_name to rig_adapter.rs for all rig-based providers
- Reconcile is_retryable() vs is_transient() error classification:
ModelNotAvailable no longer retryable, Json no longer transient
- Fix unchecked Duration subtraction panic in circuit_breaker.rs
- Make failover.rs use shared is_retryable() from retry.rs
- Remove stale #[allow(dead_code)] on NearAiResponse::id (field is used)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix: address PR review feedback — error handling, dimension validation, libSQL warning
- Replace response.text().await.unwrap_or_default() with proper error
propagation in nearai.rs and nearai_chat.rs (4 call sites). Failures
now return LlmError::RequestFailed with context instead of silently
proceeding with an empty string.
- Add embedding dimension validation in OllamaEmbeddings::embed_batch():
returns EmbeddingError if Ollama returns embeddings with a dimension
that doesn't match the configured value.
- Add runtime warning when libSQL backend is used with non-1536 embedding
dimension, since the libSQL schema uses F32_BLOB(1536) and cannot store
different-dimension vectors.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* Apply suggestions from code review
Co-authored-by: Copilot <[email protected]>
---------
Co-authored-by: panosAthDbx <[email protected]>
Co-authored-by: panosAthDBX <[email protected]>
Co-authored-by: panosAthDBX <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Copilot <[email protected]>
* feat: support per-request model override for /v1/chat/completions
- add optional model override to completion request types\n- forward request model through gateway, worker, and orchestrator proxy paths\n- use request model in NEAR AI providers with fallback to active model\n- replace model-mismatch integration test with override propagation checks\n- update FEATURE_PARITY.md note for OpenAI-compatible API behavior\n\nRefs #49
* Wire gateway OpenAI-compatible routes to active LLM provider
* Validate OpenAI model name length before streaming
* Address PR103 review feedback on model override and validation
* Report effective model in OpenAI-compatible responses
* Use async mutexes in OpenAI compatibility integration tests
* fix tests for per-request model field in response cache
* fix formatting and clippy lint after main merge
* Fix model override reporting and cache correctness
---------
Co-authored-by: Illia Polosukhin <[email protected]>
* fix(rig): prevent responses API panic on missing tool call IDs
* style: format rig adapter
* test(rig): add coverage for empty/whitespace tool call IDs
Add tests for assistant tool calls with empty and whitespace-only IDs,
and an end-to-end test documenting the seed mismatch limitation when
both assistant call and tool result are missing IDs.
* Apply suggestions from code review
Co-authored-by: Copilot <[email protected]>
---------
Co-authored-by: Illia Polosukhin <[email protected]>
Co-authored-by: Copilot <[email protected]>
* fix: prevent division-by-zero panic in ValueEstimator::is_profitable
Guard against Decimal division by zero when price is zero.
rust_decimal::Decimal panics on division by zero (unlike f64 which
returns infinity), so we short-circuit before the division.
When price is zero, a job is only profitable if the estimated cost
is negative (i.e., we get paid to do it).
Add test covering zero-price scenarios including the negative cost
edge case.
* style: fix pre-existing rustfmt and clippy issues in llm module
Fix formatting and lint issues that cause CI Code Style check to fail:
- src/llm/mod.rs: fix method chain indentation
- src/llm/rig_adapter.rs: collapse multi-line single-expression statements,
fix collapsible_if clippy warning
* fix: add missing type key to http tool body schema
The body property in HttpTool::parameters_schema() was missing the
required \"type\" key, causing OpenAI to reject all tool calls with:
Invalid schema for function 'http'
Fixes#131
* fix: add missing type key to json tool data schema
Same class of bug as http tool body — the data property in
JsonTool::parameters_schema() was missing the required "type" key,
causing OpenAI to reject all tool calls.
Fixes#131
* fix: use Chat Completions API to avoid rig-core Responses API panic
The default openai::Client routes through rig-core's Responses API,
which panics at "The tool call ID should exist!" because ironclaw
doesn't thread call_id through its ToolCall type. Switch to
openai::CompletionsClient which uses the Chat Completions API and works
correctly with the existing code.
* fix: normalize tool schemas for OpenAI strict mode compliance
GPT-5/5.2 enforce strict function calling by default. Add
normalize_schema_strict() that recursively transforms tool parameter
schemas at the provider boundary:
- Forces additionalProperties: false on all objects
- Makes required list ALL property keys
- Converts optional fields to nullable types
- Handles nested objects, array items, and combinators
Original schemas remain unchanged for other providers.
Closes#131
---------
Co-authored-by: Illia Polosukhin <[email protected]>
Add support for OpenAI, Anthropic, Ollama, and OpenAI-compatible
endpoints alongside the existing NEAR AI backend. Users can now
bring their own API keys via environment variables (LLM_BACKEND,
OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) while NEAR AI remains
the default.
Co-authored-by: Claude Opus 4.6 <[email protected]>