Skip to content

feat: implement context-window pruning middleware for semantic workspaces - #295

Open
muntasir-396 wants to merge 3 commits into
AOSSIE-Org:mainfrom
muntasir-396:feature/context-window-pruning
Open

feat: implement context-window pruning middleware for semantic workspaces#295
muntasir-396 wants to merge 3 commits into
AOSSIE-Org:mainfrom
muntasir-396:feature/context-window-pruning

Conversation

@muntasir-396

@muntasir-396 muntasir-396 commented Jul 16, 2026

Copy link
Copy Markdown

Closes #278

Description

This PR introduces a context-window pruning middleware to optimize meeting context before sending it to Gemini.

Changes

  • Added ContextPruningService
  • Added query-aware relevance scoring using:
    • Existing vector-search similarity score
    • Keyword-overlap fallback
  • Ranked retrieved meeting contexts by relevance
  • Added configurable token budget enforcement
  • Implemented sliding-window pruning
  • Added context truncation for oversized summaries
  • Added debug metrics:
    • Original tokens
    • Final tokens
    • Reduction percentage
    • Chunks removed
    • Processing latency
  • Integrated the middleware into AIService before prompt construction

Benefits

  • Reduces oversized LLM prompts
  • Improves token efficiency
  • Preserves the most relevant meeting context
  • Provides better observability through pruning metrics

Summary by CodeRabbit

  • New Features
    • Enhanced meeting-related answers by selecting and prioritizing the most relevant meeting summaries.
    • Added automatic context trimming to keep responses within safe length limits while retaining important details.
  • Bug Fixes
    • Improved resilience by handling failures during meeting-context preparation more gracefully.
  • Tests
    • Added unit tests covering meeting summary formatting and edge cases (including missing, empty, and malformed inputs).

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change adds ContextPruningService to rank and fit meeting summaries within a 1,500-token budget, optionally truncating partial summaries. AIService applies it to meeting-related queries, while new tests cover MeetingFormatter behavior.

Changes

Meeting Context Pruning

Layer / File(s) Summary
Context scoring and token pruning
lib/services/context_pruning_service.dart
Adds token estimation, relevance scoring, sorting, budget pruning, partial summary truncation, metrics logging, and cleanup of internal fields.
Meeting-query context integration
lib/services/ai_service.dart
Routes meeting summaries through the pruning service before formatting non-empty results into meetingContext, with failures handled by the existing error path.
Meeting formatter validation
test/services/meeting_formatter_test.dart
Adds coverage for summary formatting, fallbacks, empty and malformed inputs, multiple meetings, date formatting, and invalid dates.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UserMessage
  participant AIService
  participant ContextPruningService
  participant LLM
  UserMessage->>AIService: meeting-related query
  AIService->>ContextPruningService: prune summaries with maxTokens 1500
  ContextPruningService-->>AIService: optimized summaries
  AIService->>LLM: send formatted meetingContext
Loading

Possibly related issues

Possibly related PRs

Suggested labels: Dart/Flutter

Poem

I’m a bunny with summaries snug,
Pruned to fit each context hug.
High-score notes hop to the front,
Long ones lose their extra chunk.
AI gets a tidy trail—
And I twitch my whiskered tail!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The new MeetingFormatter test file is unrelated to the pruning middleware and appears outside issue #278's scope. Remove or justify the MeetingFormatter tests, or move them to a separate PR focused on formatter behavior.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: adding context-window pruning middleware for semantic workspaces.
Linked Issues check ✅ Passed The pruning service adds query-aware scoring, token-limit enforcement, truncation, and logging, matching issue #278's requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/services/ai_service.dart`:
- Around line 75-90: Move the meeting retrieval, ContextPruningService.prune
call, and MeetingFormatter.formatMeetingSummaries invocation from the pre-try
section into the existing try block in generateChatResponse. Ensure exceptions
from retrieval, pruning, formatting, or runtime casts are caught by the existing
error handler and produce the standard error result, while preserving the
current meetingContext behavior on successful non-empty results.

In `@lib/services/context_pruning_service.dart`:
- Around line 12-19: Update _calculateKeywordOverlap to normalize each query and
text word by removing punctuation and excluding empty tokens before constructing
queryWords and textWords. Preserve the existing intersection-based overlap
calculation and empty-set handling after normalization.
- Around line 87-94: Update the removed-chunk accounting in the context-pruning
loop so each skipped chunk is counted exactly once: either retain the per-chunk
increment in the loop and remove the aggregate addition after it, or eliminate
the increment and rely on the aggregate calculation. Keep chunksRemoved equal to
the actual number of removed chunks.
- Around line 5-8: Update ContextPruningService.prune() to budget the fully
rendered meeting context rather than raw summary text: include AIService’s
prepended content and MeetingFormatter.formatMeetingSummaries() additions such
as titles, dates, separators, and truncation markers when evaluating each
candidate. Recompute token estimates from the final rendered string, or reserve
equivalent overhead before accepting the last chunk, while preserving the
maxTokens limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 419c651f-716e-4f22-9bdb-e87bd4ec22c0

