Skip to content

feat(llm): add per-user model preferences and commands - #7439

Merged
think-in-universe merged 26 commits into
mainfrom
issue-7420-user-model-preference
Aug 13, 2026
Merged

think-in-universe merged 26 commits into
mainfrom
issue-7420-user-model-preference

Conversation

@italic-jinxin

Copy link
Copy Markdown
Contributor

Summary

  • Persist model preferences using caller-scoped tenant and user storage.
  • Resolve models using explicit trusted request override, then user preference, then workspace default.
  • Add authenticated model-preference API endpoints.
  • Add /model, /model use <model>, and /model default.
  • Reject stale or disallowed preferences instead of silently routing to another model or provider.

Linked Issue

Closes #7420

Validation

  • cargo test -p ironclaw_assistant --test product_commands_contract
  • cargo test -p ironclaw_assistant --test reborn_services_contract member_model_preference_commands_update_only_the_callers_preference
  • cargo test -p ironclaw_webui --test webui_v2_descriptors_contract
  • Architecture size-ceiling test
  • Relevant all-features clippy checks with warnings denied

Security Impact

Preference reads and writes are scoped to the authenticated tenant and user. Ordinary members cannot update another user's preference or modify the workspace allowlist.

Database Impact

No database schema or migration changes. Preferences use caller-scoped filesystem persistence and are retained when reset.

Blast Radius

Product contracts, caller-scoped persistence, composition wiring, model resolution, WebUI APIs, and product commands.

Rollback Plan

Revert the three #7420 commits. Persisted preference files become unused and do not affect the workspace default.

Review track

Track C — caller-scoped persistence, authorization, and runtime model-selection change.

@italic-jinxin italic-jinxin added size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Aug 10, 2026
@railway-app

railway-app Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-7439 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Aug 13, 2026 at 6:47 am

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 10, 2026 12:35 Destroyed
@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 26ebdf2c-d04f-4938-85c1-7eceb49816b1

📥 Commits

Reviewing files that changed from the base of the PR and between 50ba703 and fd29905.

📒 Files selected for processing (3)
  • crates/app/ironclaw_composition/CONTRACT.md
  • crates/app/ironclaw_composition/src/runtime.rs
  • crates/app/ironclaw_composition/src/runtime/tests/core.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added caller-scoped model preferences through /model use <model> and /model default.
    • Added WebUI controls to view and update preferred models.
    • Model status shows saved, effective, and available models, including unavailable selections.
    • Model resolution respects explicit choices, saved preferences, and workspace defaults.
  • Bug Fixes

    • Retries consistently reuse the model selected when first accepted.
    • Diagnostic-only events are excluded from product-visible operator logs.
  • Documentation

    • Updated command and API documentation for model preferences.

Walkthrough

The change adds caller-scoped model preferences with filesystem persistence, assistant commands, WebUI routes, runtime wiring, model resolution, and replay preservation. It also excludes server diagnostic events from product-visible operator logs.

Changes

User model preferences

Layer / File(s) Summary
Contracts and filesystem persistence
crates/contracts/ironclaw_product_contracts/..., crates/product/ironclaw_operator/src/llm_admin/..., crates/app/ironclaw_composition/...
Defines preference contracts and stores preferences by tenant and user in bounded JSON files.
Preference resolution and runtime wiring
crates/product/ironclaw_operator/src/llm_admin/llm_config_service.rs, crates/app/ironclaw_composition/..., crates/product/ironclaw_assistant/src/channel_workflow.rs
Resolves explicit model, stored preference, then workspace default. Composes and injects the configured service into channel workflows.
Assistant commands and capability dispatch
crates/product/ironclaw_assistant/src/commands.rs, crates/product/ironclaw_assistant/src/reborn_services/...
Adds /model use and /model default, caller-scoped audience handling, preference views, and mutation dispatch.
WebUI preference routes
crates/product/ironclaw_webui/src/webui_v2/..., crates/product/ironclaw_webui/tests/...
Adds caller-scoped GET and PUT model-preference routes with descriptors, handlers, router wiring, and contract coverage.
Inbound resolution and replay preservation
crates/product/ironclaw_assistant/src/inbound_turn.rs, crates/domains/ironclaw_threads/src/..., crates/product/ironclaw_assistant/src/error.rs
Resolves the model before acceptance and persists it in replay metadata. Retries and replays reuse the original model.
Validation
crates/extensions/ironclaw_extension_host/src/channel_host/e2e_tests.rs, crates/product/ironclaw_assistant/tests/..., crates/domains/ironclaw_threads/tests/...
Covers preference isolation, command parsing, persistence, failure recovery, idempotent replay, and application to the next turn.

Operator log filtering

Layer / File(s) Summary
Server diagnostic log exclusion
crates/product/ironclaw_operator/src/operator_logs.rs
Excludes ironclaw_server_diagnostics and its namespaces from product-visible operator logs and tests the behavior.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Mergeability Score: 🟡 Moderate · up to fd299

This PR adds per-user model preference persistence and changes recovery behavior; interrupted writes can leave sequence gaps that break recovered first-message handling, and lookup failures can be hidden, leaving recovery incomplete without a clear error. These are bounded but concrete runtime correctness risks requiring fixes or explicit owner acceptance before merge.

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description omits Change Type, the complete Test Strategy, the Track C trust-boundary checklist, and Review Follow-Through. Complete the required template sections, mark applicable validation and risk items, document test tiers and commands, and address the Track C trust-boundary checklist.
Out of Scope Changes check ⚠️ Warning The PR adds WebUI v2 model-preference routes, but [#7420] explicitly excludes WebUI model selection from scope. Remove the WebUI preference descriptors, handlers, router wiring, and related tests, or update the approved issue scope before merge.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and accurately summarizes the per-user model preference feature.
Linked Issues check ✅ Passed The changes cover [#7420] preference persistence, precedence, commands, validation, caller isolation, admin boundaries, and replay/resume preservation.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added scope: docs Documentation risk: low Changes to docs, tests, or low-risk modules and removed risk: medium Business logic, config, or moderate-risk modules labels Aug 10, 2026
@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@claude review

@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@ironloopai review

@ironloopai

ironloopai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

🧭 IronLoop Run · Review

This comment updates in place as the Run moves through its stages.

⬛ Final result · Stopped

🟨 Queued → 🟦 Working → ⬛ Stopped

Manual command by italic-jinxin · attempt 1 of 3 · stopped after 9m 44s

IronLoop stopped because the pull request target branch or head changed while this Run was active.

Run details

Run: a9d90f52-664f-40ae-a8d9-62ee4f3f19e4
Base: issue-7419-model-allowlist at 99f2d2a
Head: issue-7420-user-model-preference at 86292d0
Created: 2026-08-10 12:36 UTC
Updated: 2026-08-10 12:46 UTC

@italic-jinxin
italic-jinxin force-pushed the issue-7420-user-model-preference branch from 86292d0 to 786ea3a Compare August 10, 2026 12:46
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 10, 2026 12:46 Destroyed
@italic-jinxin
italic-jinxin force-pushed the issue-7420-user-model-preference branch from 786ea3a to 06d79c7 Compare August 10, 2026 13:09
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 10, 2026 13:09 Destroyed
@italic-jinxin italic-jinxin self-assigned this Aug 11, 2026
@italic-jinxin italic-jinxin linked an issue Aug 11, 2026 that may be closed by this pull request
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 12, 2026 04:21 Destroyed
@italic-jinxin
italic-jinxin changed the base branch from issue-7419-model-allowlist to main August 12, 2026 06:14
@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@claude review

@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@ironloopai review

@ironloopai

ironloopai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

🧭 IronLoop Run · Review

This comment updates in place as the Run moves through its stages.

🟩 Final result · Completed

🟨 Queued → 🟦 Working → 🟦 Posting results → 🟩 Completed

Manual command by italic-jinxin · attempt 1 of 3 · completed in 4m 11s

IronLoop completed the review and posted it to GitHub.

🔗 Result

Open submitted review →

Run details

Run: 25e8e5c5-5d0c-44ab-827e-f386b9606c41
Base: main at 173f078
Head: issue-7420-user-model-preference at c281833
Created: 2026-08-12 16:40 UTC
Updated: 2026-08-12 16:44 UTC

ironloopai[bot]

This comment was marked as resolved.

…-preference

# Conflicts:
#	crates/app/ironclaw_architecture_tests/tests/reborn_dependency_boundaries.rs
#	crates/product/ironclaw_assistant/src/inbound_turn.rs
#	crates/product/ironclaw_assistant/src/reborn_services.rs
#	crates/product/ironclaw_assistant/src/reborn_services/llm_config.rs
#	crates/product/ironclaw_assistant/tests/reborn_services_contract.rs
#	crates/product/ironclaw_webui/src/webui_v2/mod.rs
#	crates/product/ironclaw_webui/src/webui_v2/router.rs
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 01:23 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 01:33 Destroyed
coderabbitai[bot]

This comment was marked as resolved.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 02:00 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs (1)

6661-6665: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Test tenant isolation with the same user ID.

This test changes only the user ID. It cannot detect a regression that keys preferences by user alone. Create another router for user-alpha in a different tenant, then assert it remains unset before and after the first tenant selects or resets a model.

The PR objective requires tenant isolation. As per path instructions, “Test through the caller” requires route-level coverage at the real caller seam.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs` around
lines 6661 - 6665, Extend the test around router_with_caller and caller_for_user
to create a second user-alpha caller in a different tenant, then assert its
model preference is unset before and after user-alpha selects and resets a model
in the first tenant. Keep the assertions at the route-level caller seam and
verify tenant isolation rather than only differing user IDs.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/domains/ironclaw_threads/src/filesystem_service.rs`:
- Around line 1766-1770: In the concurrent pending-claim branch of the message
acceptance flow, ensure the returned identifier uses the updated message
identity from message.message_id rather than the stale local message_id.
Preserve the persisted record.message_id through transcript writing and
submission, and add a regression test covering a losing concurrent accept that
resumes a pending intent and verifies the returned ID matches the persisted
transcript row.

In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs`:
- Around line 980-992: Update the fallback in the USER_MODEL_PREFERENCE_VIEW
handler to return UserModelPreference with model unset (None) when no record
exists, rather than defaulting to "model-b". Adjust the initial and other-caller
assertions in this contract test to expect an empty preference object until that
caller selects a model.

---

Duplicate comments:
In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs`:
- Around line 6661-6665: Extend the test around router_with_caller and
caller_for_user to create a second user-alpha caller in a different tenant, then
assert its model preference is unset before and after user-alpha selects and
resets a model in the first tenant. Keep the assertions at the route-level
caller seam and verify tenant isolation rather than only differing user IDs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ddf43cfe-c611-4fe3-b157-e4d41d4ea32d

📥 Commits

Reviewing files that changed from the base of the PR and between 307af80 and 9030545.

📒 Files selected for processing (5)
  • crates/domains/ironclaw_threads/src/filesystem_service.rs
  • crates/domains/ironclaw_threads/tests/filesystem_session_thread_contract.rs
  • crates/product/ironclaw_operator/src/llm_admin/llm_config_service.rs
  • crates/product/ironclaw_operator/src/llm_admin/user_model_preference_store.rs
  • crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs

Comment thread crates/domains/ironclaw_threads/src/filesystem_service.rs
Comment thread crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs Outdated
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 02:43 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs (1)

882-892: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Do not mutate the test store before a failed invocation is returned.

If next_invoke_response contains Err, this branch inserts the preference before returning the error. A later GET can then observe state for a failed PUT. Move the insertion after successful response handling, or add an explicit commit-then-error contract and test it.

This finding follows from the StubServices::invoke ordering in this file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs` around
lines 882 - 892, Update StubServices::invoke so the user_model_preferences
insertion in the LLM_USER_MODEL_PREFERENCE_SET_CAPABILITY_ID branch occurs only
after next_invoke_response has completed successfully; preserve the failed
invocation response without mutating the test store, and ensure subsequent GETs
cannot observe preferences from failed PUTs.
crates/domains/ironclaw_threads/src/filesystem_service.rs (2)

1778-1792: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Propagate recovery lookup errors.

The if let Ok(Some(accepted)) pattern discards every error from accepted_message_from_idempotency_path. This hides filesystem and deserialization failures, then returns only the earlier write_new_message error. Match Ok(Some(...)), Ok(None), and Err(recovery_error) explicitly. Preserve the recovery error or attach it to the original error.

As per path instructions: “Fail loud: flag silent-failure patterns.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/domains/ironclaw_threads/src/filesystem_service.rs` around lines 1778
- 1792, Update the recovery branch in the write_new_message error path to
explicitly handle Ok(Some(accepted)), Ok(None), and Err(recovery_error) from
accepted_message_from_idempotency_path. Preserve successful recovery, while
propagating the recovery error or attaching it to the original write error
instead of silently discarding it.

Source: Path instructions


1681-1684: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Persist or reuse the reserved sequence during pending recovery.

The recovery record stores message_id and replay_metadata, but it does not store sequence. The fallback reserves a sequence at Line 1776 and writes the message later. If the reservation succeeds and the write fails, the next retry reserves a different sequence. Concurrent pending retries can consume additional sequence values. The first persisted message can then have sequence > 1, while Line 1797 treats sequence == 1 as the first message.

Make sequence reservation and message persistence atomic, or persist the reserved sequence in the recovery intent and reuse it. Add a filesystem caller-level regression test for failure after reservation and concurrent pending resumes.

As per coding guidelines: “Persisted state must remain reconstructible after interruption; test conflicts, retry exhaustion, restart, and partial-failure behavior at the public domain-operation or typed-wrapper seam.”

Also applies to: 1776-1777

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/domains/ironclaw_threads/src/filesystem_service.rs` around lines 1681
- 1684, Update the pending-recovery flow around the recovery record construction
and the fallback reservation near the message write to persist the reserved
sequence and reuse it on retries, or make reservation and persistence atomic.
Ensure concurrent or interrupted resumes cannot consume new sequence values and
that the first persisted message retains sequence 1. Add a filesystem
caller-level regression test through the public domain-operation or
typed-wrapper seam covering failure after reservation and concurrent pending
resumes.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs`:
- Line 6724: Add a same-user/different-tenant caller in the test around the
existing model-a preference setup, issue its GET after model-a is stored, and
assert an empty JSON object to verify tenant isolation. Keep the existing
different-user assertion unchanged, using the test’s established
caller-construction and request helpers.

---

Outside diff comments:
In `@crates/domains/ironclaw_threads/src/filesystem_service.rs`:
- Around line 1778-1792: Update the recovery branch in the write_new_message
error path to explicitly handle Ok(Some(accepted)), Ok(None), and
Err(recovery_error) from accepted_message_from_idempotency_path. Preserve
successful recovery, while propagating the recovery error or attaching it to the
original write error instead of silently discarding it.
- Around line 1681-1684: Update the pending-recovery flow around the recovery
record construction and the fallback reservation near the message write to
persist the reserved sequence and reuse it on retries, or make reservation and
persistence atomic. Ensure concurrent or interrupted resumes cannot consume new
sequence values and that the first persisted message retains sequence 1. Add a
filesystem caller-level regression test through the public domain-operation or
typed-wrapper seam covering failure after reservation and concurrent pending
resumes.

In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs`:
- Around line 882-892: Update StubServices::invoke so the user_model_preferences
insertion in the LLM_USER_MODEL_PREFERENCE_SET_CAPABILITY_ID branch occurs only
after next_invoke_response has completed successfully; preserve the failed
invocation response without mutating the test store, and ensure subsequent GETs
cannot observe preferences from failed PUTs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 64ecf64b-6c74-476b-bdff-4b9f512a67ce

📥 Commits

Reviewing files that changed from the base of the PR and between 9030545 and 89be82d.

📒 Files selected for processing (2)
  • crates/domains/ironclaw_threads/src/filesystem_service.rs
  • crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs

Comment thread crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 03:10 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs (1)

6660-6802: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add composed authentication tests for the model-preference routes.

webui_v2_handlers_contract.rs injects ProductSurfaceCaller directly. Existing webui_v2_app tests cover authentication only on other routes. Add valid and invalid bearer tests for both preference routes, and assert the authenticated tenant/user reaches the service. Keep the existing isolation test.

This follows the “Trusted-ingress seal” and “Test through the caller” invariants in .claude/rules and crates/product/ironclaw_webui/AGENTS.md.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs` around
lines 6660 - 6802, Extend
user_model_preference_routes_are_caller_scoped_and_do_not_require_admin with
composed-authentication coverage for both GET and PUT model-preference routes,
including valid and invalid bearer-token cases. Exercise the routes through the
webui_v2_app authentication path rather than directly injected
ProductSurfaceCaller instances, and assert valid requests propagate the
authenticated tenant and user to the service while invalid requests are
rejected. Preserve the existing caller-isolation assertions.

Sources: Coding guidelines, Path instructions, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs`:
- Around line 6660-6802: Extend
user_model_preference_routes_are_caller_scoped_and_do_not_require_admin with
composed-authentication coverage for both GET and PUT model-preference routes,
including valid and invalid bearer-token cases. Exercise the routes through the
webui_v2_app authentication path rather than directly injected
ProductSurfaceCaller instances, and assert valid requests propagate the
authenticated tenant and user to the service while invalid requests are
rejected. Preserve the existing caller-isolation assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3133ce8f-c28e-4fa2-ad14-5803e4051728

📥 Commits

Reviewing files that changed from the base of the PR and between 89be82d and 50ba703.

📒 Files selected for processing (1)
  • crates/product/ironclaw_webui/tests/webui_v2_handlers_contract.rs

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7439 August 13, 2026 06:40 Destroyed
@think-in-universe
think-in-universe added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit ad18aa1 Aug 13, 2026
49 checks passed
@think-in-universe
think-in-universe deleted the issue-7420-user-model-preference branch August 13, 2026 08:21
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
* feat(llm): add tenant model selection policy

* fix(composition): move model policy store to operator

* test(llm): specify per-user model preference behavior

* feat(llm): persist per-user model preferences

* feat(llm): add per-user model commands

* fix(llm): address model preference review findings

* fix(logging): preserve model preference error causes

* fix(model): apply user preferences to channel turns

* test(channel): cover model preference handoff

* fix(composition): keep model config wiring concrete

* fix(model): preserve resolved model across inbound replay

* fix: preserve accepted model across replay failures

* test(model): restore caller-scoped preference coverage

* fix(model): close preference review gaps

* fix(model): preserve concurrent replay identity

* test(model): cover cross-tenant preference isolation

* fix(cli): honor saved user model preference

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-7439 — fd29905a Deployed Aug 13, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Per-user LLM model preference and user model commands

2 participants