Skip to content

Add per-session model overrides - #5992

Open
mango8853 wants to merge 21 commits into
agentscope-ai:mainfrom
mango8853:deploy/session-model-overrides
Open

Add per-session model overrides#5992
mango8853 wants to merge 21 commits into
agentscope-ai:mainfrom
mango8853:deploy/session-model-overrides

Conversation

@mango8853

@mango8853 mango8853 commented Jul 12, 2026

Copy link
Copy Markdown

Description

This PR adds opt-in per-session model overrides so a single Agent can use different LLMs for different conversations without changing QwenPaw's existing default behavior.

Per-session models are disabled by default. When disabled, the Chat model selector and /model command continue to switch the model for the whole Agent. Users can enable per-session behavior from Settings > Models; saved session overrides are preserved but ignored while the feature is disabled.

The PR also adds a modal for reviewing and managing effective models across Agents and sessions, and updates the Chat header to display the model that is effective for the current session.

Related Issue: Relates to per-session model configuration support.

Security Considerations: No new secrets or authentication paths are introduced. The global opt-in flag is stored in the existing root config, while provider/model IDs for overrides remain in Agent profile configuration.

Behavior

  • Default/off: model selection and /model read, switch, list, and reset at Agent scope.
  • Enabled: the Chat selector and /model read and write the current session override.
  • Disabling the feature preserves existing overrides but removes them from effective-model resolution.
  • Backend session writes return 409 while the feature is disabled, preventing stale clients from bypassing the setting.
  • Reset-all remains available for clearing saved session overrides without changing Agent or global defaults.

Evidence

Real behavior was verified on a deployed QwenPaw instance before updating the PR:

  • Confirmed the new settings endpoint reports enabled: false by default.
  • Confirmed existing sessions resolve to their Agent or global default while the feature is disabled.
  • Confirmed the Settings > Models modal contains the opt-in switch and disables session model controls while off.
  • Confirmed the production console build and backend start successfully with the new configuration field.
  • Confirmed no deployment paths, account IDs, tokens, or machine-specific values are included in this PR.

Example effective-model query using placeholders:

GET /api/models/active?scope=effective&agent_id=agent_1&session_id=session_1

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactoring

Component(s) Affected

  • Core / Backend (app, agents, config, providers, utils, local_models)
  • Console (frontend web UI)
  • Channels (DingTalk, Lark, QQ, Discord, iMessage, etc.)
  • Skills
  • CLI
  • Documentation (website)
  • Tests
  • CI/CD
  • Scripts / Deploy

Checklist

  • I ran pre-commit run --all-files locally and it passes
  • If pre-commit auto-fixed files, I committed those changes and reran checks
  • I ran tests locally (pytest or as relevant) and they pass
  • Documentation updated (if needed)
  • Ready for review

For Channel Changes (DingTalk, Lark, QQ, Console, etc.)

  • I ran ./scripts/check-channels.sh (or ./scripts/check-channels.sh --changed) and it passes
  • Contract test exists in tests/contract/channels/test_<channel>_contract.py (REQUIRED)
  • Contract test implements create_instance() with proper channel initialization
  • All 19 contract verification points pass (see tests/contract/channels/__init__.py)
  • Optional: Unit tests in tests/unit/channels/test_<channel>.py for complex internal logic

Testing

  1. Leave per-session models disabled and verify Chat plus /model change the Agent model.
  2. Enable per-session models in Settings > Models.
  3. Configure a model for one session and verify other sessions remain unchanged.
  4. Verify the Chat header and /model report the current session's effective model.
  5. Disable the feature and verify sessions fall back to Agent/global defaults without deleting saved overrides.

Local Verification Evidence

pytest tests/unit -qq --tb=short
# passed (3 skipped)

pytest tests/unit/workspace/test_agent_model.py tests/unit/app/routers/test_provider_context_window.py tests/unit/channels/test_base_core.py -q
# 89 passed, 1 skipped

npm run test -- src/api/modules/provider.test.ts src/pages/Chat/ModelSelector/ModelSelector.test.tsx
# 2 test files passed, 28 tests passed

npm run format:check
# TypeScript and Prettier checks passed

npm run build
# Production build completed successfully

Additional Notes

The AI Review Approval check uses the ai-review-approved GitHub environment and must be approved by a maintainer before the AI review job can run.

@github-project-automation github-project-automation Bot moved this to Todo in QwenPaw Jul 12, 2026
@mango8853
mango8853 had a problem deploying to ai-review-approved July 12, 2026 13:19 — with GitHub Actions Failure
@github-actions github-actions Bot added the first-time-contributor PR created by a first time contributor label Jul 12, 2026
@github-actions

Copy link
Copy Markdown

Welcome to QwenPaw! 🐾

Hi @mango8853, thank you for your first Pull Request! 🎉

📋 About PR Template

To help maintainers review your PR faster, please make sure to include:

  • Description - What this PR does and why
  • Type of Change - Bug fix / Feature / Breaking change / Documentation / Refactoring
  • Component(s) Affected - Core / Console / Channels / Skills / CLI / Documentation / Tests / CI/CD / Scripts
  • Checklist:
    • Run and pass pre-commit run --all-files
    • Run and pass relevant tests (pytest or as applicable)
    • Update documentation if needed
  • Testing - How to test these changes
  • Local Verification Evidence:
    pre-commit run --all-files
    # paste summary result
    
    pytest
    # paste summary result

Complete PR information helps speed up the review process. You can edit the PR description to add these details.

🙌 Join Developer Community

Thanks so much for your contribution! We'd love to invite you to join the official QwenPaw developer group! You can find the Discord and DingTalk group links under the "Developer Community" section on our docs page:
https://qwenpaw.agentscope.io/docs/community

We truly appreciate your enthusiasm—and look forward to your future contributions! 😊

We'll review your PR soon.


Tip

⭐ If you find QwenPaw useful, please give us a Star!

Star QwenPaw

Staying ahead

Star QwenPaw on GitHub and be instantly notified of new releases.

Your star helps more developers discover this project! 🐾

@mango8853
mango8853 marked this pull request as ready for review July 13, 2026 01:24
@mango8853
mango8853 had a problem deploying to ai-review-approved July 13, 2026 07:18 — with GitHub Actions Failure
@mango8853
mango8853 had a problem deploying to ai-review-approved July 13, 2026 07:22 — with GitHub Actions Failure
@mango8853

Copy link
Copy Markdown
Author

when I create an agent on qwenpaw, using different apis and different models, expected to give different session a different model, especially‌ fast model for group member, big model for single chat. But I found that qwenpaw setting one model for one agent, so I make this modify and esaily swap model in /model commands and webui. I've been using this agent from Copaw to Qwenpaw, and I'm glad to see how much it's improved. So I decided to make a small contribution.

@mango8853
mango8853 had a problem deploying to ai-review-approved July 15, 2026 14:12 — with GitHub Actions Failure
@mango8853
mango8853 had a problem deploying to ai-review-approved July 15, 2026 14:45 — with GitHub Actions Failure
…overrides

# Conflicts:
#	src/qwenpaw/runtime/builder.py
@mango8853
mango8853 requested a deployment to ai-review-approved July 27, 2026 10:08 — with GitHub Actions Waiting

@RerankerGuo RerankerGuo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Independent review at exact head f32cba8e62a00a0b9996cdaf43debab9580b4f5e (macOS arm64, Python 3.11.15, Node 22). The merge base is current main bacac7410cf2ac122dd892152beff8b03f38729f, so no semantic trial resolution is needed.

The core persisted-resolution tests pass:

test_agent_model.py
test_provider_context_window.py
test_base_core.py
89 passed, 1 skipped

provider.test.ts + ModelSelector.test.tsx
29 passed

git diff --check
passed

remote Real behavior proof
passed

I found one user-visible scope regression that the current tests do not cover. When per-session models are enabled on /chat/new, resolveRuntimeSessionIdForModel() deliberately returns undefined because the new chat has no resolved runtime session ID. ModelSelector still remains interactive, and its buildModelSlotRequest() then silently falls back to scope: "agent".

An external component regression that enables the feature, renders the selector without a resolved sessionId, and selects GPT-3.5 fails with:

expected setActiveLlm not to be called with scope="agent"

received:
{
  "provider_id": "openai",
  "model": "gpt-3.5-turbo",
  "scope": "agent",
  "agent_id": "default"
}

This means a user who enabled per-session models and selects a model before sending the first message changes the model for the entire Agent, contrary to the opt-in UI contract. Please either disable/defer model selection until the new chat has a runtime session ID, or carry a pending session identity that is also used by the first backend turn. A regression should cover session_model_overrides_enabled=true with no resolved session ID and prove that no Agent-wide write occurs.

The exact changed-file pre-commit run also has merge-gate failures:

mypy:
src/qwenpaw/app/routers/providers.py:1011
Argument 1 to load_agent_config has incompatible type "str | None"; expected "str"

black:
reformats src/qwenpaw/runtime/commands/control/model_handler.py
          src/qwenpaw/app/routers/providers.py

pylint:
model_factory.py:1393 R0915 too-many-statements (54/50)
providers.py:1046 R0915 too-many-statements (51/50)

All other applicable changed-file hooks passed. actionlint was skipped because this PR changes no workflow files.

The per-session resolution direction is sound, but the new-chat scope boundary and pinned repository hooks need to be clean before merge.

@mango8853

Copy link
Copy Markdown
Author

thanks for review! I did fixed it.

@zhijianma

zhijianma commented Aug 11, 2026

