mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fmt(js): npm run fix on merge (#67995)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
4ef92d2e5d
commit
e89bc58a5b
7 changed files with 125 additions and 125 deletions
|
|
@ -64,6 +64,7 @@ describe('ModelPill pinned-override badge', () => {
|
|||
const { unmount } = render(
|
||||
<ModelPill disabled={false} model={modelState({ model: 'deepseek/deepseek-v4-flash' })} />
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('model-pinned-dot')).toBeTruthy()
|
||||
unmount()
|
||||
|
||||
|
|
|
|||
|
|
@ -247,115 +247,115 @@ export function ModelMenuPanel({ gateway, onSelectModel, requestGateway }: Model
|
|||
const slug = group.provider.slug
|
||||
|
||||
// Collapsed when stored + no active search + not the current provider.
|
||||
const collapsed =
|
||||
collapsedProviders.includes(slug) && !search && slug !== optionsProvider
|
||||
const collapsed = collapsedProviders.includes(slug) && !search && slug !== optionsProvider
|
||||
|
||||
return (
|
||||
<DropdownMenuGroup className="py-0.5" key={slug}>
|
||||
<DropdownMenuItem
|
||||
className={cn(
|
||||
dropdownMenuSectionLabel,
|
||||
'cursor-pointer hover:bg-(--ui-control-active-background)'
|
||||
)}
|
||||
className={cn(dropdownMenuSectionLabel, 'cursor-pointer hover:bg-(--ui-control-active-background)')}
|
||||
onSelect={event => {
|
||||
event.preventDefault()
|
||||
toggleCollapsedProvider(slug)
|
||||
}}
|
||||
textValue=""
|
||||
>
|
||||
{collapsed ?
|
||||
<ChevronRight className="size-2.5 shrink-0" /> :
|
||||
{collapsed ? (
|
||||
<ChevronRight className="size-2.5 shrink-0" />
|
||||
) : (
|
||||
<ChevronDown className="size-2.5 shrink-0" />
|
||||
}
|
||||
)}
|
||||
{group.provider.name}
|
||||
</DropdownMenuItem>
|
||||
{!collapsed &&
|
||||
group.families.map(family => {
|
||||
// The active id may be the base or its -fast sibling; either
|
||||
// way this one family row represents both.
|
||||
const activeId =
|
||||
group.provider.slug === optionsProvider &&
|
||||
(optionsModel === family.id || optionsModel === family.fastId)
|
||||
? optionsModel
|
||||
: null
|
||||
// The active id may be the base or its -fast sibling; either
|
||||
// way this one family row represents both.
|
||||
const activeId =
|
||||
group.provider.slug === optionsProvider &&
|
||||
(optionsModel === family.id || optionsModel === family.fastId)
|
||||
? optionsModel
|
||||
: null
|
||||
|
||||
const isCurrent = activeId !== null
|
||||
const name = modelDisplayParts(family.id).name
|
||||
// Capabilities are looked up against the active/base id; the
|
||||
// -fast variant carries the same param support as its base.
|
||||
const caps = group.provider.capabilities?.[family.id]
|
||||
const isCurrent = activeId !== null
|
||||
const name = modelDisplayParts(family.id).name
|
||||
// Capabilities are looked up against the active/base id; the
|
||||
// -fast variant carries the same param support as its base.
|
||||
const caps = group.provider.capabilities?.[family.id]
|
||||
|
||||
// Effective settings for this row: live session state when it's
|
||||
// the active model, otherwise its remembered preset (Hermes
|
||||
// defaults when unset). Row label AND submenu read from these so
|
||||
// they never disagree.
|
||||
const preset = modelPresets[modelPresetKey(group.provider.slug, family.id)] ?? {}
|
||||
const effEffort = isCurrent ? currentReasoningEffort : (preset.effort ?? '')
|
||||
const effFast = isCurrent ? currentFastMode : (preset.fast ?? false)
|
||||
// Effective settings for this row: live session state when it's
|
||||
// the active model, otherwise its remembered preset (Hermes
|
||||
// defaults when unset). Row label AND submenu read from these so
|
||||
// they never disagree.
|
||||
const preset = modelPresets[modelPresetKey(group.provider.slug, family.id)] ?? {}
|
||||
const effEffort = isCurrent ? currentReasoningEffort : (preset.effort ?? '')
|
||||
const effFast = isCurrent ? currentFastMode : (preset.fast ?? false)
|
||||
|
||||
const fastControl = resolveFastControl(
|
||||
activeId ?? family.id,
|
||||
group.provider.models ?? [],
|
||||
caps?.fast ?? false,
|
||||
effFast
|
||||
)
|
||||
const fastControl = resolveFastControl(
|
||||
activeId ?? family.id,
|
||||
group.provider.models ?? [],
|
||||
caps?.fast ?? false,
|
||||
effFast
|
||||
)
|
||||
|
||||
const meta = [
|
||||
fastControl.kind !== 'none' && fastControl.on ? copy.fast : null,
|
||||
(caps?.reasoning ?? true) ? reasoningEffortLabel(effEffort) || copy.medium : null
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
const meta = [
|
||||
fastControl.kind !== 'none' && fastControl.on ? copy.fast : null,
|
||||
(caps?.reasoning ?? true) ? reasoningEffortLabel(effEffort) || copy.medium : null
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
// Every row is a hover-Edit submenu trigger. Activating it
|
||||
// (pointer or keyboard) switches to the family's base model and
|
||||
// restores its preset; the Fast toggle inside swaps to the -fast
|
||||
// sibling (or flips the speed param). The sub-trigger has no
|
||||
// `onSelect`, so wire both click and Enter/Space for keyboard parity.
|
||||
// Clicking the row commits the model and closes the picker; the
|
||||
// edit submenu (reasoning/fast) is reached by HOVER, so you can
|
||||
// still tweak those without the click dismissing everything.
|
||||
const activate = () => {
|
||||
if (!isCurrent) {
|
||||
void selectFamily(family, group.provider)
|
||||
}
|
||||
// Every row is a hover-Edit submenu trigger. Activating it
|
||||
// (pointer or keyboard) switches to the family's base model and
|
||||
// restores its preset; the Fast toggle inside swaps to the -fast
|
||||
// sibling (or flips the speed param). The sub-trigger has no
|
||||
// `onSelect`, so wire both click and Enter/Space for keyboard parity.
|
||||
// Clicking the row commits the model and closes the picker; the
|
||||
// edit submenu (reasoning/fast) is reached by HOVER, so you can
|
||||
// still tweak those without the click dismissing everything.
|
||||
const activate = () => {
|
||||
if (!isCurrent) {
|
||||
void selectFamily(family, group.provider)
|
||||
}
|
||||
|
||||
closeMenu()
|
||||
}
|
||||
closeMenu()
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenuSub key={`${group.provider.slug}:${family.id}`}>
|
||||
<DropdownMenuSubTrigger
|
||||
className={dropdownMenuRow}
|
||||
hideChevron
|
||||
onClick={activate}
|
||||
onKeyDown={event => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
activate()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate">
|
||||
{name}
|
||||
{meta ? <span className="text-(--ui-text-tertiary)"> {meta}</span> : null}
|
||||
</span>
|
||||
{isCurrent ? <Codicon className="ml-auto text-foreground" name="check" size="0.75rem" /> : null}
|
||||
</DropdownMenuSubTrigger>
|
||||
<ModelEditSubmenu
|
||||
effort={effEffort}
|
||||
fastControl={fastControl}
|
||||
isActive={isCurrent}
|
||||
model={family.id}
|
||||
onSelectModel={nextModel => switchTo(nextModel, group.provider.slug)}
|
||||
provider={group.provider.slug}
|
||||
reasoning={caps?.reasoning ?? true}
|
||||
requestGateway={requestGateway}
|
||||
/>
|
||||
</DropdownMenuSub>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuGroup>
|
||||
)})}
|
||||
return (
|
||||
<DropdownMenuSub key={`${group.provider.slug}:${family.id}`}>
|
||||
<DropdownMenuSubTrigger
|
||||
className={dropdownMenuRow}
|
||||
hideChevron
|
||||
onClick={activate}
|
||||
onKeyDown={event => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
activate()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate">
|
||||
{name}
|
||||
{meta ? <span className="text-(--ui-text-tertiary)"> {meta}</span> : null}
|
||||
</span>
|
||||
{isCurrent ? (
|
||||
<Codicon className="ml-auto text-foreground" name="check" size="0.75rem" />
|
||||
) : null}
|
||||
</DropdownMenuSubTrigger>
|
||||
<ModelEditSubmenu
|
||||
effort={effEffort}
|
||||
fastControl={fastControl}
|
||||
isActive={isCurrent}
|
||||
model={family.id}
|
||||
onSelectModel={nextModel => switchTo(nextModel, group.provider.slug)}
|
||||
provider={group.provider.slug}
|
||||
reasoning={caps?.reasoning ?? true}
|
||||
requestGateway={requestGateway}
|
||||
/>
|
||||
</DropdownMenuSub>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuGroup>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -381,7 +381,10 @@ function ToolEntry({ part }: ToolEntryProps) {
|
|||
)
|
||||
|
||||
const showRawSearchDrilldown =
|
||||
part.toolName === 'web_search' && part.result !== undefined && toolViewMode !== 'technical' && Boolean(rawResult.trim())
|
||||
part.toolName === 'web_search' &&
|
||||
part.result !== undefined &&
|
||||
toolViewMode !== 'technical' &&
|
||||
Boolean(rawResult.trim())
|
||||
|
||||
const hasExpandableContent = Boolean(
|
||||
view.imageUrl || view.inlineDiff || showDetail || hasSearchHits || toolViewMode === 'technical'
|
||||
|
|
@ -596,9 +599,7 @@ function ToolEntry({ part }: ToolEntryProps) {
|
|||
{showRawSearchDrilldown && (
|
||||
<details className="max-w-full">
|
||||
<summary className={cn(TOOL_SECTION_LABEL_CLASS, 'mb-0')}>{copy.rawResponse}</summary>
|
||||
<pre className={cn(TOOL_SECTION_PRE_CLASS, 'mt-1 whitespace-pre-wrap wrap-anywhere')}>
|
||||
{rawResult}
|
||||
</pre>
|
||||
<pre className={cn(TOOL_SECTION_PRE_CLASS, 'mt-1 whitespace-pre-wrap wrap-anywhere')}>{rawResult}</pre>
|
||||
</details>
|
||||
)}
|
||||
{toolViewMode === 'technical' && !(isFileEdit && view.inlineDiff) && (
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ describe('forceLoneHeaderForPanes', () => {
|
|||
const chrome =
|
||||
(placement?: string, uncloseable = false) =>
|
||||
() => ({ placement, uncloseable })
|
||||
|
||||
const noCollapse = () => false
|
||||
|
||||
it('forces a header for session-tile ids even without registered chrome', () => {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ describe('Hermes REST session helpers', () => {
|
|||
if (path.startsWith('/api/profiles/sessions/sidebar')) {
|
||||
// The exact skew failure: Electron surfaces the backend catch-all.
|
||||
return Promise.reject(
|
||||
new Error('Error invoking remote method \'hermes:api\': Error: 404: {"detail":"No such API endpoint: /api/profiles/sessions/sidebar"}')
|
||||
new Error(
|
||||
'Error invoking remote method \'hermes:api\': Error: 404: {"detail":"No such API endpoint: /api/profiles/sessions/sidebar"}'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,18 +19,10 @@ const STORAGE_KEY = 'hermes.desktop.collapsed-providers'
|
|||
* the render loop only visits providers present in the active `groups`, and
|
||||
* `collapsedProviders.includes(slug)` against an absent slug is a no-op.
|
||||
*/
|
||||
export const $collapsedProviders = persistentAtom<string[]>(
|
||||
STORAGE_KEY,
|
||||
[],
|
||||
Codecs.stringArray
|
||||
)
|
||||
export const $collapsedProviders = persistentAtom<string[]>(STORAGE_KEY, [], Codecs.stringArray)
|
||||
|
||||
/** Toggle a provider slug in/out of the collapsed set. */
|
||||
export function toggleCollapsedProvider(slug: string): void {
|
||||
const current = $collapsedProviders.get()
|
||||
$collapsedProviders.set(
|
||||
current.includes(slug)
|
||||
? current.filter(s => s !== slug)
|
||||
: [...current, slug]
|
||||
)
|
||||
$collapsedProviders.set(current.includes(slug) ? current.filter(s => s !== slug) : [...current, slug])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,17 +47,22 @@ const reasoningConfigPayload = (arg: string, sid: string) => {
|
|||
|
||||
for (const part of parts) {
|
||||
const flag = part.toLowerCase()
|
||||
|
||||
if (REASONING_GLOBAL_FLAGS.has(flag)) {
|
||||
scope = 'global'
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (REASONING_SESSION_FLAGS.has(flag)) {
|
||||
// Session scope is the default; accept the flag for parity with /model.
|
||||
if (!scope) {
|
||||
scope = 'session'
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
valueParts.push(part)
|
||||
}
|
||||
|
||||
|
|
@ -486,31 +491,29 @@ export const sessionCommands: SlashCommand[] = [
|
|||
)
|
||||
}
|
||||
|
||||
ctx.gateway
|
||||
.rpc<ConfigSetResponse>('config.set', reasoningConfigPayload(arg, ctx.sid ?? ''))
|
||||
.then(
|
||||
ctx.guarded<ConfigSetResponse>(r => {
|
||||
if (!r.value) {
|
||||
return
|
||||
}
|
||||
ctx.gateway.rpc<ConfigSetResponse>('config.set', reasoningConfigPayload(arg, ctx.sid ?? '')).then(
|
||||
ctx.guarded<ConfigSetResponse>(r => {
|
||||
if (!r.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (r.value === 'hide') {
|
||||
patchUiState(state => ({
|
||||
...state,
|
||||
sections: { ...state.sections, thinking: 'hidden' },
|
||||
showReasoning: false
|
||||
}))
|
||||
} else if (r.value === 'show') {
|
||||
patchUiState(state => ({
|
||||
...state,
|
||||
sections: { ...state.sections, thinking: 'expanded' },
|
||||
showReasoning: true
|
||||
}))
|
||||
}
|
||||
if (r.value === 'hide') {
|
||||
patchUiState(state => ({
|
||||
...state,
|
||||
sections: { ...state.sections, thinking: 'hidden' },
|
||||
showReasoning: false
|
||||
}))
|
||||
} else if (r.value === 'show') {
|
||||
patchUiState(state => ({
|
||||
...state,
|
||||
sections: { ...state.sections, thinking: 'expanded' },
|
||||
showReasoning: true
|
||||
}))
|
||||
}
|
||||
|
||||
ctx.transcript.sys(`reasoning: ${r.value}`)
|
||||
})
|
||||
)
|
||||
ctx.transcript.sys(`reasoning: ${r.value}`)
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue