106 lines
4.3 KiB
Python
106 lines
4.3 KiB
Python
# SPDX-FileCopyrightText: 2026 Art Sea LLC
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import dataclass
|
|
|
|
from band_aider.ai_client.json_completion import load_json_completion
|
|
from band_aider.ai_client.openai_compatible_client import OpenAICompatibleClient
|
|
from band_aider.context.class_meta import ClassMeta
|
|
from band_aider.judgement.vibe_check import VibeCheck
|
|
from band_aider.judgement.prompt_formatter import PromptFormatterBuilder, format_prompt
|
|
|
|
|
|
@dataclass
|
|
class CurrentCotCompletedCheck(VibeCheck):
|
|
"""Decide whether one permanently bound COT task is satisfied by stabilized root evidence."""
|
|
|
|
client: OpenAICompatibleClient
|
|
prompt_formatter_builder: PromptFormatterBuilder
|
|
reason: str = ""
|
|
|
|
def __call__(self, task: str, files: list[ClassMeta]) -> bool:
|
|
"""Return True only when stabilized evidence completes the bound COT task."""
|
|
|
|
data = load_json_completion(
|
|
self.client,
|
|
self._prompt(task, files),
|
|
prompt_formatter_builder=self.prompt_formatter_builder,
|
|
check_name=type(self).__name__,
|
|
files=tuple(map(lambda file: file.location, files)),
|
|
references=[{'completed': True, 'reason': ''}],
|
|
)
|
|
completed = bool(data.get("completed"))
|
|
self.reason = str(data.get("reason") or "")
|
|
self.changes.append((self, completed))
|
|
return completed
|
|
|
|
def _file_picture(self, candidate: ClassMeta) -> dict[str, object]:
|
|
"""Return CDC-backed evidence for the production root bound to one COT."""
|
|
|
|
return {
|
|
"location": candidate.location,
|
|
"summary": candidate.summary,
|
|
"relevance": candidate.relevance,
|
|
"relevant_symbols": candidate.relevant_symbols,
|
|
"cdc": [
|
|
{
|
|
"changed_at": changed_at.isoformat(),
|
|
"actor": actor,
|
|
"description": description,
|
|
}
|
|
for changed_at, actor, description in candidate.cdc
|
|
],
|
|
}
|
|
|
|
def _prompt(self, task: str, files: list[ClassMeta]) -> str:
|
|
"""Build the completion prompt for one COT and its permanently bound root."""
|
|
|
|
expected = {
|
|
"completed": True,
|
|
"reason": "one sentence explaining the yes or no decision",
|
|
}
|
|
|
|
body = (
|
|
"Decide whether the current stabilization goal is satisfied by the current COT task.\n"
|
|
"The original stabilization goal is the immutable contract; the current task and file metadata are subordinate evidence.\n"
|
|
"Use only the current COT task and the stabilized file metadata below. "
|
|
"The CDC history is the primary evidence of work already completed.\n\n"
|
|
"The stabilized file evidence below belongs to the production root permanently bound to this COT task.\n"
|
|
"Return completed true only when the stabilized evidence shows that this bound COT task is satisfied.\n"
|
|
"Return completed false when the stabilized evidence does not demonstrate completion of this bound COT task.\n\n"
|
|
"Return strict JSON only with this shape:\n"
|
|
f"{json.dumps(expected, indent=2)}\n\n"
|
|
"ORIGINAL COT: IMMUTABLE STABILIZATION TARGET\n"
|
|
f"{format_prompt(self.prompt_formatter_builder, 'ORIGINAL STABILIZATION GOAL', self.prompt, depth=2)}\n\n"
|
|
f"Current COT task:\n{task}\n\n"
|
|
"Stabilized file evidence:\n"
|
|
f"{json.dumps([self._file_picture(file) for file in files], indent=2)}"
|
|
)
|
|
return format_prompt(
|
|
self.prompt_formatter_builder,
|
|
"CURRENT COT COMPLETION",
|
|
body,
|
|
escape=False,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class CurrentCotCompletedCheckFactory:
|
|
"""Create completion checks for permanently bound COT task/root records."""
|
|
|
|
client: OpenAICompatibleClient
|
|
prompt_formatter_builder: PromptFormatterBuilder
|
|
|
|
def create(self, original_prompt: str) -> CurrentCotCompletedCheck:
|
|
"""Create a completion judgement for one bound COT task after stabilization."""
|
|
|
|
return CurrentCotCompletedCheck(
|
|
changes=[],
|
|
prompt=original_prompt,
|
|
client=self.client,
|
|
prompt_formatter_builder=self.prompt_formatter_builder,
|
|
)
|