Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16362adb76 |
@@ -0,0 +1,998 @@
|
||||
# Context Management Deep Dive
|
||||
|
||||
This comprehensive guide explores the Adaptive Context Management System (ACMS) architecture, strategies, and best practices for managing context in cleveragents-core.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Context Management Architecture Overview](#context-management-architecture-overview)
|
||||
2. [ACMS Pipeline Components](#acms-pipeline-components)
|
||||
3. [Context Strategy Patterns](#context-strategy-patterns)
|
||||
4. [Context Inheritance and Scope Resolution](#context-inheritance-and-scope-resolution)
|
||||
5. [Budget Allocation and Utilization Metrics](#budget-allocation-and-utilization-metrics)
|
||||
6. [Implementation Guide for Custom Strategies](#implementation-guide-for-custom-strategies)
|
||||
7. [Best Practices and Performance Considerations](#best-practices-and-performance-considerations)
|
||||
8. [Integration with Plan Execution](#integration-with-plan-execution)
|
||||
9. [Real-world Examples](#real-world-examples)
|
||||
|
||||
## Context Management Architecture Overview
|
||||
|
||||
### What is Context Management?
|
||||
|
||||
Context management is the process of selecting, prioritizing, and packaging relevant information from a project's knowledge base to provide to language models (LMs) during plan execution. The ACMS ensures that:
|
||||
|
||||
- **Relevance**: Only the most pertinent information is included
|
||||
- **Budget Compliance**: Token limits are strictly respected
|
||||
- **Efficiency**: Context assembly is fast and deterministic
|
||||
- **Traceability**: All context is provenance-tracked back to its source
|
||||
|
||||
### The Three-Tier Context Model
|
||||
|
||||
ACMS organizes context into three priority tiers:
|
||||
|
||||
| Tier | Purpose | Inclusion Strategy |
|
||||
|------|---------|-------------------|
|
||||
| **hot** | Critical context that must be included | Always included first; highest priority |
|
||||
| **warm** | Standard context included when budget allows | Included after hot tier; default tier |
|
||||
| **cold** | Low-priority context included only if space remains | Included last; only if budget permits |
|
||||
|
||||
> **Note:** In v1, tiers are sort-priority labels for ranking during assembly. Full storage-tier semantics with retention policies and promotion/demotion will be implemented in future milestones.
|
||||
|
||||
### Core Concepts
|
||||
|
||||
#### Context Fragments
|
||||
|
||||
A **ContextFragment** is the atomic unit of context. Each fragment represents a single piece of information:
|
||||
|
||||
```python
|
||||
ContextFragment(
|
||||
uko_node="project://myapp/src/main.py", # UKO URI of source
|
||||
content="def main(): ...", # Rendered text content
|
||||
detail_depth=3, # Depth level (0-9)
|
||||
token_count=100, # Actual token count
|
||||
relevance_score=0.9, # Relevance (0.0-1.0)
|
||||
tier="hot", # Priority tier
|
||||
provenance=FragmentProvenance( # Source tracking
|
||||
resource_uri="project://myapp/src/main.py",
|
||||
location="line 1-10",
|
||||
resource_type="source_file"
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
**Key Properties:**
|
||||
- `fragment_id`: Unique ULID identifier (auto-generated)
|
||||
- `content`: Max 1,000,000 characters
|
||||
- `detail_depth`: Resolved depth from 0 (MODULE_LISTING) to 9 (FULL_SOURCE)
|
||||
- `token_count`: Must be >= 0; used for budget calculations
|
||||
- `relevance_score`: 0.0 (irrelevant) to 1.0 (highly relevant)
|
||||
- `metadata`: Arbitrary key-value pairs (max 64 entries)
|
||||
- `created_at`: UTC timestamp for recency-based sorting
|
||||
|
||||
#### Context Budget
|
||||
|
||||
The **ContextBudget** defines token constraints:
|
||||
|
||||
```python
|
||||
budget = ContextBudget(
|
||||
max_tokens=4096, # Total available tokens
|
||||
reserved_tokens=512 # Tokens reserved for system prompt
|
||||
)
|
||||
# Available tokens = max_tokens - reserved_tokens = 3584
|
||||
```
|
||||
|
||||
**Budget Rules:**
|
||||
- `available_tokens = max_tokens - reserved_tokens`
|
||||
- `reserved_tokens` must be < `max_tokens`
|
||||
- Pipeline never exceeds `available_tokens`
|
||||
- Fragments exceeding budget are skipped
|
||||
|
||||
#### Context Payload
|
||||
|
||||
The assembled **ContextPayload** is the final output:
|
||||
|
||||
```python
|
||||
payload = ContextPayload(
|
||||
payload_id="01ARZ3NDEKTSV4RRFFQ69G5FAV", # ULID
|
||||
plan_id="plan-1", # Associated plan
|
||||
fragments=(fragment1, fragment2, ...), # Selected fragments
|
||||
total_tokens=2048, # Sum of fragment tokens
|
||||
budget=budget, # Budget used
|
||||
budget_used=0.57, # Fraction consumed
|
||||
strategies_used=("simple-keyword",), # Contributing strategies
|
||||
context_hash="abc123...", # SHA-256 hash
|
||||
preamble="Context includes 2 files...", # Optional summary
|
||||
provenance_map={...}, # Fragment ID -> provenance
|
||||
assembled_at=datetime.now(timezone.utc) # Assembly timestamp
|
||||
)
|
||||
```
|
||||
|
||||
**Key Properties:**
|
||||
- `is_within_budget`: True if total_tokens <= available_tokens
|
||||
- `remaining_tokens`: available_tokens - total_tokens
|
||||
|
||||
### Context Request Protocol (CRP)
|
||||
|
||||
The **ContextRequest** specifies what context is needed:
|
||||
|
||||
```python
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"], # Primary focus
|
||||
breadth=2, # Graph traversal breadth
|
||||
depth=3, # Graph traversal depth
|
||||
keywords=["async", "io"], # Search keywords
|
||||
resource_types=["source_file", "decision"], # Filter by type
|
||||
detail_level=3, # Desired detail depth
|
||||
temporal_window="7d", # Historical window
|
||||
strategy_hints=["semantic-embedding"], # Preferred strategies
|
||||
)
|
||||
```
|
||||
|
||||
## ACMS Pipeline Components
|
||||
|
||||
The ACMS pipeline implements a 10-component architecture across three phases:
|
||||
|
||||
### Phase 1: Strategy Orchestration
|
||||
|
||||
#### 1. StrategySelector
|
||||
|
||||
**Purpose**: Determine which strategies can handle the request.
|
||||
|
||||
**Process**:
|
||||
1. Poll all registered strategies with `can_handle(request)`
|
||||
2. Each strategy returns confidence (0.0-1.0)
|
||||
3. Select strategies above confidence threshold
|
||||
4. Rank by confidence score
|
||||
|
||||
#### 2. BudgetAllocator
|
||||
|
||||
**Purpose**: Distribute token budget among selected strategies.
|
||||
|
||||
**Allocation Strategies**:
|
||||
- **Proportional**: Allocate based on confidence scores
|
||||
- **Equal**: Divide equally among strategies
|
||||
- **Priority**: Allocate to highest-confidence first
|
||||
|
||||
#### 3. StrategyExecutor
|
||||
|
||||
**Purpose**: Execute strategies in parallel with timeout and circuit breaker.
|
||||
|
||||
**Features**:
|
||||
- Parallel execution with configurable workers
|
||||
- Per-strategy timeout (default 30s)
|
||||
- Circuit breaker after N failures
|
||||
- Graceful degradation on timeout
|
||||
|
||||
### Phase 2: Fragment Fusion
|
||||
|
||||
#### 4. FragmentDeduplicator
|
||||
|
||||
**Purpose**: Remove duplicate fragments based on UKO node and content hash.
|
||||
|
||||
**Deduplication Rules**:
|
||||
- Same `uko_node` + same content hash = duplicate
|
||||
- Keep fragment with highest relevance score
|
||||
- Preserve provenance from all duplicates
|
||||
|
||||
#### 5. DetailDepthResolver
|
||||
|
||||
**Purpose**: Resolve appropriate detail depth for each fragment.
|
||||
|
||||
**Resolution Logic**:
|
||||
- Start with requested detail level
|
||||
- Adjust based on token budget
|
||||
- Respect fragment's max depth
|
||||
- Prefer higher depth for hot tier
|
||||
|
||||
#### 6. FragmentScorer
|
||||
|
||||
**Purpose**: Score fragments based on multiple factors.
|
||||
|
||||
**Scoring Factors**:
|
||||
- Relevance score (from strategy)
|
||||
- Tier priority (hot > warm > cold)
|
||||
- Recency (created_at)
|
||||
- Plan context alignment
|
||||
- Resource type affinity
|
||||
|
||||
#### 7. BudgetPacker
|
||||
|
||||
**Purpose**: Select fragments to fit within token budget.
|
||||
|
||||
**Packing Algorithm**:
|
||||
1. Sort fragments by score (descending)
|
||||
2. Greedily add fragments until budget exhausted
|
||||
3. Respect tier ordering (hot → warm → cold)
|
||||
4. Early termination when budget full
|
||||
|
||||
#### 8. FragmentOrderer
|
||||
|
||||
**Purpose**: Determine final fragment order in payload.
|
||||
|
||||
**Ordering Strategies**:
|
||||
- **Relevance**: By relevance_score (descending)
|
||||
- **Recency**: By created_at (descending)
|
||||
- **Tier-Relevance**: By tier, then relevance
|
||||
- **Custom**: User-defined ordering
|
||||
|
||||
### Phase 3: Context Finalization
|
||||
|
||||
#### 9. PreambleGenerator
|
||||
|
||||
**Purpose**: Generate optional summary of assembled context.
|
||||
|
||||
**Preamble Contents**:
|
||||
- Number of fragments and sources
|
||||
- Token usage and budget utilization
|
||||
- Strategies used
|
||||
- Key topics covered
|
||||
- Temporal range
|
||||
|
||||
#### 10. SkeletonCompressor
|
||||
|
||||
**Purpose**: Compress context for child plans while preserving critical information.
|
||||
|
||||
**Compression Strategy**:
|
||||
- Identify critical fragments for child focus
|
||||
- Remove redundant details
|
||||
- Preserve decision context
|
||||
- Maintain provenance
|
||||
|
||||
## Context Strategy Patterns
|
||||
|
||||
### Strategy Architecture
|
||||
|
||||
All strategies implement the `ContextStrategy` protocol:
|
||||
|
||||
```python
|
||||
class ContextStrategy(Protocol):
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Unique strategy identifier"""
|
||||
...
|
||||
|
||||
@property
|
||||
def capabilities(self) -> StrategyCapabilities:
|
||||
"""Declare backend requirements and quality"""
|
||||
...
|
||||
|
||||
def can_handle(
|
||||
self,
|
||||
request: ContextRequest,
|
||||
backends: BackendSet
|
||||
) -> float:
|
||||
"""Return confidence (0.0-1.0) for handling request"""
|
||||
...
|
||||
|
||||
def assemble(
|
||||
self,
|
||||
request: ContextRequest,
|
||||
backends: BackendSet,
|
||||
budget: ContextBudget,
|
||||
plan_context: PlanContext
|
||||
) -> list[ContextFragment]:
|
||||
"""Execute strategy and return fragments"""
|
||||
...
|
||||
|
||||
def explain(self) -> str:
|
||||
"""Human-readable description"""
|
||||
...
|
||||
```
|
||||
|
||||
### Built-in Strategies
|
||||
|
||||
#### 1. Simple Keyword Strategy
|
||||
|
||||
**Quality Score**: 0.3 (baseline)
|
||||
|
||||
**Backend Requirements**: TextBackend
|
||||
|
||||
**How It Works**:
|
||||
1. Extract keywords from request
|
||||
2. Search TextBackend using keywords
|
||||
3. Rank results by match frequency
|
||||
4. Pack greedily into budget
|
||||
|
||||
**Best For**:
|
||||
- Quick searches with clear keywords
|
||||
- Projects with good text indexing
|
||||
- Fallback when other backends unavailable
|
||||
|
||||
#### 2. Semantic Embedding Strategy
|
||||
|
||||
**Quality Score**: 0.6 (good)
|
||||
|
||||
**Backend Requirements**: VectorBackend
|
||||
|
||||
**How It Works**:
|
||||
1. Embed request using character-frequency model (v1)
|
||||
2. Search VectorBackend for similar embeddings
|
||||
3. Rank by cosine similarity
|
||||
4. Pack budget-aware results
|
||||
|
||||
**Best For**:
|
||||
- Semantic similarity searches
|
||||
- Conceptual relationships
|
||||
- Cross-domain context discovery
|
||||
|
||||
#### 3. Breadth-Depth Navigator Strategy
|
||||
|
||||
**Quality Score**: 0.85 (excellent)
|
||||
|
||||
**Backend Requirements**: GraphBackend
|
||||
|
||||
**How It Works**:
|
||||
1. Start from focus nodes in request
|
||||
2. Traverse graph outward by breadth hops
|
||||
3. Traverse downward by depth hops
|
||||
4. Collect all reachable nodes
|
||||
5. Rank by distance and relevance
|
||||
6. Pack into budget
|
||||
|
||||
**Best For**:
|
||||
- Exploring related code and decisions
|
||||
- Understanding dependencies
|
||||
- Comprehensive context assembly
|
||||
|
||||
#### 4. ARCE Strategy (Advanced Retrieval with Context Enrichment)
|
||||
|
||||
**Quality Score**: 0.95 (highest)
|
||||
|
||||
**Backend Requirements**: TextBackend, VectorBackend, GraphBackend
|
||||
|
||||
**How It Works**:
|
||||
1. **Phase 1 (40% budget)**: Text search using keywords
|
||||
2. **Phase 2 (40% budget)**: Vector similarity search
|
||||
3. **Phase 3 (20% budget)**: Graph traversal from results
|
||||
4. Merge and deduplicate results
|
||||
5. Rank by combined score
|
||||
6. Pack into budget
|
||||
|
||||
**Best For**:
|
||||
- Comprehensive context assembly
|
||||
- Multi-modal queries
|
||||
- Production use cases
|
||||
|
||||
#### 5. Temporal Archaeology Strategy
|
||||
|
||||
**Quality Score**: 0.5 (moderate)
|
||||
|
||||
**Backend Requirements**: GraphBackend, TemporalBackend (cold tier)
|
||||
|
||||
**How It Works**:
|
||||
1. Query TemporalBackend for historical nodes
|
||||
2. Filter by temporal window
|
||||
3. Traverse graph from historical nodes
|
||||
4. Collect related current nodes
|
||||
5. Rank by recency and relevance
|
||||
6. Pack into budget
|
||||
|
||||
**Best For**:
|
||||
- Understanding historical context
|
||||
- Decision archaeology
|
||||
- Long-term project evolution
|
||||
|
||||
#### 6. Plan-Decision Context Strategy
|
||||
|
||||
**Quality Score**: 0.7 (good)
|
||||
|
||||
**Backend Requirements**: TemporalBackend (warm/cold), GraphBackend
|
||||
|
||||
**How It Works**:
|
||||
1. Walk parent and ancestor plan hierarchy
|
||||
2. Retrieve decision records from warm/cold tiers
|
||||
3. Traverse graph from decisions
|
||||
4. Collect related context
|
||||
5. Rank by plan proximity and relevance
|
||||
6. Pack into budget
|
||||
|
||||
**Best For**:
|
||||
- Understanding plan context
|
||||
- Decision inheritance
|
||||
- Multi-level plan coordination
|
||||
|
||||
### Strategy Comparison Matrix
|
||||
|
||||
| Strategy | Quality | Speed | Coverage | Best For |
|
||||
|----------|---------|-------|----------|----------|
|
||||
| Simple Keyword | 0.3 | ⚡⚡⚡ | Narrow | Quick searches |
|
||||
| Semantic Embedding | 0.6 | ⚡⚡ | Broad | Semantic similarity |
|
||||
| Breadth-Depth Navigator | 0.85 | ⚡ | Very Broad | Comprehensive context |
|
||||
| ARCE | 0.95 | 🐢 | Comprehensive | Production use |
|
||||
| Temporal Archaeology | 0.5 | 🐢 | Historical | Historical context |
|
||||
| Plan-Decision Context | 0.7 | ⚡ | Hierarchical | Plan coordination |
|
||||
|
||||
## Context Inheritance and Scope Resolution
|
||||
|
||||
### Scope Hierarchy
|
||||
|
||||
Context is organized in a hierarchy of scopes:
|
||||
|
||||
```
|
||||
Global Scope
|
||||
├── Project Scope
|
||||
│ ├── Module Scope
|
||||
│ │ ├── Class Scope
|
||||
│ │ │ └── Method Scope
|
||||
│ │ └── Function Scope
|
||||
│ └── Decision Scope
|
||||
└── Temporal Scope
|
||||
├── Current
|
||||
├── Recent (7d)
|
||||
└── Historical (30d+)
|
||||
```
|
||||
|
||||
### Scope Resolution Rules
|
||||
|
||||
When assembling context for a request:
|
||||
|
||||
1. **Start at Request Focus**: Begin with explicitly requested nodes
|
||||
2. **Expand Upward**: Include parent scopes (module → project → global)
|
||||
3. **Expand Downward**: Include child scopes (class → methods)
|
||||
4. **Expand Sideways**: Include sibling scopes (related classes)
|
||||
5. **Apply Filters**: Remove out-of-scope items based on resource types
|
||||
6. **Respect Budget**: Stop expansion when budget exhausted
|
||||
|
||||
### Context Inheritance
|
||||
|
||||
Child plans inherit context from parent plans:
|
||||
|
||||
```python
|
||||
# Parent plan context
|
||||
parent_payload = ContextPayload(
|
||||
fragments=[
|
||||
ContextFragment(uko_node="project://myapp/src/main.py", ...),
|
||||
ContextFragment(uko_node="project://myapp/src/utils.py", ...),
|
||||
ContextFragment(uko_node="project://myapp/decisions/001", ...),
|
||||
]
|
||||
)
|
||||
|
||||
# Child plan inherits and specializes
|
||||
child_request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"],
|
||||
parent_context=parent_payload,
|
||||
inherit_strategy="skeleton" # Compress parent context
|
||||
)
|
||||
|
||||
# Result: Child gets focused context + compressed parent context
|
||||
child_payload = pipeline.assemble(child_request)
|
||||
```
|
||||
|
||||
**Inheritance Strategies**:
|
||||
- **Full**: Include all parent context (if budget allows)
|
||||
- **Skeleton**: Compress parent context to essentials
|
||||
- **None**: Start fresh (no parent context)
|
||||
|
||||
## Budget Allocation and Utilization Metrics
|
||||
|
||||
### Budget Planning
|
||||
|
||||
Effective budget allocation requires understanding token costs:
|
||||
|
||||
```python
|
||||
# Typical token costs
|
||||
costs = {
|
||||
"system_prompt": 512, # Reserved
|
||||
"user_request": 200, # Typical request
|
||||
"model_response": 1024, # Expected response
|
||||
"context": 2048, # Available for context
|
||||
}
|
||||
|
||||
total_budget = 4096
|
||||
reserved = 512
|
||||
available = total_budget - reserved # 3584 tokens
|
||||
```
|
||||
|
||||
### Budget Allocation Strategies
|
||||
|
||||
#### Proportional Allocation
|
||||
|
||||
Allocate based on strategy confidence scores:
|
||||
|
||||
```python
|
||||
candidates = [
|
||||
(semantic_embedding, 0.95),
|
||||
(breadth_depth, 0.85),
|
||||
(simple_keyword, 0.3)
|
||||
]
|
||||
|
||||
total_confidence = 0.95 + 0.85 + 0.3 # 2.1
|
||||
allocations = {
|
||||
semantic_embedding: int(3584 * 0.95 / 2.1), # 1621
|
||||
breadth_depth: int(3584 * 0.85 / 2.1), # 1450
|
||||
simple_keyword: int(3584 * 0.3 / 2.1), # 513
|
||||
}
|
||||
```
|
||||
|
||||
#### Priority Allocation
|
||||
|
||||
Allocate to highest-confidence strategies first:
|
||||
|
||||
```python
|
||||
allocations = {}
|
||||
remaining = 3584
|
||||
|
||||
for strategy, confidence in sorted(candidates, key=lambda x: x[1], reverse=True):
|
||||
# Allocate 50% of remaining budget
|
||||
allocation = remaining // 2
|
||||
allocations[strategy] = allocation
|
||||
remaining -= allocation
|
||||
```
|
||||
|
||||
#### Tier-Based Allocation
|
||||
|
||||
Allocate based on tier requirements:
|
||||
|
||||
```python
|
||||
allocations = {
|
||||
"hot_tier": 1000, # 28% - Critical context
|
||||
"warm_tier": 2000, # 56% - Standard context
|
||||
"cold_tier": 584, # 16% - Low-priority context
|
||||
}
|
||||
```
|
||||
|
||||
### Utilization Metrics
|
||||
|
||||
Track context assembly efficiency:
|
||||
|
||||
```python
|
||||
metrics = {
|
||||
"budget_used": payload.budget_used, # 0.57 (57%)
|
||||
"remaining_tokens": payload.remaining_tokens, # 1536
|
||||
"fragments_selected": len(payload.fragments), # 12
|
||||
"fragments_total": 45, # Total available
|
||||
"coverage": 12 / 45, # 26.7%
|
||||
"strategies_used": payload.strategies_used, # ("semantic-embedding",)
|
||||
"assembly_time_ms": 234, # Execution time
|
||||
"avg_fragment_tokens": 2048 / 12, # 170.7
|
||||
"avg_relevance": 0.82, # Mean relevance score
|
||||
}
|
||||
```
|
||||
|
||||
### Budget Optimization
|
||||
|
||||
Techniques to improve budget utilization:
|
||||
|
||||
1. **Increase Reserved Tokens**: Allocate more for system prompt
|
||||
2. **Reduce Detail Depth**: Lower detail_depth for less critical fragments
|
||||
3. **Increase Relevance Threshold**: Filter low-relevance fragments
|
||||
4. **Use Skeleton Compression**: Compress parent context for child plans
|
||||
5. **Tier-Based Filtering**: Exclude cold tier if budget tight
|
||||
|
||||
## Implementation Guide for Custom Strategies
|
||||
|
||||
### Creating a Custom Strategy
|
||||
|
||||
#### Step 1: Define Strategy Class
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.acms_service import (
|
||||
ContextStrategy,
|
||||
StrategyCapabilities,
|
||||
)
|
||||
from cleveragents.domain.models.core.context_fragment import (
|
||||
ContextBudget,
|
||||
ContextFragment,
|
||||
)
|
||||
from typing import Sequence, Any
|
||||
|
||||
|
||||
class MyCustomStrategy:
|
||||
"""Custom context strategy for specialized retrieval."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Unique strategy identifier."""
|
||||
return "my-custom-strategy"
|
||||
|
||||
@property
|
||||
def capabilities(self) -> StrategyCapabilities:
|
||||
"""Declare backend requirements and quality."""
|
||||
return StrategyCapabilities(
|
||||
uses_text=True,
|
||||
uses_vector=False,
|
||||
uses_graph=True,
|
||||
uses_temporal=False,
|
||||
resource_types=("source_file", "decision"),
|
||||
quality_score=0.75,
|
||||
supports_depth_breadth=True,
|
||||
supports_plan_hierarchy=False,
|
||||
supports_temporal=False,
|
||||
)
|
||||
|
||||
def can_handle(self, request: dict[str, Any]) -> float:
|
||||
"""Return confidence (0.0-1.0) for handling request."""
|
||||
# Check if request has required fields
|
||||
if "focus_nodes" not in request:
|
||||
return 0.0
|
||||
|
||||
# Check for specific keywords
|
||||
keywords = request.get("keywords", [])
|
||||
if any(kw in ["async", "io", "performance"] for kw in keywords):
|
||||
return 0.9 # High confidence for performance-related queries
|
||||
|
||||
return 0.6 # Moderate confidence for general queries
|
||||
|
||||
def assemble(
|
||||
self,
|
||||
fragments: Sequence[ContextFragment],
|
||||
budget: ContextBudget,
|
||||
) -> Sequence[ContextFragment]:
|
||||
"""Execute strategy and return fragments."""
|
||||
# Custom ranking logic
|
||||
ranked = sorted(
|
||||
fragments,
|
||||
key=lambda f: (
|
||||
f.tier == "hot", # Hot tier first
|
||||
f.relevance_score, # Then by relevance
|
||||
f.created_at, # Then by recency
|
||||
),
|
||||
reverse=True
|
||||
)
|
||||
|
||||
# Pack into budget
|
||||
selected = []
|
||||
total_tokens = 0
|
||||
|
||||
for fragment in ranked:
|
||||
if total_tokens + fragment.token_count <= budget.available_tokens:
|
||||
selected.append(fragment)
|
||||
total_tokens += fragment.token_count
|
||||
else:
|
||||
break # Budget exhausted
|
||||
|
||||
return selected
|
||||
|
||||
def explain(self) -> str:
|
||||
"""Human-readable description."""
|
||||
return (
|
||||
"Custom strategy that prioritizes hot-tier fragments "
|
||||
"and performance-related keywords."
|
||||
)
|
||||
```
|
||||
|
||||
#### Step 2: Register Strategy
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.acms_service import ACMSPipeline
|
||||
|
||||
# Create pipeline
|
||||
pipeline = ACMSPipeline()
|
||||
|
||||
# Register custom strategy
|
||||
strategy = MyCustomStrategy()
|
||||
pipeline.register_strategy(strategy.name, strategy)
|
||||
|
||||
# Use in assembly
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=budget,
|
||||
strategy="my-custom-strategy"
|
||||
)
|
||||
```
|
||||
|
||||
#### Step 3: Configure in TOML
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
enabled = ["simple-keyword", "my-custom-strategy"]
|
||||
|
||||
[context.strategies.custom]
|
||||
"my-custom-strategy" = "my_package.strategies:MyCustomStrategy"
|
||||
|
||||
[context.strategies."my-custom-strategy"]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 100
|
||||
```
|
||||
|
||||
## Best Practices and Performance Considerations
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
#### 1. Strategy Selection
|
||||
|
||||
**Best Practice**: Use strategy confidence scores to avoid unnecessary execution.
|
||||
|
||||
#### 2. Budget Allocation
|
||||
|
||||
**Best Practice**: Allocate more budget to higher-confidence strategies.
|
||||
|
||||
#### 3. Timeout Management
|
||||
|
||||
**Best Practice**: Set appropriate timeouts based on strategy complexity.
|
||||
|
||||
#### 4. Fragment Deduplication
|
||||
|
||||
**Best Practice**: Deduplicate early to reduce downstream processing.
|
||||
|
||||
#### 5. Detail Depth Resolution
|
||||
|
||||
**Best Practice**: Reduce detail depth for less critical fragments.
|
||||
|
||||
### Memory Efficiency
|
||||
|
||||
#### 1. Fragment Streaming
|
||||
|
||||
**Best Practice**: Stream fragments instead of loading all at once.
|
||||
|
||||
#### 2. Lazy Evaluation
|
||||
|
||||
**Best Practice**: Defer expensive operations until needed.
|
||||
|
||||
### Reliability and Robustness
|
||||
|
||||
#### 1. Circuit Breaker Pattern
|
||||
|
||||
**Best Practice**: Implement circuit breaker for failing strategies.
|
||||
|
||||
#### 2. Graceful Degradation
|
||||
|
||||
**Best Practice**: Fall back to simpler strategies when complex ones fail.
|
||||
|
||||
#### 3. Timeout Handling
|
||||
|
||||
**Best Practice**: Set reasonable timeouts with fallback.
|
||||
|
||||
### Monitoring and Observability
|
||||
|
||||
#### 1. Metrics Collection
|
||||
|
||||
**Best Practice**: Collect comprehensive metrics for monitoring.
|
||||
|
||||
#### 2. Logging
|
||||
|
||||
**Best Practice**: Log key decisions and failures.
|
||||
|
||||
## Integration with Plan Execution
|
||||
|
||||
### Context Assembly in Plan Execution
|
||||
|
||||
Context is assembled at key points in plan execution:
|
||||
|
||||
```
|
||||
Plan Execution Flow
|
||||
├── Plan Created
|
||||
│ └── Initial Context Assembly
|
||||
│ ├── StrategySelector: Choose strategies
|
||||
│ ├── BudgetAllocator: Allocate tokens
|
||||
│ └── StrategyExecutor: Execute strategies
|
||||
├── Plan Step Execution
|
||||
│ └── Context Refresh (optional)
|
||||
│ └── Incremental context updates
|
||||
├── Subplan Creation
|
||||
│ └── Context Inheritance
|
||||
│ ├── Inherit parent context
|
||||
│ └── Specialize for subplan focus
|
||||
└── Plan Completion
|
||||
└── Context Archive
|
||||
└── Store for historical reference
|
||||
```
|
||||
|
||||
### Context Request from Plan
|
||||
|
||||
Plans generate context requests based on their focus.
|
||||
|
||||
### Context Injection into Plan
|
||||
|
||||
Assembled context is injected into plan execution.
|
||||
|
||||
### Subplan Context Inheritance
|
||||
|
||||
Child plans inherit and specialize context.
|
||||
|
||||
## Real-world Examples
|
||||
|
||||
### Example 1: Implementing a New Feature
|
||||
|
||||
**Scenario**: Implement async I/O support in a Python project.
|
||||
|
||||
**Context Assembly**:
|
||||
|
||||
```python
|
||||
# 1. Create context request
|
||||
request = ContextRequest(
|
||||
focus_nodes=[
|
||||
"project://myapp/src/main.py",
|
||||
"project://myapp/src/io.py"
|
||||
],
|
||||
keywords=["async", "io", "performance"],
|
||||
breadth=2,
|
||||
depth=3,
|
||||
resource_types=["source_file", "decision"],
|
||||
detail_level=4
|
||||
)
|
||||
|
||||
# 2. Assemble context
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-async-io",
|
||||
fragments=fetch_fragments(backends, request),
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="arce" # Use comprehensive strategy
|
||||
)
|
||||
|
||||
# 3. Inspect assembled context
|
||||
print(f"Fragments: {len(payload.fragments)}")
|
||||
print(f"Tokens: {payload.total_tokens} / {payload.budget.available_tokens}")
|
||||
print(f"Budget used: {payload.budget_used:.1%}")
|
||||
print(f"Strategies: {payload.strategies_used}")
|
||||
|
||||
# 4. Use context in plan execution
|
||||
plan = Plan(
|
||||
title="Implement async I/O",
|
||||
context_payload=payload,
|
||||
context_hash=payload.context_hash
|
||||
)
|
||||
```
|
||||
|
||||
**Result**: LM receives focused context on async I/O patterns, related decisions, and performance considerations.
|
||||
|
||||
### Example 2: Debugging a Performance Issue
|
||||
|
||||
**Scenario**: Investigate slow database queries.
|
||||
|
||||
**Context Assembly**:
|
||||
|
||||
```python
|
||||
# 1. Create context request focused on database code
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/database.py"],
|
||||
keywords=["query", "performance", "slow", "index"],
|
||||
breadth=3, # Broader search for related code
|
||||
depth=2, # Less deep (focus on structure)
|
||||
resource_types=["source_file", "decision", "test"],
|
||||
detail_level=2, # Less detail to fit more context
|
||||
temporal_window="30d" # Include recent changes
|
||||
)
|
||||
|
||||
# 2. Assemble with temporal strategy
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-debug-perf",
|
||||
fragments=fetch_fragments(backends, request),
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="temporal-archaeology" # Include historical context
|
||||
)
|
||||
|
||||
# 3. Analyze context
|
||||
hot_fragments = [f for f in payload.fragments if f.tier == "hot"]
|
||||
recent_fragments = sorted(
|
||||
payload.fragments,
|
||||
key=lambda f: f.created_at,
|
||||
reverse=True
|
||||
)[:5]
|
||||
|
||||
print(f"Hot tier fragments: {len(hot_fragments)}")
|
||||
print(f"Recent changes: {[f.uko_node for f in recent_fragments]}")
|
||||
```
|
||||
|
||||
**Result**: LM receives context on database code, recent changes, and historical decisions about performance.
|
||||
|
||||
### Example 3: Code Review with Context
|
||||
|
||||
**Scenario**: Review a pull request with full context.
|
||||
|
||||
**Context Assembly**:
|
||||
|
||||
```python
|
||||
# 1. Get changed files from PR
|
||||
changed_files = [
|
||||
"project://myapp/src/auth.py",
|
||||
"project://myapp/src/security.py",
|
||||
"project://myapp/tests/test_auth.py"
|
||||
]
|
||||
|
||||
# 2. Create context request
|
||||
request = ContextRequest(
|
||||
focus_nodes=changed_files,
|
||||
breadth=1, # Narrow search (focus on changed files)
|
||||
depth=4, # Deeper (understand full context)
|
||||
resource_types=["source_file", "decision", "test"],
|
||||
detail_level=5, # Higher detail for review
|
||||
strategy_hints=["breadth-depth-navigator"] # Use graph traversal
|
||||
)
|
||||
|
||||
# 3. Assemble context
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-review-pr",
|
||||
fragments=fetch_fragments(backends, request),
|
||||
budget=ContextBudget(max_tokens=8192, reserved_tokens=512),
|
||||
strategy="breadth-depth-navigator"
|
||||
)
|
||||
|
||||
# 4. Generate review context
|
||||
review_context = {
|
||||
"changed_files": changed_files,
|
||||
"context_fragments": len(payload.fragments),
|
||||
"context_tokens": payload.total_tokens,
|
||||
"related_decisions": [
|
||||
f for f in payload.fragments
|
||||
if "decision" in f.metadata.get("resource_type", "")
|
||||
],
|
||||
"related_tests": [
|
||||
f for f in payload.fragments
|
||||
if "test" in f.uko_node
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Result**: LM receives comprehensive context on changed files, related code, decisions, and tests for thorough review.
|
||||
|
||||
### Example 4: Multi-level Plan Hierarchy
|
||||
|
||||
**Scenario**: Execute a complex plan with multiple subplans.
|
||||
|
||||
**Context Assembly**:
|
||||
|
||||
```python
|
||||
# Parent plan context
|
||||
parent_request = ContextRequest(
|
||||
focus_nodes=["project://myapp"],
|
||||
breadth=2,
|
||||
depth=2,
|
||||
detail_level=2
|
||||
)
|
||||
|
||||
parent_payload = pipeline.assemble(
|
||||
plan_id="plan-refactor",
|
||||
fragments=fetch_fragments(backends, parent_request),
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="arce"
|
||||
)
|
||||
|
||||
# Subplan 1: Refactor auth module
|
||||
subplan1_request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/auth.py"],
|
||||
parent_context=parent_payload,
|
||||
inherit_strategy="skeleton", # Compress parent
|
||||
breadth=2,
|
||||
depth=3,
|
||||
detail_level=4
|
||||
)
|
||||
|
||||
subplan1_payload = pipeline.assemble(
|
||||
plan_id="plan-refactor-auth",
|
||||
fragments=fetch_fragments(backends, subplan1_request),
|
||||
budget=ContextBudget(max_tokens=3584, reserved_tokens=512),
|
||||
strategy="breadth-depth-navigator"
|
||||
)
|
||||
|
||||
# Subplan 2: Refactor database module
|
||||
subplan2_request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/database.py"],
|
||||
parent_context=parent_payload,
|
||||
inherit_strategy="skeleton",
|
||||
breadth=2,
|
||||
depth=3,
|
||||
detail_level=4
|
||||
)
|
||||
|
||||
subplan2_payload = pipeline.assemble(
|
||||
plan_id="plan-refactor-db",
|
||||
fragments=fetch_fragments(backends, subplan2_request),
|
||||
budget=ContextBudget(max_tokens=3584, reserved_tokens=512),
|
||||
strategy="breadth-depth-navigator"
|
||||
)
|
||||
|
||||
# Execute hierarchy
|
||||
execute_plan(parent_plan, parent_payload)
|
||||
execute_plan(subplan1, subplan1_payload)
|
||||
execute_plan(subplan2, subplan2_payload)
|
||||
```
|
||||
|
||||
**Result**: Parent plan gets broad context; subplans get specialized context with parent context compressed for efficiency.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The ACMS provides a powerful, flexible system for managing context in cleveragents-core. By understanding the architecture, strategies, and best practices, you can:
|
||||
|
||||
- **Assemble relevant context** efficiently and deterministically
|
||||
- **Respect token budgets** while maximizing information density
|
||||
- **Implement custom strategies** for specialized use cases
|
||||
- **Optimize performance** through careful budget allocation
|
||||
- **Integrate seamlessly** with plan execution
|
||||
|
||||
For more information, see:
|
||||
- [Context Strategies Reference](../reference/context_strategies_reference.md)
|
||||
- [ACMS Pipeline Reference](../reference/acms_pipeline_reference.md)
|
||||
- [ACMS v1 Context Assembly Pipeline](../reference/acms.md)
|
||||
- [Context Strategy Registry](../reference/context_strategies.md)
|
||||
@@ -0,0 +1,760 @@
|
||||
# ACMS Pipeline Reference
|
||||
|
||||
Complete reference for the ACMS Pipeline components, their interactions, data flow, configuration, and monitoring.
|
||||
|
||||
## Pipeline Architecture
|
||||
|
||||
The ACMS pipeline implements a 10-component architecture across three phases:
|
||||
|
||||
```
|
||||
Phase 1: Strategy Orchestration
|
||||
├── StrategySelector
|
||||
├── BudgetAllocator
|
||||
└── StrategyExecutor
|
||||
|
||||
Phase 2: Fragment Fusion
|
||||
├── FragmentDeduplicator
|
||||
├── DetailDepthResolver
|
||||
├── FragmentScorer
|
||||
├── BudgetPacker
|
||||
└── FragmentOrderer
|
||||
|
||||
Phase 3: Context Finalization
|
||||
├── PreambleGenerator
|
||||
└── SkeletonCompressor
|
||||
```
|
||||
|
||||
## Component Reference
|
||||
|
||||
### Phase 1: Strategy Orchestration
|
||||
|
||||
#### StrategySelector
|
||||
|
||||
**Purpose**: Determine which strategies can handle the request.
|
||||
|
||||
**Input**:
|
||||
- `strategies`: List of registered strategies
|
||||
- `request`: ContextRequest with focus nodes, keywords, etc.
|
||||
- `backends`: Available backends (TextBackend, VectorBackend, etc.)
|
||||
|
||||
**Output**:
|
||||
- `candidates`: List of (strategy, confidence) tuples, sorted by confidence descending
|
||||
|
||||
**Process**:
|
||||
1. Poll each strategy with `can_handle(request, backends)`
|
||||
2. Collect confidence scores (0.0-1.0)
|
||||
3. Filter strategies with confidence >= threshold (default 0.0)
|
||||
4. Sort by confidence descending
|
||||
5. Return top candidates
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
selector_threshold = 0.0
|
||||
max_candidates = 10
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
selector = StrategySelector()
|
||||
candidates = selector.select(
|
||||
strategies=[simple_keyword, semantic_embedding, breadth_depth],
|
||||
request=context_request,
|
||||
backends=backend_set
|
||||
)
|
||||
# Returns: [(semantic_embedding, 0.95), (breadth_depth, 0.85), ...]
|
||||
```
|
||||
|
||||
#### BudgetAllocator
|
||||
|
||||
**Purpose**: Distribute token budget among selected strategies.
|
||||
|
||||
**Input**:
|
||||
- `candidates`: List of (strategy, confidence) tuples
|
||||
- `total_budget`: Available tokens for context
|
||||
- `request`: ContextRequest with budget hints
|
||||
|
||||
**Output**:
|
||||
- `allocations`: Dict mapping strategy -> allocated tokens
|
||||
|
||||
**Allocation Strategies**:
|
||||
|
||||
1. **Proportional** (default):
|
||||
```
|
||||
allocation[s] = total_budget * confidence[s] / sum(confidences)
|
||||
```
|
||||
|
||||
2. **Equal**:
|
||||
```
|
||||
allocation[s] = total_budget / len(candidates)
|
||||
```
|
||||
|
||||
3. **Priority**:
|
||||
```
|
||||
Sort by confidence, allocate 50% of remaining to each
|
||||
```
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
allocator_strategy = "proportional"
|
||||
allocator_min_budget = 100
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
allocator = BudgetAllocator()
|
||||
allocations = allocator.allocate(
|
||||
candidates=[(semantic_embedding, 0.95), (breadth_depth, 0.85)],
|
||||
total_budget=3584,
|
||||
request=context_request
|
||||
)
|
||||
# Returns: {semantic_embedding: 1900, breadth_depth: 1684}
|
||||
```
|
||||
|
||||
#### StrategyExecutor
|
||||
|
||||
**Purpose**: Execute strategies in parallel with timeout and circuit breaker.
|
||||
|
||||
**Input**:
|
||||
- `allocations`: Dict mapping strategy -> allocated tokens
|
||||
- `request`: ContextRequest
|
||||
- `backends`: Available backends
|
||||
- `plan_context`: Current plan context
|
||||
|
||||
**Output**:
|
||||
- `results`: List of StrategyResult objects
|
||||
|
||||
**Features**:
|
||||
- Parallel execution with configurable workers
|
||||
- Per-strategy timeout (default 30s)
|
||||
- Circuit breaker after N failures
|
||||
- Graceful degradation on timeout
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
executor_max_workers = 4
|
||||
executor_timeout_seconds = 30
|
||||
executor_circuit_breaker_threshold = 3
|
||||
executor_circuit_breaker_reset_timeout = 60
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
executor = StrategyExecutor(max_workers=4, timeout_seconds=30)
|
||||
results = executor.execute(
|
||||
allocations={semantic_embedding: 1900, breadth_depth: 1684},
|
||||
request=context_request,
|
||||
backends=backend_set,
|
||||
plan_context=plan_context
|
||||
)
|
||||
# Returns: [StrategyResult(...), StrategyResult(...)]
|
||||
```
|
||||
|
||||
**StrategyResult**:
|
||||
```python
|
||||
@dataclass
|
||||
class StrategyResult:
|
||||
strategy_name: str
|
||||
fragments: tuple[ContextFragment, ...]
|
||||
total_fragments: int
|
||||
tokens_used: int
|
||||
execution_time_ms: float
|
||||
errors: tuple[str, ...]
|
||||
stats: dict[str, Any]
|
||||
```
|
||||
|
||||
### Phase 2: Fragment Fusion
|
||||
|
||||
#### FragmentDeduplicator
|
||||
|
||||
**Purpose**: Remove duplicate fragments based on UKO node and content hash.
|
||||
|
||||
**Input**:
|
||||
- `fragments`: List of ContextFragment objects
|
||||
- `strategy`: Deduplication strategy ("highest_relevance", "first_seen", "most_recent")
|
||||
|
||||
**Output**:
|
||||
- `deduplicated`: List of unique fragments
|
||||
|
||||
**Deduplication Rules**:
|
||||
- Same `uko_node` + same content hash = duplicate
|
||||
- Keep fragment with highest relevance score (default)
|
||||
- Merge provenance from all duplicates
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
deduplicator_strategy = "highest_relevance"
|
||||
deduplicator_merge_provenance = true
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
deduplicator = FragmentDeduplicator()
|
||||
deduplicated = deduplicator.deduplicate(
|
||||
fragments=[frag1, frag2, frag1_duplicate],
|
||||
strategy="highest_relevance"
|
||||
)
|
||||
# Returns: [frag1 (with merged provenance), frag2]
|
||||
```
|
||||
|
||||
#### DetailDepthResolver
|
||||
|
||||
**Purpose**: Resolve appropriate detail depth for each fragment.
|
||||
|
||||
**Input**:
|
||||
- `fragments`: List of ContextFragment objects
|
||||
- `budget`: ContextBudget
|
||||
- `request`: ContextRequest with desired detail level
|
||||
|
||||
**Output**:
|
||||
- `resolved`: List of fragments with adjusted detail_depth
|
||||
|
||||
**Resolution Logic**:
|
||||
1. Start with requested detail level
|
||||
2. Adjust based on token budget
|
||||
3. Respect fragment's max depth
|
||||
4. Prefer higher depth for hot tier
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
resolver_default_depth = 3
|
||||
resolver_hot_tier_boost = 2
|
||||
resolver_budget_aware = true
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
resolver = DetailDepthResolver()
|
||||
resolved = resolver.resolve(
|
||||
fragments=[frag1, frag2],
|
||||
budget=budget,
|
||||
request=context_request
|
||||
)
|
||||
# Returns: fragments with adjusted detail_depth
|
||||
```
|
||||
|
||||
#### FragmentScorer
|
||||
|
||||
**Purpose**: Score fragments based on multiple factors.
|
||||
|
||||
**Input**:
|
||||
- `fragments`: List of ContextFragment objects
|
||||
- `plan_context`: Current plan context
|
||||
- `request`: ContextRequest
|
||||
|
||||
**Output**:
|
||||
- `scored`: List of (fragment, score) tuples
|
||||
|
||||
**Scoring Factors**:
|
||||
- Relevance score (from strategy): 40%
|
||||
- Tier priority (hot > warm > cold): 30%
|
||||
- Recency (created_at): 20%
|
||||
- Plan context alignment: 10%
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
scorer_relevance_weight = 0.4
|
||||
scorer_tier_weight = 0.3
|
||||
scorer_recency_weight = 0.2
|
||||
scorer_plan_weight = 0.1
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
scorer = FragmentScorer()
|
||||
scored = scorer.score(
|
||||
fragments=[frag1, frag2],
|
||||
plan_context=plan_context,
|
||||
request=context_request
|
||||
)
|
||||
# Returns: [(frag1, 0.92), (frag2, 0.78)]
|
||||
```
|
||||
|
||||
#### BudgetPacker
|
||||
|
||||
**Purpose**: Select fragments to fit within token budget.
|
||||
|
||||
**Input**:
|
||||
- `scored_fragments`: List of (fragment, score) tuples
|
||||
- `budget`: ContextBudget
|
||||
|
||||
**Output**:
|
||||
- `packed`: List of selected fragments
|
||||
|
||||
**Packing Algorithm**:
|
||||
1. Sort fragments by score (descending)
|
||||
2. Respect tier ordering (hot → warm → cold)
|
||||
3. Greedily add fragments until budget exhausted
|
||||
4. Early termination when budget full
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
packer_tier_priority = ["hot", "warm", "cold"]
|
||||
packer_greedy = true
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
packer = BudgetPacker()
|
||||
packed = packer.pack(
|
||||
scored_fragments=[(frag1, 0.92), (frag2, 0.78)],
|
||||
budget=budget
|
||||
)
|
||||
# Returns: [frag1, frag2] (total tokens <= budget.available_tokens)
|
||||
```
|
||||
|
||||
#### FragmentOrderer
|
||||
|
||||
**Purpose**: Determine final fragment order in payload.
|
||||
|
||||
**Input**:
|
||||
- `fragments`: List of ContextFragment objects
|
||||
- `strategy`: Ordering strategy ("relevance", "recency", "tier-relevance", "custom")
|
||||
|
||||
**Output**:
|
||||
- `ordered`: List of fragments in final order
|
||||
|
||||
**Ordering Strategies**:
|
||||
- **Relevance**: By relevance_score (descending)
|
||||
- **Recency**: By created_at (descending)
|
||||
- **Tier-Relevance**: By tier (hot > warm > cold), then relevance
|
||||
- **Custom**: User-defined ordering
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
orderer_strategy = "tier-relevance"
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
orderer = FragmentOrderer()
|
||||
ordered = orderer.order(
|
||||
fragments=[frag1, frag2],
|
||||
strategy="tier-relevance"
|
||||
)
|
||||
# Returns: [hot_frag, warm_frag1, warm_frag2, cold_frag]
|
||||
```
|
||||
|
||||
### Phase 3: Context Finalization
|
||||
|
||||
#### PreambleGenerator
|
||||
|
||||
**Purpose**: Generate optional summary of assembled context.
|
||||
|
||||
**Input**:
|
||||
- `payload`: ContextPayload (before finalization)
|
||||
- `strategies_used`: Tuple of strategy names
|
||||
- `budget_used`: Fraction of budget consumed
|
||||
|
||||
**Output**:
|
||||
- `preamble`: String summary of context
|
||||
|
||||
**Preamble Contents**:
|
||||
- Number of fragments and sources
|
||||
- Token usage and budget utilization
|
||||
- Strategies used
|
||||
- Key topics covered
|
||||
- Temporal range
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
preamble_enabled = true
|
||||
preamble_include_stats = true
|
||||
preamble_max_length = 500
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
generator = PreambleGenerator()
|
||||
preamble = generator.generate(
|
||||
payload=payload,
|
||||
strategies_used=["semantic-embedding"],
|
||||
budget_used=0.57
|
||||
)
|
||||
# Returns: "Context includes 5 fragments from 3 sources..."
|
||||
```
|
||||
|
||||
#### SkeletonCompressor
|
||||
|
||||
**Purpose**: Compress context for child plans while preserving critical information.
|
||||
|
||||
**Input**:
|
||||
- `parent_context`: Parent ContextPayload
|
||||
- `child_focus`: List of focus nodes for child plan
|
||||
- `skeleton_budget`: Token budget for compressed context
|
||||
|
||||
**Output**:
|
||||
- `compressed`: Compressed ContextPayload for child plan
|
||||
|
||||
**Compression Strategy**:
|
||||
1. Identify critical fragments for child focus
|
||||
2. Remove redundant details
|
||||
3. Preserve decision context
|
||||
4. Maintain provenance
|
||||
|
||||
**Configuration**:
|
||||
```toml
|
||||
[context.strategies]
|
||||
compressor_enabled = true
|
||||
compressor_preserve_decisions = true
|
||||
compressor_preserve_hot_tier = true
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```python
|
||||
compressor = SkeletonCompressor()
|
||||
compressed = compressor.compress(
|
||||
parent_context=parent_payload,
|
||||
child_focus=["project://myapp/src/main.py"],
|
||||
skeleton_budget=1024
|
||||
)
|
||||
# Returns: compressed ContextPayload for child plan
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Complete Pipeline Flow
|
||||
|
||||
```
|
||||
ContextRequest
|
||||
↓
|
||||
StrategySelector
|
||||
↓ (candidates: [(strategy, confidence), ...])
|
||||
BudgetAllocator
|
||||
↓ (allocations: {strategy: budget, ...})
|
||||
StrategyExecutor
|
||||
↓ (results: [StrategyResult, ...])
|
||||
Merge Results
|
||||
↓ (fragments: [ContextFragment, ...])
|
||||
FragmentDeduplicator
|
||||
↓ (deduplicated: [ContextFragment, ...])
|
||||
DetailDepthResolver
|
||||
↓ (resolved: [ContextFragment, ...])
|
||||
FragmentScorer
|
||||
↓ (scored: [(ContextFragment, score), ...])
|
||||
BudgetPacker
|
||||
↓ (packed: [ContextFragment, ...])
|
||||
FragmentOrderer
|
||||
↓ (ordered: [ContextFragment, ...])
|
||||
PreambleGenerator
|
||||
↓ (preamble: str)
|
||||
SkeletonCompressor (optional)
|
||||
↓ (compressed: ContextPayload)
|
||||
ContextPayload
|
||||
```
|
||||
|
||||
### Example Data Structures
|
||||
|
||||
**ContextRequest**:
|
||||
```python
|
||||
{
|
||||
"focus_nodes": ["project://myapp/src/main.py"],
|
||||
"breadth": 2,
|
||||
"depth": 3,
|
||||
"keywords": ["async", "io"],
|
||||
"resource_types": ["source_file", "decision"],
|
||||
"detail_level": 3,
|
||||
"temporal_window": "7d",
|
||||
"strategy_hints": ["semantic-embedding"]
|
||||
}
|
||||
```
|
||||
|
||||
**StrategyResult**:
|
||||
```python
|
||||
{
|
||||
"strategy_name": "semantic-embedding",
|
||||
"fragments": [
|
||||
ContextFragment(...),
|
||||
ContextFragment(...),
|
||||
...
|
||||
],
|
||||
"total_fragments": 45,
|
||||
"tokens_used": 2048,
|
||||
"execution_time_ms": 234,
|
||||
"errors": [],
|
||||
"stats": {
|
||||
"similarity_scores": [0.95, 0.87, ...],
|
||||
"backend_queries": 3,
|
||||
"cache_hits": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ContextPayload**:
|
||||
```python
|
||||
{
|
||||
"payload_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
|
||||
"plan_id": "plan-1",
|
||||
"fragments": [
|
||||
ContextFragment(...),
|
||||
ContextFragment(...),
|
||||
...
|
||||
],
|
||||
"total_tokens": 2048,
|
||||
"budget": {
|
||||
"max_tokens": 4096,
|
||||
"reserved_tokens": 512,
|
||||
"available_tokens": 3584
|
||||
},
|
||||
"budget_used": 0.57,
|
||||
"strategies_used": ["semantic-embedding"],
|
||||
"context_hash": "abc123...",
|
||||
"preamble": "Context includes 5 fragments...",
|
||||
"provenance_map": {
|
||||
"fragment-id-1": {...},
|
||||
"fragment-id-2": {...},
|
||||
...
|
||||
},
|
||||
"assembled_at": "2024-04-19T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration and Tuning
|
||||
|
||||
### Global Configuration
|
||||
|
||||
```toml
|
||||
[context]
|
||||
max_tokens = 4096
|
||||
reserved_tokens = 512
|
||||
|
||||
[context.strategies]
|
||||
enabled = ["simple-keyword", "semantic-embedding", "breadth-depth-navigator"]
|
||||
default_strategy = "arce"
|
||||
|
||||
[context.strategies.simple-keyword]
|
||||
enabled = true
|
||||
timeout_seconds = 10
|
||||
max_fragments = 50
|
||||
|
||||
[context.strategies.semantic-embedding]
|
||||
enabled = true
|
||||
timeout_seconds = 20
|
||||
max_fragments = 100
|
||||
|
||||
[context.strategies.breadth-depth-navigator]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 150
|
||||
|
||||
[context.strategies.arce]
|
||||
enabled = true
|
||||
timeout_seconds = 45
|
||||
max_fragments = 200
|
||||
text_budget_fraction = 0.4
|
||||
vector_budget_fraction = 0.4
|
||||
graph_budget_fraction = 0.2
|
||||
```
|
||||
|
||||
### Per-Component Tuning
|
||||
|
||||
#### StrategySelector Tuning
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
selector_threshold = 0.0 # Minimum confidence to select
|
||||
max_candidates = 10 # Maximum strategies to execute
|
||||
```
|
||||
|
||||
**Tuning Tips**:
|
||||
- Increase `selector_threshold` to filter low-confidence strategies
|
||||
- Decrease `max_candidates` to reduce execution time
|
||||
|
||||
#### BudgetAllocator Tuning
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
allocator_strategy = "proportional" # "proportional", "equal", "priority"
|
||||
allocator_min_budget = 100
|
||||
```
|
||||
|
||||
**Tuning Tips**:
|
||||
- Use "proportional" for quality-aware allocation
|
||||
- Use "equal" for fair distribution
|
||||
- Use "priority" for greedy allocation
|
||||
|
||||
#### StrategyExecutor Tuning
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
executor_max_workers = 4
|
||||
executor_timeout_seconds = 30
|
||||
executor_circuit_breaker_threshold = 3
|
||||
executor_circuit_breaker_reset_timeout = 60
|
||||
```
|
||||
|
||||
**Tuning Tips**:
|
||||
- Increase `max_workers` for parallel execution (up to CPU cores)
|
||||
- Increase `timeout_seconds` for complex strategies
|
||||
- Adjust `circuit_breaker_threshold` for fault tolerance
|
||||
|
||||
#### FragmentScorer Tuning
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
scorer_relevance_weight = 0.4
|
||||
scorer_tier_weight = 0.3
|
||||
scorer_recency_weight = 0.2
|
||||
scorer_plan_weight = 0.1
|
||||
```
|
||||
|
||||
**Tuning Tips**:
|
||||
- Increase `relevance_weight` for quality-focused assembly
|
||||
- Increase `tier_weight` for tier-aware assembly
|
||||
- Increase `recency_weight` for recent-focused assembly
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
### Key Metrics
|
||||
|
||||
| Metric | Description | Target |
|
||||
|--------|-------------|--------|
|
||||
| `assembly_time_ms` | Total pipeline execution time | < 1000ms |
|
||||
| `fragments_selected` | Number of fragments in payload | 5-50 |
|
||||
| `tokens_used` | Total tokens in payload | < available_tokens |
|
||||
| `budget_used` | Fraction of budget consumed | 0.5-0.9 |
|
||||
| `avg_relevance` | Average relevance score | > 0.7 |
|
||||
| `strategy_success_rate` | Fraction of successful strategies | > 0.8 |
|
||||
| `dedup_ratio` | Fraction of duplicates removed | 0.0-0.3 |
|
||||
|
||||
### Logging
|
||||
|
||||
Enable debug logging:
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logging.getLogger("cleveragents.acms").setLevel(logging.DEBUG)
|
||||
```
|
||||
|
||||
### Metrics Collection
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.acms_service import ACMSPipeline
|
||||
|
||||
pipeline = ACMSPipeline()
|
||||
payload = pipeline.assemble(plan_id, fragments, budget)
|
||||
|
||||
# Collect metrics
|
||||
metrics = {
|
||||
"payload_id": payload.payload_id,
|
||||
"plan_id": payload.plan_id,
|
||||
"total_tokens": payload.total_tokens,
|
||||
"budget_used": payload.budget_used,
|
||||
"fragments_count": len(payload.fragments),
|
||||
"strategies_used": payload.strategies_used,
|
||||
"avg_relevance": sum(f.relevance_score for f in payload.fragments) / len(payload.fragments),
|
||||
"tier_distribution": {
|
||||
"hot": sum(1 for f in payload.fragments if f.tier == "hot"),
|
||||
"warm": sum(1 for f in payload.fragments if f.tier == "warm"),
|
||||
"cold": sum(1 for f in payload.fragments if f.tier == "cold"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Strategy Selection Optimization
|
||||
|
||||
```python
|
||||
# Good: Filter low-confidence strategies
|
||||
candidates = [
|
||||
(s, conf) for s, conf in candidates if conf >= 0.7
|
||||
]
|
||||
|
||||
# Avoid: Execute all strategies
|
||||
candidates = all_strategies
|
||||
```
|
||||
|
||||
### Budget Allocation Optimization
|
||||
|
||||
```python
|
||||
# Good: Proportional allocation
|
||||
allocations = allocator.allocate(
|
||||
candidates=high_confidence,
|
||||
total_budget=3584,
|
||||
strategy="proportional"
|
||||
)
|
||||
|
||||
# Avoid: Equal allocation
|
||||
allocations = {s: 3584 // len(strategies) for s in strategies}
|
||||
```
|
||||
|
||||
### Execution Optimization
|
||||
|
||||
```python
|
||||
# Good: Parallel execution with reasonable timeout
|
||||
executor = StrategyExecutor(max_workers=4, timeout_seconds=30)
|
||||
|
||||
# Avoid: Sequential execution or excessive timeout
|
||||
executor = StrategyExecutor(max_workers=1, timeout_seconds=300)
|
||||
```
|
||||
|
||||
### Fragment Deduplication Optimization
|
||||
|
||||
```python
|
||||
# Good: Deduplicate early
|
||||
deduplicated = deduplicator.deduplicate(fragments)
|
||||
scored = scorer.score(deduplicated, plan_context)
|
||||
|
||||
# Avoid: Deduplicate after scoring
|
||||
scored = scorer.score(fragments, plan_context)
|
||||
deduplicated = deduplicator.deduplicate(scored)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Slow Pipeline Execution
|
||||
|
||||
**Problem**: Pipeline takes > 1 second.
|
||||
|
||||
**Solution**:
|
||||
1. Check `executor_timeout_seconds` - reduce if too high
|
||||
2. Check `executor_max_workers` - increase if too low
|
||||
3. Check strategy complexity - use simpler strategies
|
||||
4. Check fragment count - reduce `max_fragments`
|
||||
|
||||
### Low Quality Context
|
||||
|
||||
**Problem**: Assembled context is not relevant.
|
||||
|
||||
**Solution**:
|
||||
1. Increase `selector_threshold` to filter low-confidence strategies
|
||||
2. Use higher-quality strategy (e.g., ARCE)
|
||||
3. Increase `scorer_relevance_weight` for quality focus
|
||||
4. Adjust strategy-specific parameters
|
||||
|
||||
### Out of Memory
|
||||
|
||||
**Problem**: Pipeline consumes too much memory.
|
||||
|
||||
**Solution**:
|
||||
1. Reduce `max_fragments` limit
|
||||
2. Reduce `executor_max_workers` for parallel execution
|
||||
3. Enable fragment streaming
|
||||
4. Use simpler strategies
|
||||
|
||||
### Budget Exceeded
|
||||
|
||||
**Problem**: Assembled context exceeds budget.
|
||||
|
||||
**Solution**:
|
||||
1. Check `BudgetPacker` implementation
|
||||
2. Reduce `max_fragments` limit
|
||||
3. Increase `reserved_tokens` to reduce available budget
|
||||
4. Enable detail depth reduction
|
||||
|
||||
## See Also
|
||||
|
||||
- [Context Management Deep Dive](../guides/context_management_deep_dive.md)
|
||||
- [Context Strategies Reference](./context_strategies_reference.md)
|
||||
- [ACMS v1 Context Assembly Pipeline](./acms.md)
|
||||
- [Context Strategy Registry](./context_strategies.md)
|
||||
@@ -0,0 +1,750 @@
|
||||
# Context Strategies Reference
|
||||
|
||||
Complete reference for all context strategies in the ACMS, including configuration options, performance characteristics, and use case recommendations.
|
||||
|
||||
## Strategy Overview
|
||||
|
||||
| Strategy | Quality | Speed | Coverage | Backends | Best For |
|
||||
|----------|---------|-------|----------|----------|----------|
|
||||
| Simple Keyword | 0.3 | ⚡⚡⚡ | Narrow | Text | Quick searches, fallback |
|
||||
| Semantic Embedding | 0.6 | ⚡⚡ | Broad | Vector | Semantic similarity |
|
||||
| Breadth-Depth Navigator | 0.85 | ⚡ | Very Broad | Graph | Comprehensive context |
|
||||
| ARCE | 0.95 | 🐢 | Comprehensive | All | Production use |
|
||||
| Temporal Archaeology | 0.5 | 🐢 | Historical | Graph + Temporal | Historical context |
|
||||
| Plan-Decision Context | 0.7 | ⚡ | Hierarchical | Temporal + Graph | Plan coordination |
|
||||
|
||||
## Simple Keyword Strategy
|
||||
|
||||
### Overview
|
||||
|
||||
The Simple Keyword Strategy performs text-based keyword search using the TextBackend. It's the fastest strategy and serves as a fallback when other backends are unavailable.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.3** (baseline)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: TextBackend
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Extract keywords from the ContextRequest
|
||||
2. Query TextBackend using keyword search
|
||||
3. Rank results by match frequency and relevance
|
||||
4. Pack greedily into token budget
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.simple-keyword]
|
||||
enabled = true
|
||||
timeout_seconds = 10
|
||||
max_fragments = 50
|
||||
keyword_boost_factor = 1.5
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | true | Enable this strategy |
|
||||
| `timeout_seconds` | int | 10 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 50 | Maximum fragments returned |
|
||||
| `keyword_boost_factor` | float | 1.5 | Boost for exact keyword matches |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 50-200ms (typical)
|
||||
- **Memory Usage**: Low (streaming results)
|
||||
- **Scalability**: Excellent (linear with keyword count)
|
||||
- **Parallelization**: Not applicable (single-threaded)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Quick searches with clear keywords
|
||||
- Projects with good text indexing
|
||||
- Fallback when other backends unavailable
|
||||
- Real-time context assembly with tight latency budgets
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.acms_service import ACMSPipeline
|
||||
|
||||
pipeline = ACMSPipeline()
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="simple-keyword"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- Limited to exact keyword matches
|
||||
- No semantic understanding
|
||||
- Cannot traverse relationships
|
||||
- Requires good text indexing
|
||||
|
||||
## Semantic Embedding Strategy
|
||||
|
||||
### Overview
|
||||
|
||||
The Semantic Embedding Strategy uses vector similarity search to find semantically related context. It uses character-frequency embeddings as a v1 approximation.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.6** (good)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: VectorBackend
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Embed the ContextRequest using character-frequency model
|
||||
2. Query VectorBackend for similar embeddings
|
||||
3. Rank by cosine similarity
|
||||
4. Pack budget-aware results
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.semantic-embedding]
|
||||
enabled = true
|
||||
timeout_seconds = 20
|
||||
max_fragments = 100
|
||||
similarity_threshold = 0.5
|
||||
embedding_model = "character-frequency-v1"
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | true | Enable this strategy |
|
||||
| `timeout_seconds` | int | 20 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 100 | Maximum fragments returned |
|
||||
| `similarity_threshold` | float | 0.5 | Minimum similarity score (0.0-1.0) |
|
||||
| `embedding_model` | str | "character-frequency-v1" | Embedding model to use |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 100-500ms (typical)
|
||||
- **Memory Usage**: Medium (embedding cache)
|
||||
- **Scalability**: Good (logarithmic with vector index size)
|
||||
- **Parallelization**: Supported (multiple similarity searches)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Semantic similarity searches
|
||||
- Conceptual relationships
|
||||
- Cross-domain context discovery
|
||||
- Finding related code patterns
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.context_fragment import ContextRequest
|
||||
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"],
|
||||
keywords=["async", "io"]
|
||||
)
|
||||
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="semantic-embedding"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- v1 uses character-frequency embeddings (not true semantic)
|
||||
- Requires VectorBackend
|
||||
- Cannot traverse relationships
|
||||
- Sensitive to embedding quality
|
||||
|
||||
### Future Improvements
|
||||
|
||||
- Integration with real embedding models (e.g., OpenAI, Anthropic)
|
||||
- Fine-tuned embeddings for code
|
||||
- Hybrid semantic-keyword search
|
||||
|
||||
## Breadth-Depth Navigator Strategy
|
||||
|
||||
### Overview
|
||||
|
||||
The Breadth-Depth Navigator Strategy traverses the knowledge graph to find related context. It explores outward (breadth) and downward (depth) from focus nodes.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.85** (excellent)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: GraphBackend
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Start from focus nodes in ContextRequest
|
||||
2. Traverse graph outward by breadth hops
|
||||
3. Traverse downward by depth hops
|
||||
4. Collect all reachable nodes
|
||||
5. Rank by distance and relevance
|
||||
6. Pack into budget
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.breadth-depth-navigator]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 150
|
||||
default_breadth = 2
|
||||
default_depth = 3
|
||||
distance_decay = 0.8
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | true | Enable this strategy |
|
||||
| `timeout_seconds` | int | 30 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 150 | Maximum fragments returned |
|
||||
| `default_breadth` | int | 2 | Default breadth hops |
|
||||
| `default_depth` | int | 3 | Default depth hops |
|
||||
| `distance_decay` | float | 0.8 | Decay factor per hop |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 200-1000ms (typical)
|
||||
- **Memory Usage**: Medium (graph traversal state)
|
||||
- **Scalability**: Good (exponential with breadth/depth)
|
||||
- **Parallelization**: Supported (parallel hop traversal)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Exploring related code and decisions
|
||||
- Understanding dependencies
|
||||
- Comprehensive context assembly
|
||||
- Finding transitive relationships
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"],
|
||||
breadth=2,
|
||||
depth=3
|
||||
)
|
||||
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="breadth-depth-navigator"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- Requires GraphBackend
|
||||
- Can be slow with large graphs
|
||||
- Exponential complexity with breadth/depth
|
||||
- May include irrelevant distant nodes
|
||||
|
||||
### Optimization Tips
|
||||
|
||||
- Reduce breadth/depth for faster execution
|
||||
- Use distance decay to prioritize nearby nodes
|
||||
- Filter by resource type to reduce graph size
|
||||
- Increase timeout for large graphs
|
||||
|
||||
## ARCE Strategy (Advanced Retrieval with Context Enrichment)
|
||||
|
||||
### Overview
|
||||
|
||||
ARCE is the most comprehensive strategy, combining text search, vector similarity, and graph traversal. It's the recommended strategy for production use cases.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.95** (highest)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: TextBackend, VectorBackend, GraphBackend
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Phase 1 (40% budget)**: Text search using keywords
|
||||
2. **Phase 2 (40% budget)**: Vector similarity search
|
||||
3. **Phase 3 (20% budget)**: Graph traversal from results
|
||||
4. Merge and deduplicate results
|
||||
5. Rank by combined score
|
||||
6. Pack into budget
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.arce]
|
||||
enabled = true
|
||||
timeout_seconds = 45
|
||||
max_fragments = 200
|
||||
text_budget_fraction = 0.4
|
||||
vector_budget_fraction = 0.4
|
||||
graph_budget_fraction = 0.2
|
||||
dedup_strategy = "highest_relevance"
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | true | Enable this strategy |
|
||||
| `timeout_seconds` | int | 45 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 200 | Maximum fragments returned |
|
||||
| `text_budget_fraction` | float | 0.4 | Budget for text search |
|
||||
| `vector_budget_fraction` | float | 0.4 | Budget for vector search |
|
||||
| `graph_budget_fraction` | float | 0.2 | Budget for graph traversal |
|
||||
| `dedup_strategy` | str | "highest_relevance" | Deduplication strategy |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 500-2000ms (typical)
|
||||
- **Memory Usage**: High (multiple result sets)
|
||||
- **Scalability**: Good (parallel phases)
|
||||
- **Parallelization**: Excellent (3 phases in parallel)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Comprehensive context assembly
|
||||
- Multi-modal queries
|
||||
- Production use cases
|
||||
- High-quality context requirements
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"],
|
||||
keywords=["async", "io"],
|
||||
breadth=2
|
||||
)
|
||||
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="arce"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- Requires all three backends
|
||||
- Slower than single-backend strategies
|
||||
- Higher memory usage
|
||||
- May return too many fragments
|
||||
|
||||
### Optimization Tips
|
||||
|
||||
- Adjust budget fractions based on query type
|
||||
- Increase timeout for complex queries
|
||||
- Use deduplication to reduce redundancy
|
||||
- Filter by resource type to reduce results
|
||||
|
||||
## Temporal Archaeology Strategy
|
||||
|
||||
### Overview
|
||||
|
||||
The Temporal Archaeology Strategy retrieves historical context from the cold tier and traverses relationships from historical nodes.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.5** (moderate)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: GraphBackend, TemporalBackend (cold tier)
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Query TemporalBackend for historical nodes
|
||||
2. Filter by temporal window
|
||||
3. Traverse graph from historical nodes
|
||||
4. Collect related current nodes
|
||||
5. Rank by recency and relevance
|
||||
6. Pack into budget
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.temporal-archaeology]
|
||||
enabled = false
|
||||
timeout_seconds = 60
|
||||
max_fragments = 100
|
||||
default_temporal_window = "7d"
|
||||
include_current_context = true
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | false | Enable this strategy |
|
||||
| `timeout_seconds` | int | 60 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 100 | Maximum fragments returned |
|
||||
| `default_temporal_window` | str | "7d" | Default time window |
|
||||
| `include_current_context` | bool | true | Include current context |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 1000-5000ms (typical)
|
||||
- **Memory Usage**: High (temporal queries)
|
||||
- **Scalability**: Fair (depends on cold tier size)
|
||||
- **Parallelization**: Limited (sequential phases)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Understanding historical context
|
||||
- Decision archaeology
|
||||
- Long-term project evolution
|
||||
- Regression analysis
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"],
|
||||
temporal_window="30d"
|
||||
)
|
||||
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="temporal-archaeology"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- Requires cold tier (not always available)
|
||||
- Slow execution
|
||||
- May include outdated information
|
||||
- Limited to historical data
|
||||
|
||||
### Temporal Window Format
|
||||
|
||||
- `"1d"` - Last 1 day
|
||||
- `"7d"` - Last 7 days
|
||||
- `"30d"` - Last 30 days
|
||||
- `"90d"` - Last 90 days
|
||||
- `"1y"` - Last 1 year
|
||||
- `"all"` - All history
|
||||
|
||||
## Plan-Decision Context Strategy
|
||||
|
||||
### Overview
|
||||
|
||||
The Plan-Decision Context Strategy walks the plan hierarchy to retrieve decision records and related context.
|
||||
|
||||
### Quality Score
|
||||
|
||||
**0.7** (good)
|
||||
|
||||
### Backend Requirements
|
||||
|
||||
- **Required**: TemporalBackend (warm/cold), GraphBackend
|
||||
- **Optional**: None
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Walk parent and ancestor plan hierarchy
|
||||
2. Retrieve decision records from warm/cold tiers
|
||||
3. Traverse graph from decisions
|
||||
4. Collect related context
|
||||
5. Rank by plan proximity and relevance
|
||||
6. Pack into budget
|
||||
|
||||
### Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies.plan-decision-context]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 100
|
||||
include_ancestor_decisions = true
|
||||
max_ancestor_depth = 5
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `enabled` | bool | true | Enable this strategy |
|
||||
| `timeout_seconds` | int | 30 | Per-strategy timeout |
|
||||
| `max_fragments` | int | 100 | Maximum fragments returned |
|
||||
| `include_ancestor_decisions` | bool | true | Include ancestor decisions |
|
||||
| `max_ancestor_depth` | int | 5 | Maximum ancestor levels |
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
- **Execution Time**: 200-800ms (typical)
|
||||
- **Memory Usage**: Medium (plan hierarchy)
|
||||
- **Scalability**: Good (linear with plan depth)
|
||||
- **Parallelization**: Supported (parallel ancestor traversal)
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Understanding plan context
|
||||
- Decision inheritance
|
||||
- Multi-level plan coordination
|
||||
- Plan dependency analysis
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
request = ContextRequest(
|
||||
focus_nodes=["project://myapp/src/main.py"]
|
||||
)
|
||||
|
||||
payload = pipeline.assemble(
|
||||
plan_id="plan-1",
|
||||
fragments=fragments,
|
||||
budget=ContextBudget(max_tokens=4096, reserved_tokens=512),
|
||||
strategy="plan-decision-context"
|
||||
)
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- Requires plan hierarchy
|
||||
- Limited to decision context
|
||||
- May miss non-decision context
|
||||
- Depends on plan structure
|
||||
|
||||
## Strategy Selection Guide
|
||||
|
||||
### When to Use Each Strategy
|
||||
|
||||
#### Simple Keyword
|
||||
- ✅ Quick searches with clear keywords
|
||||
- ✅ Fallback when other backends unavailable
|
||||
- ✅ Real-time context with tight latency budgets
|
||||
- ❌ Semantic understanding needed
|
||||
- ❌ Relationship traversal needed
|
||||
|
||||
#### Semantic Embedding
|
||||
- ✅ Semantic similarity searches
|
||||
- ✅ Conceptual relationships
|
||||
- ✅ Cross-domain discovery
|
||||
- ❌ Exact keyword matching needed
|
||||
- ❌ Relationship traversal needed
|
||||
|
||||
#### Breadth-Depth Navigator
|
||||
- ✅ Exploring related code
|
||||
- ✅ Understanding dependencies
|
||||
- ✅ Comprehensive context
|
||||
- ❌ Quick searches needed
|
||||
- ❌ Historical context needed
|
||||
|
||||
#### ARCE
|
||||
- ✅ Comprehensive context assembly
|
||||
- ✅ Multi-modal queries
|
||||
- ✅ Production use cases
|
||||
- ❌ Quick searches needed
|
||||
- ❌ Limited backends available
|
||||
|
||||
#### Temporal Archaeology
|
||||
- ✅ Historical context
|
||||
- ✅ Decision archaeology
|
||||
- ✅ Long-term evolution
|
||||
- ❌ Current context needed
|
||||
- ❌ Quick searches needed
|
||||
|
||||
#### Plan-Decision Context
|
||||
- ✅ Plan coordination
|
||||
- ✅ Decision inheritance
|
||||
- ✅ Multi-level plans
|
||||
- ❌ Non-decision context needed
|
||||
- ❌ No plan hierarchy
|
||||
|
||||
### Fallback Chain
|
||||
|
||||
When a strategy fails, the system falls back to simpler strategies:
|
||||
|
||||
```
|
||||
ARCE (0.95)
|
||||
↓ (if unavailable)
|
||||
Breadth-Depth Navigator (0.85)
|
||||
↓ (if unavailable)
|
||||
Semantic Embedding (0.6)
|
||||
↓ (if unavailable)
|
||||
Simple Keyword (0.3)
|
||||
```
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
### Execution Time
|
||||
|
||||
```
|
||||
Simple Keyword: ████ 50-200ms
|
||||
Semantic Embedding: ██████████ 100-500ms
|
||||
Breadth-Depth: ███████████████ 200-1000ms
|
||||
Plan-Decision: ██████████ 200-800ms
|
||||
ARCE: ████████████████████ 500-2000ms
|
||||
Temporal Archaeology: ████████████████████████ 1000-5000ms
|
||||
```
|
||||
|
||||
### Memory Usage
|
||||
|
||||
```
|
||||
Simple Keyword: ██ Low
|
||||
Semantic Embedding: ████ Medium
|
||||
Breadth-Depth: ████ Medium
|
||||
Plan-Decision: ████ Medium
|
||||
ARCE: ██████ High
|
||||
Temporal Archaeology: ██████ High
|
||||
```
|
||||
|
||||
### Coverage
|
||||
|
||||
```
|
||||
Simple Keyword: ██ Narrow
|
||||
Temporal Archaeology: ███ Moderate
|
||||
Semantic Embedding: ████ Broad
|
||||
Plan-Decision: ████ Hierarchical
|
||||
Breadth-Depth: █████ Very Broad
|
||||
ARCE: ██████ Comprehensive
|
||||
```
|
||||
|
||||
## Configuration Best Practices
|
||||
|
||||
### Global Configuration
|
||||
|
||||
```toml
|
||||
[context.strategies]
|
||||
enabled = ["simple-keyword", "semantic-embedding", "breadth-depth-navigator"]
|
||||
default_strategy = "arce"
|
||||
fallback_chain = ["arce", "breadth-depth-navigator", "semantic-embedding", "simple-keyword"]
|
||||
|
||||
[context.strategies.simple-keyword]
|
||||
enabled = true
|
||||
timeout_seconds = 10
|
||||
max_fragments = 50
|
||||
|
||||
[context.strategies.semantic-embedding]
|
||||
enabled = true
|
||||
timeout_seconds = 20
|
||||
max_fragments = 100
|
||||
|
||||
[context.strategies.breadth-depth-navigator]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 150
|
||||
|
||||
[context.strategies.arce]
|
||||
enabled = true
|
||||
timeout_seconds = 45
|
||||
max_fragments = 200
|
||||
|
||||
[context.strategies.plan-decision-context]
|
||||
enabled = true
|
||||
timeout_seconds = 30
|
||||
max_fragments = 100
|
||||
```
|
||||
|
||||
### Per-Project Overrides
|
||||
|
||||
```bash
|
||||
# Set strategies for a project
|
||||
agents project context set \
|
||||
--strategy simple-keyword \
|
||||
--strategy semantic-embedding \
|
||||
--strategy breadth-depth-navigator
|
||||
|
||||
# View current strategies
|
||||
agents project context list
|
||||
```
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
### Key Metrics
|
||||
|
||||
- **Execution Time**: Strategy execution wall-clock time
|
||||
- **Fragment Count**: Number of fragments returned
|
||||
- **Token Usage**: Total tokens in assembled context
|
||||
- **Budget Utilization**: Percentage of budget used
|
||||
- **Relevance Score**: Average relevance of fragments
|
||||
- **Tier Distribution**: Hot/warm/cold fragment counts
|
||||
|
||||
### Logging
|
||||
|
||||
Enable debug logging to monitor strategy execution:
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logging.getLogger("cleveragents.acms").setLevel(logging.DEBUG)
|
||||
```
|
||||
|
||||
### Example Metrics Output
|
||||
|
||||
```
|
||||
Strategy: semantic-embedding
|
||||
Execution Time: 234ms
|
||||
Fragments: 12
|
||||
Tokens: 2048
|
||||
Budget Used: 57%
|
||||
Avg Relevance: 0.82
|
||||
Tier Distribution: hot=2, warm=8, cold=2
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Strategy Not Selected
|
||||
|
||||
**Problem**: Expected strategy not selected.
|
||||
|
||||
**Solution**:
|
||||
1. Check strategy is enabled in configuration
|
||||
2. Verify `can_handle()` returns confidence > 0
|
||||
3. Check required backends are available
|
||||
4. Review strategy selection logs
|
||||
|
||||
### Slow Execution
|
||||
|
||||
**Problem**: Strategy takes too long.
|
||||
|
||||
**Solution**:
|
||||
1. Reduce `max_fragments` limit
|
||||
2. Decrease `breadth` and `depth` parameters
|
||||
3. Increase `timeout_seconds` if appropriate
|
||||
4. Switch to faster strategy
|
||||
|
||||
### Low Quality Results
|
||||
|
||||
**Problem**: Assembled context is not relevant.
|
||||
|
||||
**Solution**:
|
||||
1. Try higher-quality strategy (e.g., ARCE)
|
||||
2. Adjust `similarity_threshold` for semantic strategy
|
||||
3. Increase `breadth` and `depth` for navigator
|
||||
4. Provide better keywords in request
|
||||
|
||||
### Out of Memory
|
||||
|
||||
**Problem**: Strategy consumes too much memory.
|
||||
|
||||
**Solution**:
|
||||
1. Reduce `max_fragments` limit
|
||||
2. Switch to lower-memory strategy
|
||||
3. Reduce `breadth` and `depth` parameters
|
||||
4. Enable fragment streaming
|
||||
|
||||
## See Also
|
||||
|
||||
- [Context Management Deep Dive](../guides/context_management_deep_dive.md)
|
||||
- [ACMS Pipeline Reference](./acms_pipeline_reference.md)
|
||||
- [ACMS v1 Context Assembly Pipeline](./acms.md)
|
||||
- [Context Strategy Registry](./context_strategies.md)
|
||||
Reference in New Issue
Block a user