Skip to main content

agent-context-memory

Implements context window management and memory architectures for LLM agents including token budgeting, sliding window strategies, summarization fallbacks, cross-turn state persistence, and external vector store integration.

설치로 이동

소스 정보

저장소
paulpas/agent-skill-router
최근 소스 활동
2026년 6월 4일 23:31
감지된 SKILL.md 언어
영어
스타
4
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
agent-context-memory
description
Implements context window management and memory architectures for LLM agents including token budgeting, sliding window strategies, summarization fallbacks, cross-turn state persistence, and external vector store integration.
license
MIT
compatibility
opencode
metadata
{"version":"1.0.0","domain":"agent","triggers":"context window management, memory architecture, token budgeting, sliding window, conversation summary, cross-turn state, long-term memory, short-term memory","role":"implementation","scope":"implementation","output-format":"code","content-types":["code","guidance","do-dont"],"related-skills":"observability-patterns, agentic-evaluation, multi-agent-orchestration","archetypes":["tactical","strategic"],"anti_triggers":"brainstorming, vague ideation","response_profile":{"verbosity":"low","directive_strength":"high","abstraction_level":"operational"}}
# Agent Context and Memory Management Manages context windows and memory architectures for LLM agents to prevent token overflow, preserve critical state across turns, and retrieve relevant information efficiently. Implements token budgeting, sliding window strategies, summarization fallbacks, cross-turn persistence, and vector store integration. ## TL;DR Checklist - [ ] Initialize a token budget manager before the first agent step - [ ] Implement sliding window that preserves system prompt while trimming conversation history - [ ] Configure summarization fallback when approaching context limits - [ ] Cross-reference external memory store for relevant prior state - [ ] Apply relevance threshold filtering to all vector retrievals - [ ] Serialize and merge cross-turn agent state with deterministic merge rules --- ## When to Use Use this skill when: - Building multi-turn agents where conversation history exceeds token limits (e.g., long-running research or coding agents) - Need persistent state across agent invocations (session-based workflows that span multiple requests) - Agent loses critical context after N turns due to sliding window truncation, causing repetitive or inconsistent behavior - Designing an agent that references external knowledge bases during execution and needs to merge retrieved facts into context - Building agents with strict cost constraints where unbounded context growth leads to runaway API costs - Implementing long-running task completion (e.g., multi-step data analysis) where early-turn decisions must be remembered --- ## When NOT to Use Avoid this skill for: - Production monitoring and tracing — use `observability-patterns` instead - Debugging agent failures or root cause analysis — use `agent-debugging` instead - Multi-agent coordination and task routing — use `multi-agent-orchestration` instead - Simple single-turn query answering where context never exceeds limits — the overhead is unnecessary --- ## Core Workflow 1. **Initialize Token Budget** — Create a budget manager tracking input tokens, output tokens, and remaining context before each agent invocation. Include system prompt token count as a fixed cost. **Checkpoint:** Budget must be checked BEFORE every LLM call, not after. 2. **Implement Sliding Window Strategy** — Configure which parts of the conversation to preserve (system prompt, recent messages) vs trim (older turns). Use token-based trimming rather than message-count-based. **Checkpoint:** Always preserve the system prompt and the user's most recent input. Never truncate mid-thought. 3. **Configure Summarization Fallback** — When the sliding window approach still exceeds limits, trigger a summarization pass using a separate LLM call to condense trimmed context into a summary paragraph. **Checkpoint:** The summary must include key decisions made and current task state, not just a text compression. 4. **Integrate External Memory Store** — For cross-turn or cross-session persistence, implement vector store retrieval that fetches relevant prior state based on the current query. Use semantic similarity for retrieval. **Checkpoint:** Only retrieve memories relevant to the current task — include a relevance filter threshold (e.g., cosine similarity > 0.7). --- ## Implementation Patterns ### Pattern 1: Token Budget Manager A token budget manager tracks per-step and total token consumption, enforces hard limits before each LLM call, and provides cost estimation from token counts. It treats the system prompt as a fixed overhead that must be accounted for in every budget check. ```python """Token budget management for LLM agent context windows.""" from dataclasses import dataclass, field from enum import Enum import time class BudgetAction(Enum): """Action to take when budget is exceeded.""" STOP = "stop" # Raise an error and halt the agent step SUMMARIZE = "summarize" # Trigger summarization fallback TRIM = "trim" # Apply sliding window trim @dataclass class TokenUsage: """Tracks token consumption for a single operation.""" input_tokens: int = 0 output_tokens: int = 0 system_prompt_tokens: int = 0 @property def total_tokens(self) -> int: return self.input_tokens + self.output_tokens @property def remaining_input_tokens(self) -> int: return max(0, self.max_input_tokens - self.input_tokens) @property def utilization_ratio(self) -> float: if self.max_input_tokens == 0: return 1.0 return self.input_tokens / self.max_input_tokens # Fixed per-model costs (override in config) max_input_tokens: int = 8192 max_output_tokens: int = 4096 @dataclass class StepBudgetResult: """Result of a budget check before an LLM call.""" allowed: bool remaining_input_tokens: int utilization_ratio: float action_hint: BudgetAction | None = None message: str = "" class TokenBudgetManager: """ Manages token budgets for agent steps, enforcing hard limits before each LLM call to prevent context overflow and cost runaway. Usage: manager = TokenBudgetManager(max_input_tokens=8192) manager.record_system_prompt(system_prompt_text) # Before every LLM call: result = manager.check_budget(conversation_messages, estimated_output=500) if not result.allowed: context = manager.apply_fallback_strategy() result = manager.check_budget(context, estimated_output=500) """ def __init__( self, max_input_tokens: int = 8192, max_output_tokens: int = 4096, safety_margin_ratio: float = 0.1, on_exceed: BudgetAction = BudgetAction.TRIM, ) -> None: self.max_input_tokens = max_input_tokens self.max_output_tokens = max_output_tokens self.safety_margin = max_input_tokens * safety_margin_ratio self.on_exceed = on_exceed self._system_prompt_tokens: int = 0 self._cumulative_input_tokens: int = 0 self._cumulative_output_tokens: int = 0 self._step_start_time: float | None = None self._step_token_count: int = 0 def record_system_prompt(self, prompt_text: str, token_estimator: object) -> None: """ Register the system prompt token count as a fixed overhead. Args: prompt_text: The system prompt string (used for logging). token_estimator: An object with an estimate_tokens(text: str) -> int method. Can be tiktoken.Encoding or any compatible estimator. """ self._system_prompt_tokens = token_estimator.estimate_tokens(prompt_text) def count_conversation_tokens( self, messages: list[dict[str, str]], token_estimator: object ) -> int: """Count total tokens for a list of message dicts with 'content' keys.""" total = 0 for msg in messages: content = msg.get("content", "") if content: total += token_estimator.estimate_tokens(content) return total def check_budget( self, conversation_messages: list[dict[str, str]], estimated_output_tokens: int = 0, ) -> StepBudgetResult: """ Check whether the proposed LLM call fits within budget. This MUST be called before every LLM call, not just at startup. Accounts for system prompt overhead plus conversation tokens. Args: conversation_messages: List of message dicts with 'role' and 'content'. estimated_output_tokens: Expected output token count for this step. Returns: StepBudgetResult indicating if the call is allowed and what action to take. """ conversation_tokens = self.count_conversation_tokens( conversation_messages, type("Est", (), {"estimate_tokens": lambda _, t: len(t.split())})() # placeholder — use real estimator in production ) required_input = self._system_prompt_tokens + conversation_tokens remaining = self.max_input_tokens - required_input utilization = required_input / self.max_input_tokens if self.max_input_tokens > 0 else 1.0 headroom = remaining - estimated_output_tokens if headroom >= 0 and required_input <= (self.max_input_tokens - self.safety_margin): return StepBudgetResult( allowed=True, remaining_input_tokens=remaining, utilization_ratio=round(utilization, 3), ) # Budget exceeded — determine fallback action if headroom < 0: message = ( f"Context budget exceeded by {abs(headroom)} tokens " f"(system: {self._system_prompt_tokens}, conversation: {conversation_tokens}). " f"Estimated output: {estimated_output_tokens}." ) else: message = ( f"Context approaching limit ({utilization * 100:.0f}% utilized), " f"safety margin breached. Remaining input: {remaining} tokens." ) return StepBudgetResult( allowed=False, remaining_input_tokens=max(0, remaining), utilization_ratio=round(utilization, 3), action_hint=self.on_exceed, message=message, ) def record_step_usage(self, input_token_count: int, output_token_count: int) -> None: """Record token usage after an LLM call completes.""" self._cumulative_input_tokens += input_token_count self._cumulative_output_tokens += output_token_count self._step_token_count = input_token_count + output_token_count @property def total_tokens_consumed(self) -> int: return self._cumulative_input_tokens + self._cumulative_output_tokens def get_cost_estimate( self, input_price_per_million: float = 1.50, output_price_per_million: float = 6.00, ) -> dict[str, float]: """Estimate cumulative cost based on token usage and model pricing.""" input_cost = (self._cumulative_input_tokens / 1_000_000) * input_price_per_million output_cost = (self._cumulative_output_tokens / 1_000_000) * output_price_per_million return { "input_cost_usd": round(input_cost, 4), "output_cost_usd": round(output_cost, 4), "total_cost_usd": round(input_cost + output_cost, 4), } ``` ### Pattern 2: Sliding Window with Token-Aware Trimming Trims conversation history based on token counts rather than message counts. Always preserves the system prompt and the user's most recent input. Handles variable-length messages efficiently by trimming from the oldest turn backward. ```python """Sliding window strategy for context window management.""" from dataclasses import dataclass from typing import Protocol class TokenEstimator(Protocol): """Interface for counting tokens in text.""" def estimate_tokens(self, text: str) -> int: ... @dataclass(frozen=True) class WindowConfig: """Configuration for the sliding window strategy.""" max_tokens: int = 8192 min_recent_messages: int = 3 # Always keep at least N recent messages preserve_system_prompt: bool = True trim_strategy: str = "token_weighted" # "token_weighted" or "message_rounds" class SlidingWindowManager: """ Implements token-aware sliding window trimming for conversation history. Key behaviors: - Always preserves system prompt (stored separately) - Always preserves the user's most recent input - Trims from oldest turn backward using token-based thresholds - Never truncates mid-thought — trims at message boundaries Usage: window = SlidingWindowManager() window.set_system_prompt(system_text, estimator) context = window.apply(messages, conversation, config) """ def __init__(self) -> None: self._system_prompt: str = "" self._system_tokens: int = 0 def set_system_prompt(self, prompt: str, estimator: TokenEstimator) -> None: """Register system prompt and count its token overhead.""" self._system_prompt = prompt self._system_tokens = estimator.estimate_tokens(prompt) def apply( self, conversation_messages: list[dict[str, str]], config: WindowConfig | None = None, estimator: TokenEstimator | None = None, ) -> list[dict[str, str]]: """ Apply sliding window to trim conversation while preserving critical context. Args: conversation_messages: Full list of message dicts with 'role' and 'content'. config: Window trimming configuration. Defaults to max 8192 tokens. estimator: Token counting function. Required if token-based trim is used. Returns: Trimmed list of messages that fits within the configured token budget. """ if config is None: config = WindowConfig() result_messages: list[dict[str, str]] = [] # Step 1: Always include system prompt at the top if self._system_prompt and config.preserve_system_prompt: result_messages.append({"role": "system", "content": self._system_prompt}) # Step 2: Separate user's most recent input from the rest recent_user_message: dict[str, str] | None = None earlier_messages: list[dict[str, str]] = [] for msg in conversation_messages: if msg.get("role") == "user": recent_user_message = msg else: earlier_messages.append(msg) # Step 3: Count tokens for the buffer (system + earlier messages) total_tokens = self._system_tokens buffered: list[dict[str, str]] = [] for msg in earlier_messages: msg_tokens = estimator.estimate_tokens(msg.get("content", "")) if estimator else len(msg.get("content", "").split()) # Add message only if it fits within budget if total_tokens + msg_tokens <= config.max_tokens - self._system_tokens: buffered.append(msg) total_tokens += msg_tokens elif not result_messages: # At least include the message to avoid empty context buffered.append(msg) total_tokens += msg_tokens # Reverse so chronological order is maintained (oldest first) buffered.reverse() # Step 4: Reconstruct with buffer + recent user message result_messages.extend(buffered) if recent_user_message: result_messages.append(recent_user_message) return result_messages def remaining_budget( self, current_messages: list[dict[str, str]], estimator: TokenEstimator, max_tokens: int = 8192, ) -> int: """Calculate how many tokens remain before hitting the window limit.""" consumed = self._system_tokens for msg in current_messages: consumed += estimator.estimate_tokens(msg.get("content", "")) return max(0, max_tokens - consumed) def trim_to_budget( self, messages: list[dict[str, str]], estimator: TokenEstimator, target_max_tokens: int = 8192, ) -> list[dict[str, str]]: """ Aggressively trim messages to fit within a strict token budget. Strips from the oldest non-system, non-user-last message backward until the total fits. Never removes system prompt or last user input. """ budget = target_max_tokens - self._system_tokens result: list[dict[str, str]] = [] last_user_idx = None # Find the last user message (preserve it) for i, msg in enumerate(messages): if msg.get("role") == "user": last_user_idx = i # Collect all messages except the preserved last user message trimmable = [msg for i, msg in enumerate(messages) if i != last_user_idx] total = self._system_tokens kept: list[dict[str, str]] = [] for msg in reversed(trimmable): # Start from newest msg_tokens = estimator.estimate_tokens(msg.get("content", "")) if total + msg_tokens <= budget: kept.insert(0, msg) total += msg_tokens else: break # Add back the preserved last user message if last_user_idx is not None: result.extend(kept) result.append(messages[last_user_idx]) else: result = kept return result ``` ### Pattern 3: Conversation Summarization Fallback When sliding window trimming still exceeds limits, this pattern triggers a summarization pass. The summarizer prompt explicitly requests key decisions, current task state, and remaining questions — not just text compression. The result merges the summary with recent messages into the context window. ```python """Conversation summarization fallback for context overflow.""" from dataclasses import dataclass import json @dataclass class ConversationSummary: """Structured summary of trimmed conversation history."""
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기