mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-07 17:28:03 +08:00
* feat(acp): save concrete model defaults in canvas
* test(acp): verify provider models from subprocesses
* feat(acp): per-conversation agent chip + versioned Claude model picker
User-visible changes:
- Conversation cards now show a single inline chip `[brand mark] {model}`
on every conversation. ACP cards always render (identity info); OpenHands
native cards render whenever `agent.llm.model` is present. New
`AgentBrandIcon` covers Claude / Codex / Gemini brand marks with a
terminal-glyph fallback; the OpenHands logo is recolored via
`[&_path]:fill-current` so it inherits the muted-grey chip color
(the shipped SVG hardcodes `fill="white"`).
- Settings → Agent dropdown for Claude Code lists 10 versioned options
(Opus 4.7, 4.6, 4.6/1M, 4.5, 4.1; Sonnet 4.6, 4.6/1M, 4.5; Haiku 4.5;
opusplan). Default switched from `sonnet` to `claude-opus-4-7`.
Canonical IDs were verified against the bundled `claude` CLI binary's
model registry — the static SDK `.mjs` shims don't carry the full
registry. `[1m]` aliases used for 1M-context variants (no canonical
`claude-*-1m` IDs ship in the SDK).
- `ConversationCardFooter` chip resolves the ACP model string from
`current_model_name → current_model_id → agent.acp_model → agent.llm.model`
(the `"acp-managed"` sentinel is filtered out), so the chip works
whether or not the agent-server populates the SDK runtime fields.
- Removed dead `showLlmProfiles` plumbing on `ConversationCard` /
`CompactConversationRow` / `ConversationPanel` pass-throughs that
used to gate the OpenHands model line behind a metadata-menu toggle.
Chip is now always shown when a model exists.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(acp): adapter cleanup + drop unauthenticated model-check script
- Extract `resolveAcpDisplayModel(info)` from the triple-nested ternary
in `toAppConversation`. Same precedence chain (runtime name → runtime
id → configured model → llm.model minus sentinel), just expressed once
with a loop and named conditions.
- Name the `"acp-managed"` literal as `ACP_MANAGED_SENTINEL` (exported)
and the `"default" / "default (recommended)"` strings as
`ACP_DEFAULT_PLACEHOLDERS`. The sentinel was referenced from 7 places
across source and tests.
- Trim `DirectConversationInfo.agent.kind` JSDoc to 3 lines (was 7).
- Delete `scripts/check-acp-provider-models.mjs` and revert the CI step +
triggers in `.github/workflows/acp-providers-sync.yml`. The script
spawned each ACP wrapper unauthenticated and validated Canvas's lists
against the wrapper's fallback model set — which is only 3 models for
Claude Code (sonnet / sonnet[1m] / haiku) regardless of what the
wrapper actually accepts. The check flagged every legitimately-added
Opus entry as drift. Removing it; followup tracked in #740 for moving
the lists into `@openhands/typescript-client`.
- Remove `test:acp-models` npm script (only invoked the deleted file).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): plug review-flagged gaps in model resolution + chip path
Five behavioral fixes + two refactors from review feedback on PR #730:
- F1: ``normalizeAgent`` and ``requireDirectConversationInfo`` were
dropping ``agent.acp_model``, ``current_model_id``, and
``current_model_name`` on the way in from the wire — so the chip
resolver only worked in unit tests (which build ``DirectConversationInfo``
in-process) and silently fell back to provider-name labels in production.
Normalizer now preserves all three.
- F2: ChatInputActions gated rendering ChatInputModel on
``isCloud || conversation?.agent_kind === "acp"``, so on a local home
screen with no active conversation it always picked SwitchProfileButton.
SwitchProfileButton then hid itself for ACP — net result: the home-ACP
model label never appeared. Added ``isHomeAcp`` derivation from
``settings.agent_settings.agent_kind`` so the chat input picks
ChatInputModel in that case too.
- F3: Switching the preset dropdown to Custom set ``isCustomAcpModel``
but left ``acpModel`` untouched, so a user moving Claude Code → Custom
+ typing a custom command could save ``acp_model: "claude-opus-4-7"``
on an unrelated wrapper. Now clears ``acpModel`` on Custom selection.
- F4: ``buildConfiguredAcpAgentSettings`` was stripping null / empty
``acp_model`` and not falling back to ``provider.default_model``, so
existing users with ``acp_model: null`` saw the new registered default
in Settings → Agent but their next conversation still started with the
agent-server's own default (UI/runtime mismatch). Conversation creation
now substitutes the provider default for empty values, matching what
the form displays.
- F5: ``isAcpDefaultPlaceholder`` was applied only to runtime fields, not
to the ``configured`` (``agent.acp_model``) or ``sdkLlm``
(``agent.llm.model``) fallback rungs of the precedence chain. Older
settings that persisted the literal ``"Default (recommended)"`` could
surface it on chips. Filter now applies uniformly.
- R1: All five surfaces (Settings form, conversation creation,
ChatInputModel, conversation adapter, chip) now route through one
helper, ``resolveEffectiveAcpModel({ runtimeName, runtimeId,
configured, sdkLlm, providerDefault })`` in ``acp-providers.ts``.
Placeholder + sentinel filtering live in one place. ``providerDefault``
is opt-in — chip omits it (don't lie about what's running), settings
/ creation / chat-input pass it (silently substitute the registry
default).
- R2: ``ACPProviderIcon`` no longer includes ``"openhands"`` — it's
ACP-only again. Reintroduced ``AgentBrandIconKind = "openhands" |
ACPProviderIcon`` for surfaces that can render either harness's mark.
Tests: ``acp-server-conversation-service.test.ts`` now exercises the wire
path with the new fields. ``agent-server-adapter.test.ts`` adds two cases
covering placeholder filtering on configured + sdkLlm rungs.
``agent-settings.test.tsx`` adds a Custom-preset-clears-default
regression. ``chat-input-model.test.tsx`` swaps the
"home + ACP renders nothing" assertion for "home + ACP shows the provider
default" — that's the new correct behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): translate new agent-settings keys + harmonize Gemini labels
Addresses the latest review pass:
- Translates ``SETTINGS$AGENT_CUSTOM_MODEL`` and ``SETTINGS$AGENT_MODEL_HINT``
into all 14 non-English locales (ja, zh-CN, zh-TW, ko-KR, no, it, pt, es,
ar, fr, tr, de, uk, ca). Both keys previously fell back to English text
on every non-English client, blocking the model dropdown's hint copy and
Custom-model label from being legible.
- Harmonizes the Gemini model labels with the Claude / Codex pattern —
raw IDs like ``gemini-3.1-pro-preview`` become ``Gemini 3.1 Pro
(preview)`` so the three providers read consistently in the dropdown.
- Adds provenance notes to ``CODEX_MODELS`` and ``GEMINI_MODELS`` mirroring
the Claude one — naming the upstream source the list was extracted from
and pointing at agent-canvas#740 (the long-term "move ACP model lists to
``@openhands/typescript-client``" plan).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): address review — chip labels, dead toggle, icon de-dup, shared hook
- Chip shows the provider's picker label (e.g. "Claude Opus 4.7") instead of
the raw acp_model ID via new labelForAcpModel(); falls back to the raw ID
for custom overrides and the provider name when no model. (#1)
- Drop the stale version from the 1M labels (opus[1m]/sonnet[1m] →
"Claude Opus (1M)" / "Claude Sonnet (1M)") so the version-agnostic alias
and its label can't disagree. (#2)
- Remove the now no-op "Show LLM profiles" filter-menu row + its wiring
(chip is unconditional now; the preference no longer affects cards). (#4)
- Onboarding AgentOptionIcon delegates to AgentBrandIcon; delete the
duplicated brand-mark path constants and per-kind SVG markup. (#5)
- Name the OpenHands logo aspect ratio (3:2) so the chip and onboarding
tile render identically. (#7)
- Extract useAcpModelContext() shared by chat-input-actions and
chat-input-model to kill the duplicated isHomeAcp / destination-path /
label logic. (#6)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): gate the agent chip behind the restored "LLM model" toggle
The chip was unconditional, which (a) silently flipped OpenHands cards from
main's model-hidden-by-default to always-shown and (b) left the panel's
"LLM model" toggle a no-op (then deleted). Restore one toggle that gates the
unified chip for BOTH ACP and OpenHands cards (default OFF), matching the
sibling "Repo and branch" metadata toggle.
- Footer: chip (ACP brand mark + model, OpenHands logo + model) now renders
only when showAgentChip is set.
- Restore showLlmProfiles plumbing: filter-menu row + ConversationPanel/
ConversationCard/CompactConversationRow pass-throughs (panel + filter-menu
are now byte-identical to main).
- ConversationCard.shouldRenderFooter gates ACP under the toggle too.
Net effect vs main for OpenHands: identical by default (hidden); when the
toggle is on, the only change is the OpenHands logo added next to the model
name. ACP identity chip becomes opt-in via the same toggle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): reconcile model on command edit, unify chip labels, dedupe provider lookup
Review follow-ups for the versioned ACP model picker + agent chip:
- agent-settings: editing the command textarea into a different provider
(or a custom command) now reconciles the model selector, so Save can no
longer silently persist e.g. claude-opus-4-7 against a Codex/custom
wrapper. The preset dropdown already did this; the textarea is the other
way a user switches providers. Also always show the custom-model input
when the dropdown is on "Custom" so a mismatched value is visible/editable
rather than hidden.
- chat input: surface the provider's human label (e.g. "Claude Opus 4.7")
for ACP conversations, matching the conversation-list chip, instead of the
raw acp_model id.
- relabel the conversation-panel "LLM model" toggle to "Agent / model" — it
now governs the ACP brand chip too.
- extract getAcpProvider() and replace the repeated ACP_PROVIDERS.find()
lookups across the adapter, settings, and the constants module.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(acp): stop filling the OpenHands logo's transparent hand paths
AgentBrandIcon recolored the OpenHands logo with a blanket
``[&_path]:fill-current``, which also overrode the two ``fill="transparent"``
hand shapes — turning the mark into a solid white blob on the onboarding tile
(and a filled blob on the conversation chip). The logo asset has 5
``fill="white"`` wordmark paths and 2 ``fill="transparent"`` hands; only the
former should inherit ``currentColor``.
Scope the override to ``[&_path:not([fill=transparent])]:fill-current`` so the
hands stay transparent (negative space), restoring the original two-tone logo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Debug Agent <debug@example.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>