Copy link
Copy Markdown
Member

Hi @mango8853,

感谢你的贡献
看了下这个 PR 的实现,感觉目前的改动有点偏重了,引入了新的 API、配置字段以及独立 Modal,且与已有的 model_slot_override 透传通道并行运行,增加了维护成本。

建议参考项目中 session_project_dir 的设计模式,对方案进行简化:

  1. 参考 session_project_dir 模式 目前的 project_dir 解析是每次请求通过 get_project_dir_for_request() 动态获取的。建议 model_slot_override 也走同样的"请求级解析"路线,而不是在 agent.json 中新增配置字段。

  2. 保存在 chat.meta.runtime_context 建议将会话级的模型覆盖值保存在 chat.meta.runtime_context.model_slot_override。这样既实现了跨请求的持久化(类似 project_dir)

  3. 统一解析入口, 收敛解析逻辑:

  • Request body 携带的 override(前端实时选择)
  • chat.meta 中的 override(已持久化)
  • agent_config.active_model(Agent 默认)
  • Global 默认
  1. 消费点统一替换 目前代码库中所有直接读取 agent_config.active_model 的地方(如 create_model_and_formatter, _get_active_model_info 等)

@mango8853

Copy link
Copy Markdown
Author

hi, @zhijianma ,非常感谢您的回复,确实现在的改动太重了。在考虑了您的建议后,我觉得还是缺少一个直观判别每个会话在用什么模型的指示,如果在控制-会话里面的列表中,channel后面增加一列model来显示每个会话使用的模型,您觉得这个改动能接受吗?

@zhijianma

Copy link
Copy Markdown
Member

hi, @zhijianma ,非常感谢您的回复,确实现在的改动太重了。在考虑了您的建议后,我觉得还是缺少一个直观判别每个会话在用什么模型的指示,如果在控制-会话里面的列表中,channel后面增加一列model来显示每个会话使用的模型,您觉得这个改动能接受吗?

我感觉是没有必要的,我更倾向于在ModelSelector中修改 和 回显, 而不再是 agent 维度的修改。当然新建对话的初始模型暂时复用agent模型。

@mango8853
mango8853 requested a deployment to ai-review-approved August 12, 2026 02:27 — with GitHub Actions Waiting
@mango8853

Copy link
Copy Markdown
Author

hi, @zhijianma ,非常感谢您的回复,确实现在的改动太重了。在考虑了您的建议后,我觉得还是缺少一个直观判别每个会话在用什么模型的指示,如果在控制-会话里面的列表中,channel后面增加一列model来显示每个会话使用的模型,您觉得这个改动能接受吗?

我感觉是没有必要的,我更倾向于在ModelSelector中修改 和 回显, 而不再是 agent 维度的修改。当然新建对话的初始模型暂时复用agent模型。

好的,已经按要求修改了

@zhijianma

Copy link
Copy Markdown
Member

@mango8853

有几个问题:

  • Provider API 修改不当
    模型已经保存到了chat.meta 可以回显, 修改可以通过request下发
  • 本末倒置:
    代码中出现类似 _apply_session_model_slot 的逻辑,在链路中间修改了 request 对象, 通过一个 get_current_model_slot() 函数算出结果传给下游,而不是去改 input 对象。
  • 违反 DRY 原则
    到处都在重复 chat = await ...; resolve_effective_model_slot(chat_meta=...) 这种重复代码。 收敛为一个统一的 Context 获取函数,所有消费点统一调用,不需要在每个地方重新去查 chat 再解析。

@mango8853
mango8853 requested a deployment to ai-review-approved August 14, 2026 03:35 — with GitHub Actions Waiting
…overrides

# Conflicts:
#	console/src/pages/Chat/index.tsx
#	tests/unit/agents/tools/test_view_media.py
@mango8853
mango8853 requested a deployment to ai-review-approved August 14, 2026 03:44 — with GitHub Actions Waiting
@mango8853

Copy link
Copy Markdown
Author

@mango8853

有几个问题:

  • Provider API 修改不当
    模型已经保存到了chat.meta 可以回显, 修改可以通过request下发
  • 本末倒置:
    代码中出现类似 _apply_session_model_slot 的逻辑,在链路中间修改了 request 对象, 通过一个 get_current_model_slot() 函数算出结果传给下游,而不是去改 input 对象。
  • 违反 DRY 原则
    到处都在重复 chat = await ...; resolve_effective_model_slot(chat_meta=...) 这种重复代码。 收敛为一个统一的 Context 获取函数,所有消费点统一调用,不需要在每个地方重新去查 chat 再解析。

了解了,修复了并检查了其他地方

@mango8853
mango8853 requested a deployment to ai-review-approved August 25, 2026 02:10 — with GitHub Actions Waiting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

first-time-contributor PR created by a first time contributor Under Review

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants