160 lines
5.6 KiB
Python
160 lines
5.6 KiB
Python
# SPDX-FileCopyrightText: 2026 Art Sea LLC
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
"""Memory-backed semantic summary contracts for ``FileManager``."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from band_aider.context.class_meta import ClassMeta, ContentType
|
|
from band_aider.judgement.file_manager import FileManager
|
|
from band_aider.judgement.file_parser import FileParser
|
|
from band_aider.judgement.prompt_formatter import MarkdownPromptFormatterBuilder
|
|
from tests.support.completion_clients import (
|
|
ScriptedOpenAICompatibleClient,
|
|
StaticOpenAICompatibleClient,
|
|
)
|
|
from tests.support.memory_repo_exec import MemoryRepoExec
|
|
|
|
|
|
def _manager(client: ScriptedOpenAICompatibleClient) -> FileManager:
|
|
"""Build one real manager over source and test exhibits held only in memory."""
|
|
|
|
root = Path("/testbed/file-manager-summary")
|
|
repo_exec = MemoryRepoExec(root)
|
|
repo_exec.write_text(root / "src" / "service.py", "def service() -> str:\n return 'before'\n")
|
|
repo_exec.write_text(
|
|
root / "tests" / "test_service.py",
|
|
"from service import service\n\ndef test_service() -> None:\n assert service() == 'before'\n",
|
|
)
|
|
formatter = MarkdownPromptFormatterBuilder()
|
|
parser_client = StaticOpenAICompatibleClient(
|
|
json.dumps(
|
|
{
|
|
"location": "",
|
|
"summary": "memory fixture",
|
|
"relevance": ["fixture relevance"],
|
|
"irrelevance": [],
|
|
"relevant_symbols": {"service": "fixture symbol"},
|
|
}
|
|
)
|
|
)
|
|
return FileManager(
|
|
parser=FileParser(parser_client, formatter, repo_exec),
|
|
client=client,
|
|
repo_root=root,
|
|
src_root=root / "src",
|
|
test_root=root / "tests",
|
|
actor="test",
|
|
prompt_formatter_builder=formatter,
|
|
repo_exec=repo_exec,
|
|
prompt="FILE_MANAGER_TASK_SENTINEL",
|
|
)
|
|
|
|
|
|
def _source(manager: FileManager) -> ClassMeta:
|
|
"""Return the sole source exhibit after proving the fixture populated it."""
|
|
|
|
source = manager.current_src("src/service.py")
|
|
assert source is not None
|
|
return source
|
|
|
|
|
|
def _test(manager: FileManager) -> ClassMeta:
|
|
"""Return the sole test exhibit after proving the fixture populated it."""
|
|
|
|
test = manager.current_test("tests/test_service.py")
|
|
assert test is not None
|
|
return test
|
|
|
|
|
|
def test_file_manager_summarizes_dirty_memory_metadata_with_a_stationary_response() -> None:
|
|
"""Dirty metadata produces the LLM-backed completion summary without repository IO."""
|
|
|
|
client = ScriptedOpenAICompatibleClient(
|
|
(
|
|
json.dumps({"cdc": "SOURCE_CDC_SENTINEL"}),
|
|
json.dumps({"summary": "WORK_SUMMARY_SENTINEL"}),
|
|
)
|
|
)
|
|
manager = _manager(client)
|
|
source = _source(manager)
|
|
updated_source = ClassMeta(
|
|
location=source.location,
|
|
summary="updated source summary",
|
|
relevance=["updated relevance"],
|
|
relevant_symbols={"service": "updated symbol"},
|
|
content_type=ContentType.Source,
|
|
)
|
|
|
|
manager.upsert_src(updated_source, "SOURCE_UPDATE_PROMPT_SENTINEL")
|
|
summary = manager.summarize("SUMMARY_HINT_SENTINEL")
|
|
|
|
refreshed = _source(manager)
|
|
assert summary == "WORK_SUMMARY_SENTINEL"
|
|
assert refreshed.summary == "updated source summary"
|
|
assert refreshed.cdc[-1][2] == "SOURCE_CDC_SENTINEL"
|
|
assert manager.src_net_effects() == {"src/service.py": "changed"}
|
|
assert manager.test_net_effects() == {"tests/test_service.py": "unchanged"}
|
|
assert "WORK SUMMARY" in client.prompts[-1]
|
|
assert "SOURCE_UPDATE_PROMPT_SENTINEL" not in client.prompts[-1]
|
|
|
|
|
|
def test_file_manager_squashes_dirty_memory_metadata_to_its_upstream_owner() -> None:
|
|
"""A scoped manager transfers only explicitly dirty metadata to its upstream owner."""
|
|
|
|
client = ScriptedOpenAICompatibleClient(
|
|
(
|
|
json.dumps({"cdc": "SCOPED_SOURCE_CDC_SENTINEL"}),
|
|
json.dumps(
|
|
{
|
|
"summary": "SCOPED_SHARED_SUMMARY_SENTINEL",
|
|
"files": {
|
|
"src/service.py": "SCOPED_SOURCE_SUMMARY_SENTINEL",
|
|
"tests/test_service.py": "SCOPED_TEST_SUMMARY_SENTINEL",
|
|
},
|
|
}
|
|
),
|
|
)
|
|
)
|
|
upstream = _manager(client)
|
|
scoped = FileManager.from_manager(upstream)
|
|
source = _source(scoped)
|
|
test = _test(scoped)
|
|
|
|
scoped.upsert_src(
|
|
ClassMeta(
|
|
location=source.location,
|
|
summary="scoped source summary",
|
|
relevance=["scoped source relevance"],
|
|
relevant_symbols={"service": "scoped symbol"},
|
|
content_type=ContentType.Source,
|
|
),
|
|
"SCOPED_SOURCE_UPDATE_SENTINEL",
|
|
)
|
|
scoped.upsert_test(
|
|
ClassMeta(
|
|
location=test.location,
|
|
summary="scoped test summary",
|
|
relevance=["ignored test relevance"],
|
|
relevant_symbols={"test_service": "ignored test symbol"},
|
|
content_type=ContentType.Test,
|
|
),
|
|
"SCOPED_TEST_UPDATE_SENTINEL",
|
|
)
|
|
|
|
scoped.squash_to_upstream("SCOPED_HINT_SENTINEL")
|
|
|
|
upstream_source = _source(upstream)
|
|
upstream_test = _test(upstream)
|
|
assert upstream_source.summary == "scoped source summary"
|
|
assert upstream_test.summary == "scoped test summary"
|
|
assert upstream_source.cdc[-1][2] == "SCOPED_SOURCE_SUMMARY_SENTINEL"
|
|
assert upstream_test.cdc[-1][2] == "SCOPED_TEST_SUMMARY_SENTINEL"
|
|
assert upstream.src_dirty == {"src/service.py": True}
|
|
assert upstream.test_dirty == {"tests/test_service.py": True}
|
|
assert "SCOPED CDC SUMMARY" in client.prompts[-1]
|
|
assert "SCOPED_HINT_SENTINEL" in client.prompts[-1]
|