Adds an optional path_suffix field that lets users override the API path
for OpenAI-compatible endpoints. When set, the suffix replaces the default
/v1/<path> pattern, enabling use with endpoints that don't accept /v1/
prefixes (e.g. /chat/completions instead of /v1/chat/completions).
Changes:
- ProviderConfigToml (config crate): path_suffix field
- ProviderConfig (tui crate): path_suffix field
- merge_provider_config: propagates path_suffix
- merge_project_provider_config: propagates path_suffix
- api_url: delegates to new api_url_with_suffix function
- api_url_with_suffix: uses suffix when present, skips /v1 versioning
- DeepSeekClient: reads path_suffix from config, passes to URL builder
- config.example.toml: documents the new option
- Tests for the new URL building behavior
Closes#2089
Thread allow_shell into system prompt composition and remove shell-only guidance
when shell tools are not available.
This keeps the prompt aligned with the runtime tool catalog and prevents the
model from trying exec_shell or task_shell_* after allow_shell = false.
- add r/R shortcut to re-enter API key for any provider in picker
- guard against Ctrl/Alt/Meta modifiers (only plain r triggers)
- dynamic footer: 'apply' when key exists, 'set key' otherwise
- add 'R edit key' hint to picker footer
- add route/model to scoped auth status output
- add tests for r shortcut, ctrl-r guard, footer text, and route/model
Ports #2717 with review fix. Fixes#2662.
- auth status shows every known provider with config/keyring/env status
- auth status --provider <id> shows detailed single-provider info
- auth list now probes keyring for all providers (was only active)
- /logout clears only the active provider's key (was clearing all)
- add clear_active_provider_api_key for scoped TOML key removal
- add Huggingface to ProviderArg enum
- add auth status tests for all-provider and scoped views
Fixes#2716
Per the layered-authority clarification (base myth → global Constitution → repo
constitution = local law → task packet → runtime policy), extend
.codewhale/constitution.json beyond authority+verification with optional:
- protected_invariants — repo invariants the agent must not break
- branch_policy — branch/release policy in effect
- escalate_when — conditions to stop and escalate to the user
All optional; rendered as concise model-facing prose. The global Brother Whale
identity anchor and Constitution in prompts/base.md are unchanged (verified
untouched on this branch). Dogfood constitution.json filled with CodeWhale's
real invariants (prefix-cache byte-stability, transcript replay, stable Rust,
cli/tui parity), branch policy (codex/v0.8.53), and escalation rules. Docs note
the layered hierarchy.
cargo test -p codewhale-tui --bins → 3946 passed; clippy clean.
Splits repo-level guidance into two clear artifacts and deprecates the
confusing WHALE.md concept (overlapped with AGENTS.md):
- AGENTS.md is the canonical cross-agent project-instructions file.
- .codewhale/constitution.json is the CodeWhale-specific repo authority /
prioritization policy (when local sources conflict, which to trust first; what
to verify before claiming done). Rendered into the system prompt as a
higher-authority <codewhale_repo_constitution> block; takes precedence over a
legacy WHALE.md.
WHALE.md migration (compat-preserving):
- AGENTS.md now ranks above WHALE.md in both project and global discovery; with
both present, AGENTS.md wins.
- WHALE.md is still read as a legacy fallback, but now emits a deprecation
warning and is never created or recommended (init.rs no longer suggests it).
- Discovery/docs updated; the global CodeWhale Constitution in prompts/base.md
is unaffected (different thing).
constitution.json:
- New RepoConstitution (serde, all fields optional, unknown fields ignored,
schema_version checked). Discovered at .codewhale/constitution.json in the
workspace or any parent up to the git root. Malformed JSON warns, never panics.
- Loaded after the auto-generate fallback so it can't be clobbered.
.gitignore: ignore .codewhale/ contents at any depth EXCEPT the committed
constitution.json (a directory exclude can't be negated, so **/.codewhale/* +
negation). init.rs writes the same pattern for new repos. Dogfood: this repo's
.codewhale/constitution.json added.
find_git_root made pub(crate) and reused (no duplicate loader).
Tests: AGENTS-over-WHALE precedence, WHALE legacy-read-with-warning,
constitution render + system-block surfacing, malformed-constitution warning,
gitignore-keeps-constitution. cargo test -p codewhale-tui --bins → 3946 passed;
clippy clean.
Targets codex/v0.8.53.
Design-only deliverables for the v0.8.53 "tool surface diet / canonical
surfaces" cutover (no catalog code in this cycle). Grounded in a verified
inventory of the actual tool registry.
- docs/TOOL_LIFECYCLE.md (#2681): the umbrella policy. Five lifecycle states
(active / deferred / hidden-compatibility / deprecated / removed) modeled as
const name-sets + an alias table in tool_catalog.rs (not a per-ToolSpec
field), so registration stays untouched and old transcripts always replay.
Includes the deprecation manifest (exec_wait/exec_interact/tts →
hidden-compat; todo_* → checklist_* deprecated; 11 legacy subagent names are
already non-visible dead code → cleanup + guardrail), per-mode/per-provider
active-catalog budget (incl. Arcee's 8-tool first-turn set), prefix-cache
safety rules, and the tool_agent decision: canonical but DeepSeek-V4-gated.
- docs/CODEBASE_SEARCH_DESIGN.md (#2680, v0.9.0): local-first FTS5/BM25 +
symbol/path ranking + RRF hybrid; rusqlite storage; mtime/branch/vendor
invalidation; an explainable tool contract returning reasons[]; and a real
CodeWhale query eval set. Complements grep_files/file_search, never replaces.
- docs/SKILL_INVOCATION_DESIGN.md (0.9.0): the $<skill-name> inline invocation
syntax (the token IS the skill name), namespaced resolution, ambiguity-
suggests-not-guesses, visible activation line, and a smallest-viable slice.
- docs/VISION_NORTH_STAR.md (0.9.0+): intent router, hybrid codebase
intelligence, WhaleFlow typed workflow IR, skills/rules runtime, the layered
context-memory stack, tool repair/autoload, the evaluation loop, and the
command-surface taxonomy (/memory small · /context dashboard · /rules ·
/workflow · /overlay · $<skill> · codebase_search). Marked DIRECTION, not
committed 0.8.53 work; also records the deferred-not-done diet items.
Targets codex/v0.8.53.
v0.8.53 tool/deferred/error UX (PR group 4), low-risk subset:
- #2654: add git_log and git_show to DEFAULT_ACTIVE_NATIVE_TOOLS so read-only
git history joins git_diff/git_status in the active partition (kept
alphabetical → prefix-cache head stays sorted/byte-stable). git_blame and
other history tools remain deferred.
- #2655: rlm_open's source-count error now echoes common misnamed fields with a
"did you mean file_path/content/url" hint; rlm_eval's missing-`code` error
explains it runs raw Python and shows an example. Schema descriptions for
rlm_eval name/code sharpened.
- #2659: likely_field_corrections gains RLM source-field rename hints (the
role/type vocabulary change itself lives in the WS3 PR #2684 to avoid a
double-edit of normalize_role_alias).
Deferred to the medium-risk batch: #2648 (render deferred-tool hydration
distinctly from "done") — needs a ToolStatus/cell-build change with wider
render blast radius than this low-risk PR.
Verification: cargo test -p codewhale-tui --bins → 3944 passed, 0 failed
(incl. prefix-cache sort invariant); cargo clippy clean.
Targets codex/v0.8.53.
Make the sub-agent surface easier for less-capable models to drive:
- Unify role/type vocabulary (#2649): normalize_role_alias now accepts the
full set SubAgentType::from_str accepts (reviewer/implementer/verifier/...),
and SubAgentType::from_str learns `planner`, so the dual-validation pass no
longer rejects natural roles with a stale four-value hint. Error strings and
schema descriptions now enumerate the real accepted aliases.
- agent_eval/agent_close always active (#2605) so a first call executes instead
of hydrating its schema and forcing a double-invoke; both accept an
`agent_name` session alias (#2650).
- Self-diagnosing name conflicts (#2656): the duplicate-name error names the
conflicting agent_id and its status.
- Self-describing completion sentinels (#2658): subagent.done now carries
result_clipped / summary_complete / next_action so the parent knows whether
to trust the previous-line summary or call agent_eval.
- Actionable child-model-unavailable diagnostics (#2653): a provider 403/404
is annotated with the model id and recovery path instead of a bare error.
Tests: role vocabulary acceptance + error wording, agent_name resolution,
duplicate-name diagnostics, clipped-result sentinel, child-model annotation,
agent_eval/agent_close default-active. Full tui suite green (3948), clippy clean.
Targets codex/v0.8.53 (v0.8.53 stabilization).
Adds OpenAI-compatible image_url content blocks to the chat message
model, wiring attached images through build_chat_messages_with_reasoning
as multimodal user-content arrays. When images are present, user
messages emit a content array of text + image_url parts instead of a
plain string, matching the OpenAI vision API shape.
- models.rs: new ImageUrlContent struct, ContentBlock::ImageUrl variant
- client/chat.rs: image_parts collection, multimodal wire format for
user messages, image-aware message inspection, stream-event no-op
- Exhaustiveness arms added across 10 files (compaction, seam_manager,
capacity_flow, purge, notifications, session_picker, utils,
working_set, rlm/session, runtime_api)
- Test: request_builder_emits_openai_image_url_parts_for_user_images
Credit: @xyuai (PR #2587 — root cause + initial implementation)
Closes: #2584
Co-authored-by: xyuai <xyuai@users.noreply.github.com>
Adds 8 missing Fixed entries for commits that landed after the
release-prep commit (06612495f): DEC CSI fragment fix, engine panic
recovery, nested file-picker, command-palette scroll, .NET/Windows
env, config key warnings, diff-render whitespace, and model
persistence. Adds Community credits for contributors whose work
landed or shaped this release cycle.
`workspace_completions_honor_configured_walk_depth` placed its probe file at
component depth 9 and asserted the *default* walk excludes it — true at the
old default (6) but not the new one (10). Move the probe to depth 12 so it
stays past the default while remaining within the explicit deeper walk (16)
and the unlimited (0) cases the test also exercises.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
`legacy_sse_closed_stream_reconnects_and_retries_tool_call` passed in
isolation but flaked under parallel load. The mock server dropped the
tool-call response whenever `active_sse` was momentarily `None` — which
happens when the retry POST is scheduled ahead of the reconnecting GET /sse
that re-stores the SSE sender. The client then hung until timeout and the
test failed.
Make the server wait briefly (bounded, 5s) for the SSE channel before
sending, so response delivery no longer depends on the order in which the
two server tasks are scheduled.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
Resolves the workspace clippy warnings so the release gate
(`cargo clippy --workspace --all-targets -- -D warnings`) is clean:
- chat.rs: elide needless lifetime on `next_arcee_waf_trigger` (returned
strs are `'static`).
- llm_client/mod.rs: use `enumerate()` instead of a manual loop counter in
`truncate_for_error` (explicit_counter_loop).
- ui.rs: `#[allow(clippy::too_many_arguments)]` on `apply_model_picker_choice`
with rationale (8 distinct handles/states; a struct would only obscure it).
- file_picker.rs: gate the test-only `WALK_DEPTH` const and `new_with_relevance`
convenience ctor behind `#[cfg(test)]` (the #2488 change moved production
callers to `new_with_relevance_and_depth`).
The 6 schema_migration registry structs the issue noted are no longer flagged
(their trait impls keep them live). Also normalizes rustfmt formatting on the
touched lines.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
Shell tools (`exec_shell`, `task_shell_start`, …) only register when
`allow_shell` is true, but `allow_shell` and `sandbox_mode` are top-level
keys. Placing them under a `[general]` or `[sandbox]` table — neither of
which CodeWhale defines — makes TOML silently drop them, so `allow_shell`
stays false and the tools vanish from the catalog with no explanation.
Following the existing `warn_on_misplaced_root_base_url` precedent, emit a
startup warning naming the misplaced keys and telling the user to move them
to the top of the file. With the keys correctly placed, shell tools register
on Windows too (no sandbox required for danger-full-access).
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
`exec_shell` runs with `env_clear()` plus a strict allowlist. On Windows
there is no sandbox, so commands run directly — but the allowlist dropped
`APPDATA`, `LOCALAPPDATA`, `ProgramData`, `ProgramFiles*`, and the `DOTNET_*`
/ `NUGET_*` variables that `dotnet restore` and NuGet rely on to locate
their package cache, HTTP cache, and config. Restore therefore failed
through the tool while working in the user's own shell, where the full
environment is present.
Add the .NET/NuGet and Windows app-data path variables to the shell
allowlist (`DOTNET_*` via prefix, like `LC_*`). NuGet credential vars
(`NuGetPackageSourceCredentials_*`) still fall outside the allowlist and are
not exported. Also benefits npm/pip on Windows, which use the same paths.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
The palette sized its scroll window by entry count (`popup_height - 7`)
while the same fixed-height popup also rendered the 9-line header plus
per-section labels and separators. Those uncounted rows pushed the selected
entry past the bottom clip line, so pressing Down made the cursor vanish and
the list appear frozen until the index finally exceeded the oversized budget.
Size the window against the real rendered cost: subtract the actual header
height and account for section labels/separators when choosing the visible
range, guaranteeing the selection stays on screen and the list scrolls.
Adds unit tests for the window helper.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
`ignore`'s `max_depth(Some(6))` excludes files inside a 6-level-deep
directory (they sit at component depth 7), so @-mention completion and the
Ctrl+P picker silently missed them. Raise the default walk depth to 10
(covers conventionally nested Java/.NET/web trees) and make the Ctrl+P
picker honor the configurable `mention_walk_depth` — including `0` for an
unlimited walk — so it matches @-mention behavior and the existing
"set mention_walk_depth 0 to search deeper" guidance.
The walk stays bounded by `.gitignore` and `MAX_CANDIDATES`. Adds a
regression test covering depth-6 miss, default reach, and unlimited.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
A panic inside `handle_deepseek_turn` unwound through `engine.run()` and was
caught by `spawn_supervised("engine-event-loop")`, which wrote a crash dump
and let the whole engine task exit. The UI never received `TurnComplete`, so
it sat on "working" forever and every subsequent turn was dead too — exactly
the "the engine have stopped" / stuck-on-working reports.
Wrap the turn call in `catch_unwind` so a panic now surfaces as a failed
`TurnComplete` (with a clear, actionable message) and the engine keeps
running. The crash dump is still written via a new `record_caught_panic`
helper so maintainers retain the `~/.codewhale/crashes/` diagnostics.
Also dedupes the panic-message extraction in `spawn_supervised` /
`spawn_blocking_supervised` into a shared `panic_message` helper.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1
Terminal mode set/reset chatter (bracketed paste `[?2004h/l`, mouse
capture `[?1000h`, focus reporting `[?1004h`, synchronized output
`[?2026h`) ends in `h`/`l`, but the composer's CSI fragment filter only
treated `u` (Kitty keyboard) as a terminator. During dense streaming the
leading `[` leaked into the input and corrupted editing — a regression of
the #1915 control-sequence filter.
Accept `h`/`l` as terminators too, but only after a numeric parameter so
ordinary prose like `[?help]` is preserved (real mode sequences are always
`[?<number><letter>`; Kitty's parameter-less `[?u` still matches). Adds
regression tests for the mode sequences and the false-positive guard.
https://claude.ai/code/session_01MQrnh6wHfrEYN5BBdMarC1