Skip to content

feat(team): team enhancements, subagentModel, parallel tool exec - #3250

Open
TheArchitectit wants to merge 775 commits into
ultraworkers:mainfrom
TheArchitectit:feat/team-pr-clean
Open

TheArchitectit wants to merge 775 commits into
ultraworkers:mainfrom
TheArchitectit:feat/team-pr-clean

Conversation

@TheArchitectit

@TheArchitectit TheArchitectit commented Jun 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Ports the agent-team enhancement layer onto main so the model can spin up
coordinated sub-agent teams for parallel work. 2,095 lines added across 11 files
— zero deletions of existing upstream functionality.

Single clean commit built from upstream/main. No TUI, LSP, or setup-wizard
contamination from other in-flight work.


Motivation

The TeamCreate, TeamDelete, and Agent tools already existed, but they
didn't work end-to-end because:

  1. subagentModel was silently dropped — /setup saved the sub-agent model
    into settings.json but RuntimeConfig never stored or exposed it, so
    agents always fell back to a hard-coded default.
  2. Sub-agents couldn't reach the user's provider — the main CLI calls
    inject_config_as_env_fallbacks() to set CLAWCUSTOMOPENAI_API_KEY /
    CLAWCUSTOMOPENAI_BASE_URL from /setup-saved config, but the sub-agent
    spawn path in tools never did, so custom providers were invisible.
  3. providerFallbacks.primary silently overrode the agent's model — the
    configured fallback primary replaced whatever model resolve_agent_model
    picked, routing agents to a dead model instead of the session's provider.
  4. 404 model-not-found killed the chain — a dead primary was not retryable,
    so the fallback chain never advanced to working models.

This PR fixes all four and adds the team coordination tools the model needs
to orchestrate multi-agent work.


What's included

1. subagentModel config wiring (bug fix)

The subagentModel field was validated by config_validate.rs but never
stored or read
— the setting from /setup was silently dropped.

Change File
RuntimeFeatureConfig.subagent_model field runtime/src/config.rs
RuntimeConfig::subagent_model() accessor runtime/src/config.rs
parse_optional_subagent_model() (reads subagentModel / subagent_model, blank → None) runtime/src/config.rs
runtime::inject_config_as_env_fallbacks() — moved from private main.rs fn to pub fn in runtime so sub-agents can call it runtime/src/config.rs + runtime/src/lib.rs
resolve_agent_model fallback chain: explicit model → subagentModel → session provider model → DEFAULT_AGENT_MODEL tools/src/lib.rs

2. Parallel tool execution (perf)

When the model emits multiple tool_use blocks in one response, read-only
tools now run concurrently via std::thread::scope instead of
sequentially.

Parallel-safe tools: read_file, glob_search, grep_search,
WebFetch, WebSearch, ToolSearch, Skill, LSP, GitStatus,
GitDiff, GitLog, GitShow, Agent, AgentMessage, AgentSuggestion,
TeamStatus, TeamInfo, TaskGet, TaskList, TaskOutput

Sequential tools: everything else (writes, side-effects)

Change File
ToolCall, ToolResult, TurnProgressReporter re-exported from runtime runtime/src/conversation.rs + runtime/src/lib.rs
ToolExecutor::execute_batch default impl on trait runtime/src/conversation.rs
CliToolExecutor::execute_batch override with parallel-safe classification rusty-claude-cli/src/main.rs

3. Team coordination layer (feature)

New tools and capabilities for multi-agent work:

Tool Purpose
TeamCreate Spawn N agents (1–6× presets: tiny/small/medium/large/xlarge/mega) with a shared prompt
TeamDelete Mark a team deleted, clean inbox, release task claims
TeamStatus Live snapshot, final summary, or event inbox for a team
AgentMessage Send/receive messages between agents (shared mailbox)
TaskClaim Claim/list/complete tasks to prevent duplicate work across agents
AgentSuggestion Agents suggest AGENTS.md patterns/pitfalls

