Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from types import MappingProxyType
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_cli.plugins import (
|
||||
MAX_SYSTEM_PROMPT_SECTIONS_TOTAL_CHARS,
|
||||
PluginContext,
|
||||
PluginManager,
|
||||
PluginManifest,
|
||||
)
|
||||
|
||||
|
||||
def _context(manager: PluginManager, name: str = "example-plugin") -> PluginContext:
|
||||
return PluginContext(
|
||||
PluginManifest(name=name, key=name, source="user"),
|
||||
manager,
|
||||
)
|
||||
|
||||
|
||||
def test_registration_validates_stable_id_position_budget_and_duplicates():
|
||||
manager = PluginManager()
|
||||
ctx = _context(manager)
|
||||
|
||||
for invalid_id in ("", "UPPER.case", "has space", "line\nbreak", "x" * 129):
|
||||
with pytest.raises(ValueError):
|
||||
ctx.register_system_prompt_section(invalid_id, "content")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
ctx.register_system_prompt_section("example.rules", "content", position="priority-17")
|
||||
with pytest.raises(ValueError):
|
||||
ctx.register_system_prompt_section("example.rules", "content", max_chars=0)
|
||||
|
||||
ctx.register_system_prompt_section("example.rules", "content")
|
||||
with pytest.raises(ValueError, match="already registered"):
|
||||
_context(manager, "other-plugin").register_system_prompt_section(
|
||||
"example.rules", "other content"
|
||||
)
|
||||
|
||||
|
||||
def test_render_is_deterministic_bounded_and_session_info_is_read_only(caplog):
|
||||
manager = PluginManager()
|
||||
ctx = _context(manager)
|
||||
observed = []
|
||||
|
||||
def render_b(info):
|
||||
observed.append(info)
|
||||
with pytest.raises(TypeError):
|
||||
info["session_id"] = "changed"
|
||||
return "B"
|
||||
|
||||
ctx.register_system_prompt_section("example.z", render_b, max_chars=4)
|
||||
ctx.register_system_prompt_section("example.a", "A", max_chars=4)
|
||||
ctx.register_system_prompt_section("example.too-large", "12345", max_chars=4)
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="hermes_cli.plugins"):
|
||||
rendered = manager.render_system_prompt_sections({"session_id": "session-1"})
|
||||
|
||||
assert [(item.id, item.content) for item in rendered] == [
|
||||
("example.a", "A"),
|
||||
("example.z", "B"),
|
||||
]
|
||||
assert isinstance(observed[0], MappingProxyType)
|
||||
assert observed[0]["session_id"] == "session-1"
|
||||
assert "exceeded max_chars" in caplog.text
|
||||
|
||||
|
||||
def test_render_fails_open_for_callback_failure_wrong_type_and_aggregate_budget(caplog):
|
||||
manager = PluginManager()
|
||||
ctx = _context(manager)
|
||||
|
||||
def boom(_info):
|
||||
raise RuntimeError("plugin exploded")
|
||||
|
||||
ctx.register_system_prompt_section("example.boom", boom)
|
||||
ctx.register_system_prompt_section("example.wrong", lambda _info: {"not": "text"})
|
||||
chunk = (MAX_SYSTEM_PROMPT_SECTIONS_TOTAL_CHARS // 2) - 200
|
||||
ctx.register_system_prompt_section("example.first", "a" * chunk, max_chars=chunk)
|
||||
ctx.register_system_prompt_section("example.second", "b" * chunk, max_chars=chunk)
|
||||
ctx.register_system_prompt_section("example.zzlast", "c" * 500, max_chars=500)
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="hermes_cli.plugins"):
|
||||
rendered = manager.render_system_prompt_sections({})
|
||||
|
||||
assert [item.id for item in rendered] == ["example.first", "example.second"]
|
||||
assert "plugin exploded" in caplog.text
|
||||
assert "returned dict, not str" in caplog.text
|
||||
assert "aggregate" in caplog.text
|
||||
Reference in New Issue
Block a user