Files
zk-data-agent/tests/test_new_slash_commands.py
Abdelrahman Abdallah aacf0a212a Created src/prompt_constants.py (550+ lines) porting all constants from npm src/constants/:
┌──────────────────┬───────────────────────────┬───────────────────────────────────────────────┐
│ Category         │ npm Source                │ Items                                         │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Product metadata │ product.ts                │ URLs, base URLs                               │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ System prefixes  │ system.ts                 │ 3 prompt prefixes                             │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Cyber risk       │ cyberRiskInstruction.ts   │ Safety instruction                            │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ API limits       │ apiLimits.ts              │ 10 image/PDF/media limits                     │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Tool limits      │ toolLimits.ts             │ 6 result size constants                       │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Spinner verbs    │ spinnerVerbs.ts           │ 187 whimsical gerunds                         │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Completion verbs │ turnCompletionVerbs.ts    │ 8 past-tense verbs                            │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Figures/symbols  │ figures.ts                │ 25 Unicode UI symbols                         │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ XML tags         │ xml.ts                    │ 30+ tag constants                             │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Messages         │ messages.ts               │ NO_CONTENT_MESSAGE                            │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Date utilities   │ common.ts                 │ 4 functions                                   │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Section caching  │ systemPromptSections.ts   │ Memoized/volatile sections                    │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Output styles    │ outputStyles.ts           │ 3 built-in configs                            │
├──────────────────┼───────────────────────────┼───────────────────────────────────────────────┤
│ Prompt helpers   │ prompts.ts                │ Knowledge cutoff, language, scratchpad, hooks │
└──────────────────┴───────────────────────────┴───────────────────────────────────────────────┘

91 new tests in tests/test_prompt_constants.py. All 17 SQL todos done.
2026-04-08 00:02:53 +02:00

300 lines
12 KiB
Python

