mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
feat(cli): add numbered keyboard shortcuts to approval and clarify prompts
This commit is contained in:
parent
b341b19fff
commit
d1ed6f4fb4
1 changed files with 107 additions and 16 deletions
123
cli.py
123
cli.py
|
|
@ -8016,8 +8016,18 @@ class HermesCLI:
|
||||||
choice_wrapped: list[tuple[int, str]] = []
|
choice_wrapped: list[tuple[int, str]] = []
|
||||||
for i, choice in enumerate(choices):
|
for i, choice in enumerate(choices):
|
||||||
label = choice_labels.get(choice, choice)
|
label = choice_labels.get(choice, choice)
|
||||||
prefix = '❯ ' if i == selected else ' '
|
# Show number prefix for quick selection (1-9 for items 1-9, 0 for 10th item)
|
||||||
for wrapped in _wrap_panel_text(f"{prefix}{label}", inner_text_width, subsequent_indent=" "):
|
if i < 9:
|
||||||
|
num_prefix = str(i + 1)
|
||||||
|
elif i == 9:
|
||||||
|
num_prefix = '0'
|
||||||
|
else:
|
||||||
|
num_prefix = ' ' # No number for items beyond 10th
|
||||||
|
if i == selected:
|
||||||
|
prefix = f'❯ {num_prefix}. '
|
||||||
|
else:
|
||||||
|
prefix = f' {num_prefix}. '
|
||||||
|
for wrapped in _wrap_panel_text(f"{prefix}{label}", inner_text_width, subsequent_indent=" "):
|
||||||
choice_wrapped.append((i, wrapped))
|
choice_wrapped.append((i, wrapped))
|
||||||
|
|
||||||
# Budget vertical space so HSplit never clips the command or choices.
|
# Budget vertical space so HSplit never clips the command or choices.
|
||||||
|
|
@ -9192,6 +9202,29 @@ class HermesCLI:
|
||||||
self._clarify_state["selected"] = min(max_idx, self._clarify_state["selected"] + 1)
|
self._clarify_state["selected"] = min(max_idx, self._clarify_state["selected"] + 1)
|
||||||
event.app.invalidate()
|
event.app.invalidate()
|
||||||
|
|
||||||
|
# Number keys for quick clarify selection (1-9, 0 for 10th item)
|
||||||
|
def _make_clarify_number_handler(idx):
|
||||||
|
def handler(event):
|
||||||
|
if self._clarify_state and not self._clarify_freetext:
|
||||||
|
choices = self._clarify_state.get("choices") or []
|
||||||
|
# Map index to choice (treating "Other" as the last option)
|
||||||
|
if idx < len(choices):
|
||||||
|
# Select a numbered choice
|
||||||
|
self._clarify_state["response_queue"].put(choices[idx])
|
||||||
|
self._clarify_state = None
|
||||||
|
self._clarify_freetext = False
|
||||||
|
event.app.invalidate()
|
||||||
|
elif idx == len(choices):
|
||||||
|
# Select "Other" option
|
||||||
|
self._clarify_freetext = True
|
||||||
|
event.app.invalidate()
|
||||||
|
return handler
|
||||||
|
|
||||||
|
for _num in range(10):
|
||||||
|
# 1-9 select items 0-8, 0 selects item 9 (10thitem)
|
||||||
|
_idx = 9 if _num == 0 else _num - 1
|
||||||
|
kb.add(str(_num), filter=Condition(lambda: bool(self._clarify_state) and not self._clarify_freetext))(_make_clarify_number_handler(_idx))
|
||||||
|
|
||||||
# --- Dangerous command approval: arrow-key navigation ---
|
# --- Dangerous command approval: arrow-key navigation ---
|
||||||
|
|
||||||
@kb.add('up', filter=Condition(lambda: bool(self._approval_state)))
|
@kb.add('up', filter=Condition(lambda: bool(self._approval_state)))
|
||||||
|
|
@ -9233,6 +9266,20 @@ class HermesCLI:
|
||||||
event.app.current_buffer.reset()
|
event.app.current_buffer.reset()
|
||||||
event.app.invalidate()
|
event.app.invalidate()
|
||||||
|
|
||||||
|
# Number keys for quick approval selection (1-9, 0 for 10th item)
|
||||||
|
def _make_approval_number_handler(idx):
|
||||||
|
def handler(event):
|
||||||
|
if self._approval_state and idx < len(self._approval_state["choices"]):
|
||||||
|
self._approval_state["selected"] = idx
|
||||||
|
self._handle_approval_selection()
|
||||||
|
event.app.invalidate()
|
||||||
|
return handler
|
||||||
|
|
||||||
|
for _num in range(10):
|
||||||
|
# 1-9 select items 0-8, 0 selects item 9 (10th item)
|
||||||
|
_idx = 9 if _num == 0 else _num - 1
|
||||||
|
kb.add(str(_num), filter=Condition(lambda: bool(self._approval_state)))(_make_approval_number_handler(_idx))
|
||||||
|
|
||||||
# --- History navigation: up/down browse history in normal input mode ---
|
# --- History navigation: up/down browse history in normal input mode ---
|
||||||
# The TextArea is multiline, so by default up/down only move the cursor.
|
# The TextArea is multiline, so by default up/down only move the cursor.
|
||||||
# Buffer.auto_up/auto_down handle both: cursor movement when multi-line,
|
# Buffer.auto_up/auto_down handle both: cursor movement when multi-line,
|
||||||
|
|
@ -9801,14 +9848,32 @@ class HermesCLI:
|
||||||
selected = state.get("selected", 0)
|
selected = state.get("selected", 0)
|
||||||
preview_lines = _wrap_panel_text(question, 60)
|
preview_lines = _wrap_panel_text(question, 60)
|
||||||
for i, choice in enumerate(choices):
|
for i, choice in enumerate(choices):
|
||||||
prefix = "❯ " if i == selected and not cli_ref._clarify_freetext else " "
|
# Show number prefix for quick selection (1-9 for items 1-9, 0 for 10th item)
|
||||||
preview_lines.extend(_wrap_panel_text(f"{prefix}{choice}", 60, subsequent_indent=" "))
|
if i < 9:
|
||||||
|
num_prefix = str(i + 1)
|
||||||
|
elif i == 9:
|
||||||
|
num_prefix = '0'
|
||||||
|
else:
|
||||||
|
num_prefix = ' '
|
||||||
|
if i == selected and not cli_ref._clarify_freetext:
|
||||||
|
prefix = f"❯ {num_prefix}. "
|
||||||
|
else:
|
||||||
|
prefix = f" {num_prefix}. "
|
||||||
|
preview_lines.extend(_wrap_panel_text(f"{prefix}{choice}", 60, subsequent_indent=" "))
|
||||||
|
# "Other" option in preview
|
||||||
|
other_num = len(choices) + 1
|
||||||
|
if other_num < 10:
|
||||||
|
other_num_prefix = str(other_num)
|
||||||
|
elif other_num == 10:
|
||||||
|
other_num_prefix = '0'
|
||||||
|
else:
|
||||||
|
other_num_prefix = ' '
|
||||||
other_label = (
|
other_label = (
|
||||||
"❯ Other (type below)" if cli_ref._clarify_freetext
|
f"❯ {other_num_prefix}. Other (type below)" if cli_ref._clarify_freetext
|
||||||
else "❯ Other (type your answer)" if selected == len(choices)
|
else f"❯ {other_num_prefix}. Other (type your answer)" if selected == len(choices)
|
||||||
else " Other (type your answer)"
|
else f" {other_num_prefix}. Other (type your answer)"
|
||||||
)
|
)
|
||||||
preview_lines.extend(_wrap_panel_text(other_label, 60, subsequent_indent=" "))
|
preview_lines.extend(_wrap_panel_text(other_label, 60, subsequent_indent=" "))
|
||||||
box_width = _panel_box_width("Hermes needs your input", preview_lines)
|
box_width = _panel_box_width("Hermes needs your input", preview_lines)
|
||||||
inner_text_width = max(8, box_width - 2)
|
inner_text_width = max(8, box_width - 2)
|
||||||
|
|
||||||
|
|
@ -9816,18 +9881,35 @@ class HermesCLI:
|
||||||
choice_wrapped: list[tuple[int, str]] = []
|
choice_wrapped: list[tuple[int, str]] = []
|
||||||
if choices:
|
if choices:
|
||||||
for i, choice in enumerate(choices):
|
for i, choice in enumerate(choices):
|
||||||
prefix = '❯ ' if i == selected and not cli_ref._clarify_freetext else ' '
|
# Show number prefix for quick selection (1-9 for items 1-9, 0 for 10th item)
|
||||||
for wrapped in _wrap_panel_text(f"{prefix}{choice}", inner_text_width, subsequent_indent=" "):
|
if i < 9:
|
||||||
|
num_prefix = str(i + 1)
|
||||||
|
elif i == 9:
|
||||||
|
num_prefix = '0'
|
||||||
|
else:
|
||||||
|
num_prefix = ' '
|
||||||
|
if i == selected and not cli_ref._clarify_freetext:
|
||||||
|
prefix = f'❯ {num_prefix}. '
|
||||||
|
else:
|
||||||
|
prefix = f' {num_prefix}. '
|
||||||
|
for wrapped in _wrap_panel_text(f"{prefix}{choice}", inner_text_width, subsequent_indent=" "):
|
||||||
choice_wrapped.append((i, wrapped))
|
choice_wrapped.append((i, wrapped))
|
||||||
# Trailing Other row(s)
|
# Trailing Other row(s)
|
||||||
other_idx = len(choices)
|
other_idx = len(choices)
|
||||||
if selected == other_idx and not cli_ref._clarify_freetext:
|
other_num = other_idx + 1
|
||||||
other_label_mand = '❯ Other (type your answer)'
|
if other_num < 10:
|
||||||
elif cli_ref._clarify_freetext:
|
other_num_prefix = str(other_num)
|
||||||
other_label_mand = '❯ Other (type below)'
|
elif other_num == 10:
|
||||||
|
other_num_prefix = '0'
|
||||||
else:
|
else:
|
||||||
other_label_mand = ' Other (type your answer)'
|
other_num_prefix = ' '
|
||||||
other_wrapped = _wrap_panel_text(other_label_mand, inner_text_width, subsequent_indent=" ")
|
if selected == other_idx and not cli_ref._clarify_freetext:
|
||||||
|
other_label_mand = f'❯ {other_num_prefix}. Other (type your answer)'
|
||||||
|
elif cli_ref._clarify_freetext:
|
||||||
|
other_label_mand = f'❯ {other_num_prefix}. Other (type below)'
|
||||||
|
else:
|
||||||
|
other_label_mand = f' {other_num_prefix}. Other (type your answer)'
|
||||||
|
other_wrapped = _wrap_panel_text(other_label_mand, inner_text_width, subsequent_indent=" ")
|
||||||
elif cli_ref._clarify_freetext:
|
elif cli_ref._clarify_freetext:
|
||||||
# Freetext-only mode: the guidance line takes the place of choices.
|
# Freetext-only mode: the guidance line takes the place of choices.
|
||||||
other_wrapped = _wrap_panel_text(
|
other_wrapped = _wrap_panel_text(
|
||||||
|
|
@ -9892,6 +9974,15 @@ class HermesCLI:
|
||||||
|
|
||||||
# "Other" option (trailing row(s), only shown when choices exist)
|
# "Other" option (trailing row(s), only shown when choices exist)
|
||||||
other_idx = len(choices)
|
other_idx = len(choices)
|
||||||
|
# Calculate number prefix for "Other" option
|
||||||
|
other_num = other_idx + 1
|
||||||
|
if other_num < 10:
|
||||||
|
other_num_prefix = str(other_num)
|
||||||
|
elif other_num == 10:
|
||||||
|
other_num_prefix = '0'
|
||||||
|
else:
|
||||||
|
other_num_prefix = ' '
|
||||||
|
|
||||||
if selected == other_idx and not cli_ref._clarify_freetext:
|
if selected == other_idx and not cli_ref._clarify_freetext:
|
||||||
other_style = 'class:clarify-selected'
|
other_style = 'class:clarify-selected'
|
||||||
elif cli_ref._clarify_freetext:
|
elif cli_ref._clarify_freetext:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue