- Abort now transitions to CLOSED state and returns Err(Aborted)
- Closed sessions no longer emit SessionStart before rejecting input
- Add set_reasoning_effort() for mid-session reasoning effort changes
- Fix spawn_agent truncation limit from 30k to spec-required 20k
- Add JSON Schema validation of tool arguments before execution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
resolve_model() was passing raw alias strings (e.g. "gpt5") directly to
APIs instead of resolving them to actual model IDs (e.g. "gpt-5.2").
Also rename gpt-5.2-mini to gpt-5-mini, which is the correct OpenAI
model ID.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all stub tools in profiles with real make_*_tool() factories,
wire up project docs discovery in session, add missing events
(SessionStart, SteeringInjected, Error), enrich environment context
block, fix per-tool truncation modes, improve loop detection to check
all groups, add SIGTERM-before-SIGKILL on timeout, and update subagent
with SubAgentResult struct.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend the Middleware trait with process_stream_event() for event-level
observation/transformation of streaming responses. Add
wrap_stream_with_middleware() helper. Re-export set_default_client at the
crate root per spec Section 2.5.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New crate `unified-llm-cli` with binary `ullm` providing:
- `prompt` command: generate text via streaming/non-streaming, with
system prompts, options (-o temperature=0.5), stdin piping, and
token usage display
- `models list` command: browse catalog models with --provider and
--query filters
- Auto-detects provider from catalog for correct API routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Enforce stream_read timeout (30s default) in all 4 providers' streaming code
- Add with_timeout() builder method to all adapter constructors
- Fix ResponseFormatType::JsonObject to serialize as "json" per spec
- Add STEP_FINISH to StreamEventType enum in spec doc
- Add UnsupportedToolChoice error and enforce in all adapters via validate_tool_choice()
- Fix error classification to check status code before message content
- Add stop_sequences support to OpenAI Responses API adapter
- Handle Gemini thought parts (thought: true) in both complete and streaming paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OpenAI adapter: include is_error flag on function_call_output items
- Anthropic adapter: extract retry_after from headers in streaming error path
- Error retryability: unknown errors now default to retryable per spec
- stream_object: add ObjectStreamResult wrapper with object() accessor
- TimeoutConfig: add From<f64> for total-only timeout shorthand
- Message::tool_result: accept serde_json::Value to preserve structured content
- GenerateParams: expose repair_tool_call field wired to execute_all_tools_with_repair
- Both generate() and stream() tool loops use repair-aware execution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Anthropic adapter estimates reasoning_tokens from thinking block text lengths
- Add tool call validation against JSON schema + repair_tool_call callback
- Call adapter.initialize() on provider registration
- Extract model catalog to catalog.json data file loaded via include_str!
- Add ContentPart::Other variant for unknown/extensible content kinds
- Change StreamEvent::Error field from String to SdkError
- Add ToolContext (tool_call_id, messages, abort_signal) to execute handlers
- Gemini adapter uses gRPC status codes from error bodies for classification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Audio/Document content part handling across all providers:
Anthropic supports documents natively, Gemini supports both audio
and documents, OpenAI and OpenAI-compatible produce text fallbacks
- Add stop_when support to streaming tool loops (was only in generate())
- Add retry on initial stream connection (matching generate() behavior)
- Add total and per_step timeout support to streaming tool loops
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add StepFinish stream event variant emitted between tool execution steps
during streaming, matching spec section 5.9. Add OPENAI_ORG_ID and
OPENAI_PROJECT_ID env var support with corresponding HTTP headers. Add
default_headers builder method to all four provider adapters for custom
header injection in programmatic setup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Anthropic: Add response_format support via tool-based extraction (JsonSchema
injects synthetic tool, JsonObject appends system prompt instruction)
- Anthropic: Pass Request.metadata through to Messages API
- Anthropic: Refactor complete()/stream() to share build_api_request()
- Gemini: Parse rate limit headers from HTTP responses in complete() and stream()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add abort signal support using CancellationToken for cooperative cancellation
of generate() and stream() calls
- Fix max_tool_rounds=0 to skip tool execution entirely (was executing first round)
- Add StreamResult wrapper with response(), text_stream(), partial_response()
and multi-step tool loop support in high-level stream()
- Add OpenAI metadata and provider_options.openai pass-through to Responses API
- Add Gemini provider_options.gemini pass-through (safety settings, cached content)
- Add OpenAI-compatible provider_options.<name> pass-through using adapter name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse x-ratelimit-* headers into RateLimitInfo for Anthropic, OpenAI, and
OpenAI-compatible providers (previously hardcoded to None)
- Add "not found"/"does not exist" and "unauthorized"/"invalid key" error
message classification patterns for ambiguous HTTP status codes
- Apply TimeoutConfig.total to wrap the entire multi-step generate() loop
(previously only per_step was used)
- Add metadata field to GenerateParams with builder method, pass through to
Request instead of hardcoding None
- Implement stream_object() for streaming structured output with incremental
JSON parsing via new ObjectStreamEvent type (Partial/Delta/Complete variants)
- Add OpenAI-compatible Chat Completions adapter for third-party endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared provider helpers (parse_error_body, send_and_read_body,
extract_system_prompt, ApiMessage) into providers/common.rs, eliminating
duplicated logic across all three providers. Simplify StepResult and
GenerateResult to derive fields from the embedded Response rather than
storing redundant copies. Remove stringly-typed ToolCall.r#type and
ResponseFormat.r#type in favor of proper enums. Remove unused dependencies
(hyper, clap, rayon, base64, etc.), use LazyLock for the model catalog,
and fix miscellaneous idiom issues (unnecessary Vec collects, inconsistent
error Display, module_name_repetitions).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable clippy::all, pedantic, nursery, and cargo lint groups at the
workspace level. Fix all resulting warnings: merge identical match arms,
add #[must_use] and doc sections, derive Eq, use clone_from, add type
alias for complex types, extract helpers to reduce function length, and
add crate metadata.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>