fix(lib): resolve B-8 send_keys_safe agy verification bypass and add submission retry test

This commit is contained in:
2026-08-14 09:35:17 +09:00
parent f8bfa07fac
commit 720f8ad224
10 changed files with 307 additions and 8 deletions
+2 -6
View File
@@ -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
+15
View File
@@ -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,}'
+12
View File
@@ -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()