📥 Commits

Reviewing files that changed from the base of the PR and between 36cb2b8 and e3fa07f.

📒 Files selected for processing (2)
  • lib/services/ai_service.dart
  • lib/services/context_pruning_service.dart

Comment thread lib/services/ai_service.dart Outdated
Comment thread lib/services/context_pruning_service.dart
Comment thread lib/services/context_pruning_service.dart
Comment thread lib/services/context_pruning_service.dart Outdated

@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 (2)
lib/services/context_pruning_service.dart (2)

66-106: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the same scope for original and final token metrics.

originalTokens excludes the reserved header, while currentTokens always includes it—even when no meeting context is returned. A no-pruning run can report a negative reduction. Compute both values from equivalent rendered contexts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/services/context_pruning_service.dart` around lines 66 - 106, Update the
token accounting around the pruning method’s originalTokens and currentTokens
metrics to use equivalent rendered contexts, including the reserved “Relevant
meeting information” header only when that context is returned. Ensure
no-pruning results cannot report a negative reduction, while preserving the
existing chunk selection and truncation behavior.

72-94: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Budget the fully combined candidate after every mutation.

Each chunk is measured as formatMeetingSummaries([chunk]), but the final formatter adds inter-chunk separators. The partial path also adds formatter metadata and the truncation marker without remeasuring, while Line 93 assumes it exactly fills the remaining budget. The rendered meeting context can still exceed maxTokens.

Build and measure header + formatMeetingSummaries(candidateChunks) before accepting a chunk; shrink partial text until that rendered candidate fits.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/services/context_pruning_service.dart` around lines 72 - 94, The chunk
selection logic in the pruning method must budget the fully rendered candidate,
not individual chunks. Before accepting or mutating a chunk, build the candidate
combined context using the formatter header and
formatMeetingSummaries(candidateChunks), measure its rendered token count, and
only accept it when it fits maxTokens; for partial chunks, iteratively shrink
the summary text (including metadata and truncation marker) until the complete
rendered candidate fits, rather than assuming remainingTokens can be added
directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/services/meeting_formatter_test.dart`:
- Around line 124-136: Update MeetingFormatter.formatMeetingSummary to validate
action_items entries before treating them as maps, skipping null or otherwise
malformed items while continuing to format valid entries. Replace the test’s
throwsA expectation with an assertion for the formatter’s safe fallback output,
while preserving normal behavior for valid action items.

---

Outside diff comments:
In `@lib/services/context_pruning_service.dart`:
- Around line 66-106: Update the token accounting around the pruning method’s
originalTokens and currentTokens metrics to use equivalent rendered contexts,
including the reserved “Relevant meeting information” header only when that
context is returned. Ensure no-pruning results cannot report a negative
reduction, while preserving the existing chunk selection and truncation
behavior.
- Around line 72-94: The chunk selection logic in the pruning method must budget
the fully rendered candidate, not individual chunks. Before accepting or
mutating a chunk, build the candidate combined context using the formatter
header and formatMeetingSummaries(candidateChunks), measure its rendered token
count, and only accept it when it fits maxTokens; for partial chunks,
iteratively shrink the summary text (including metadata and truncation marker)
until the complete rendered candidate fits, rather than assuming remainingTokens
can be added directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6534048a-0192-4d45-8295-082367e16f5c

📥 Commits

Reviewing files that changed from the base of the PR and between e3fa07f and a8feb91.

📒 Files selected for processing (3)
  • lib/services/ai_service.dart
  • lib/services/context_pruning_service.dart
  • test/services/meeting_formatter_test.dart

Comment on lines +124 to +136
test('throws Error when action items list contains null (Malformed input)', () {
final Map<String, dynamic> summary = <String, dynamic>{
'action_items': <dynamic>[null],
};

expect(
() => MeetingFormatter.formatMeetingSummary(
title: 'Malformed Sync',
date: '2026-07-25 at 10:00',
summary: summary,
),
throwsA(isA<Error>()), // Catches NoSuchMethodError or TypeError depending on Dart version
);

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not codify a crash for malformed action items.

This accepts a runtime failure when externally supplied summary data contains a null/non-map item. MeetingFormatter indexes every item as a map, so one malformed entry aborts formatting the entire meeting context. Validate or skip invalid entries in the formatter, then assert a safe fallback here instead.

As per path instructions, **/*.dart requires proper input validation and error handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/services/meeting_formatter_test.dart` around lines 124 - 136, Update
MeetingFormatter.formatMeetingSummary to validate action_items entries before
treating them as maps, skipping null or otherwise malformed items while
continuing to format valid entries. Replace the test’s throwsA expectation with
an assertion for the formatter’s safe fallback output, while preserving normal
behavior for valid action items.

Source: Path instructions

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.

[Optimization]: Implement dynamic Context-Window Pruning and Token Truncation Middleware for Semantic Workspaces

1 participant