Skip to content

Conversation

@gunnarnordqvist
Copy link

Summary

  • Add granular context control for subagents to optimize performance with small local models
  • Enable 90-99% token reduction and 5-10× faster inference for lightweight models

Implementation

This PR introduces native context filtering for subagents, allowing fine-grained control over what parent session context is passed to subagents.

Key Features

Context Modes:

  • none (default) - No parent context, maintains current behavior
  • summary - Compact session summary (~100-500 tokens)
  • filtered - Selective inclusion by message type and tool results
  • full - All context with configurable limits

Configuration:

context:
  mode: filtered
  maxTokens: 2000
  includeToolResults: ["read", "edit"]
  includeMessageTypes: ["user"]

Performance Impact

Before: 45,000 tokens → 8 seconds (llama3.2:1b)
After: 200 tokens → 1 second (99% reduction, 8× faster)

Changes

  • New files:

    • packages/opencode/src/session/context-filter.ts - Core filtering logic (246 lines)
    • packages/opencode/src/session/context-filter.test.ts - Comprehensive tests (237 lines)
    • .opencode/agent/ - Example agent configurations
  • Modified files:

    • packages/opencode/src/config/config.ts - Context filter schema
    • packages/opencode/src/agent/agent.ts - Agent context support
    • packages/opencode/src/tool/task.ts - Apply filtering before subagent invocation
    • AGENTS.md - Documentation

Backward Compatibility

  • ✅ Fully backward compatible
  • ✅ Default mode is none (current behavior)
  • ✅ Optional feature, no breaking changes
  • ✅ All existing tests passing

Testing

cd packages/opencode
bun test src/session/context-filter.test.ts

Test Results: ✅ 11 tests passing, 32 assertions

Addresses #4096

Copilot AI review requested due to automatic review settings November 9, 2025 10:03
Copy link
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 implements context filtering for subagents to control what parent session context they receive. This enables better performance for lightweight local models by limiting the amount of context passed to them.

  • Introduces a ContextFilter module with multiple filtering modes (none, summary, filtered, full)
  • Adds context configuration to agent definitions with token/message limits
  • Updates the task tool to gather and filter parent session context before passing it to subagents

Reviewed Changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/opencode/src/session/context-filter.ts Core filtering logic with four modes for context control
packages/opencode/src/session/context-filter.test.ts Comprehensive test suite covering all filtering modes
packages/opencode/src/config/config.ts Schema definition for context filter configuration
packages/opencode/src/agent/agent.ts Adds context property to agent schema and parsing
packages/opencode/src/tool/task.ts Integrates context filtering into task execution with debug logging
AGENTS.md Documentation for context control feature
.opencode/agent/*.md Example agent configurations demonstrating context control

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

Comment on lines 101 to 105
console.log('\n🔍 [CONTEXT FILTER DEBUG]')
console.log(' Agent:', agent.name)
console.log(' Mode: none (or no config)')
console.log(' Context parts: 0')
console.log('')
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

Debug console.log statements should be removed or replaced with a proper logging mechanism. The codebase uses a Log utility (imported in other files like session/compaction.ts) for structured logging. Consider using that instead or removing these debug statements before merging to production.

Copilot uses AI. Check for mistakes.
})

// Gather parent session context if agent has context config
const contextParts: any[] = []
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

Using any[] for contextParts bypasses TypeScript's type safety. Since the parts are later filtered to only include specific types (text, file, agent) and should match MessageV2.Part[], declare this as const contextParts: MessageV2.Part[] = [] for better type safety.

Suggested change
const contextParts: any[] = []
const contextParts: MessageV2.Part[] = []

Copilot uses AI. Check for mistakes.
// DEBUG: Log context filtering results
const estimatedTokens = Math.round(
allowedParts.reduce((sum, part) => {
if (part.type === 'text') return sum + ((part as any).text.length / 4)
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

Using (part as any) bypasses type safety. Since the type has already been checked as 'text', use a proper type assertion: (part as MessageV2.TextPart).text.length / 4. This provides compile-time type checking and better IDE support.

Suggested change
if (part.type === 'text') return sum + ((part as any).text.length / 4)
if (part.type === 'text') return sum + ((part as MessageV2.TextPart).text.length / 4)

Copilot uses AI. Check for mistakes.

for (const part of msg.parts) {
if (part.type === "tool" && part.state.status === "completed") {
const toolName = (part as MessageV2.ToolPart).tool
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

[nitpick] The type assertion (part as MessageV2.ToolPart) is used after checking part.type === 'tool', which is correct. However, TypeScript should be able to narrow the type automatically. Consider using a type guard or restructuring the code to leverage TypeScript's discriminated union narrowing for better type safety without manual assertions.

Suggested change
const toolName = (part as MessageV2.ToolPart).tool
const toolName = part.tool

Copilot uses AI. Check for mistakes.
if (remaining > 100) {
const truncatedPart: MessageV2.TextPart = {
...part,
text: (part as MessageV2.TextPart).text.substring(0, remaining) + "\n...(truncated)",
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

[nitpick] While the type assertion is safe here due to the preceding type check, consider using TypeScript's type narrowing. You could assign the part to a typed variable after the check (e.g., const textPart: MessageV2.TextPart = part) to avoid repetitive type assertions and improve code clarity.

Copilot uses AI. Check for mistakes.
*/
function estimatePartSize(part: MessageV2.Part): number {
if (part.type === "text") {
return (part as MessageV2.TextPart).text.length
Copy link

Copilot AI Nov 9, 2025

Choose a reason for hiding this comment

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

[nitpick] Similar to other type assertions in this file, consider using a type guard or local variable after the type check to avoid type assertions and leverage TypeScript's type narrowing capabilities.

Suggested change
return (part as MessageV2.TextPart).text.length
const textPart = part;
return textPart.text.length;

Copilot uses AI. Check for mistakes.
@gunnarnordqvist
Copy link
Author

#4096

Gunnar Nordqvist added 3 commits November 13, 2025 16:49
Implements granular control over what context from parent sessions is passed to subagents, enabling significant performance improvements for small local models.

Features:
- Four context modes: none, summary, filtered, full
- Configurable token and message limits
- Selective filtering by message types and tool results
- Backward compatible (defaults to 'none' mode)
- Comprehensive unit tests
- Example configurations and documentation

This addresses issue anomalyco#4096 by providing native context control without requiring external proxies.

Performance impact:
- 99% reduction in token usage for small models
- 8x faster inference times with llama3.2:1b
- Enables practical use of lightweight local models as subagents
- Document context control feature in AGENTS.md with modes and examples
- Move example agents to .opencode/agent/ (code-reviewer, doc-reader, log-analyzer, quick-search)
- Follow standard OpenCode documentation structure
- Update types to use MessageV2.WithParts instead of MessageV2.Info
- Change ToolPart.name to ToolPart.tool (API change)
- Add null checks for config parameter
- Filter context parts to only allowed types (text, file, agent) for prompt
- Fix test helper to use correct callID format
- All tests passing
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.

2 participants