Skip to content

feat(core): enhance TaskContextPackager for external agents#432

Merged
frankbria merged 2 commits into
mainfrom
feature/issue-410-context-packager-enhancement
Mar 10, 2026
Merged

feat(core): enhance TaskContextPackager for external agents#432
frankbria merged 2 commits into
mainfrom
feature/issue-410-context-packager-enhancement

Conversation

@frankbria

@frankbria frankbria commented Mar 10, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #410: [Phase 4] Task Context Packager for External Agents

Enhances the existing TaskContextPackager (from PR #408) with the methods specified in issue #410:

  • build_agent_context() — Bridges TaskContext (internal Python objects) → AgentContext (protocol, all strings/primitives). This is the anti-corruption layer between CodeFrame internals and the adapter protocol.
  • to_file_list() — Extracts relevant file paths for engines that take explicit file lists (e.g., Aider)
  • to_task_file() — Writes prompt to a file for engines that read task files
  • Retry supportbuild() now accepts attempt/previous_errors params, producing a "Previous Attempt Errors" section

Acceptance Criteria

  • ContextPackager assembles AgentContext from all CodeFrame sources
  • to_prompt_string() produces clean, engine-agnostic prompt (exists as build().prompt, enhanced with retry)
  • to_file_list() extracts relevant file paths
  • to_task_file() writes context to temp file for file-based engines
  • Retry context includes previous errors and attempt number
  • Unit tests for context assembly and rendering (16 new tests)
  • ReactAgent refactored to use packager → Deferred to [Phase 4] Unify ReactAgent context assembly with TaskContextPackager #431 (separate concern, no user-facing value since external engine path already uses TaskContextPackager)
  • Integration test: same context as ReactAgent → Deferred with [Phase 4] Unify ReactAgent context assembly with TaskContextPackager #431

Test Plan

  • 26 tests passing (10 existing + 16 new) in test_context_packager.py
  • All 1614 core tests passing
  • Ruff linting clean

Implementation Notes

Closes #410

Summary by CodeRabbit

  • New Features

    • Retry-aware context handling: attempts and previous errors are surfaced in built prompts and agent context.
    • New agent-context assembly and improved context → file extraction and prompt-to-disk capabilities.
  • Tests

    • Expanded coverage for agent-context assembly, retry formatting/behavior, gate overrides, and file-output fidelity.

…d utility methods (#410)

Adds three new methods to the existing TaskContextPackager:
- build_agent_context(): bridges TaskContext → AgentContext for adapter protocol
- to_file_list(): extracts relevant file paths for file-based engines (Aider)
- to_task_file(): writes prompt to file for file-reading engines

Also adds retry support to build() with attempt/previous_errors params that
produce a "Previous Attempt Errors" section in the prompt.

Closes #410
@coderabbitai

coderabbitai Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds retry-aware agent-context packaging: TaskContextPackager now builds AgentContext (including retry/error details), exposes file-list and task-file exporters, and appends retry sections into rendered prompts.

Changes

Cohort / File(s) Summary
Context Packager Implementation
codeframe/core/context_packager.py
Added build_agent_context(), to_file_list(), to_task_file(), and _build_retry_section() methods. Extended build() signature to accept attempt and previous_errors and appended retry details into prompt rendering. Imports updated to include Path and AgentContext.
Tests for Packager
tests/core/test_context_packager.py
Added rich_task_context fixture, imported FileInfo and AgentContext, and new test cases covering AgentContext assembly, retry rendering (including multiline error collapse), gate overrides, to_file_list() extraction, and to_task_file() writing and content verification.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Packager as TaskContextPackager
    participant Loader as TaskContext (source)
    participant FS as Filesystem
    Caller->>Packager: build_agent_context(task_id, attempt, previous_errors, gate_names)
    Packager->>Loader: load task context & PRD, files, blockers, preferences
    Loader-->>Packager: TaskContext, FileInfo, loaded_files
    Packager->>Packager: _build_retry_section(attempt, previous_errors)
    Packager->>FS: to_task_file(packaged, path) (optional write)
    FS-->>Packager: Path written
    Packager-->>Caller: AgentContext (prd_content, files, gates, retry info)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through tasks and prompts today,

Packed PRDs and files in a neat array,
When errors returned and attempts grew tall,
I stitched a retry note to help fix them all,
Now agents bound off, ready to play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.93% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main enhancement: adding external agent support to TaskContextPackager through new methods.
Linked Issues check ✅ Passed All core coding objectives from #410 are met: build_agent_context, to_file_list, to_task_file implemented; retry support with attempt and previous_errors; unit tests (16 new) added; engine-agnostic prompt generation; no ReactAgent refactoring (deferred).
Out of Scope Changes check ✅ Passed All changes are directly scoped to TaskContextPackager enhancement: new methods on TaskContextPackager, imports (Path, AgentContext), build signature update, internal helper method, and comprehensive test additions—no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-410-context-packager-enhancement

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/core/test_context_packager.py (1)

3-10: ⚠️ Potential issue | 🟠 Major

Mark these new tests as v2.

This file adds coverage for the new packager surface, but none of the tests are marked with @pytest.mark.v2 and there is no module-level pytestmark. That makes the suite inconsistent with the repo's v2 test-selection rules.

💡 Proposed fix
 import pytest
 from pathlib import Path
 from unittest.mock import MagicMock, patch
 
 from codeframe.core.context_packager import TaskContextPackager, PackagedContext
 from codeframe.core.context import TaskContext, FileInfo
 from codeframe.core.adapters.agent_adapter import AgentContext
+
+pytestmark = pytest.mark.v2
As per coding guidelines, `tests/**/*.py`: `New v2 Python tests must be marked with `@pytest.mark.v2` decorator or pytestmark = pytest.mark.v2`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/test_context_packager.py` around lines 3 - 10, This test module
(the one importing TaskContextPackager, PackagedContext, TaskContext, FileInfo
and AgentContext) is missing the v2 marker required for new v2 tests; add either
a module-level marker (pytestmark = pytest.mark.v2) near the top of the file or
decorate each test function/class with `@pytest.mark.v2` so pytest selects these
as v2 tests (keep the existing import pytest at the top).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@codeframe/core/context_packager.py`:
- Around line 111-123: The returned AgentContext from build_agent_context is
missing the dependency_context field so downstream adapters lose dependency
guidance; update the return in build_agent_context to populate
dependency_context from the incoming context (e.g., context.dependency_context
or a safe default like {}) so AgentContext.dependency_context is set alongside
task_id, prd_content, relevant_files, etc., ensuring adapters consuming
AgentContext receive the dependency information.
- Around line 126-135: The docstring promises files "sorted by relevance score"
but to_file_list currently just returns packaged.context.relevant_files in
whatever order it has; update to_file_list to sort
packaged.context.relevant_files by each item's relevance_score (e.g.,
reverse=True to place highest relevance first) before mapping to fi.path, or if
you prefer to relax the contract instead, update the docstring to remove the
sorting claim; reference the to_file_list method,
PackagedContext.packaged.context.relevant_files entries (their relevance_score),
and fi.path when making the change and ensure the sort is stable and handles
missing/None relevance_score safely.
- Around line 59-60: The code currently uses "gate_names or ['pytest', 'ruff']"
which treats an explicit empty list as falsy and thus ignores caller intent; in
both build() and build_agent_context() replace that expression with an explicit
None check (e.g., if gate_names is None: gates = ['pytest','ruff'] else: gates =
gate_names) so that an empty list is honored, then pass gates into
self._build_gate_section; update the same pattern where gate_names is used
(refer to the build, build_agent_context, and _build_gate_section calls).

---

Outside diff comments:
In `@tests/core/test_context_packager.py`:
- Around line 3-10: This test module (the one importing TaskContextPackager,
PackagedContext, TaskContext, FileInfo and AgentContext) is missing the v2
marker required for new v2 tests; add either a module-level marker (pytestmark =
pytest.mark.v2) near the top of the file or decorate each test function/class
with `@pytest.mark.v2` so pytest selects these as v2 tests (keep the existing
import pytest at the top).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6aeac56-75ea-420a-a51a-d758805cc85e

📥 Commits

Reviewing files that changed from the base of the PR and between c37498f and 424c7dc.

📒 Files selected for processing (2)
  • codeframe/core/context_packager.py
  • tests/core/test_context_packager.py

Comment thread codeframe/core/context_packager.py Outdated
Comment on lines +111 to +123
return AgentContext(
task_id=task_id,
task_title=context.task.title,
task_description=context.task.description or "",
prd_content=prd_content,
tech_stack=context.tech_stack,
project_preferences=project_preferences,
relevant_files=relevant_files,
file_contents=file_contents,
blocker_history=blocker_history,
verification_gates=gates,
attempt=attempt,
previous_errors=previous_errors or [],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

build_agent_context() drops dependency context.

AgentContext exposes a dependency_context field, and the packager contract here is to bridge task context into that adapter shape, but the returned object never populates it. Any adapter that consumes AgentContext instead of the rendered prompt will silently lose dependency guidance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/context_packager.py` around lines 111 - 123, The returned
AgentContext from build_agent_context is missing the dependency_context field so
downstream adapters lose dependency guidance; update the return in
build_agent_context to populate dependency_context from the incoming context
(e.g., context.dependency_context or a safe default like {}) so
AgentContext.dependency_context is set alongside task_id, prd_content,
relevant_files, etc., ensuring adapters consuming AgentContext receive the
dependency information.

Comment thread codeframe/core/context_packager.py
@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Code Review - PR 432: Enhance TaskContextPackager for External Agents Good implementation of 410. The anti-corruption layer pattern is correct, the test class structure is clean, and the retry section is a useful addition. Five issues and some minor items follow in subsequent comments.

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Issue 1 - dependency_context field not populated (gap): AgentContext defines dependency_context: str | None = None at codeframe/core/adapters/agent_adapter.py:53, but build_agent_context() never populates it. If a task has dependency context loaded (e.g., from the dependency graph / DAG analysis), it will be silently dropped when crossing the boundary to an external adapter. Either: (a) Populate it from context if a source exists in TaskContext, or (b) add a comment/TODO acknowledging the gap now (e.g., TODO(431): dependency_context not yet wired).

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Issue 2 - Asymmetric retry behavior between build() and build_agent_context(): In build() (line 56), the retry section is silently skipped if attempt > 0 but previous_errors is empty/None. In build_agent_context(), attempt and previous_errors are passed straight through to AgentContext with no such guard - so build_agent_context(attempt=1) produces AgentContext(attempt=1, previous_errors=[]). These two paths behave differently for the same inputs. The behavior of build() (skip retry section when errors are empty) seems right, but it should be consistent or at least documented.

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Issue 3 - Multiline errors break markdown in _build_retry_section: The code does: for error in errors: lines.append(f'- {error}'). Real pytest/ruff errors are frequently multiline. If an error contains newlines, this produces broken markdown (a list item that spans lines without continuation indent). Consider stripping or collapsing to a single line for the prompt context.

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Issue 4 - Double context load when using both paths: Both build() and build_agent_context() independently call self._loader.load(task_id). For adapters needing both a prompt string and structured AgentContext, the context loads twice. Fine for the current separate-path design, but worth a note if both are ever needed for the same task.

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Issue 5 - Missing test for custom gate_names in build_agent_context(): There is a test verifying verification_gates defaults to [pytest, ruff], but no test for the gate_names override parameter. Easy to add: def test_custom_gate_names(self, mock_workspace, rich_task_context): with patch('codeframe.core.context_packager.ContextLoader') as MockLoader: MockLoader.return_value.load.return_value = rich_task_context; packager = TaskContextPackager(mock_workspace); ctx = packager.build_agent_context('task-99', gate_names=['build']); assert ctx.verification_gates == ['build']

@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Minor items: (1) test_defaults_for_optional_fields builds a full bare_ctx inline - a dedicated bare_task_context fixture would be more reusable. (2) to_file_list() docstring claims 'sorted by relevance score' but the order depends on what ContextLoader returns - worth verifying or softening the claim. Summary: The core design is solid - the build_agent_context() to AgentContext bridge is exactly the right pattern for the adapter layer, and the 16 new tests cover the happy paths well. Main actionable items: (1) Address the dependency_context gap, (2) Fix multiline error rendering in _build_retry_section, (3) Document or align the retry-section asymmetry between build() and build_agent_context(). Items 4 and 5 are optional improvements.

…ring

- Fix gate_names=[] being treated as falsy (use `is not None` check)
- Collapse multiline errors to single lines in retry section
- Fix to_file_list docstring to not claim explicit sorting
- Add tests for custom gate_names and multiline error collapsing
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
Repository owner deleted a comment from claude Bot Mar 10, 2026
@claude

claude Bot commented Mar 10, 2026

Copy link
Copy Markdown

Review: feat(core): enhance TaskContextPackager for external agents

This is a solid implementation of the context packaging layer for Phase 4 agent adapters. The anti-corruption layer design is sound, the gate_names None-check pattern is correct (avoiding the falsy-empty-list bug), and the retry section logic is clean. Good test coverage overall.

Three items to address before merging:


1. Missing pytestmark = pytest.mark.v2 (required by CLAUDE.md)

tests/core/test_context_packager.py has no module-level pytestmark and no per-class markers. CLAUDE.md explicitly states all tests in tests/core/ must participate in uv run pytest -m v2. CodeRabbit flagged this and it hasn't been addressed yet. One-line fix at the top of the test file:

pytestmark = pytest.mark.v2

2. dependency_context is silently omitted from build_agent_context()

AgentContext (line 53 of agent_adapter.py) defines dependency_context: str | None = None, but build_agent_context() never sets it. Since TaskContext currently has no dependency context field this can't be populated yet — but the gap should be documented with a TODO comment at the return site so it isn't forgotten when task dependency data becomes available (e.g., in the follow-up for issue 431).


3. Minor: test setup duplication

Ten of the eleven TestBuildAgentContext tests repeat identical boilerplate for patching ContextLoader. A shared @pytest.fixture would reduce this noticeably. Not a blocker, but worth addressing before more tests are added in issue 431.


Summary

Issue Severity
1 Missing pytestmark = pytest.mark.v2 Required (CLAUDE.md rule)
2 dependency_context not populated — no TODO Should document
3 Test setup duplication Suggestion

The gate_names handling is correct — both build() and build_agent_context() now use if gate_names is not None rather than a falsy-or pattern, which is the right approach and is validated by test_empty_gate_names_override. This directly addresses one of CodeRabbit's original flagged issues.

Item 1 is the only hard blocker.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/core/test_context_packager.py (1)

1-9: ⚠️ Potential issue | 🟠 Major

Missing @pytest.mark.v2 marker for v2 functionality tests.

This file tests new Phase 4 TaskContextPackager functionality but lacks the required v2 marker. As per coding guidelines, tests/**/*.py: "New v2 Python tests must be marked with @pytest.mark.v2 decorator or pytestmark = pytest.mark.v2".

🔧 Proposed fix: Add module-level pytestmark
 """Tests for TaskContextPackager."""
 
 import pytest
 from pathlib import Path
 from unittest.mock import MagicMock, patch
 
+pytestmark = pytest.mark.v2
+
 from codeframe.core.context_packager import TaskContextPackager, PackagedContext
 from codeframe.core.context import TaskContext, FileInfo
 from codeframe.core.adapters.agent_adapter import AgentContext
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/test_context_packager.py` around lines 1 - 9, Add the required v2
pytest marker at module scope so these tests for
TaskContextPackager/PackagedContext (which use TaskContext, FileInfo and
AgentContext) are marked as v2; add a module-level pytestmark = pytest.mark.v2
(or decorate the test functions with `@pytest.mark.v2`) at the top of the test
file to satisfy the new v2 test requirement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/core/test_context_packager.py`:
- Around line 363-371: Add the module-level pytest v2 marker by defining
pytestmark = pytest.mark.v2 at the top of the test module so the file is marked
as v2; ensure pytest is imported if not already. Locate the
tests/core/test_context_packager.py module (where
test_returns_relevant_file_paths, TaskContextPackager, and to_file_list are
defined) and add the single-line marker near the top of the file (after imports)
to match other test modules.

---

Outside diff comments:
In `@tests/core/test_context_packager.py`:
- Around line 1-9: Add the required v2 pytest marker at module scope so these
tests for TaskContextPackager/PackagedContext (which use TaskContext, FileInfo
and AgentContext) are marked as v2; add a module-level pytestmark =
pytest.mark.v2 (or decorate the test functions with `@pytest.mark.v2`) at the top
of the test file to satisfy the new v2 test requirement.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 401648cf-9b97-4727-9e48-f5ab92e4b0f5

📥 Commits

Reviewing files that changed from the base of the PR and between 424c7dc and b17e3e8.

📒 Files selected for processing (2)
  • codeframe/core/context_packager.py
  • tests/core/test_context_packager.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • codeframe/core/context_packager.py

Comment on lines +363 to +371
def test_returns_relevant_file_paths(self, mock_workspace, rich_task_context):
with patch("codeframe.core.context_packager.ContextLoader") as MockLoader:
MockLoader.return_value.load.return_value = rich_task_context

packager = TaskContextPackager(mock_workspace)
packaged = packager.build("task-99")
files = packager.to_file_list(packaged)

assert files == ["src/auth.py", "tests/test_auth.py"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify to_file_list implementation to check if ordering is preserved
ast-grep --pattern $'def to_file_list($_, $_):
    $$$
'

Repository: frankbria/codeframe

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Search for to_file_list method definition
rg "def to_file_list" -A 10 --type py

echo "---"

# Also search for rich_task_context fixture
rg "def rich_task_context" -A 5 --type py

echo "---"

# Check the relevant_files in context
rg "relevant_files" tests/core/test_context_packager.py -B 2 -A 2

Repository: frankbria/codeframe

Length of output: 2970


🏁 Script executed:

#!/bin/bash
# Check if the test has `@pytest.mark.v2` decorator or module-level pytestmark
sed -n '360,375p' tests/core/test_context_packager.py

echo "---"

# Check for pytestmark at module level
head -30 tests/core/test_context_packager.py | grep -n pytestmark

Repository: frankbria/codeframe

Length of output: 781


🏁 Script executed:

#!/bin/bash
# Check the full file structure and look for pytest markers
head -50 tests/core/test_context_packager.py

echo "---"

# Search for all pytest.mark decorators in the file
rg "@pytest\.mark" tests/core/test_context_packager.py

Repository: frankbria/codeframe

Length of output: 1746


🏁 Script executed:

#!/bin/bash
# Verify if there are any existing test classes/methods with `@pytest.mark.v2` in other test files
rg "@pytest\.mark\.v2|pytestmark.*v2" tests/ --type py | head -20

Repository: frankbria/codeframe

Length of output: 1439


Add v2 test marker per coding guidelines.

The test file is missing the required pytestmark = pytest.mark.v2 module-level marker. Add this to the top of tests/core/test_context_packager.py to comply with the v2 test marking requirements, consistent with other test files in the repository.

The ordering assertion in test_returns_relevant_file_paths is correct and not brittle—the list comprehension in to_file_list preserves insertion order of relevant_files, and the docstring correctly documents this as "relevance order."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/test_context_packager.py` around lines 363 - 371, Add the
module-level pytest v2 marker by defining pytestmark = pytest.mark.v2 at the top
of the test module so the file is marked as v2; ensure pytest is imported if not
already. Locate the tests/core/test_context_packager.py module (where
test_returns_relevant_file_paths, TaskContextPackager, and to_file_list are
defined) and add the single-line marker near the top of the file (after imports)
to match other test modules.

@frankbria frankbria merged commit 2054e3c into main Mar 10, 2026
13 checks passed
@frankbria frankbria deleted the feature/issue-410-context-packager-enhancement branch March 24, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 4] Task Context Packager for External Agents

1 participant