Skip to content

feat: Feishu model-picker card, multi-key provider groups, i18n card copy - #129974

Open
daydayup123v wants to merge 1 commit into
NousResearch:mainfrom
daydayup123v:feat/feishu-picker-multikey
Open

daydayup123v wants to merge 1 commit into
NousResearch:mainfrom
daydayup123v:feat/feishu-picker-multikey

Conversation

@daydayup123v

Copy link
Copy Markdown

What does this PR do?

Two related improvements to model switching, developed together.

1. Feishu: native interactive /model card. Picking a provider, model, and reasoning effort (minimal/low/medium/high/xhigh/max/ultra, plus none and keep) now happens in one native card, and the gateway commits model + effort in a single atomic config write. Every card action re-validates the requesting operator, chat, message, bound session, and profile; stale card revisions are fenced, so a delayed click can never apply to a session that has been replaced by /new or to a chat the card does not belong to. While an agent is running, the switch is refused with the existing busy message unless the user confirms "continue" in the card.

Previously, Feishu users switched models through text commands, and there was no way to pick reasoning effort from the chat.

2. Same-URL, different-key custom providers stay separate. Two custom providers that share one base URL but authenticate with different API keys are now tracked as distinct groups through config entries, the provider catalog, slug resolution, the /model listing, session and global restore, model-discovery write-back, and the runtime credential pool — so the second key group is never hidden by, overwritten by, or restored as the first. Each group is listed under the name the user gave it when adding it; only exactly identical names fall back to a suffix.

The card copy is served from agent/i18n (gateway.model.picker.*, added to all 17 locales); the language is captured when the card is sent so an open card never repaints mid-flow. The same change fixes doubled \n escapes in the previously shipped /fast and /reasoning picker strings (15 locales), which rendered a literal backslash-n; a regression test now renders every locale's picker strings and asserts real line breaks.

Type of Change

  • ✨ New feature (Feishu picker card; multi-key provider groups)
  • 🐛 Bug fix (picker newline escapes)

Changes Made

  • plugins/platforms/feishu/model_picker.py (new): card state machine (provider → model → effort → apply/confirm), per-card update lock, revision fencing, TTL.
  • gateway/slash_commands_model.py: picker plumbing; authorization/session re-checks on every action; one atomic commit per apply.
  • hermes_cli/model_switch.py, utils.py: model+effort persistence goes through one targeted read-modify-write (_CONFIG_RW_LOCK + dotted-key update) so concurrent writers are not clobbered.
  • hermes_cli/custom_provider_identity.py (new) + providers.py, config_providers.py, model_switch_providers.py, main_provider_setup.py, model_setup_flows_custom.py, runtime_provider_custom.py, cli_model_switch_mixin.py, agent/credential_pool.py: one shared identity for same-URL key groups across listing, selection, persistence, restore, and the runtime pool.
  • locales/*.yaml (17 files): gateway.model.picker.* keys; newline-escape fix.
  • Tests: tests/gateway/test_feishu_model_picker.py (new), tests/hermes_cli/test_same_relay_key_routing.py (new), plus aligned suites; tests/agent/test_i18n.py regression for real newlines.

How to Test

  1. Add two custom providers with the same base URL and different API keys; send /model in a Feishu chat — both groups appear separately, named as you added them.
  2. Open the card: provider → model → effort (e.g. ultra) → Apply. The config updates model + reasoning_effort in one atomic write.
  3. Press Apply twice, or after /new: the delayed click is refused with "this card's session or authorization changed"; nothing lands on the new session.

Local test evidence

  • Repository test runner (scripts/run_tests.sh) across all affected areas —
    300 files: 2,367 tests passed, 13 skipped, 0 failing tests. (The only red rows
    in the sweep were two PM-toolchain suites that require the uv binary, which
    was absent from the test box; with uv on PATH they pass 11/11.)
  • Focused set while developing: 48 files / 576 tests, 0 failures.

Checklist

  • Conventional commit message
  • Tests added/updated for the new behavior
  • Exercised against the Feishu adapter on Ubuntu (WSL2)
  • Full pytest tests/ sweep — CI will run the full matrix; local run covered the affected areas above

…copy

/model on Feishu becomes a native interactive card: provider, model, and the
full reasoning-effort set (minimal/low/medium/high/xhigh/max/ultra, plus
none/keep) are picked in one card and committed once by the gateway in a
single atomic config write. Every card action re-validates the operator,
chat, message, bound session, and profile; stale card revisions are fenced
so a delayed click cannot land on a replaced session.

Custom providers sharing one base URL but using different API keys are kept
as separate groups through config entries, the provider catalog, slug
resolution, picker listing, session and global restore, model discovery,
and the runtime credential pool. Groups display under the name the user
gave each one when adding it.

The card copy is served from agent/i18n (gateway.model.picker.*), translated
in all 17 locales, with the language captured when the card is sent. This
also fixes doubled newline escapes in the existing /fast and /reasoning
picker strings (15 locales) that rendered a literal backslash-n.

Tests: scripts/run_tests.sh - 48 related files, 576 tests, 0 failures.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins platform/feishu Feishu / Lark adapter area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Oct 1, 2026

This branch has not been deployed

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

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/feishu Feishu / Lark adapter sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants