Skip to content

Commit 86c9317

Browse files
authored
fix(kiro): handle Kiro CLI 2.0 Credits-before-separator layout (#188)
Kiro 2.0 renders Credits via ANSI cursor-up, placing it before the separator in raw tmux scrollback. Add forward scan from credits_idx+1 as fallback when pre-credits scan finds no separator. When separator is after credits_idx, extract content from prev_credits_idx+1 to credits_idx. 🤖 Assisted by AI
1 parent 23075f3 commit 86c9317

2 files changed

Lines changed: 46 additions & 3 deletions

File tree

src/cli_agent_orchestrator/providers/kiro_cli.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,11 +393,28 @@ def _extract_tui_message(self, clean_output: str) -> str:
393393
separator_idx = i
394394
break
395395

396+
# Kiro 2.0: separator is AFTER credits_idx. Scan forward to find it.
396397
if separator_idx is None:
397-
raise ValueError("No Kiro CLI response found - no separator before Credits marker")
398+
next_credits_idx = len(lines)
399+
for i in range(credits_idx + 1, len(lines)):
400+
if re.search(TUI_CREDITS_PATTERN, lines[i]):
401+
next_credits_idx = i
402+
break
403+
for i in range(credits_idx + 1, next_credits_idx):
404+
if re.search(TUI_SEPARATOR_PATTERN, lines[i].strip()):
405+
separator_idx = i
406+
break
407+
408+
if separator_idx is None:
409+
raise ValueError("No Kiro CLI response found - no separator found near Credits marker")
398410

399411
# Extract content between separator and Credits
400-
content_lines = lines[separator_idx + 1 : credits_idx]
412+
if separator_idx > credits_idx:
413+
# Kiro 2.0: separator after Credits. Content precedes credits_idx.
414+
content_lines = lines[prev_credits_idx + 1 : credits_idx]
415+
else:
416+
# Pre-2.0: separator before Credits (existing behavior)
417+
content_lines = lines[separator_idx + 1 : credits_idx]
401418

402419
# Skip the first paragraph (user message echo).
403420
# The user message is the first block of non-empty lines after the separator.

test/providers/test_kiro_cli_unit.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,9 +943,35 @@ def test_tui_extraction_no_separator(self, mock_tmux):
943943

944944
provider = KiroCliProvider("test1234", "test-session", "window-0", "developer")
945945

946-
with pytest.raises(ValueError, match="no separator before Credits"):
946+
with pytest.raises(ValueError, match="no separator found near Credits"):
947947
provider.extract_last_message_from_script(output)
948948

949+
@patch("cli_agent_orchestrator.providers.kiro_cli.tmux_client")
950+
def test_tui_extraction_kiro2_forward_scan(self, mock_tmux):
951+
"""Test extraction exercises the Kiro 2.0 forward scan path.
952+
953+
Layout: two Credits lines (prev turn + current turn), separator ONLY after
954+
the second Credits line. The forward scan from prev_credits_idx+1 to
955+
credits_idx finds no separator (separator_idx stays None), then the
956+
forward scan from credits_idx+1 finds the separator, triggering the
957+
separator_idx > credits_idx branch which extracts prev_credits_idx+1:credits_idx.
958+
"""
959+
output = (
960+
"▸ Credits: 0.10 • Time: 1s\n" # prev turn Credits (prev_credits_idx=0)
961+
" Content between turns\n" # content for current turn
962+
"\n"
963+
" Agent response here.\n"
964+
"\n"
965+
"▸ Credits: 0.24 • Time: 3s\n" # current turn Credits (credits_idx=5)
966+
"────────────────────────────────────────────────────\n" # separator AFTER credits
967+
"developer · auto · 3%\n"
968+
" Ask a question or describe a task ↵"
969+
)
970+
provider = KiroCliProvider("test1234", "test-session", "window-0", "developer")
971+
message = provider.extract_last_message_from_script(output)
972+
assert "Agent response here." in message
973+
assert "Content between turns" not in message
974+
949975
def test_tui_credits_pattern(self):
950976
"""Test TUI Credits pattern matches expected formats."""
951977
from cli_agent_orchestrator.providers.kiro_cli import TUI_CREDITS_PATTERN

0 commit comments

Comments
 (0)