尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Context engineering for AI Agents. Manage your LLM's context window with caching, compaction, summarization, and graceful degradation.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗SR2 manages the full lifecycle of what goes into an LLM's context window: layer assembly, compaction, summarization, memory, token budgeting, KV-cache alignment, and graceful degradation.
Version: 2.0.0-alpha (revamp branch — clean-slate rebuild)
SR2 is not a library you call once, and not a harness. It's a distinct middle tier in the agent stack: a context runtime that sits between your agent harness and the LLM provider.
┌──────────────────────────────────────────────────────────┐
│ HARNESS your agent / Claude Code / LangGraph │
│ owns: I/O, session identity, agent personality, │
│ tool *implementations*, config │
└───────────────────────────┬─────────────────────────────────┘
│ turn(user_input)
▼
┌──────────────────────────────────────────────────────────┐
│ SR2 the context runtime │
│ owns: WHAT fills the window + how it evolves │
│ drives the multi-iteration tool loop: │
│ compile → call LLM → run tools → repeat → post-process │
│ layers · resolvers · transformers · memory · compaction │
│ summarization · budgeting · cache alignment · degradation │
└───────────────────────────┬─────────────────────────────────┘
│ CompletionRequest (injected ↓)
▼
┌──────────────────────────────────────────────────────────┐
│ LLMCallable LiteLLMCallable (default) / your own │
│ owns: the raw provider HTTP call (Anthropic, OpenAI, …) │
└──────────────────────────────────────────────────────────┘
Context management is a closed loop, not a one-shot transform:
compile context → call the model → observe the response → post-process (memory extraction, compaction, summarization, cache tracking)
A pure "compile-only" library forces the harness into a two-call dance — compile, call the LLM yourself, then hand the response back — and every guarantee SR2 makes (cache-stable prefixes, correct conversation-zone transitions, reliable post-processing) depends on the harness getting that dance exactly right. So SR2 owns the turn loop instead.
It does not own the provider HTTP call or tool execution. Both are injected dependencies (inversion of control):
| Dependency | Type | Provided by | SR2's use |
|---|---|---|---|
llm | LLMCallable (complete / stream) | harness | called each LLM iteration |
tool_executor | async (ToolUseBlock) -> ToolResultBlock | harness | called per tool request; SR2 never implements tools |
token_counter | TokenCounter | harness | budget enforcement |
memory_store, memory_extractor, tracer, provenance_store | protocols | harness (optional) | memory, observability |
This is how SR2 owns the lifecycle without becoming a provider client or a harness. The harness supplies adapters + I/O + personality; SR2 drives the turn.
The same SR2 core ships two ways:
LiteLLMCallable, call turn() in-process.
This is the primary mode (see Quick Start).sr2-relay provides; it's a thin wire-format adapter over the
same turn().SR2.turn(user_input) -> AsyncIterator[StreamEvent] is the entry point. Per
turn it:
LLMCallabletool_executor
(concurrently, order-preserving), appends results, and loopsmax_tool_iterations)end event, then awaits post_processCallers see a clean stream: text and usage events, loop-progress events
(tool_use_emitted, tool_result_received, iteration_complete), and exactly
one end. At most one error event may appear per phase, always before end.
import asyncio
from sr2 import SR2
from sr2.config.models import PipelineConfig
from sr2.integrations.litellm import LiteLLMCallable
from sr2.pipeline.token_counting import CharacterTokenCounter
from sr2.models import TextBlock
config = PipelineConfig(
layers=[
{"name": "system", "target": "system",
"resolvers": [{"type": "static",
"config": {"text": "You are a helpful assistant."}}]},
{"name": "conversation", "target": "messages",
"resolvers": [{"type": "session"}, {"type": "input"}]},
]
)
sr2 = SR2(
config,
llm=LiteLLMCallable("anthropic/claude-haiku-4-5-20251001"),
token_counter=CharacterTokenCounter(),
)
async def main():
async for event in sr2.turn([TextBlock(text="Hello")]):
if event.type == "text":
print(event.text, end="")
asyncio.run(main())
Or run a config straight from the CLI:
sr2 configs/minimal.yaml
See QUICKSTART.md for the YAML config shape, tool wiring, and multi-turn sessions.
The pipeline runs on an EventBus, not a fixed sequence. Components subscribe
to event names (turn_start, user_input, assistant_response, …); the engine
drives a drain-process loop each turn until no component produces new work.
A layer is the unit of context. Each layer holds resolvers (produce
content), transformers (reshape content), and optional tool providers
(produce tool definitions). Layers compile to one of three targets — system,
messages, or tools — and enforce a per-layer token budget.
Layer order drives KV-cache efficiency: stable layers (system prompt, project context) go first and stay cached; dynamic layers (conversation) go last.
Four extension points, each a runtime_checkable Protocol, discovered lazily
via Python entry points — nothing activates unless your config names it:
| Group | Protocol | Built-ins |
|---|---|---|
sr2.resolvers | Resolver | static, input, session, event_payload, memory, markdown_file, static_text |
sr2.transformers | Transformer | summarize, memory_extraction, compaction |
sr2.extractors | MemoryExtractor | rule_based |
sr2.tool_providers | ToolProvider | (extension point; no built-ins yet) |
Add a capability by registering an entry point — never by modifying the engine (Open/Closed).
MemoryStore / MemoryExtractor protocols; MemoryResolver
injects relevant memories on input, MemoryExtractionTransformer saves them
from responses. In-memory store ships with core.schema_and_sample,
result_summary) with an optional cost gate (cache-invalidation economics).CircuitBreaker (closed/open/half-open) plus a
5-level DegradationLadder.InMemoryProvenanceStore or durable SQLiteProvenanceStore); Tracer
captures per-component firing records with a human-readable timeline.src/sr2/). The v1 multi-package
monorepo, runtime, bridge, and premium split are gone.InMemoryMemoryStore); async persistence backends can be added via the MemoryStore protocol.The authoritative module map and architecture reference lives in CLAUDE.md. High level:
src/sr2/
__init__.py # public API — `from sr2 import SR2`, plus core models
sr2.py # facade re-export of the SR2 orchestrator
orchestrator.py # SR2 class: the turn loop
models.py # core data models (TextBlock, Message, ToolDefinition, …)
protocols/llm.py # LLMCallable, CompletionRequest/Response, StreamEvent
integrations/ # LiteLLMCallable
config/ # Pydantic config models
pipeline/ # engine, event bus, layers, resolvers, transformers, tracing
memory/ # stores, extractors, resolver
compaction/ # rule engine + cost gate
degradation/ # circuit breaker, ladder
tokenization/ # tiktoken counter
v2.0.0-alpha on revamp. Turn loop, event-driven pipeline, layers,
resolvers/transformers, memory, compaction, degradation, provenance, and tracing
are in place. post_process is a wired no-op pending the extraction/maintenance
hookup.
Apache-2.0. See LICENSE.