Implemented the next parity slice: prompt-budget preflight and context collapse.
Core changes:
- Added claw-code/src/token_budget.py for projected prompt size, chat-framing overhead, output reserve, and soft/hard input limits.
- Wired preflight prompt-length validation and auto-compact/context collapse into claw-code/src/agent_runtime.py.
- Extended claw-code/src/compact.py so compaction reports usage back to the runtime.
- Added inspection surfaces in claw-code/src/agent_slash_commands.py and claw-code/src/main.py:
- /token-budget and /budget
- token-budget
- Hardened claw-code/src/tokenizer_runtime.py so arbitrary simple model names fall back cleanly instead of trying a slow Transformers
lookup.
- Exported the new helpers in claw-code/src/__init__.py.
Docs and tracking:
- Updated claw-code/PARITY_CHECKLIST.md to mark prompt-length validation, token-budget calculation, and auto-compact/context collapse as
done.
- Updated claw-code/README.md and claw-code/TESTING_GUIDE.md with the new commands and behavior.
Tests:
- Added claw-code/tests/test_token_budget.py.
- Updated claw-code/tests/test_agent_runtime.py, claw-code/tests/test_agent_slash_commands.py, claw-code/tests/test_main.py, and claw-code/
tests/test_agent_context_usage.py.
- Verified with:
- /data/fs201059/aa17626/miniconda3/bin/python3 -m compileall src tests
- /data/fs201059/aa17626/miniconda3/bin/python3 -m unittest -v tests.test_token_budget
tests.test_agent_runtime.AgentRuntimeTests.test_agent_rejects_prompt_before_backend_when_preflight_input_budget_is_exceeded
tests.test_agent_runtime.AgentRuntimeTests.test_agent_auto_compacts_context_before_next_model_call tests.test_agent_slash_commands
tests.test_main tests.test_compact tests.test_tokenizer_runtime tests.test_agent_context_usage
- Result: 71 tests, OK
This commit is contained in:
@@ -99,7 +99,7 @@ class AgentSlashCommandTests(unittest.TestCase):
|
||||
workspace = Path(tmp_dir)
|
||||
(workspace / 'CLAUDE.md').write_text('repo instructions\n', encoding='utf-8')
|
||||
agent = LocalCodingAgent(
|
||||
model_config=ModelConfig(model='Qwen/Qwen3-Coder-30B-A3B-Instruct'),
|
||||
model_config=ModelConfig(model='test-model'),
|
||||
runtime_config=AgentRuntimeConfig(cwd=workspace),
|
||||
)
|
||||
result = agent.run('/context')
|
||||
@@ -107,6 +107,18 @@ class AgentSlashCommandTests(unittest.TestCase):
|
||||
self.assertIn('### Estimated usage by category', result.final_output)
|
||||
self.assertIn('### Memory Files', result.final_output)
|
||||
|
||||
def test_token_budget_command_renders_local_report(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
workspace = Path(tmp_dir)
|
||||
agent = LocalCodingAgent(
|
||||
model_config=ModelConfig(model='test-model'),
|
||||
runtime_config=AgentRuntimeConfig(cwd=workspace),
|
||||
)
|
||||
result = agent.run('/token-budget')
|
||||
self.assertIn('# Token Budget', result.final_output)
|
||||
self.assertIn('Hard input limit', result.final_output)
|
||||
self.assertIn('Auto-compact buffer', result.final_output)
|
||||
|
||||
def test_mcp_and_resource_commands_render_local_reports(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
workspace = Path(tmp_dir)
|
||||
@@ -198,6 +210,34 @@ class AgentSlashCommandTests(unittest.TestCase):
|
||||
self.assertIn('# Search Provider', provider_result.final_output)
|
||||
self.assertIn('backup-search', provider_result.final_output)
|
||||
|
||||
def test_lsp_commands_render_local_reports(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
workspace = Path(tmp_dir)
|
||||
(workspace / 'sample.py').write_text(
|
||||
'def helper(value):\n'
|
||||
' """Double a value."""\n'
|
||||
' return value * 2\n'
|
||||
'\n'
|
||||
'def run(item):\n'
|
||||
' return helper(item)\n',
|
||||
encoding='utf-8',
|
||||
)
|
||||
agent = LocalCodingAgent(
|
||||
model_config=ModelConfig(model='Qwen/Qwen3-Coder-30B-A3B-Instruct'),
|
||||
runtime_config=AgentRuntimeConfig(cwd=workspace),
|
||||
)
|
||||
summary_result = agent.run('/lsp')
|
||||
symbols_result = agent.run('/lsp symbols sample.py')
|
||||
definition_result = agent.run('/lsp definition sample.py 6 12')
|
||||
diagnostics_result = agent.run('/lsp diagnostics sample.py')
|
||||
self.assertIn('# LSP', summary_result.final_output)
|
||||
self.assertIn('Indexed candidate files: 1', summary_result.final_output)
|
||||
self.assertIn('# LSP Document Symbols', symbols_result.final_output)
|
||||
self.assertIn('function helper', symbols_result.final_output)
|
||||
self.assertIn('# LSP Definition', definition_result.final_output)
|
||||
self.assertIn('function helper', definition_result.final_output)
|
||||
self.assertIn('# LSP Diagnostics', diagnostics_result.final_output)
|
||||
|
||||
def test_remote_commands_render_and_update_local_remote_runtime(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
workspace = Path(tmp_dir)
|
||||
@@ -387,7 +427,7 @@ class AgentSlashCommandTests(unittest.TestCase):
|
||||
def test_tools_and_status_commands_render_local_reports(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
agent = LocalCodingAgent(
|
||||
model_config=ModelConfig(model='Qwen/Qwen3-Coder-30B-A3B-Instruct'),
|
||||
model_config=ModelConfig(model='test-model'),
|
||||
runtime_config=AgentRuntimeConfig(cwd=Path(tmp_dir)),
|
||||
)
|
||||
tools_result = agent.run('/tools')
|
||||
|
||||
Reference in New Issue
Block a user