Supporting infrastructure:

  • Shared mailbox directory at ~/.clawd-agents/mailbox/team/{team_id}/
  • Background team watcher thread — polls agent .json files every 2s,
    prints [team] progress to stderr, writes events to -events.jsonl
  • Mode presets — tiny/1x through mega/6x controlling agent count
    and role distribution (Explore, Plan, Verification, Reviewer)
  • /team slash command — on|off|status to toggle CLAWD_AGENT_TEAMS
    (required by TeamCreate)
  • Enriched tool descriptions on TeamCreate and Agent steering the
    model toward correct usage

4. Model-resolution robustness fixes (bug fix)

Fix Detail
qualify_for_provider() Bare model names (e.g. claude-haiku-4-5-20251001) get custom/ prefix when the active provider is custom-openai, so sub-agents route through the same endpoint as the main session
providerFallbacks.primary precedence The caller's resolved model is now the primary; providerFallbacks.primary + fallbacks are appended as recovery entries, deduped. Previously the config primary silently replaced the caller's model
404 model-not-found chain fallthrough Added fallback_chain_eligible() that treats 404/400 "not found" as chain-eligible, so a dead configured primary advances to kimi/qwen/etc. Added ApiError::status_code() and response_body() accessors for the detection
Sub-agents inject /setup credentials run_agent_job() calls runtime::inject_config_as_env_fallbacks() before building the agent runtime, so custom providers set up via /setup work for spawned agents

5. Also fixed

Fix File
lane_completion.rs test helper set stale team_id/task_id fields tools/src/lane_completion.rs
/team slash command had no validate_slash_command_input match arm (parsed as Unknown) commands/src/lib.rs
ApiError gains status_code() and response_body() public accessors api/src/error.rs
model_token_limit catch-all: _ => Some(...) → _ => None — unknown models skip preflight, let API enforce limits (caught by @Offwhite-Del) api/src/providers/mod.rs
Lsp variant added to match arms commands/src/lib.rs + rusty-claude-cli/src/main.rs
DEFAULT_CUSTOM_OPENAI_BASE_URL constant added api/src/providers/openai_compat.rs
Provider chain precedence test updated to match new behavior tools/src/lib.rs

Verification

Build

cargo check --workspace              ✅
cargo build -p rusty-claude-cli --release  ✅

Tests

tools/src/lib.rs           112 passed  (incl. 3 fallback_chain_tests, 4 provider_runtime_client chain tests)
commands/src/lib.rs         42 passed  (incl. /team parse regression)
runtime team_cron            17 passed
rusty-claude-cli bin        207 passed

Live testing (IdleDefense repo, Godot 4.6 game)

  • /team on → TeamCreate with 4 agents → all agents spawned, claimed tasks, read files
  • Agents used custom/openclaw provider (via qualify_for_provider)
  • TeamStatus showed live progress, inbox messages, task claims
  • 2/4 agents completed full reports (Explore + Verification), 2/4 hit iteration limits on complex analysis prompts (expected — increase max_iterations or simplify prompts for large repos)

Diff stats

 rust/crates/api/src/error.rs             |   43 +
 rust/crates/api/src/lib.rs               |    3 +-
 rust/crates/api/src/providers/mod.rs     |   39 +-
 rust/crates/api/src/providers/openai_compat.rs | 1 +
 rust/crates/commands/src/lib.rs          |   28 +-
 rust/crates/runtime/src/config.rs        |   70 +
 rust/crates/runtime/src/conversation.rs  |  203 +-
 rust/crates/runtime/src/lib.rs           |    5 +-
 rust/crates/rusty-claude-cli/src/main.rs |    3 +
 rust/crates/tools/src/lane_completion.rs |    2 +
 rust/crates/tools/src/lib.rs             | 1699 ++++++++++++++++++++++++
 11 files changed, 2095 insertions(+), 113 deletions(-)

Key files

File Lines What it does
tools/src/lib.rs +1,699 All team tool logic: TeamCreate, TeamDelete, TeamStatus, AgentMessage, TaskClaim, AgentSuggestion, mode presets, mailbox, watcher, qualify_for_provider, fallback_chain_eligible
runtime/src/conversation.rs +203 ToolCall/ToolResult types, TurnProgressReporter trait, execute_batch default impl
runtime/src/config.rs +70 subagent_model field/accessor/parser, inject_config_as_env_fallbacks
api/src/error.rs +43 status_code()/response_body() accessors for chain-fallback detection
api/src/providers/mod.rs +39 model_token_limit generic fallback, custom-openai provider entry

