fix(lib): resolve B-8 send_keys_safe agy verification bypass and add submission retry test
This commit is contained in:
@@ -1584,13 +1584,9 @@ send_keys_safe() {
|
||||
_sks_herdr set-buffer -b "$sks_buf" "$text"
|
||||
_sks_herdr paste-buffer -b "$sks_buf" -t "$sess"
|
||||
_sks_herdr delete-buffer -b "$sks_buf" 2>/dev/null || true
|
||||
if [[ "$sess" =~ "agy" ]]; then
|
||||
_sks_herdr send-keys -t "$sess" C-m
|
||||
return 0
|
||||
fi
|
||||
local was_popup=0
|
||||
if [[ "$sess" =~ "cline" ]] || [[ "$sess" =~ "claude" ]]; then
|
||||
# Skip strict paste check due to scrollout false-positives, proceed to C-m loop
|
||||
if [[ "$sess" =~ "cline" ]] || [[ "$sess" =~ "claude" ]] || [[ "$sess" =~ "agy" ]]; then
|
||||
# Skip strict paste check due to scrollout false-positives, proceed to C-m submission loop
|
||||
true
|
||||
else
|
||||
sleep 0.5
|
||||
|
||||
@@ -18,6 +18,9 @@ def main():
|
||||
# Emit shell-eval friendly facts
|
||||
print(f"AGENT_NAME={adapter.name}")
|
||||
print(f"OWN_KEY={adapter.own_key}")
|
||||
print(f"INPUT_PROMPT={adapter.input_prompt or ''}")
|
||||
print(f"INPUT_PLACEHOLDER={adapter.input_placeholder or ''}")
|
||||
print(f"INPUT_RULE_PATTERN={adapter.input_rule_pattern or ''}")
|
||||
|
||||
elif cmd == 'resolve':
|
||||
name = sys.argv[2] if len(sys.argv) > 2 else ''
|
||||
@@ -27,6 +30,18 @@ def main():
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
|
||||
elif cmd == 'input-region':
|
||||
agent_name = sys.argv[2] if len(sys.argv) > 2 else ''
|
||||
pane_text = sys.stdin.read()
|
||||
from lib_py.agents.input_region import extract_input_region
|
||||
try:
|
||||
region = extract_input_region(pane_text, agent_name)
|
||||
print(region)
|
||||
sys.exit(0)
|
||||
except Exception as ex:
|
||||
print(f"ERROR: {ex}", file=sys.stderr)
|
||||
sys.exit(5)
|
||||
|
||||
else:
|
||||
print(f"ERROR: Unknown CLI command {cmd!r}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -10,3 +10,15 @@ class AgyAgentAdapter(BaseAgentAdapter):
|
||||
@property
|
||||
def own_key(self) -> str:
|
||||
return 'agy_conversation_id_own'
|
||||
|
||||
@property
|
||||
def input_prompt(self) -> str:
|
||||
return '>'
|
||||
|
||||
@property
|
||||
def input_placeholder(self) -> str:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def input_rule_pattern(self) -> str:
|
||||
return '─{10,}'
|
||||
|
||||
@@ -10,3 +10,15 @@ class ClaudeAgentAdapter(BaseAgentAdapter):
|
||||
@property
|
||||
def own_key(self) -> str:
|
||||
return 'claude_session_id_own'
|
||||
|
||||
@property
|
||||
def input_prompt(self) -> str:
|
||||
return '❯'
|
||||
|
||||
@property
|
||||
def input_placeholder(self) -> str:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def input_rule_pattern(self) -> str:
|
||||
return '─{10,}'
|
||||
|
||||
@@ -10,3 +10,15 @@ class ClineAgentAdapter(BaseAgentAdapter):
|
||||
@property
|
||||
def own_key(self) -> str:
|
||||
return 'cline_conversation_id_own'
|
||||
|
||||
@property
|
||||
def input_prompt(self) -> str:
|
||||
return '❯'
|
||||
|
||||
@property
|
||||
def input_placeholder(self) -> str:
|
||||
return 'Ask anything...'
|
||||
|
||||
@property
|
||||
def input_rule_pattern(self) -> str:
|
||||
return '─{10,}'
|
||||
|
||||
@@ -27,6 +27,18 @@ class BaseAgentAdapter:
|
||||
def own_key(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def input_prompt(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
@property
|
||||
def input_placeholder(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
@property
|
||||
def input_rule_pattern(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def derive_session_name(self, slug: str, role: str = "creator") -> str:
|
||||
r = role.lower()
|
||||
return f"{slug}-{r}-{self.name}"
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# input_region.py — Rule-based input region extraction and normalization (T2 & T3)
|
||||
|
||||
import re
|
||||
from lib_py.agents.registry import get_adapter
|
||||
|
||||
def extract_input_region(pane_text: str, agent_name: str) -> str:
|
||||
"""
|
||||
Extracts the input area text between horizontal rule separators (─{10,}) for a given agent.
|
||||
If rules are absent, falls back to full pane_text to support mocks and unruled panes.
|
||||
Strips leading prompt tokens ('>', '❯') and placeholders ('Ask anything...').
|
||||
Raises ValueError for unsupported agents (like hermes with no input area facts).
|
||||
"""
|
||||
adapter = get_adapter(agent_name)
|
||||
if not adapter or not adapter.input_prompt:
|
||||
raise ValueError(f"Agent {agent_name!r} has no input area facts")
|
||||
|
||||
rule_pattern = adapter.input_rule_pattern or r'─{10,}'
|
||||
rule_re = re.compile(rule_pattern)
|
||||
lines = pane_text.splitlines()
|
||||
rule_indices = [i for i, line in enumerate(lines) if rule_re.search(line)]
|
||||
|
||||
if len(rule_indices) >= 2:
|
||||
# Exclude the rule lines themselves: lines between rule_indices[-2] + 1 and rule_indices[-1]
|
||||
region_lines = lines[rule_indices[-2] + 1:rule_indices[-1]]
|
||||
elif len(rule_indices) == 1:
|
||||
region_lines = lines[rule_indices[0] + 1:]
|
||||
else:
|
||||
region_lines = lines
|
||||
|
||||
region_text = "\n".join(region_lines)
|
||||
|
||||
prompt = adapter.input_prompt
|
||||
if prompt:
|
||||
region_text = re.sub(r'^\s*' + re.escape(prompt) + r'\s*', '', region_text, flags=re.MULTILINE)
|
||||
|
||||
placeholder = adapter.input_placeholder
|
||||
if placeholder:
|
||||
region_text = region_text.replace(placeholder, '')
|
||||
|
||||
return region_text.strip()
|
||||
Reference in New Issue
Block a user