"""Tests for /files, /copy, /export, /stats, /tag, /rename, /branch, /effort, /doctor."""
from __future__ import annotations
import json
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
from src.agent_runtime import LocalCodingAgent
from src.agent_session import AgentMessage, AgentSessionState
from src.agent_types import AgentRuntimeConfig, ModelConfig, UsageStats
def _make_agent(tmp_dir: str) -> LocalCodingAgent:
return LocalCodingAgent(
model_config=ModelConfig(model='test-model'),
runtime_config=AgentRuntimeConfig(cwd=Path(tmp_dir)),
)
def _set_session(agent: LocalCodingAgent, messages: list[AgentMessage]) -> None:
session = AgentSessionState(
system_prompt_parts=('You are a helper.',),
messages=messages,
)
agent.last_session = session
class TestFilesCommand(unittest.TestCase):
def test_no_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/files')
self.assertIn('No active session', result.final_output)
def test_no_files_in_context(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='Hi'),
])
result = agent.run('/files')
self.assertIn('No files loaded', result.final_output)
def test_files_from_tool_calls(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Read main.py'),
AgentMessage(
role='assistant', content='',
tool_calls=(
{'id': 'tc1', 'type': 'function', 'function': {
'name': 'Read',
'arguments': json.dumps({'file_path': '/home/user/project/main.py'}),
}},
),
),
AgentMessage(
role='tool', content='print("hello")',
name='Read',
tool_call_id='tc1',
metadata={'path': '/home/user/project/main.py'},
),
])
result = agent.run('/files')
self.assertIn('Files in context', result.final_output)
self.assertIn('main.py', result.final_output)
class TestCopyCommand(unittest.TestCase):
def test_no_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/copy')
self.assertIn('No active session', result.final_output)
def test_no_assistant_messages(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
])
result = agent.run('/copy')
self.assertIn('No assistant responses', result.final_output)
def test_copies_latest_response(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='First response.'),
AgentMessage(role='user', content='More'),
AgentMessage(role='assistant', content='Second response with details.'),
])
result = agent.run('/copy')
self.assertIn('Copied', result.final_output)
self.assertIn('response.md', result.final_output)
# Verify the file was written
tmp_file = Path(tempfile.gettempdir()) / 'claw-code' / 'response.md'
self.assertTrue(tmp_file.exists())
content = tmp_file.read_text()
self.assertEqual(content, 'Second response with details.')
def test_copies_nth_response(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='First.'),
AgentMessage(role='user', content='More'),
AgentMessage(role='assistant', content='Second.'),
])
result = agent.run('/copy 1')
tmp_file = Path(tempfile.gettempdir()) / 'claw-code' / 'response.md'
content = tmp_file.read_text()
self.assertEqual(content, 'First.')
class TestExportCommand(unittest.TestCase):
def test_no_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/export')
self.assertIn('No active session', result.final_output)
def test_exports_with_auto_filename(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='Hi there'),
])
result = agent.run('/export')
self.assertIn('Exported 2 messages', result.final_output)
self.assertIn('.txt', result.final_output)
def test_exports_with_custom_filename(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='Hi'),
])
result = agent.run('/export my_chat')
self.assertIn('my_chat.txt', result.final_output)
out_file = Path(tmp) / 'my_chat.txt'
self.assertTrue(out_file.exists())
content = out_file.read_text()
self.assertIn('Hello', content)
self.assertIn('Hi', content)
class TestStatsCommand(unittest.TestCase):
def test_shows_statistics(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='Hi'),
AgentMessage(role='user', content='Question'),
])
agent.cumulative_usage = UsageStats(input_tokens=500, output_tokens=200)
result = agent.run('/stats')
self.assertIn('Session Statistics', result.final_output)
self.assertIn('3 total', result.final_output)
self.assertIn('2 user', result.final_output)
self.assertIn('1 assistant', result.final_output)
self.assertIn('500', result.final_output)
self.assertIn('200', result.final_output)
class TestTagCommand(unittest.TestCase):
def test_no_tags_initially(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/tag')
self.assertIn('No tags set', result.final_output)
def test_add_tag(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/tag important')
self.assertIn('Added tag: important', result.final_output)
def test_toggle_tag(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
agent.run('/tag my-tag')
result = agent.run('/tag my-tag')
self.assertIn('Removed tag: my-tag', result.final_output)
def test_list_tags(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
agent.run('/tag alpha')
agent.run('/tag beta')
result = agent.run('/tag')
self.assertIn('alpha', result.final_output)
self.assertIn('beta', result.final_output)
class TestRenameCommand(unittest.TestCase):
def test_no_name(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/rename')
self.assertIn('Usage', result.final_output)
def test_rename_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/rename My Cool Session')
self.assertIn('renamed to: My Cool Session', result.final_output)
class TestBranchCommand(unittest.TestCase):
def test_no_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/branch')
self.assertIn('No active session', result.final_output)
def test_branch_with_session(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
AgentMessage(role='assistant', content='Hi'),
])
result = agent.run('/branch my-feature')
self.assertIn('Created branch "my-feature"', result.final_output)
self.assertIn('Saved to:', result.final_output)
def test_branch_auto_name(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
_set_session(agent, [
AgentMessage(role='user', content='Hello'),
])
result = agent.run('/branch')
self.assertIn('Created branch "branch-', result.final_output)
class TestEffortCommand(unittest.TestCase):
def test_show_current_effort(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/effort')
self.assertIn('Current effort level: auto', result.final_output)
def test_set_effort_level(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/effort high')
self.assertIn('Set effort level to: high', result.final_output)
def test_invalid_effort_level(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/effort extreme')
self.assertIn('Invalid effort level', result.final_output)
def test_all_valid_levels(self) -> None:
for level in ('low', 'medium', 'high', 'max', 'auto'):
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run(f'/effort {level}')
self.assertIn(f'Set effort level to: {level}', result.final_output)
class TestDoctorCommand(unittest.TestCase):
def test_shows_report(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
agent = _make_agent(tmp)
result = agent.run('/doctor')
output = result.final_output
self.assertIn('Doctor Report', output)
self.assertIn('Python version', output)
self.assertIn('git', output)
self.assertIn('Model', output)
self.assertIn('Working directory', output)
def test_detects_claude_md(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
(Path(tmp) / 'CLAUDE.md').write_text('memory file')
agent = _make_agent(tmp)
result = agent.run('/doctor')
self.assertIn('CLAUDE.md', result.final_output)
self.assertIn('found', result.final_output)
if __name__ == '__main__':
unittest.main()