- Resolve .gitignore conflict: include both nix entries and .claude/
- Update AnthropicRuntimeClient::new() test calls to match new signature
- Fix explicit_model_provider_hint test to unset OPENAI_BASE_URL env var
The PermissionMode enum intentionally does not implement PartialOrd
to prevent silent re-ranking of the privilege ladder. Use the explicit
covers() method for privilege comparisons instead of < and >=.
execute_batch already keyed results to original call slots; this makes
that airtight: panicking worker threads resolve to their own index via
a fallback tuple instead of colliding with slot 0, and results are
asserted to follow call order with a regression test that mixes a
workspace-escape read among valid reads at cap=2.
Adds the fan-out bound: parallel-safe calls run in waves of at most
maxParallelToolCalls (default 8, CLAWD_PARALLEL_TOOL_CALLS env, or the
new setting applied via with_max_parallel_tool_calls at runtime build).
Sequential behavior is preserved: allowed_tools checks still run
before dispatch, and ToolSearch stays off the parallel path.
TeamCreate resolves maxConcurrentAgents from the per-team input, then
the maxConcurrentAgents setting, then unlimited (pre-fix behavior).
The cap is persisted in the manifest and registered on a process-wide
gate; agent threads still spawn immediately but block on an RAII slot
before entering their run loop, so manifest/task-claim semantics are
unchanged. TeamDelete forgets the gate so queued agents drain and no
stale team entries accumulate. Includes a gate regression test.
Adds optional positive-integer parsing for the two new fan-out caps
next to subagentModel, in both camelCase and snake_case forms. Zero
parses as unset; non-numeric values are a named config error. Covered
by three regression tests mirroring the subagentModel test style.
Review fixes for PR #3250:
1. Restore workspace-level unsafe_code = "forbid" (was downgraded to
"warn" for TUI support). The per-crate [lints.rust] unsafe_code =
"allow" on rusty-claude-cli already overrides it where needed.
2. Fix TaskClaim TOCTOU race in claim_task(). Replace exists()-then-write
with OpenOptions::create_new(true) which atomically fails if the lock
file already exists, eliminating the race window between the check and
the write.
3. Remove TUI scaffolding deps (ratatui, tui-textarea, gag, crossbeam-channel,
libc, unicode-width) and the /tui slash command spec — these belong in
a future TUI PR and are unused in the current source.
Also updates the provider chain precedence test to reflect the new behavior
where the caller's resolved model is the chain primary.
Co-Authored-By: Claw <noreply@openclaw.ai>
Adds 3 unit tests covering the original silent-drop bug:
- camelCase 'subagentModel' key reads end-to-end
- snake_case 'subagent_model' key reads end-to-end
- blank value returns None (falls back to default model)
Requested by @1716775457damn in PR review.
Restores the fix from @Offwhite-Del that was lost during rebase.
Unknown models now return None so preflight skips the context-window
check and lets the API enforce its own limits.
Port the agent-team enhancement layer onto upstream/main so the model
can spin up coordinated sub-agent teams for parallel work.
subagentModel config wiring (fix):
- Add subagent_model field to RuntimeFeatureConfig + RuntimeConfig::subagent_model()
accessor so the subagentModel setting (already validated by config_validate.rs)
is now actually read and stored.
- Agent tool's resolve_agent_model falls back to subagentModel from config
when no explicit model is passed.
Provider namespace separation:
- New 'custom-openai' provider kind with dedicated env vars
(CLAWCUSTOMOPENAI_API_KEY / CLAWCUSTOMOPENAI_BASE_URL)
- /setup wizard saves kind: 'custom-openai' for option 5
- Bare model name normalized to 'custom/' prefix to avoid proxy 404s
- Sub-agents inherit /setup-saved provider config via inject_config_as_env_fallbacks
Parallel tool execution:
- Override execute_batch to classify read-only tools as parallel-safe
and run them concurrently via std::thread::scope
- Results return in original model order
Team coordination layer:
- AgentMessage, TaskClaim, TeamStatus tools + shared mailbox directory
- Mode presets (tiny/1x ... mega/6x) + enriched TeamCreate/Agent descriptions
- Background team watcher
- /team slash command: on/off/status/toggle
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Explain the provider compatibility behavior that now has executable coverage so future changes preserve routing, custom gateway slugs, diagnostics, and extra-body passthrough semantics.
Constraint: Task 2 requires docs/status evidence while leader owns Ultragoal checkpoints and .omx/ultragoal remains untouched.
Rejected: Add a new CLI status command | broader than the assigned provider compatibility documentation/status surface.
Confidence: high
Scope-risk: narrow
Directive: Keep docs aligned with provider_diagnostics_for_model, MessageRequest::extra_body, and OpenAI-compatible slash-model tests.
Tested: cargo test --manifest-path rust/Cargo.toml -p api custom_openai_gateway_preserves_slash_model_ids_and_extra_body_params; cargo test --manifest-path rust/Cargo.toml -p api provider_diagnostics_explain_openai_compatible_capabilities; cargo check --manifest-path rust/Cargo.toml -p api
Not-tested: Live provider calls requiring external credentials.
Co-authored-by: OmX <omx@local>
The follow-up docs gate needed the parity manifest reference string that the mock parity diff checker requires, so this records the verified map-only repair after leader integration.
Constraint: Task 11 scope allowed only PARITY.md, rust/MOCK_PARITY_HARNESS.md, and docs/g007-plugin-mcp-verification-map.md; only PARITY.md needed a change.
Rejected: Editing harness code or .omx/ultragoal | checks proved the remaining gap was docs-map text only and Ultragoal state is leader-owned.
Confidence: high
Scope-risk: narrow
Directive: Keep auto_compact_triggered parity_refs synchronized with PARITY.md when mock parity scenarios change.
Tested: cd rust && python3 scripts/run_mock_parity_diff.py; python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json; rg -n auto_compact_triggered token_cost_reporting auto_compaction threshold from env G007 Plugin/MCP G007-plugin-mcp 12 scripted scenarios 21 captured PARITY.md rust/MOCK_PARITY_HARNESS.md docs/g007-plugin-mcp-verification-map.md; git diff --check
Not-tested: Full workspace suite; Task 11 was a docs/parity-map follow-up with focused executable map validation.
Co-authored-by: OmX <omx@oh-my-codex.dev>
Fixes#3259: When rendering markdown in streaming mode, block-level elements
(code blocks, lists, tables, etc.) were losing trailing newlines due to
render_markdown() calling trim_end(). This caused improper spacing when chunks
were split at block boundaries.
Solution:
- Track last_output_ends_with_newline in MarkdownStreamState to detect when
previous output ended without proper spacing
- In push(): add leading newlines before block elements if previous chunk
didn't end with newlines
- In push(): restore trailing newlines after code block/table closings that
were trimmed by render_markdown()
- Add ensure_newlines() helper to prepare spacing before block starts
- Add comprehensive streaming tests that verify idempotence across all
possible chunk split positions
This ensures that streaming renders produce byte-identical output regardless
of where the input is split into chunks, which is critical for displaying
markdown as it arrives from the API while maintaining proper formatting.
- Add real implementations for /status, /cost, and /version slash commands
- /status shows session metadata including message count and token usage
- /cost displays cumulative token usage including cache metrics
- /version shows the claw-code version
- All three commands are fully backed by existing Session infrastructure
- Add comprehensive tests for all three commands
- Remove expectations that these commands return None
These commands fulfill the requirement to implement 2-3 missing GJC slash
commands that the existing claw-code runtime can fully support.
- Add selector field to ReadFileInput accepting GJC syntax (:50, :50-200, :50+150, :raw)
- Implement read_file_with_selector and read_file_in_workspace_with_selector
- Add apply_line_selector to parse and apply selectors to file contents
- Add truncation_footer field to ReadFileOutput for GJC-compatible output
- Add comprehensive tests for selector parsing and application through tool entry point
Selectors take precedence over offset/limit for backward compatibility.
Closes#3323
- Support line range selectors: :50, :50-200, :50+150, :5-16,960-973
- Support special modes: :raw, :conflicts
- Parse comma-separated ranges with automatic merging of overlapping/adjacent ranges
- Comprehensive unit tests covering all selector formats
- Fixes#3323 Slice 2.1 - Phase 1a (read tool selector parsing)
Five defects found by auditing the agent stack, all of which let the harness act
confidently on a wrong picture of its own state.
1. A turn that errored discarded the record of tools that had already run. The CLI
hands run_turn a CLONE of the session; the turn appends the user message, each
assistant reply, and a tool_result per executed tool to that clone alone. The error
path dropped it while the side effects of those tools remained on disk, and the
recovery path then replayed the same user input against a session showing no sign
they had ever run — inviting a second execution of tools that are not idempotent.
The clone is now adopted before teardown, and recovery resumes the turn instead of
replaying it (new ConversationRuntime::resume_turn).
2. Every sizing guard was computed against the model NAME's context window. With a
local server behind a cloud model alias that is 200k against a much smaller
backend, which does not make the preflights inaccurate — it makes them unreachable.
CLAW_CONTEXT_WINDOW now declares the real window; model_token_limit honours it and
returns a limit for unrecognised models instead of None, max_tokens is capped to a
quarter of it, and the auto-compaction threshold derives from it (70%) rather than
defaulting to a 200k-window constant.
3. Whether to recover by discarding conversation history was decided by substring
matching on rendered error prose, including strings that ordinary transport and
decode failures also produce — so a dropped connection cost the session its
transcript. Classification now happens in the API layer, where the error still has
its type and the request is still in hand: typed overflow errors, plus ambiguous
transport failures only when the request actually filled the window. The two
copy-pasted detection blocks are gone.
4. The top-level agent loop had no iteration ceiling (usize::MAX) while spawned
subagents were bounded at 32. It now gets the same bound, overridable with
CLAW_MAX_TURN_ITERATIONS.
5. Auto-continue nudges were injected as USER turns, so harness-authored text was
persisted, re-sent on every later request, and folded into compaction summaries as
something the user had said. They are recorded as system turns now; the wire
payload is unchanged.
Also replaces the repository's own self-host section, which described a translator
and a serving stack no longer in the request path. That file is folded into the
system prompt verbatim, so it was briefing the model with an architecture that does
not exist.
(cherry picked from commit c8834cb4d1a3372eb70241429f641162a420297e)