neues modell

This commit is contained in:
Christoph Schwörer
2026-09-01 08:12:07 +02:00
parent 611fd0a80c
commit 654339464e
109 changed files with 70505 additions and 27 deletions
@@ -160,6 +160,91 @@ class OpenCodeAdapterTests(unittest.TestCase):
self.assertEqual(1, len(result["written_files"]))
class ReadonlyShellTests(unittest.TestCase):
"""Denylist: alles erlaubt ausser schreibenden und bauenden Kommandos."""
def test_catch_all_allow_comes_first(self):
# OpenCode wertet der Reihe nach aus, die letzte passende Regel gewinnt.
# Stuende das Catch-all hinten, waere jede Sperre wirkungslos.
perms = ADAPTER.readonly_shell_permissions()
self.assertEqual("allow", perms["*"])
self.assertEqual("*", next(iter(perms)))
def test_writing_and_building_commands_are_denied(self):
perms = ADAPTER.readonly_shell_permissions()
for muster in ("rm *", "mv *", "sed -i*", "git commit*", "git push*",
"dotnet *", "msbuild *", "npm install*",
"Remove-Item *", "Set-Content *", "Out-File *"):
self.assertEqual("deny", perms[muster], muster)
def test_reading_commands_need_no_rule(self):
# Der Kern der Umstellung: Lesekommandos - auch als Pipeline - sind
# erlaubt, ohne einzeln aufgefuehrt zu sein. Genau daran scheiterte
# 'Get-ChildItem ... | Format-Table ...' unter der Allowlist.
perms = ADAPTER.readonly_shell_permissions()
for kommando in ("ls -la", "cat foo.cs", "rg muster",
"Get-ChildItem -Recurse | Format-Table Name",
"find . -name *.cs"):
self.assertNotIn(kommando, perms)
self.assertEqual("allow", perms["*"])
def test_no_reading_command_is_denied(self):
verboten_praefixe = ("ls", "cat", "rg", "grep", "find", "head", "tail",
"Get-ChildItem", "Get-Content", "Select-String",
"git status", "git log", "dir", "type")
for muster, aktion in ADAPTER.readonly_shell_permissions().items():
if aktion != "deny":
continue
for praefix in verboten_praefixe:
self.assertFalse(
muster.lower().startswith(praefix.lower()),
f"Lesekommando gesperrt: {muster}",
)
class UsageCapturedTests(unittest.TestCase):
"""Eine Null aus einem laufenden Subagenten ist kein Messwert."""
def _result(self, session, output):
return ADAPTER.normalize_result(
session=session, events=[], model_ref="lmstudio/google/gemma-4-e4b",
mode="builtin", effort="high", exit_code=1, timed_out=True,
interrupted=False, duration_s=3600.0, output_dir=output, errors=[],
provider="lmstudio", effort_applied=False,
)
def test_running_subagent_with_zero_tokens_is_not_captured(self):
session = {
"info": {"model": {"id": "google/gemma-4-e4b"},
"tokens": {"input": 0, "output": 0, "reasoning": 0,
"cache": {"read": 0, "write": 0}}},
"messages": [{
"info": {"role": "assistant"},
"parts": [{"type": "tool", "tool": "task",
"state": {"status": "running",
"input": {"subagent_type": "explore"}}}],
}],
}
with tempfile.TemporaryDirectory() as temp_dir:
result = self._result(session, Path(temp_dir))
self.assertFalse(result["usage_captured"])
self.assertIn("nicht erfasst", result["usage_note"])
self.assertIn("1 Subagent(en)", result["usage_note"])
def test_real_token_counts_are_marked_captured(self):
session = {
"info": {"model": {"id": "google/gemma-4-e4b"},
"tokens": {"input": 100, "output": 10, "reasoning": 0,
"cache": {"read": 0, "write": 0}}},
"messages": [{"info": {"role": "assistant"},
"parts": [{"type": "text", "text": "ok"}]}],
}
with tempfile.TemporaryDirectory() as temp_dir:
result = self._result(session, Path(temp_dir))
self.assertTrue(result["usage_captured"])
self.assertNotIn("usage_note", result)
class OpenCodeLmStudioTests(unittest.TestCase):
def test_model_reference_uses_lmstudio_provider(self):
self.assertEqual(