47#include <unordered_map>
48#include <unordered_set>
51#include <nlohmann/json_fwd.hpp>
97 void* user_data =
nullptr;
108 std::vector<Message>
run(std::vector<Message> messages,
211 const std::string& session_key);
401 const std::vector<Message>& messages)
const;
514 const std::string&
input);
614 const std::string&
tier =
"");
777 void end_turn(
const std::string& key);
926 std::vector<Message>
messages_for(
const std::string& key)
const;
949 std::vector<Message> messages);
1005 void (*observer)(
const char*,
size_t,
void*),
1028 void (*observer)(
int state,
void* user_data),
1112 bool has_tier(
const std::string& name)
const;
1127 const std::string& name)
const;
1160 const std::unordered_map<std::string,
1161 std::vector<std::string>>&
rules);
1174 const std::string&
tier)
const;
1341 void clear_pause_for_fresh_turn();
1346 mutable std::mutex metrics_mutex_;
1412 const std::string& reason,
1414 const std::string& terminal_reason);
1431 const std::string& content,
1432 const std::string& finish_reason);
1442 bool handle_terminal_finish_reasons(
1454 bool record_explicit_completion_failure(
1469 void finalize_delegation_result(
1479 void relay_partial_result(
LoopContext&
ctx,
const std::string& summary);
1489 const std::string& terminal_reason = {});
1497 bool should_stop(
const LoopContext&
ctx)
const;
1513 static bool is_terminal_state(
const LoopContext&
ctx);
1528 void reinject_context_anchors(LoopContext&
ctx);
1534 void register_directive_handlers();
1537 void dir_stop(LoopContext&,
const Directive&, DirectiveResult&);
1538 void dir_tier_change(LoopContext&,
const Directive&, DirectiveResult&);
1539 void dir_delegate(LoopContext&,
const Directive&, DirectiveResult&);
1540 void dir_pipeline(LoopContext&,
const Directive&, DirectiveResult&);
1541 void dir_complete(LoopContext&,
const Directive&, DirectiveResult&);
1542 void dir_clear_todos(LoopContext&,
const Directive&, DirectiveResult&);
1543 void dir_inject(LoopContext&,
const Directive&, DirectiveResult&);
1544 void dir_prune(LoopContext&,
const Directive&, DirectiveResult&);
1545 void dir_anchor(LoopContext&,
const Directive&, DirectiveResult&);
1546 void dir_phase(LoopContext&,
const Directive&, DirectiveResult&);
1547 void dir_notify(LoopContext&,
const Directive&, DirectiveResult&);
1555 std::pair<std::string, std::vector<ToolCall>> parse_tool_calls(
1556 const std::string& raw_content);
1568 bool process_tool_results(LoopContext&
ctx,
1569 const std::vector<ToolCall>& tool_calls);
1578 void execute_pending_delegation(LoopContext&
ctx);
1593 bool reject_delegation_if_guarded(LoopContext&
ctx,
1594 const PendingDelegation&
pending);
1609 bool reject_pipeline_if_guarded(LoopContext&
ctx,
1610 const PendingPipeline&
pending);
1617 void execute_pending_pipeline(LoopContext&
ctx);
1627 bool should_auto_chain(
const LoopContext&
ctx,
1628 const std::string& finish_reason,
1629 const std::string& content);
1639 bool try_auto_chain(LoopContext&
ctx,
1640 const std::string& finish_reason,
1641 const std::string& content);
1665 void fire_post_generate_hook(GenerateResult& result,
1666 const std::string&
tier,
1667 const std::vector<Message>& messages);
1682 void capture_validation_feedback(LoopContext&
ctx);
1704 void dispatch_post_generate(LoopContext&
ctx,
1705 GenerateResult& result);
1720 void process_generation_result(LoopContext&
ctx,
1721 GenerateResult& result);
1734 void dispatch_pending_or_halt(LoopContext&
ctx);
1754 void charge_thinking_budget(LoopContext&
ctx,
size_t content_len,
1773 void nudge_budget_completion(LoopContext&
ctx);
1791 void hard_cut_budget(LoopContext&
ctx);
1805 bool fire_complete_hook(
const std::string& summary,
1806 const LoopContext&
ctx);
1815 bool fire_delegate_pre_hook(
const PendingDelegation&
pending,
1829 void fire_delegate_complete_hook(
const std::string& target,
1831 const std::string& summary =
"");
1852 std::filesystem::path get_repo_dir();
1860 std::filesystem::path get_repo_dir_locked();
1868 std::string system_prompt_copy()
const;
1906 SandboxManager* ensure_sandbox_manager(
1907 const std::filesystem::path& root);
1915 std::pair<ScopedSandbox::SwapDirFn, void*> dir_swap_snapshot()
const;
1942 bool resolve_latest_for_target(LoopContext&
ctx,
1945 bool resolve_resume_delegation(
1964 bool fetch_resume_payload(
1966 const std::string&
id,
1985 DelegationResult run_pending_delegation(
1987 const PendingDelegation&
pending,
1997 void fire_delegation_start(
const LoopContext&
ctx,
1998 const std::string&
tier,
1999 const std::string& task);
2008 void fire_delegation_complete(
const LoopContext&
ctx,
2009 const std::string&
tier,
2010 const struct DelegationResult& result);
2013 LoopMetrics last_metrics_;
2014 std::unordered_map<std::string, LoopMetrics>
2017 LoopConfig loop_config_;
2018 EngineCallbacks callbacks_;
2019 std::atomic<bool> interrupt_flag_{
false};
2030 std::atomic<bool> pause_flag_{
false};
2031 void (*external_interrupt_cb_)(
void*) =
nullptr;
2032 void* external_interrupt_data_ =
nullptr;
2033 void (*external_reset_cb_)(
void*) =
nullptr;
2034 void* external_reset_data_ =
nullptr;
2040 DelegationCallbacks delegation_cb_;
2041 mutable std::mutex delegation_cb_mutex_;
2042 char* (*validation_provider_)(
void*) =
nullptr;
2043 void* validation_provider_data_ =
nullptr;
2044 std::unordered_map<std::string, std::string> context_anchors_;
2048 mutable std::mutex anchors_mutex_;
2049 ToolExecutionInterface tool_exec_;
2050 TierResolutionInterface tier_res_;
2051 StorageInterface storage_;
2052 DirectiveProcessor directive_processor_;
2053 TokenCounter token_counter_;
2054 CompactionManager compaction_manager_;
2055 ContextManager context_manager_;
2056 ResponseGenerator response_generator_;
2058 std::optional<std::filesystem::path> cached_repo_dir_;
2059 bool repo_dir_checked_ =
false;
2060 std::filesystem::path project_dir_override_;
2063 std::map<std::filesystem::path, SandboxManager> sandbox_mgrs_;
2064 SessionRootInterface session_root_;
2066 void* swap_dir_data_ =
nullptr;
2071 mutable std::mutex sandbox_mutex_;
2074 mutable std::mutex queue_mutex_;
2075 std::deque<std::string> user_message_queue_;
2076 std::atomic<bool> running_flag_{
false};
2079 std::atomic<int64_t> last_activity_epoch_s_{0};
2080 void (*queue_observer_)(
const char*,
size_t,
void*) =
nullptr;
2081 void* queue_observer_data_ =
nullptr;
2084 void (*state_observer_)(
int,
void*) =
nullptr;
2085 void* state_observer_data_ =
nullptr;
2096 std::optional<std::string> pop_queued_user_message();
2113 ConversationState& active_conversation();
2126 std::unordered_map<std::string, ConversationState> conversations_;
2140 mutable std::mutex conversations_mutex_;
2156 std::atomic<bool> interrupt{
false};
2165 mutable std::mutex runs_mutex_;
2168 std::unordered_map<std::string, std::shared_ptr<RunState>> active_runs_;
2172 bool concurrent_sessions_ =
true;
2180 std::shared_ptr<RunState> this_thread_run()
const;
2188 bool run_interrupted()
const;
2196 std::string active_session_key_;
2202 mutable std::mutex session_key_mutex_;
2203 std::string system_prompt_;
2207 mutable std::mutex prompt_mutex_;
2209 std::unordered_map<std::string, WorkspacePrompts> workspace_prompts_;
2211 std::unordered_map<std::string, std::string> session_workspace_;
2221 std::optional<std::string> workspace_prompt_for(
const std::string&
session,
2222 const std::string&
tier)
const;
2223 SessionLogger* session_logger_ =
nullptr;
2226 std::unordered_map<std::string, ChildContextInfo> tier_info_;
2227 std::unordered_map<std::string, std::vector<std::string>> handoff_rules_;
2229 std::unordered_set<std::string> relay_single_delegate_tiers_;
2236 void wire_internal_tier_resolution();
2249 void apply_identity_overrides(LoopContext&
ctx);
2265 void begin_loop_preamble(LoopContext&
ctx);
2274 int resolve_max_iterations(
const LoopContext&
ctx)
const;
2283 int resolve_max_tool_calls(
const LoopContext&
ctx)
const;
2294 static ChildContextInfo tri_resolve_tier(
2295 const std::string& name,
void*
ud);
2304 static bool tri_tier_exists(
2305 const std::string& name,
void*
ud);
2314 static std::vector<std::string> tri_get_handoff_targets(
2315 const std::string& name,
void*
ud);
2325 static std::string tri_get_tier_param(
2326 const std::string& name,
const std::string&
param,
void*
ud);
Core agent execution engine.
std::vector< std::string > isolation_unsafe_tools(const LoopContext &ctx, const std::string &target_tier)
Child-visible external tools that break the isolation claim.
void cancel_pause()
Cancel pause and interrupt completely.
bool queue_user_message(const std::string &message)
Append a user message to the mid-gen queue.
void set_external_reset(void(*cb)(void *user_data), void *user_data)
Register the external transport interrupt-release callback.
CompactionManager & compaction_manager()
Borrowed reference to the engine's built-in CompactionManager.
void set_validation_provider(char *(*provider)(void *), void *user_data)
Register a JSON provider for the validation block in ON_COMPLETE hook context.
bool is_delegation_cycle(const LoopContext &ctx, const std::string &target) const
Check whether pending delegation would close a cycle.
bool try_begin_turn()
Claim a turn for the session bound to THIS thread (gh#158).
size_t user_message_queue_depth() const
Snapshot of the queue depth.
std::string session_system_prompt(const std::string &session) const
The untiered system prompt a fresh conversation in session would be seeded with (gh#179).
std::vector< Message > run(std::vector< Message > messages, const std::string &tier_override="")
Run the engine on a set of messages.
bool interrupt_session(const std::string &key)
Interrupt exactly one session's run (gh#158).
bool set_session_messages(const std::string &key, std::vector< Message > messages)
Replace one session's conversation wholesale (gh#165, v2.13.0).
void seed_system_prompt_for_tier(const std::string &tier)
Seed a tier's system prompt on an empty conversation (gh#99).
void clear_user_message_queue()
Drop all queued user messages.
const std::vector< Message > & get_messages() const
Get conversation messages (read-only).
bool prepare_next_turn(std::vector< Message > &pending)
Pull the next queued user message into pending (gh#40).
void set_callbacks(const EngineCallbacks &callbacks)
Set callback functions for loop events.
std::size_t active_run_count() const
Number of runs currently in flight on this handle (gh#158).
void seed_system_prompt(const std::vector< Message > &new_messages)
Prepend the configured system prompt if this turn needs it.
std::vector< Message > run_turn(const std::string &input)
Run a single conversation turn (stateful).
DelegationCallbacks delegation_callbacks_snapshot() const
Atomically snapshot the registered delegation callbacks.
void set_stream_observer(TokenCallback observer, void *user_data)
Set the global stream observer.
bool session_interrupted(const std::string &key) const
Whether a named session's in-flight run carries an interrupt.
LoopMetrics last_loop_metrics() const
Get metrics from the most recent completed run.
const LoopConfig & loop_config() const
Get loop configuration.
std::vector< std::string > session_keys() const
Keys of every session the engine currently holds.
void set_session_root_interface(const SessionRootInterface &iface)
Inject the session-root / tool-reach seam (gh#160, v2.13.0).
void set_project_dir(const std::filesystem::path &project_dir)
Set the configured project directory (gh#31, v2.1.6).
bool is_running() const
Whether a top-level run_turn is currently in progress.
DirectiveProcessor & directive_processor()
Get directive processor for external hook wiring.
std::vector< Message > run_drain_loop(std::string pending, const std::string &tier_override)
Shared drain loop for run_turn / run_turn_as (gh#99).
int run_streaming(const std::string &input, TokenCallback on_token, void *user_data, int *cancel_flag, const std::string &tier="")
Run a streaming conversation turn (stateful).
void interrupt()
Interrupt the running loop (thread-safe).
bool concurrent_sessions() const
Whether per-session concurrency is enabled (gh#158).
void pause()
Pause generation (thread-safe).
bool is_delegation_repeat_blocked(const LoopContext &ctx, const std::string &target) const
Predicate: should this delegation be blocked because the same target has just failed too many times?...
void bind_session_workspace(const std::string &session, const std::string &workspace)
Record that session belongs to workspace.
void clear_conversation_for(const std::string &key)
Clear one session's history, keeping the session itself.
SandboxManager * sandbox_for_session(const std::string &session_key)
Sandbox manager for a session, or nullptr when isolation is off (gh#160).
void set_hooks(const HookInterface &hooks)
Set the hook dispatch interface.
void set_tier_resolution(const TierResolutionInterface &tier_res)
Set the tier resolution interface for delegation.
void run_loop(LoopContext &ctx, bool inherit_interrupt=false)
Run the engine loop on a pre-built context.
void set_session_logger(SessionLogger *logger)
Set session logger for model transcript logging.
const TierResolutionInterface & tier_resolution() const
Get the tier resolution interface.
std::string active_session_key() const
Session whose turn is currently running.
void set_storage(const StorageInterface &storage)
Set the storage interface for persistence.
std::unordered_map< std::string, LoopMetrics > per_tier_metrics() const
Per-tier aggregated metrics since engine start.
void set_concurrent_sessions(bool enabled)
Allow runs on DIFFERENT session keys to proceed together.
std::vector< std::string > get_tier_allowed_tools(const std::string &name) const
Return the allowed tool names registered for a tier (gh#121 regression).
std::size_t message_count_for(const std::string &key) const
Message count for a named session.
bool drop_session(const std::string &key)
Forget a session entirely.
void clear_conversation()
Clear conversation history.
std::vector< Message > run_turn_as(const std::string &tier, const std::string &input)
Run a single turn under a named tier's grammar/identity (gh#99).
void set_queue_observer(void(*observer)(const char *, size_t, void *), void *user_data)
Register an observer that fires when a queued user message is consumed and seeded as the next turn.
std::pair< int, int > context_usage(const std::vector< Message > &messages) const
Get context usage for a message list.
bool fold_complete_into_assistant(LoopContext &ctx, const Message &tool_result_msg) const
gh#68 (v2.3.4): fold entropic.complete summary into the prior assistant message, suppressing the JSON...
void set_system_prompt(const std::string &prompt)
Set the system prompt for conversation state.
void set_relay_single_delegate(const std::string &name)
Mark a tier as relay-on-single-delegate.
void set_state_observer(void(*observer)(int state, void *user_data), void *user_data)
Register a persistent state-transition observer.
void set_active_session(const std::string &key)
Bind this turn to a caller-scoped session (gh#144, v2.12.0).
size_t message_count() const
Get conversation message count.
static constexpr int MAX_DELEGATION_DEPTH
Max delegation nesting depth (0=root, 1=child, 2=max).
std::vector< Message > messages_for(const std::string &key) const
Messages held by a named session.
void set_delegation_callbacks(ent_decision_t(*on_start)(const ent_delegation_request_t *, void *), ent_decision_t(*on_complete)(const ent_delegation_result_t *, void *), void *user_data)
Register delegation start/complete callbacks (gh#29, v2.1.5).
void end_turn()
Release the turn this thread claimed (gh#158).
ToolExecutorHooks build_directive_hooks()
Build ToolExecutorHooks wired to this engine's DirectiveProcessor.
void set_workspace_prompts(const std::string &workspace, WorkspacePrompts prompts)
Register (or replace) one workspace's assembled prompts.
void set_dir_swap(ScopedSandbox::SwapDirFn swap_fn, void *user_data)
Install the directory-swap callback used by sandboxing.
void defang_meta_action_envelope(Message &msg) const
gh#88: reshape a meta-tool {"action":...} result so the model is not primed to parrot the call-shaped...
void set_handoff_rules(const std::unordered_map< std::string, std::vector< std::string > > &rules)
Store handoff rules for tier delegation.
void set_tier_info(const std::string &name, const ChildContextInfo &info)
Store pre-resolved tier context info.
void set_message_queue_capacity(int cap)
Set the runtime capacity of the mid-gen queue.
const std::string & tier_system_prompt(const std::string &name) const
A tier's resolved system prompt (gh#98).
std::filesystem::path resolve_session_root(const std::string &session_key)
Resolve the root a session's tools operate in (gh#160).
EngineCallbacks & callbacks()
Get mutable reference to engine callbacks.
void clear_workspace_prompts(const std::string &workspace)
Forget a workspace's prompts; its sessions fall back to the handle's.
void reset_interrupt()
Reset interrupt flag for next run.
bool has_tier(const std::string &name) const
Whether a tier name is known (gh#99).
void set_external_interrupt(void(*cb)(void *user_data), void *user_data)
Register a callback invoked alongside interrupt().
bool tier_requires_explicit_completion(const std::string &tier) const
Check if a tier requires an explicit entropic.complete / entropic.delegate tool call to conclude its ...
int64_t seconds_since_last_activity() const
gh#35: seconds since the engine last serviced a run().
std::atomic< bool > & run_cancel_flag()
The cancel flag of the run executing on THIS thread (gh#158).
void set_tool_executor(const ToolExecutionInterface &tool_exec)
Set the tool execution interface.
Manages automatic context compaction.
Processes tool directives via registry-based dispatch.
Create, finalize, and discard per-delegation filesystem sandboxes.
void(*)(const std::string &session_key, const std::filesystem::path &path, bool entering, void *user_data) SwapDirFn
Callback type for directory swapping.
Manages session_model.log for raw streaming content.
Auto-compaction for context management.
Context management subsystem for the agentic loop.
gh#144: one caller's conversation, as a value.
Directive processing for tool-to-engine communication.
Types for the agentic loop engine.
Public C API for the Entropic inference engine.
ent_decision_t
Consumer decision returned from delegation callbacks.
entropic_hook_point_t
Hook points in the engine lifecycle.
Hook dispatch interface injected into engine subsystems.
Function pointer types for core-to-inference communication.
std::size_t remaining
Unexamined count.
Activate model on GPU (WARM → ACTIVE).
@ enabled
Named in enabled_mcpjson_servers, or enable-all is set.
@ optional
optional: every escape asks the host's path approver
@ tier
The TIER's identity frontmatter grammar: stem (gh#154).
void(*)(const char *, size_t, void *) TokenCallback
Token callback type matching the C API signature.
AgentState
C++ enum class for agent execution states.
Response generation subsystem for the agentic loop.
Filesystem-based sandbox isolation for delegations.
Session model log — raw streaming transcript.
Streaming filter that strips a model family's reasoning blocks.
Request describing a delegation that is about to run.
Result of a finalized delegation, delivered to the consumer.
Grouped consumer-registered delegation callbacks (gh#29).
Resolved tier information for building child delegation contexts.
Auto-compaction configuration.
Result returned from a child delegation loop.
Callback function pointer types for engine events.
Configuration for the agentic loop.
Mutable state carried through the agentic loop.
Metrics collected during loop execution.
A message in a conversation.
Where a session's tools live, and what it can reach (gh#160).
Storage interface for conversation persistence.
Tier resolution callbacks for delegation and auto-chain.
One workspace's assembled system prompts (gh#179, v2.14.0).