What this does NOT include

This PR is purely additive on top of upstream/main. It does not include:

  • TUI / split-pane dashboard changes (separate PR)
  • LSP module restructuring (already merged)
  • Setup wizard / provider config changes (already merged)
  • Custom-openai namespace routing (separate PR)
  • Hooks refactoring (separate PR)

🤖 Generated with Claude Code

code-yeongyu and others added 30 commits May 27, 2026 11:39
…pty success; now returns unknown_option error
…lugin_source_not_found instead of unknown+null
…now return non-null hints via fallback table
…ng not-found instead of unexpected_extra_args
…limited usage string

Parity with ultraworkers#791 (config extra-arg fix). The plugins arg parser emitted
'unexpected extra arguments after claw plugins show ...' with no newline
delimiter, so split_error_hint returned None. Added usage hint after newline.
60 CLI contract tests pass.
…ed usage string

claw '' and claw '   ' returned empty_prompt + hint:null because the
error message had no newline delimiter. Added usage hint. 61 CLI
contract tests pass.
…tion classifier arms

Two classifier arms had no corresponding assert_eq! in
test_classify_error_kind_returns_correct_discriminants: invalid_history_count
(both prefix and contains paths) and unknown_option (ultraworkers#790). Now 49/39 = full
coverage of all classify_error_kind return values.
…(plugins extra-arg, empty-prompt, classifier coverage)
… returned wrong error instead of unexpected_extra_args
…ltraworkers#3161)

Keep malformed diff invocations with trailing JSON format flags on the parser error path and lock the contract with focused output-format regressions.

Constraint: Do not touch tracked .omx state files.

Rejected: Repeating direct binary smoke loops | local auth/provider configuration intercepts those invocations and obscures parser behavior.

Confidence: high

Scope-risk: narrow

Tested: git diff --check; cargo fmt --check; cargo test -p rusty-claude-cli diff_extra_args_have_typed_error_kind_and_hint_766 --test output_format_contract; cargo test -p rusty-claude-cli diff_trailing_json_after_malformed_args_is_bounded_json_3129 --test output_format_contract; cargo test -p rusty-claude-cli diff_non_git_dir_has_error_kind_and_hint_801 --test output_format_contract
…ailures

Extend auto-compaction error detection to handle additional error patterns
from llama.cpp backends: 'Context size has been exceeded',
'exceed_context_size_error', 'exceeds the available context size'. Also
recover from reqwest 'error decoding response body' errors — some
llama.cpp instances return a non-SSE plaintext HTTP 500 on context overflow,
causing the SSE deserializer to fail.

Add dynamic threshold adaptation: parse server-reported context window
size from error messages (e.g., '(81920 tokens)') and set the auto-
compaction trigger at 70% of that value. This replaces the need for a
hardcoded threshold, adapting automatically to any backend's limits.

This patch was developed with assistance from OpenCode and local Qwen 3.6
API server.
@1716775457damn

Copy link
Copy Markdown

Team enhancements with subagentModel and parallel tool execution is a solid feature addition. The ability to configure per-team subagent models will help with cost optimization and specialization.

procaffe121 and others added 6 commits July 31, 2026 17:08
No behavior change. Move the inline probe out of
unshare_user_namespace_works into a reusable unshare_probe helper and a
cached working_unshare_mapping() that picks the first working candidate
from UNSHARE_MAPPING_CANDIDATES, so the launcher and the capability probe
share one code path.
…icted

Plain `unshare --user --map-root-user` fails on kernels and containers
that block unprivileged writes to /proc/self/uid_map (e.g. GitHub Actions,
restricted AppArmor profiles). On those systems util-linux delegates to the
setuid newuidmap/newgidmap helpers when --map-auto is also present.

Add the combined form as a fallback candidate and build the launcher args
from the probed mapping, so systems without newuidmap/newgidmap or a
/etc/subuid range keep using the plain form.
… fallback

The fallback candidate relies on the setuid newuidmap/newgidmap helpers
(uidmap package) plus a subuid/subgid range for the current user. Note in
the candidate docs that the startup probe rejects the candidate when those
are missing, so the plain --map-root-user form is used instead.
The startup probe validated only the mapping flags against the trivial
program `true`, but the real launcher always adds
--mount --ipc --pid --uts --fork. On environments where the user
namespace is created but mount propagation inside it is restricted
(e.g. AppArmor-restricted CI runners), the fallback mapping passed the
probe and the sandbox activated, yet every sandboxed command died with
"cannot change root filesystem propagation: Permission denied",
silently returning empty tool output and breaking the mock parity
suite.

The candidates now define the complete static launcher shape (mapping
flags + namespace flags), so probe success implies launch success; the
launcher reuses the candidate instead of re-appending the namespace
flags, keeping probe and launch as one source of truth. The
order-guarding test asserts the namespace flags are present in every
candidate.

Co-authored-by: linkst <2024023709@m.scnu.edu.cn>
…ap-auto-fallback

fix(sandbox): fall back to --map-auto when root-user mapping is restricted
Root knowledge base plus complexity-scored subdirectory files for the
rust/ workspace, its five highest-mass crates (runtime, rusty-claude-cli,
api, tools, commands, plugins), and the src/ Python porting workspace.

Generated via init-deep: 13 parallel explore agents, LSP/ast-grep code
map, centrality-scored placement. Snapshot in .omo/init-deep.json (local).
@1716775457damn

Copy link
Copy Markdown

Two details worth pinning down for the parallel read-only execution: (1) result ordering — if tool results are appended in completion order rather than call order, the transcript becomes non-deterministic across runs for the same input, which hurts reproducibility and makes failures hard to replay; keying results to the original call index would keep it stable. (2) a concurrency bound — unbounded fan-out against a local model server will queue or thrash, so a configurable cap with a sane default (and a per-team override alongside subagentModel) would be safer. Also worth confirming the workspace-scope check runs per tool call rather than once for the whole batch, since parallelism makes it easy to smuggle one out-of-scope path among several valid ones.

@TheArchitectit

Copy link
Copy Markdown
Contributor Author

All three points addressed in 6ee9e03..697911b (feat/team-pr-clean):

1. Deterministic ordering — was already index-keyed, now airtight + tested
execute_batch sorts results into original call slots and never appends in completion order. The real hole was panic handling: a panicking worker thread used to fall back to index 0 (or leave a gap). Each spawn now carries its own fallback tuple (idx, tool_use_id, tool_name), so even a panic lands in its correct slot. Regression test: parallel_batch_results_follow_call_index_even_with_workspace_escapes runs 6 reads at cap=2 (forcing two waves with interleaved completion) and asserts results[i].tool_use_id == t{i} and correct per-slot content.

Documented parity caveat in-code: parallel-safe calls execute before sequential ones within a batch (slots still call-order), so models must not emit intra-batch dependent calls.

2. Bounded fan-out — cap + per-team override

  • maxParallelToolCalls (also max_parallel_tool_calls) in settings; CLAWD_PARALLEL_TOOL_CALLS env; default 8. Parallel-safe calls run in bounded waves via thread::scope.
  • Per-team: TeamCreate.maxConcurrentAgents input, falling back to the maxConcurrentAgents setting, falling back to unlimited (pre-fix behavior preserved). Enforced by a process-wide AgentGate (Mutex+Condvar, RAII slot released on drop/panic). The gate bounds execution, not thread creation — manifests, task claims, and Agent() return semantics are unchanged. TeamDelete forgets the gate so queued agents drain. Gate regression test covers block-until-release and drop-releases-slot.
  • ToolSearch deliberately stays sequential: the sequential path merges live MCP state; the stateless registry path wouldn't produce identical output.

3. Workspace-scope check runs per call — confirmed
Enforcement is inside each GlobalToolRegistry::execute arm (classify_read_path_permission + maybe_enforce_permission_check_with_mode, then read_file_in_workspace → validate_workspace_boundary against the workspace root per invocation). Nothing caches a scope decision for the batch; the allowed_tools guard also runs per call before dispatch. The ordering test above proves it empirically: an out-of-scope ../escape.txt smuggled between five valid reads fails with escapes workspace boundary while its neighbors succeed.

Validation: cargo fmt clean; full test suites pass — runtime 615, tools 116, cli 212 (+integration suites); clippy on the three crates adds zero new warnings beyond the pre-existing baseline.

@1716775457damn

Copy link
Copy Markdown

Thanks for the thorough follow-up — all three points are properly closed:

  1. Panic-safe slot fallback for result ordering looks right; keying every spawn to its own (index, tool_use_id, tool_name) tuple removes the worst failure mode, and the workspace-escape regression test at cap=2 is a solid way to prove per-call ordering.
  2. The AgentGate RAII bound is a clean choice — bounding execution rather than thread creation keeps manifest/task-claim semantics intact, and TeamDelete forgetting the gate so queued agents drain is a good edge-case catch.
  3. Confirming the workspace-scope check runs per invocation (with allowed_tools still gating before dispatch) resolves my last concern about smuggling an out-of-scope path into a parallel batch.

This is ready once #3248 lands and the base commits are rebased away. No further blocking feedback from my side.

TheArchitectit added a commit to TheArchitectit/claw-code that referenced this pull request Sep 11, 2026
…ve TUI deps

Review fixes for PR ultraworkers#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>
TheArchitectit added a commit to TheArchitectit/claw-code that referenced this pull request Sep 11, 2026
…ve TUI deps

Review fixes for PR ultraworkers#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>
@TheArchitectit

Copy link
Copy Markdown
Contributor Author

Resubmitted as requested (re: #3248 comment): rebased onto current main and dropped the three custom-OpenAI namespace commits (fefa608, 2d6540c, 0c339e7) that #3248 supersedes. The PR now carries the 8 team commits only (head 77a23db).

Review note: with the trio dropped, the test config_model_normalizes_bare_name_to_custom_prefix_for_custom_openai_provider was also removed — it exercises the custom/ model normalization that lands with #3248, and the intermediate push briefly failed CI on it. It should be restored and re-validated together with #3248's merge.

FYI: #3248 still shows OPEN / no merge commit on main as of 13:18 UTC on our side, so the dropped trio is not yet in main — nothing further needed from this PR when it lands.

TheArchitectit and others added 8 commits September 11, 2026 13:20
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>
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.
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.
…ve TUI deps

Review fixes for PR ultraworkers#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>
…ings

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.
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.
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.
TheArchitectit added a commit to TheArchitectit/claw-code that referenced this pull request Sep 11, 2026
…ve TUI deps

Review fixes for PR ultraworkers#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>
@1716775457damn

Copy link
Copy Markdown

Thanks for the cleanup — splitting the three OpenAI-compat namespace commits out and keeping this PR focused on the 8 team commits makes review much easier, especially once #3248 lands. The deterministic per-call ordering (panic-safe slot fallback) and the cap=2 ordering regression test look solid. Will re-review head-to-head and merge after CI passes.

@1716775457damn

Copy link
Copy Markdown

Confirmed head 77a23db now carries just the 8 team commits — much cleaner to review than the previous 11-commit history. Alignment on the handoff: merge #3248 first, then restore the custom/ model-normalization test (config_model_normalizes_bare_name_to_custom_prefix_for_custom_openai_provider) and validate it against the merged base so we don't lose that coverage, then this PR gets its final pass. Once CI on the cleaned head is green, it's ready to merge from my side.

@1716775457damn

Copy link
Copy Markdown

#3248 已合并进 main,之前的 merge-order 阻塞正式解除。rebase 掉三个 base commit 后请把 config_model_normalizes_bare_name_to_custom_prefix_for_custom_openai_provider 测试恢复并跑一遍(它验证 custom/ 前缀归一化,属于 #3248 落地的关键覆盖)。77a23db 恢复测试 + CI 全绿后我做最终 head-to-head 复评,通过即可合并。

@1716775457damn

Copy link
Copy Markdown

状态同步:#3248 已合入 main,之前的 merge-order 阻塞已解除。请按上一条安排:rebase 后恢复 config_model_normalizes_bare_name_to_custom_prefix_for_custom_openai_provider 测试并确认通过(它覆盖 custom/ 前缀归一化,是 #3248 落地的关键校验),CI 全绿后我直接做最终 head-to-head 复评并合并。若 rebase 有冲突也可以贴出来一起看。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.