27 : compaction_(compaction),
28 callbacks_(callbacks),
29 hooks_(std::move(hooks)) {}
42 if (context_length <= 0) {
46 logger->debug(
"Updating context limit: {} -> {}",
63 std::vector<size_t> indices;
64 for (
size_t i = 0; i < ctx.
messages.size(); ++i) {
65 auto it = ctx.
messages[i].metadata.find(
"tool_name");
66 if (it != ctx.
messages[i].metadata.end()) {
73 && indices.size() >
static_cast<size_t>(keep_recent)) {
74 cut = indices.size() -
static_cast<size_t>(keep_recent);
81 for (
size_t j = 0; j < cut; ++j) {
82 auto& msg = ctx.
messages[indices[j]];
83 if (msg.content.rfind(
"[Previous:", 0) == 0) {
86 auto name_it = msg.metadata.find(
"tool_name");
87 std::string name = (name_it != msg.metadata.end())
88 ? name_it->second :
"unknown";
89 int chars =
static_cast<int>(msg.content.size());
91 msg.content =
"[Previous: " + name +
" result — "
92 + std::to_string(chars) +
" chars, pruned]";
98 logger->info(
"Pruned {} tool result(s), freed {} chars",
101 return {pruned, freed};
132 if (usage < threshold) {
141 auto tn = msg.metadata.find(
"tool_name");
142 if (tn == msg.metadata.end()) {
145 if (msg.content.rfind(
"[Previous:", 0) == 0) {
148 auto ai = msg.metadata.find(
"added_at_iteration");
149 if (ai == msg.metadata.end()) {
153 try { added = std::stoi(ai->second); }
154 catch (...) {
continue; }
155 if (current - added < ttl) {
168 msg.metadata[
"original_content"] = msg.content;
169 int chars =
static_cast<int>(msg.content.size());
170 msg.content =
"[Previous: " + tn->second +
" result — "
171 + std::to_string(chars) +
" chars, pruned]";
177 logger->info(
"[AUTO-PRUNE] Pruned {} results (TTL={})", pruned, ttl);
190 if (usage < threshold) {
194 auto last = ctx.
metadata.find(
"last_warning_iteration");
196 if (last != ctx.
metadata.end() && last->second == iter_str) {
202 int pct =
static_cast<int>(usage * 100.0f);
205 warning.
role =
"user";
206 warning.
content =
"[CONTEXT WARNING] Context at "
207 + std::to_string(pct) +
"% capacity ("
208 + std::to_string(cur_tok) +
"/" + std::to_string(max_tok)
209 +
" tokens). Capture findings with entropic.todo if needed,"
210 " then call entropic.prune_context.";
211 ctx.
messages.push_back(std::move(warning));
212 ctx.
metadata[
"last_warning_iteration"] = iter_str;
213 logger->info(
"[WARNING] Context at {}% — warning injected", pct);
229 int pct = (cur * 100) / max;
230 logger->info(
"Context: {}/{} tokens ({}%)", cur, max, pct);
238 if (result.compacted) {
240 result.new_token_count);
253 if (hook_iface_.fire_pre ==
nullptr) {
return false; }
255 std::string json =
"{\"token_count\":"
256 + std::to_string(tok) +
",\"force\":"
257 + (force ?
"true" :
"false") +
"}";
259 int rc = hook_iface_.fire_pre(hook_iface_.registry,
263 logger->info(
"ON_PRE_COMPACT hook cancelled compaction");
279 logger->info(
"Compacted: {} -> {} tokens", old_count, new_count);
281 std::string json =
"{\"old\":" + std::to_string(old_count)
282 +
",\"new\":" + std::to_string(new_count) +
"}";
287 if (hook_iface_.fire_post !=
nullptr) {
288 std::string json =
"{\"tokens_before\":" + std::to_string(old_count)
289 +
",\"tokens_after\":" + std::to_string(new_count) +
"}";
291 hook_iface_.fire_post(hook_iface_.registry,
Manages automatic context compaction.
CompactionConfig config
Compaction configuration.
TokenCounter & counter
Shared token counter.
CompactionResult check_and_compact(std::vector< Message > &messages, bool force=false, const std::string &conversation_id="")
Check if compaction is needed and perform if so.
void fire_post_compact_hooks(LoopContext &ctx, int old_count, int new_count)
Fire post-compaction callbacks + ON_POST_COMPACT hook.
std::pair< int, int > prune_tool_results(LoopContext &ctx, int keep_recent)
Replace old tool results with stubs.
void prune_old_tool_results(LoopContext &ctx)
Auto-prune tool results older than TTL iterations.
void refresh_context_limit(LoopContext &ctx, int context_length)
Refresh context limit based on tier config.
ContextManager(CompactionManager &compaction, EngineCallbacks &callbacks, ContextManagerHooks hooks={})
Construct a context manager.
bool fire_pre_compact_hook(LoopContext &ctx, bool force)
Fire ON_PRE_COMPACT; report whether compaction was cancelled.
void inject_context_warning(LoopContext &ctx)
Inject context usage warning if over threshold.
void check_compaction(LoopContext &ctx, bool force=false)
Check and perform compaction if needed.
int max_tokens
Maximum context window size.
void clear_cache()
Clear the token count cache.
int count_messages(const std::vector< Message > &messages) const
Count total tokens in a message list.
float usage_percent(const std::vector< Message > &messages) const
Get usage as fraction of context window (0.0–1.0).
Context management subsystem for the agentic loop.
@ ENTROPIC_HOOK_ON_POST_COMPACT
12: After context compaction
@ ENTROPIC_HOOK_ON_PRE_COMPACT
11: Before context compaction
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Activate model on GPU (WARM → ACTIVE).
float warning_threshold_percent
Warning trigger (0.3–0.9)
int tool_result_ttl
Tool result TTL in turns (>= 1; v2.1.3 #6: gated on fill, no upper bound)
Engine-level hooks called during context management.
std::function< void(LoopContext &)> after_compaction
Post-compaction hook.
Callback function pointer types for engine events.
void(* on_compaction)(const char *json, void *ud)
Compaction result.
void * user_data
Opaque pointer passed to all callbacks.
Mutable state carried through the agentic loop.
LoopMetrics metrics
Timing and counts.
std::string conversation_id
Conversation ID for storage (v1.8.8)
std::unordered_map< std::string, std::string > metadata
Runtime metadata.
std::vector< Message > messages
Conversation history.
int iterations
Total iterations completed.
A message in a conversation.
std::string content
Message text content (always populated)
std::string role
Message role.