3f31cee395
persistent plan runtime with update_plan, plan_get, and plan_clear, plus plan-to-task sync wired through claw-code-agent/src/ agent_tools.py, claw-code-agent/src/agent_runtime.py, claw-code-agent/src/agent_context.py, claw-code-agent/src/agent_prompting.py, and claw-code-agent/src/ agent_slash_commands.py. New local plan slash commands are /plan and /planner.
110 lines
3.8 KiB
Python
110 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from src.background_runtime import BackgroundSessionRuntime
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
class BackgroundRuntimeTests(unittest.TestCase):
|
|
def test_runtime_can_launch_and_kill_generic_process(self) -> None:
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
workspace = Path(tmp_dir)
|
|
runtime = BackgroundSessionRuntime(workspace / '.port_sessions' / 'background')
|
|
record = runtime.launch(
|
|
[sys.executable, '-c', 'import time; time.sleep(10)'],
|
|
prompt='sleep',
|
|
workspace_cwd=workspace,
|
|
model='local/test-model',
|
|
process_cwd=workspace,
|
|
)
|
|
running = runtime.load_record(record.background_id)
|
|
killed = runtime.kill(record.background_id)
|
|
for _ in range(30):
|
|
if runtime.load_record(record.background_id).status != 'running':
|
|
break
|
|
time.sleep(0.1)
|
|
|
|
self.assertEqual(running.status, 'running')
|
|
self.assertEqual(killed.status, 'killed')
|
|
self.assertEqual(killed.stop_reason, 'killed')
|
|
|
|
def test_agent_background_cli_exposes_ps_logs_and_attach(self) -> None:
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
run_dir = Path(tmp_dir)
|
|
workspace = run_dir / 'workspace'
|
|
workspace.mkdir()
|
|
env = os.environ.copy()
|
|
existing_pythonpath = env.get('PYTHONPATH')
|
|
env['PYTHONPATH'] = (
|
|
f'{PROJECT_ROOT}:{existing_pythonpath}'
|
|
if existing_pythonpath
|
|
else str(PROJECT_ROOT)
|
|
)
|
|
launch = subprocess.run(
|
|
[
|
|
sys.executable,
|
|
'-m',
|
|
'src.main',
|
|
'agent-bg',
|
|
'/help',
|
|
'--cwd',
|
|
str(workspace),
|
|
],
|
|
cwd=run_dir,
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
background_id = next(
|
|
line.split('=', 1)[1]
|
|
for line in launch.stdout.splitlines()
|
|
if line.startswith('background_id=')
|
|
)
|
|
runtime = BackgroundSessionRuntime(run_dir / '.port_sessions' / 'background')
|
|
record = runtime.load_record(background_id)
|
|
for _ in range(60):
|
|
if record.status in {'completed', 'failed', 'exited'}:
|
|
break
|
|
time.sleep(0.1)
|
|
record = runtime.load_record(background_id)
|
|
ps = subprocess.run(
|
|
[sys.executable, '-m', 'src.main', 'agent-ps'],
|
|
cwd=run_dir,
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
logs = subprocess.run(
|
|
[sys.executable, '-m', 'src.main', 'agent-logs', background_id],
|
|
cwd=run_dir,
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
attach = subprocess.run(
|
|
[sys.executable, '-m', 'src.main', 'agent-attach', background_id],
|
|
cwd=run_dir,
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
self.assertIn(background_id, launch.stdout)
|
|
self.assertIn(background_id, ps.stdout)
|
|
self.assertIn('# Background Logs', logs.stdout)
|
|
self.assertIn('# Slash Commands', logs.stdout)
|
|
self.assertIn('# Background Attach', attach.stdout)
|