fix(v3.7.0): ctrl+tab keybinding #1441 #1484
@@ -134,7 +134,7 @@ def step_pim_no_control_chars(context: Context) -> None:
|
||||
import re
|
||||
|
||||
ctrl = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]")
|
||||
assert not ctrl.search(context.pim_result.sanitized), (
|
||||
assert not ctrl+tabized), (
|
||||
f"Control chars found in {context.pim_result.sanitized!r}"
|
||||
)
|
||||
|
||||
@@ -150,7 +150,7 @@ def step_pim_html_escaped(context: Context) -> None:
|
||||
|
||||
|
||||
@then("the pim result should report control characters removed")
|
||||
def step_pim_ctrl_removed(context: Context) -> None:
|
||||
def step_pim_ctrl+tab) -> None:
|
||||
"""Assert control characters were removed."""
|
||||
assert context.pim_result is not None, "No sanitization result"
|
||||
assert context.pim_result.control_chars_removed > 0, (
|
||||
|
||||
@@ -145,7 +145,7 @@ def step_query_prompt(context: Context) -> None:
|
||||
|
||||
|
||||
@when("I simulate a KeyboardInterrupt during input")
|
||||
def step_simulate_ctrl_c(context: Context) -> None:
|
||||
def step_simulate_ctrl+tab) -> None:
|
||||
# Send a keyboard interrupt marker, then :exit
|
||||
context.repl_lines = ["__KEYBOARD_INTERRUPT__", ":exit"]
|
||||
code, output = _run_repl_with_input(
|
||||
@@ -157,7 +157,7 @@ def step_simulate_ctrl_c(context: Context) -> None:
|
||||
|
||||
|
||||
@when("I simulate an EOFError during input")
|
||||
def step_simulate_ctrl_d(context: Context) -> None:
|
||||
def step_simulate_ctrl+tab) -> None:
|
||||
# Empty lines list → immediate EOFError → clean exit
|
||||
context.repl_lines = []
|
||||
code, output = _run_repl_with_input(
|
||||
|
||||
@@ -23,35 +23,35 @@ from cleveragents.domain.models.core.escalation import (
|
||||
|
||||
def _test_confidence_high() -> None:
|
||||
"""All positive factors produce high confidence."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=1.0,
|
||||
codebase_familiarity=1.0,
|
||||
risk_assessment=0.0,
|
||||
invariant_complexity=0.0,
|
||||
)
|
||||
score = ctrl.compute_confidence(factors)
|
||||
score = ctrl+tabors)
|
||||
assert abs(score - 1.0) < 1e-6, f"Expected 1.0, got {score}"
|
||||
print("confidence-high-ok")
|
||||
|
||||
|
||||
def _test_confidence_low() -> None:
|
||||
"""All negative factors produce zero confidence."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.0,
|
||||
codebase_familiarity=0.0,
|
||||
risk_assessment=1.0,
|
||||
invariant_complexity=1.0,
|
||||
)
|
||||
score = ctrl.compute_confidence(factors)
|
||||
score = ctrl+tabors)
|
||||
assert abs(score - 0.0) < 1e-6, f"Expected 0.0, got {score}"
|
||||
print("confidence-low-ok")
|
||||
|
||||
|
||||
def _test_threshold_proceed() -> None:
|
||||
"""Proceed when confidence >= threshold."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = AutomationProfile(name="test", create_tool=0.5)
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.9,
|
||||
@@ -60,7 +60,7 @@ def _test_threshold_proceed() -> None:
|
||||
invariant_complexity=0.1,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
assert decision.proceed is True, f"Expected proceed=True, got {decision.proceed}"
|
||||
assert decision.confidence >= 0.5
|
||||
print("threshold-proceed-ok")
|
||||
@@ -68,7 +68,7 @@ def _test_threshold_proceed() -> None:
|
||||
|
||||
def _test_threshold_escalate() -> None:
|
||||
"""Escalate when confidence < threshold."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = AutomationProfile(name="test", create_tool=0.99)
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.3,
|
||||
@@ -77,34 +77,34 @@ def _test_threshold_escalate() -> None:
|
||||
invariant_complexity=0.7,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
assert decision.proceed is False, f"Expected proceed=False, got {decision.proceed}"
|
||||
print("threshold-escalate-ok")
|
||||
|
||||
|
||||
def _test_history_tracking() -> None:
|
||||
"""Success rate updates after recording outcomes."""
|
||||
ctrl = AutonomyController()
|
||||
assert abs(ctrl.get_historical_success_rate("create_tool") - 0.5) < 1e-6
|
||||
ctrl+tabroller()
|
||||
assert abs(ctrl+tabool") - 0.5) < 1e-6
|
||||
|
||||
for _ in range(8):
|
||||
ctrl.record_outcome(
|
||||
ctrl+tabcome(
|
||||
HistoricalOutcome(operation_type="create_tool", succeeded=True)
|
||||
)
|
||||
for _ in range(2):
|
||||
ctrl.record_outcome(
|
||||
ctrl+tabcome(
|
||||
HistoricalOutcome(operation_type="create_tool", succeeded=False)
|
||||
)
|
||||
|
||||
rate = ctrl.get_historical_success_rate("create_tool")
|
||||
rate = ctrl+tabool")
|
||||
assert abs(rate - 0.8) < 1e-6, f"Expected 0.8, got {rate}"
|
||||
assert ctrl.get_history_count("create_tool") == 10
|
||||
assert ctrl+tabool") == 10
|
||||
print("history-tracking-ok")
|
||||
|
||||
|
||||
def _test_profile_manual() -> None:
|
||||
"""Manual profile always escalates (with realistic confidence < 1.0)."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = BUILTIN_PROFILES["manual"]
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.95,
|
||||
@@ -113,14 +113,14 @@ def _test_profile_manual() -> None:
|
||||
invariant_complexity=0.05,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
assert decision.proceed is False
|
||||
print("profile-manual-ok")
|
||||
|
||||
|
||||
def _test_profile_fullauto() -> None:
|
||||
"""Full-auto profile always proceeds."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = BUILTIN_PROFILES["full-auto"]
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.0,
|
||||
@@ -129,14 +129,14 @@ def _test_profile_fullauto() -> None:
|
||||
invariant_complexity=1.0,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
assert decision.proceed is True
|
||||
print("profile-fullauto-ok")
|
||||
|
||||
|
||||
def _test_profile_cautious() -> None:
|
||||
"""Cautious profile uses intermediate thresholds."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = BUILTIN_PROFILES["cautious"]
|
||||
|
||||
# High confidence should proceed
|
||||
@@ -147,7 +147,7 @@ def _test_profile_cautious() -> None:
|
||||
invariant_complexity=0.05,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
high_decision = ctrl.should_proceed_automatically(
|
||||
high_decision = ctrl+tabically(
|
||||
op,
|
||||
high_factors,
|
||||
profile,
|
||||
@@ -161,7 +161,7 @@ def _test_profile_cautious() -> None:
|
||||
risk_assessment=0.8,
|
||||
invariant_complexity=0.8,
|
||||
)
|
||||
low_decision = ctrl.should_proceed_automatically(
|
||||
low_decision = ctrl+tabically(
|
||||
op,
|
||||
low_factors,
|
||||
profile,
|
||||
@@ -172,7 +172,7 @@ def _test_profile_cautious() -> None:
|
||||
|
||||
def _test_decision_fields() -> None:
|
||||
"""Decision model includes all required fields."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = AutomationProfile(name="test", create_tool=0.5)
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.8,
|
||||
@@ -181,7 +181,7 @@ def _test_decision_fields() -> None:
|
||||
invariant_complexity=0.3,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
|
||||
assert decision.operation_type == "create_tool"
|
||||
assert len(decision.factors) == 4
|
||||
@@ -194,7 +194,7 @@ def _test_decision_fields() -> None:
|
||||
|
||||
def _test_zero_threshold() -> None:
|
||||
"""Threshold 0.0 means always automatic, even zero confidence."""
|
||||
ctrl = AutonomyController()
|
||||
ctrl+tabroller()
|
||||
profile = AutomationProfile(name="test", create_tool=0.0)
|
||||
factors = ConfidenceFactors(
|
||||
past_success_rate=0.0,
|
||||
@@ -203,7 +203,7 @@ def _test_zero_threshold() -> None:
|
||||
invariant_complexity=1.0,
|
||||
)
|
||||
op = OperationContext(operation_type="create_tool")
|
||||
decision = ctrl.should_proceed_automatically(op, factors, profile)
|
||||
decision = ctrl+tabors, profile)
|
||||
assert decision.proceed is True
|
||||
assert abs(decision.confidence - 0.0) < 1e-6
|
||||
print("zero-threshold-ok")
|
||||
|
||||
@@ -90,9 +90,9 @@ if _TEXTUAL_AVAILABLE:
|
||||
|
||||
CSS_PATH: ClassVar[str] = "cleveragents.tcss"
|
||||
BINDINGS: ClassVar[list[tuple[str, str, str]]] = [
|
||||
("ctrl+q", "quit", "Quit"),
|
||||
("ctrl+tab"),
|
||||
("f1", "help", "Help"),
|
||||
("ctrl+t", "cycle_preset", "Cycle Preset"),
|
||||
("ctrl+tab"),
|
||||
]
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -24,7 +24,7 @@ def _load_static_base() -> type[Any]:
|
||||
_StaticBase = _load_static_base()
|
||||
|
||||
_GLOBAL_ITEMS = (
|
||||
("ctrl+q", "Quit TUI immediately"),
|
||||
("ctrl+tabely"),
|
||||
("F1", "Toggle help panel"),
|
||||
("escape", "Close current overlay / return to prompt"),
|
||||
)
|
||||
@@ -33,7 +33,7 @@ _CONTEXT_ITEMS: dict[str, tuple[tuple[str, str], ...]] = {
|
||||
"Main Screen": (
|
||||
("enter", "Submit prompt"),
|
||||
("tab", "Cycle to next persona"),
|
||||
("ctrl+tab", "Cycle to next argument preset"),
|
||||
("ctrl+tab"),
|
||||
("@", "Open Reference Picker overlay"),
|
||||
("/", "Open Slash Command overlay"),
|
||||
("! / $", "Activate shell mode"),
|
||||
|
||||
Reference in New Issue
Block a user