Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@ the GitHub Release body, so a release with no entry here fails.

Versioning follows [docs/versioning.md](docs/versioning.md).

## [0.5.0] - 2026-09-04

### Added

- `agent_core.components.cycle` — the product-neutral write → audit → feedback →
re-write loop, extracted from ApodexHarness. `WriteAuditCycle` owns max-rounds,
the wall-clock budget with between-round estimation, the missing-artifact
output check, writer-exception and missing-output capture as synthetic audits,
per-round persistence of the audit trail, and failure-isolated round-observer
dispatch. Ships the `AuditReport` / `WriterOutput` / `AuditFinding` /
`CycleOutput` contracts with JSON round-trip, `DefaultFeedbackRenderer`,
`SessionBackedWriter` / `SessionBackedAuditor`, `ScoreThresholdAuditor`,
`MajorityVoteAuditor`, `select_best_attempt`, `select_by_answer_consensus`, and
the `BestSoFarObserver` / `PlateauAbortObserver` / `MetricsObserver` built-ins.
- `agent_core.components.verifier` — the `Verifier` and `Generator` protocols,
the `Verdict` model with nesting, `GroundTruth` / `VerifierContext` with
automatic oracle-field stripping at runtime, the six composers (Pipeline,
Ensemble, Fallback, Cascade, Parallel, ConsensusVerifier), and the
`AuditReport` ↔ `Verdict` bridge so a `Verifier` can stand in for a
`CycleAuditor`.
- `agent_core.components.observers.conclude_phase_observer.ConcludePhaseObserver`
— nudges a session toward emitting its structured output once it crosses a
ratio of its turn budget, instead of exploring until `max_turns` kills it and
returning empty content. `cycle.builders` depends on it.

Scoring vocabularies stay free-form strings by design, and concrete writers and
auditors stay in the product. See
[docs/cycle-verifier-boundary.md](docs/cycle-verifier-boundary.md).

### Fixed

- `SessionBackedWriter._ensure_session` declared `-> str` while returning the
`str | None` attribute it caches into. Behavior is unchanged — the bus does
return an id — but the annotation no longer overstates what was proven.

### Consumer action

None required. This release only adds modules; nothing existing changed shape.
A product adopting these should replace its own copies with import aliases
rather than keeping both, since divergence is the failure this package exists to
prevent.

## [0.4.0] - 2026-09-03

### Added
Expand Down
102 changes: 102 additions & 0 deletions agent_core/components/cycle/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""WriteAuditCycle — iterate-until-pass artifact production.

Generic write → audit → feedback → re-write loop over arbitrary
caller-supplied :class:`Writer` and :class:`Auditor` implementations.
The cycle owns the loop mechanics (max-rounds, wall-clock budget,
output existence check, exception capture, per-round persistence,
observer hooks); callers own the role-specific prompts, tools, and
rendering.

Quick start::

from agent_core.components.cycle import (
WriteAuditCycle, SessionBackedWriter, SessionBackedAuditor,
DefaultFeedbackRenderer,
)

writer = SessionBackedWriter(
bus=bus, task_id=task_id,
role_id="paper_writer", name="paper_writer",
system_prompt=PAPER_WRITER_PROMPT,
initial_prompt="Write a 3-section research paper on X.",
tools=[file_editor, read_text, web_search],
max_turns=80, llm_timeout=300,
work_dir=work_dir,
output_check=lambda wd: missing_in(
wd, ["sections/intro.md", "sections/method.md"],
),
)
auditor = SessionBackedAuditor(
bus=bus, task_id=task_id,
role_id="paper_auditor",
system_prompt=PAPER_AUDITOR_PROMPT, # must define AuditReport JSON schema
# tools defaults to [] — Codex-style hard tool restriction.
tools=[read_text, grep], # whitelist read-only inspection
max_turns=40, llm_timeout=300,
conclude_ratio=0.8,
)
cycle = WriteAuditCycle(
writer=writer, auditor=auditor,
work_dir=work_dir,
output_check=writer.output_check,
max_rounds=10,
)
output: CycleOutput = await cycle.run()

See ``internal-docs/WRITE_AUDIT_CYCLE_REQUIREMENTS.md`` for the full spec
(FR1–FR11, NFR1–NFR7) and
``internal-docs/architecture/guide-write-audit-cycle.md`` for the user guide.
"""
from agent_core.components.cycle.builders import (
MajorityVoteAuditor,
ScoreThresholdAuditor,
SessionBackedAuditor,
SessionBackedWriter,
parse_score_response,
select_best_attempt,
select_by_answer_consensus,
)
from agent_core.components.cycle.default_renderer import DefaultFeedbackRenderer
from agent_core.components.cycle.observers import (
BaseRoundObserver,
CycleContext,
RoundIntervention,
RoundObserver,
)
from agent_core.components.cycle.observers_builtin import (
BestSoFarObserver,
MetricsObserver,
PlateauAbortObserver,
)
from agent_core.components.cycle.protocols import FeedbackRenderer
from agent_core.components.cycle.types import (
AuditFinding,
AuditReport,
CycleOutput,
WriterOutput,
)
from agent_core.components.cycle.write_audit_cycle import WriteAuditCycle

__all__ = [
"AuditFinding",
"AuditReport",
"BaseRoundObserver",
"BestSoFarObserver",
"CycleContext",
"CycleOutput",
"DefaultFeedbackRenderer",
"FeedbackRenderer",
"MajorityVoteAuditor",
"MetricsObserver",
"PlateauAbortObserver",
"RoundIntervention",
"RoundObserver",
"ScoreThresholdAuditor",
"SessionBackedAuditor",
"SessionBackedWriter",
"WriteAuditCycle",
"WriterOutput",
"parse_score_response",
"select_best_attempt",
"select_by_answer_consensus",
]
Loading