Skip to content

Add provider-aware metadata digest#94

Merged
jbarnes850 merged 2 commits intomainfrom
feature/metadata-digest
Oct 30, 2025
Merged

Add provider-aware metadata digest#94
jbarnes850 merged 2 commits intomainfrom
feature/metadata-digest

Conversation

@jbarnes850
Copy link
Copy Markdown
Contributor

Summary

  • add an OpenAI adapter digest helper that projects execution metadata and enforces provider budgets
  • derive default character budgets from the provider context window (≈10% using 4 chars/token) while keeping overrides simple
  • expose digest stats + budget utilisation in the payload/logs and document the new config knobs

Testing

  • pytest tests/unit/connectors/test_prompt_digest.py tests/unit/test_openai_adapter.py

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a provider-aware prompt digest system to prevent oversized execution metadata from exceeding LLM context window limits. The digest compresses large metadata sections into summaries while preserving high-signal information.

  • Adds MetadataDigestConfig to configure budget limits and trimming behavior per provider
  • Implements build_prompt_digest() to intelligently trim metadata sections based on character budgets
  • Integrates digest logic into OpenAI adapter's message building pipeline

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
atlas/connectors/prompt_digest.py New module implementing metadata digest builder with provider-aware budgets and intelligent section trimming
atlas/config/models.py Adds MetadataDigestConfig class and integrates it into OpenAIAdapterConfig
atlas/connectors/openai.py Updates _build_messages to use digest system and handle errors
tests/unit/test_openai_adapter.py Adds test verifying adapter trims large metadata blobs
tests/unit/connectors/test_prompt_digest.py New test file with comprehensive digest functionality tests
docs/learning_eval.md Documents the prompt digest feature, configuration options, and playbook entry schema updates

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread atlas/config/models.py
class MetadataDigestConfig(BaseModel):
"""Controls how execution metadata is projected into LLM-facing prompts.

Defaults reserve roughly 10%% of the provider's published context window, assuming ~4 characters per token.
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

Double percent sign '%%' should be a single '%'.

Suggested change
Defaults reserve roughly 10%% of the provider's published context window, assuming ~4 characters per token.
Defaults reserve roughly 10% of the provider's published context window, assuming ~4 characters per token.

Copilot uses AI. Check for mistakes.
assert "session_learning_audit" in digest["digest_stats"]["omitted_metadata_keys"]
audit_summary = digest["session"]["session_reward_audit_summary"]
assert audit_summary["entries"] == 50
assert "payload" not in audit_summary["sample"][0]
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

This assertion checks if the string 'payload' is not in audit_summary['sample'][0], but based on line 16 where the metadata creates a list of strings ['payload'] * 200, the sample entries would be the string 'payload' itself, not a dict/mapping. The assertion should verify the sample was trimmed, but this logic appears incorrect for the data structure being tested.

Suggested change
assert "payload" not in audit_summary["sample"][0]
# The sample should be trimmed; check its length is less than the original (200)
assert len(audit_summary["sample"]) < 200

Copilot uses AI. Check for mistakes.
if provider in config.provider_char_budgets:
return config.provider_char_budgets[provider]
token_limit = PROVIDER_TOKEN_LIMITS.get(provider)
if token_limit:
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

[nitpick] The magic number calculation token_limit * 0.025 * 4 could be clearer. Consider extracting this formula to a named constant or adding an inline comment explaining the relationship (e.g., '2.5% of context window * 4 chars/token').

Suggested change
if token_limit:
if token_limit:
# Character budget: 2.5% of context window (token_limit) * average chars per token (4)

Copilot uses AI. Check for mistakes.
if value.isdigit():
return int(value), value
try:
return int(value.split("-", 1)[0]), value
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

The step key parsing assumes step IDs follow a 'number-suffix' format but doesn't handle the case where the split produces an empty string before the hyphen (e.g., '-123'). Consider validating that the first part is non-empty before calling int().

Suggested change
return int(value.split("-", 1)[0]), value
prefix = value.split("-", 1)[0]
if prefix == "":
return math.inf, value
return int(prefix), value

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +55
digest = build_prompt_digest(metadata, self._config.llm, self._config.metadata_digest)
except PromptDigestTooLargeError as exc:
raise AdapterError(str(exc)) from exc
messages.append({"role": "system", "content": digest})
try:
stats = json.loads(digest).get("digest_stats", {})
except json.JSONDecodeError:
stats = {}
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

The digest JSON is parsed twice: once in build_prompt_digest() during encoding (line 48), and again here (line 53) for logging. Consider having build_prompt_digest() return both the encoded string and stats dict to avoid redundant parsing.

Suggested change
digest = build_prompt_digest(metadata, self._config.llm, self._config.metadata_digest)
except PromptDigestTooLargeError as exc:
raise AdapterError(str(exc)) from exc
messages.append({"role": "system", "content": digest})
try:
stats = json.loads(digest).get("digest_stats", {})
except json.JSONDecodeError:
stats = {}
digest, stats = build_prompt_digest(metadata, self._config.llm, self._config.metadata_digest)
except PromptDigestTooLargeError as exc:
raise AdapterError(str(exc)) from exc
messages.append({"role": "system", "content": digest})

Copilot uses AI. Check for mistakes.
@jbarnes850 jbarnes850 self-assigned this Oct 29, 2025
@jbarnes850 jbarnes850 added the enhancement New feature or request label Oct 29, 2025
@jbarnes850 jbarnes850 force-pushed the feature/metadata-digest branch from 705c9b8 to 6c33ad7 Compare October 29, 2025 20:32
@jbarnes850 jbarnes850 linked an issue Oct 30, 2025 that may be closed by this pull request
@jbarnes850 jbarnes850 merged commit 48e99f9 into main Oct 30, 2025
1 check passed
@jbarnes850 jbarnes850 deleted the feature/metadata-digest branch October 30, 2025 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Development

Successfully merging this pull request may close these issues.

Trim execution metadata before adapter prompts

2 participants