Users of OpenAI-compatible reasoning models (o4-mini, o3, deepseek-r1,
etc.) had no way to control reasoning effort — the field was missing from
MessageRequest and never emitted in the request body.
Changes:
- Add `reasoning_effort: Option<String>` to `MessageRequest` in types.rs
- Annotated with skip_serializing_if = "Option::is_none" for clean JSON
- Accepted values: "low", "medium", "high" (passed through verbatim)
- In `build_chat_completion_request`, emit `"reasoning_effort"` when set
- Two unit tests:
- `reasoning_effort_is_included_when_set`: o4-mini + "high" → field present
- `reasoning_effort_omitted_when_not_set`: gpt-4o, no field → absent
Existing callers use `..Default::default()` and are unaffected.
One struct-literal test that listed all fields explicitly updated with
`reasoning_effort: None`.
The CLI flag to expose this to users is a follow-up (ROADMAP #34 partial).
This commit lands the foundational API-layer plumbing needed for that.
Partial ROADMAP #34.
OpenAI /responses validates tool function schemas strictly:
- object types must have "properties" (at minimum {})
- "additionalProperties": false is required
/chat/completions is lenient and accepts schemas without these fields,
but /responses rejects them with "object schema missing properties" /
"invalid_function_parameters".
Add normalize_object_schema() which recursively walks the JSON Schema
tree and fills in missing "properties"/{} and "additionalProperties":false
on every object-type node. Existing values are not overwritten.
Call it in openai_tool_definition() before building the request payload
so both /chat/completions and /responses receive strict-validator-safe
schemas.
Add unit tests covering:
- bare object schema gets both fields injected
- nested object schemas are normalised recursively
- existing additionalProperties is not overwritten
Fixes the live repro where gpt-5.4 via OpenAI compat accepted connection
and routing but rejected every tool call with schema validation errors.
Closes ROADMAP #33.
web_search_extracts_and_filters_results set CLAWD_WEB_SEARCH_BASE_URL
without holding env_lock(), while the sibling test
web_search_handles_generic_links_and_invalid_base_url always held it.
Under parallel test execution the two tests interleave set_var/remove_var
calls, pointing the search client at the wrong mock server port and
causing assertion failures.
Fix: add env_lock() guard at the top of web_search_extracts_and_filters_results,
matching the serialization pattern already used by every other env-mutating
test in this module.
Root cause of CI flake on run 24127551802.
Identified and fixed during dogfood session.
Add rust/crates/rusty-claude-cli/build.rs that:
- Captures git rev-parse --short HEAD at build time → GIT_SHA env
- Reads Cargo's TARGET env var → TARGET env
- Derives BUILD_DATE from SOURCE_DATE_EPOCH / BUILD_DATE env or
the current date via `date +%Y-%m-%d` fallback
- Registers rerun-if-changed on .git/HEAD and .git/refs so the SHA
stays fresh across commits
Update main.rs DEFAULT_DATE to pick up BUILD_DATE from option_env!()
instead of the hardcoded 2026-03-31 static string.
Before: `claw --version` always showed Git SHA: unknown, Target: unknown,
Build date: 2026-03-31 in local builds.
After: e.g. Git SHA: 7f53d82, Target: aarch64-apple-darwin, Build date: 2026-04-08
Generated by droid (Kimi K2.5 Turbo) via acpx (wrote build.rs),
cleaned up by Jobdori (added BUILD_DATE step, updated main.rs const).
Co-Authored-By: Droid <noreply@factory.ai>
ProviderClient::from_model_with_anthropic_auth was dispatching every
ProviderKind::OpenAi match to OpenAiCompatConfig::openai(), which reads
OPENAI_API_KEY and points at api.openai.com. But DashScope models
(qwen-plus, qwen/qwen3-coder, etc.) also return ProviderKind::OpenAi
from detect_provider_kind because DashScope speaks the OpenAI wire
format. The metadata layer correctly identifies them as needing
DASHSCOPE_API_KEY and the DashScope compatible-mode endpoint, but that
metadata was being ignored at dispatch time.
Result: users running `claw --model qwen-plus` with DASHSCOPE_API_KEY
set would get a "missing OPENAI_API_KEY" error instead of being routed
to DashScope.
Fix: consult providers::metadata_for_model in the OpenAi dispatch arm
and pick dashscope() vs openai() based on metadata.auth_env.
Adds a regression test asserting ProviderClient::from_model("qwen-plus")
builds with the DashScope base URL. Exposes a pub base_url() accessor
on OpenAiCompatClient so the test can verify the routing.
Authored by droid (Kimi K2.5 Turbo) via acpx, cleaned up by Jobdori
(removed unsafe blocks unnecessary under edition 2021, imported
ProviderClient from super, adopted EnvVarGuard pattern from
providers/mod.rs tests).
Co-Authored-By: Droid <noreply@factory.ai>