Entropic 2.14.3
Local-first agentic inference engine
Loading...
Searching...
No Matches
entropic::AgentEngine Class Reference

Core agent execution engine. More...

#include <entropic/core/engine.h>

Classes

struct  DelegationCallbacks
 Grouped consumer-registered delegation callbacks (gh#29). More...
 

Public Member Functions

 AgentEngine (const InferenceInterface &inference, const LoopConfig &loop_config, const CompactionConfig &compaction_config)
 Construct an agent engine.
 
std::vector< Message > run (std::vector< Message > messages, const std::string &tier_override="")
 Run the engine on a set of messages.
 
void set_callbacks (const EngineCallbacks &callbacks)
 Set callback functions for loop events.
 
void set_tool_executor (const ToolExecutionInterface &tool_exec)
 Set the tool execution interface.
 
void set_tier_resolution (const TierResolutionInterface &tier_res)
 Set the tier resolution interface for delegation.
 
void set_storage (const StorageInterface &storage)
 Set the storage interface for persistence.
 
void set_hooks (const HookInterface &hooks)
 Set the hook dispatch interface.
 
void set_project_dir (const std::filesystem::path &project_dir)
 Set the configured project directory (gh#31, v2.1.6).
 
void set_session_root_interface (const SessionRootInterface &iface)
 Inject the session-root / tool-reach seam (gh#160, v2.13.0).
 
void set_dir_swap (ScopedSandbox::SwapDirFn swap_fn, void *user_data)
 Install the directory-swap callback used by sandboxing.
 
std::filesystem::path resolve_session_root (const std::string &session_key)
 Resolve the root a session's tools operate in (gh#160).
 
SandboxManager * sandbox_for_session (const std::string &session_key)
 Sandbox manager for a session, or nullptr when isolation is off (gh#160).
 
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 set_stream_observer (TokenCallback observer, void *user_data)
 Set the global stream observer.
 
void set_validation_provider (char *(*provider)(void *), void *user_data)
 Register a JSON provider for the validation block in ON_COMPLETE hook context.
 
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).
 
DelegationCallbacks delegation_callbacks_snapshot () const
 Atomically snapshot the registered delegation callbacks.
 
void set_external_interrupt (void(*cb)(void *user_data), void *user_data)
 Register a callback invoked alongside interrupt().
 
void set_external_reset (void(*cb)(void *user_data), void *user_data)
 Register the external transport interrupt-release callback.
 
void run_loop (LoopContext &ctx, bool inherit_interrupt=false)
 Run the engine loop on a pre-built context.
 
const TierResolutionInterface & tier_resolution () const
 Get the tier resolution interface.
 
void interrupt ()
 Interrupt the running loop (thread-safe).
 
void reset_interrupt ()
 Reset interrupt flag for next run.
 
void pause ()
 Pause generation (thread-safe).
 
void cancel_pause ()
 Cancel pause and interrupt completely.
 
std::pair< int, int > context_usage (const std::vector< Message > &messages) const
 Get context usage for a message list.
 
EngineCallbacks & callbacks ()
 Get mutable reference to engine callbacks.
 
const LoopConfig & loop_config () const
 Get loop configuration.
 
DirectiveProcessor & directive_processor ()
 Get directive processor for external hook wiring.
 
LoopMetrics last_loop_metrics () const
 Get metrics from the most recent completed run.
 
std::unordered_map< std::string, LoopMetrics > per_tier_metrics () const
 Per-tier aggregated metrics since engine start.
 
void set_system_prompt (const std::string &prompt)
 Set the system prompt for conversation state.
 
void set_session_logger (SessionLogger *logger)
 Set session logger for model transcript logging.
 
std::vector< Message > run_turn (const std::string &input)
 Run a single conversation turn (stateful).
 
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).
 
std::vector< Message > run_turn (std::vector< Message > new_messages)
 Run a single conversation turn from a pre-built message list (gh#37).
 
void seed_system_prompt (const std::vector< Message > &new_messages)
 Prepend the configured system prompt if this turn needs it.
 
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).
 
void seed_system_prompt_for_tier (const std::string &tier)
 Seed a tier's system prompt on an empty conversation (gh#99).
 
bool prepare_next_turn (std::vector< Message > &pending)
 Pull the next queued user message into pending (gh#40).
 
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).
 
int run_streaming (std::vector< Message > new_messages, TokenCallback on_token, void *user_data, int *cancel_flag)
 Streaming conversation turn from a pre-built message list (gh#37).
 
void clear_conversation ()
 Clear conversation history.
 
size_t message_count () const
 Get conversation message count.
 
const std::vector< Message > & get_messages () const
 Get conversation messages (read-only).
 
bool queue_user_message (const std::string &message)
 Append a user message to the mid-gen queue.
 
size_t user_message_queue_depth () const
 Snapshot of the queue depth.
 
void clear_user_message_queue ()
 Drop all queued user messages.
 
void set_message_queue_capacity (int cap)
 Set the runtime capacity of the mid-gen queue.
 
bool is_running () const
 Whether a top-level run_turn is currently in progress.
 
bool try_begin_turn (const std::string &key)
 Try to claim one turn for a named session (gh#144 / gh#158).
 
bool try_begin_turn ()
 Claim a turn for the session bound to THIS thread (gh#158).
 
void end_turn (const std::string &key)
 Release a turn claimed by try_begin_turn (gh#144 / gh#158).
 
void end_turn ()
 Release the turn this thread claimed (gh#158).
 
std::size_t active_run_count () const
 Number of runs currently in flight on this handle (gh#158).
 
void set_concurrent_sessions (bool enabled)
 Allow runs on DIFFERENT session keys to proceed together.
 
bool concurrent_sessions () const
 Whether per-session concurrency is enabled (gh#158).
 
bool interrupt_session (const std::string &key)
 Interrupt exactly one session's run (gh#158).
 
bool session_interrupted (const std::string &key) const
 Whether a named session's in-flight run carries an interrupt.
 
std::atomic< bool > & run_cancel_flag ()
 The cancel flag of the run executing on THIS thread (gh#158).
 
void set_active_session (const std::string &key)
 Bind this turn to a caller-scoped session (gh#144, v2.12.0).
 
std::string active_session_key () const
 Session whose turn is currently running.
 
std::vector< Message > messages_for (const std::string &key) const
 Messages held by a named session.
 
bool set_session_messages (const std::string &key, std::vector< Message > messages)
 Replace one session's conversation wholesale (gh#165, v2.13.0).
 
std::size_t message_count_for (const std::string &key) const
 Message count for a named session.
 
void clear_conversation_for (const std::string &key)
 Clear one session's history, keeping the session itself.
 
bool drop_session (const std::string &key)
 Forget a session entirely.
 
std::vector< std::string > session_keys () const
 Keys of every session the engine currently holds.
 
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.
 
void set_state_observer (void(*observer)(int state, void *user_data), void *user_data)
 Register a persistent state-transition observer.
 
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 clear_workspace_prompts (const std::string &workspace)
 Forget a workspace's prompts; its sessions fall back to the handle's.
 
void bind_session_workspace (const std::string &session, const std::string &workspace)
 Record that session belongs to workspace.
 
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).
 
void set_tier_info (const std::string &name, const ChildContextInfo &info)
 Store pre-resolved tier context info.
 
bool has_tier (const std::string &name) const
 Whether a tier name is known (gh#99).
 
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).
 
const std::string & tier_system_prompt (const std::string &name) const
 A tier's resolved system prompt (gh#98).
 
void set_relay_single_delegate (const std::string &name)
 Mark a tier as relay-on-single-delegate.
 
void set_handoff_rules (const std::unordered_map< std::string, std::vector< std::string > > &rules)
 Store handoff rules for tier delegation.
 
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 turn.
 
bool is_delegation_cycle (const LoopContext &ctx, const std::string &target) const
 Check whether pending delegation would close a cycle.
 
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? (gh#64)
 
int64_t seconds_since_last_activity () const
 gh#35: seconds since the engine last serviced a run().
 
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 tool-result user message that would otherwise land in history.
 
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 envelope.
 
CompactionManager & compaction_manager ()
 Borrowed reference to the engine's built-in CompactionManager.
 

Static Public Attributes

static constexpr int MAX_DELEGATION_DEPTH = 2
 Max delegation nesting depth (0=root, 1=child, 2=max).
 

Detailed Description

Core agent execution engine.

Owns all engine subsystems: ResponseGenerator, ContextManager, CompactionManager, DirectiveProcessor. Implements the agentic loop (plan-act-observe-repeat) with proper state management and termination conditions.

Version
1.8.6

Definition at line 65 of file engine.h.

Constructor & Destructor Documentation

◆ AgentEngine()

entropic::AgentEngine::AgentEngine ( const InferenceInterface &  inference,
const LoopConfig &  loop_config,
const CompactionConfig &  compaction_config 
)

Construct an agent engine.

Parameters
inferenceInference interface (function pointers).
loop_configLoop configuration.
compaction_configCompaction configuration.
Version
1.8.4
Parameters
inferenceInference interface.
loop_configLoop configuration.
compaction_configCompaction configuration. @dg_internal
Version
2.12.0

Definition at line 136 of file engine.cpp.

Member Function Documentation

◆ active_run_count()

std::size_t entropic::AgentEngine::active_run_count ( ) const

Number of runs currently in flight on this handle (gh#158).

Runs currently in flight on this handle (gh#158).

Returns
Active run count; 0 when idle. @utility
Version
2.13.0
Returns
Active run count. @dg_internal
Version
2.13.0

Definition at line 3679 of file engine.cpp.

◆ active_session_key()

std::string entropic::AgentEngine::active_session_key ( ) const

Session whose turn is currently running.

Session bound to this thread, else to the handle (gh#158).

gh#158 (v2.13.0): returns BY VALUE. The handle-wide fallback is a std::string every starting run assigns, and a caller on another thread — a host polling context, which is the whole point of the fallback — read it with no synchronization at all. A reference handed out across that write is a data race on the string itself, not a merely stale answer.

Returns
The active key; "" when idle or unkeyed. @utility
Version
2.13.0

A thread that bound a session gets its own answer — two concurrent runs each need one, and a single member field can hold only the last writer's. A thread that never bound one (an API call reading context, a direct engine driver in a test) falls back to the handle field, which is what keeps the legacy unkeyed accessors reading what they read in v2.12.0.

Returned BY VALUE, and the handle-wide fallback is read under session_key_mutex_: the member is a std::string that every starting run assigns, so a caller on another thread reading it unsynchronized — which is precisely what the unkeyed accessors do — was a data race on a string, not merely a stale answer.

Returns
The session key in force on this thread. @dg_internal
Version
2.13.0 [reviewed]

Definition at line 3575 of file engine.cpp.

◆ bind_session_workspace()

void entropic::AgentEngine::bind_session_workspace ( const std::string &  session,
const std::string &  workspace 
)

Record that session belongs to workspace.

Record a session's workspace (gh#179).

Parameters
sessionSession key.
workspaceWorkspace name.
Version
2.14.0
Parameters
sessionSession key.
workspaceWorkspace name. @req REQ-MCP-027
Version
2.14.0

Definition at line 3873 of file engine.cpp.

◆ build_directive_hooks()

ToolExecutorHooks entropic::AgentEngine::build_directive_hooks ( )

Build ToolExecutorHooks wired to this engine's DirectiveProcessor.

Returns hooks with process_directives bridged to directive_processor(). Eliminates the need for facade bridge functions.

Returns
Configured ToolExecutorHooks.
Version
2.0.2
Returns
Configured hooks. @dg_internal
Version
2.0.2

Definition at line 4504 of file engine.cpp.

◆ callbacks()

EngineCallbacks & entropic::AgentEngine::callbacks ( )
inline

Get mutable reference to engine callbacks.

Used by ToolExecutor which holds a reference that survives set_callbacks() reassignment (same pattern as ResponseGenerator).

Returns
Reference to internal callbacks member. @utility
Version
2.0.1

Definition at line 413 of file engine.h.

◆ cancel_pause()

void entropic::AgentEngine::cancel_pause ( )

Cancel pause and interrupt completely.

Cancel pause and interrupt.

Version
1.8.4

@req REQ-LOOP-006

Version
1.8.4

Definition at line 1406 of file engine.cpp.

◆ clear_conversation()

void entropic::AgentEngine::clear_conversation ( )

Clear conversation history.

Version
2.0.2

@dg_internal

Version
2.12.0

Definition at line 4228 of file engine.cpp.

◆ clear_conversation_for()

void entropic::AgentEngine::clear_conversation_for ( const std::string &  key)

Clear one session's history, keeping the session itself.

Clear one session's history, keeping the session — see header.

Parameters
keySession key. @req REQ-LOOP-001
Version
2.12.0
Parameters
keySession key. @dg_internal
Version
2.13.0

Definition at line 4290 of file engine.cpp.

◆ clear_user_message_queue()

void entropic::AgentEngine::clear_user_message_queue ( )

Drop all queued user messages.

Drop all queued messages atomically.

@threadsafety Thread-safe.

Version
2.1.10

@dg_internal

Version
2.1.10

Definition at line 4417 of file engine.cpp.

◆ clear_workspace_prompts()

void entropic::AgentEngine::clear_workspace_prompts ( const std::string &  workspace)

Forget a workspace's prompts; its sessions fall back to the handle's.

Forget a workspace's prompts (gh#179).

Parameters
workspaceWorkspace name.
Version
2.14.0
Parameters
workspaceWorkspace name. @req REQ-MCP-027
Version
2.14.0

Definition at line 3859 of file engine.cpp.

◆ compaction_manager()

CompactionManager & entropic::AgentEngine::compaction_manager ( )
inline

Borrowed reference to the engine's built-in CompactionManager.

gh#76 (v2.3.27): the facade-level CompactorRegistry borrows this reference at construction so consumer-registered compactors can fall back to the built-in default. Lifetime: the CompactionManager outlives the registry because both are owned by the engine handle (registry is destroyed in entropic_destroy before the engine).

@utility

Version
2.3.27

Definition at line 1289 of file engine.h.

◆ concurrent_sessions()

bool entropic::AgentEngine::concurrent_sessions ( ) const

Whether per-session concurrency is enabled (gh#158).

Returns
true when distinct keys may run together. @utility
Version
2.13.0
Returns
true when distinct keys may run together. @dg_internal
Version
2.13.0

Definition at line 3703 of file engine.cpp.

◆ context_usage()

std::pair< int, int > entropic::AgentEngine::context_usage ( const std::vector< Message > &  messages) const

Get context usage for a message list.

Get context usage.

Parameters
messagesMessage list.
Returns
(tokens_used, max_tokens).
Version
1.8.4
Parameters
messagesMessage list.
Returns
(tokens_used, max_tokens). @req REQ-COMPACT-001
Version
1.8.4

Definition at line 1419 of file engine.cpp.

◆ defang_meta_action_envelope()

void entropic::AgentEngine::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 envelope.

gh#88 de-fang logic — see header.

delegate / pipeline (and peers) return their result as {"action":"x",...} JSON. Pushed verbatim into context, the model echoes that shape as its next "tool call" — which common_chat (PEG_GEMMA4) does not parse, so the call no-ops and the loop spirals to the iteration cap. The typed directive is already built by ToolExecutor::build_directive (target/task copied into the struct) before this runs, so the model-facing content can be replaced with a non-call prose status line without affecting dispatch. entropic.complete is de-fanged earlier by the fold above.

Public so unit tests can exercise the transform without spinning the full engine loop.

Parameters
msgTool-result message; content reshaped in place when it is an entropic.* meta-tool action envelope. @utility
Version
2.7.1

@req REQ-LOOP-007

Version
2.7.1

Definition at line 1813 of file engine.cpp.

◆ delegation_callbacks_snapshot()

AgentEngine::DelegationCallbacks entropic::AgentEngine::delegation_callbacks_snapshot ( ) const

Atomically snapshot the registered delegation callbacks.

Hot path is execute_pending_delegation / execute_pending_pipeline: they grab the triple under the mutex once and pass it forward to the per-call DelegationManager. Prevents a torn read where the consumer reassigns the callbacks mid-delegation. (Hardening landed alongside the 2.1.5 verification pass.)

Returns
Copy of the current callback struct. @utility
Version
2.1.5
Returns
Copy of the current callback triple. @req REQ-DELEG-002
Version
2.1.5

Definition at line 258 of file engine.cpp.

◆ directive_processor()

DirectiveProcessor & entropic::AgentEngine::directive_processor ( )
inline

Get directive processor for external hook wiring.

Returns
Reference to internal directive processor. @utility
Version
2.0.1

Definition at line 429 of file engine.h.

◆ drop_session()

bool entropic::AgentEngine::drop_session ( const std::string &  key)

Forget a session entirely.

Forget a session entirely — see header.

The default session ("") is cleared rather than erased, so the legacy reference-returning accessors stay total.

Parameters
keySession key.
Returns
true when a session was dropped or cleared. @req REQ-LOOP-001
Version
2.12.0
Parameters
keySession key.
Returns
true when a session was dropped or cleared. @dg_internal
Version
2.13.0

Definition at line 4303 of file engine.cpp.

◆ end_turn() [1/2]

void entropic::AgentEngine::end_turn ( )

Release the turn this thread claimed (gh#158).

Release the turn this thread claimed — see header (gh#158).

Releases by the key recorded at claim time, so a caller that claimed "A" cannot accidentally release "" — which is what an unkeyed release would have done for every pre-gh#158 call site.

@req REQ-API-009

Version
2.13.0

@dg_internal

Version
2.13.0

Definition at line 3666 of file engine.cpp.

◆ end_turn() [2/2]

void entropic::AgentEngine::end_turn ( const std::string &  key)

Release a turn claimed by try_begin_turn (gh#144 / gh#158).

Release a turn claimed for a named session — see header.

Only the caller whose try_begin_turn returned true may call this.

Parameters
keySession key that was claimed. @req REQ-API-009
Version
2.13.0
Parameters
keySession key that was claimed. @dg_internal
Version
2.13.0

Definition at line 3646 of file engine.cpp.

◆ fold_complete_into_assistant()

bool entropic::AgentEngine::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 tool-result user message that would otherwise land in history.

gh#68 fold logic — see header.

Returns true when the message was folded (caller should NOT push it). Returns false when the message should be pushed as-is.

Conservative — only folds when ALL of:

  1. msg.metadata["tool_name"] == "entropic.complete"
  2. ctx.messages.back() exists and has role == "assistant"
  3. that assistant message has empty content (typically the post-strip body when the model emitted only a tool_call)
  4. ctx.metadata["explicit_completion_summary"] is populated (set by dir_complete before this runs)

If the model also emitted prose around the tool_call, the assistant body is non-empty and we leave both messages alone to avoid silently overwriting legitimate text.

Public so unit tests can exercise the predicate without spinning the full engine loop + mocking the tool executor.

@utility

Version
2.3.4
Returns
true when the completion summary was folded into a trailing empty assistant message; false when the tool result was not entropic.complete or the turn was not foldable. @req REQ-LOOP-007
Version
2.3.7

Definition at line 1176 of file engine.cpp.

◆ get_messages()

const std::vector< Message > & entropic::AgentEngine::get_messages ( ) const

Get conversation messages (read-only).

Get conversation messages.

TOTAL over keys since gh#158 (v2.13.0) — see message_count(). An unknown active session yields an empty vector rather than throwing.

Returns
Const reference to the active session's message vector, or to an empty one when that session is unknown.
Version
2.13.0
Returns
Const reference to messages. @dg_internal
Version
2.13.0 [reviewed]

Definition at line 4365 of file engine.cpp.

◆ get_tier_allowed_tools()

std::vector< std::string > entropic::AgentEngine::get_tier_allowed_tools ( const std::string &  name) const

Return the allowed tool names registered for a tier (gh#121 regression).

Return allowed tool names for a tier (gh#121 regression test hook).

Exposed so facade-level tests can verify that populate_tier_info captured the correct allowed_tools list after cache_tier_allowed_tools filled h->tier_allowed_tools. Returns empty when the tier is unknown or when no allowed_tools were registered.

Parameters
nameTier name.
Returns
Allowed tool names (empty = unknown tier or all tools permitted).
Version
2.9.19
Parameters
nameTier name.
Returns
Allowed tools, empty when tier unknown or no filter registered. @req REQ-IDEN-001 @req REQ-LOOP-004
Version
2.9.19

Definition at line 4552 of file engine.cpp.

◆ has_tier()

bool entropic::AgentEngine::has_tier ( const std::string &  name) const

Whether a tier name is known (gh#99).

Backs entropic_run_as's unknown-tier validation. True once the tier has resolved context info (set_tier_info ran for it at configure time).

Parameters
nameTier name.
Returns
true if the tier is known.
Version
2.8.0
Parameters
nameTier name.
Returns
true if the tier has resolved context info. @req REQ-IDEN-001
Version
2.8.0

Definition at line 4540 of file engine.cpp.

◆ interrupt()

void entropic::AgentEngine::interrupt ( )

Interrupt the running loop (thread-safe).

Interrupt the running loop.

Version
1.8.4

Callable from any thread and polled per-token on the generation path, so interrupt() runs many times for a single Ctrl+C. Log only on the 0→1 transition to avoid flooding the session log. (P1-4, 2.0.6-rc16)

@req REQ-LOOP-006

Version
2.13.0

Definition at line 1292 of file engine.cpp.

◆ interrupt_session()

bool entropic::AgentEngine::interrupt_session ( const std::string &  key)

Interrupt exactly one session's run (gh#158).

Interrupt exactly one session's run — see header (gh#158).

interrupt() means "every run on this handle" and keeps that meaning. This means "that one", and deliberately does NOT fire the external transport latch: ServerManager::interrupt_external_tools() trips EVERY transport at once, so using it here would abort another session's in-flight MCP call — the gh#150 failure mode, re-introduced through a different door. The interrupted run's own tool call still aborts, because the run publishes its cancel token to its own thread (RunCancelScope) and the transport polls it.

Parameters
keySession whose run to interrupt. No-op when it is not running.
Returns
true when a run was found and flagged. @req REQ-LOOP-006
Version
2.13.0
Parameters
keySession whose run to interrupt.
Returns
true when a run was found and flagged. @dg_internal
Version
2.13.0

Definition at line 3728 of file engine.cpp.

◆ is_delegation_cycle()

bool entropic::AgentEngine::is_delegation_cycle ( const LoopContext &  ctx,
const std::string &  target 
) const

Check whether pending delegation would close a cycle.

Detect delegation cycles via ancestor chain check.

Exposed for unit tests. (P1-9, 2.0.6-rc16)

Parameters
ctxLoop context (ancestor chain + locked tier).
targetProposed delegation target tier.
Returns
true if target is already in the ancestor chain or matches the active locked_tier. @utility
Version
2.0.6-rc16

Targets already present in delegation_ancestor_tiers or matching the active locked_tier would re-enter an ancestor loop, which the depth cap only catches after repeated waste. (P1-9, 2.0.6-rc16)

Parameters
ctxLoop context.
targetPending delegation target tier name.
Returns
true if target would close a cycle. @req REQ-DELEG-001
Version
2.0.6-rc16

Definition at line 1145 of file engine.cpp.

◆ is_delegation_repeat_blocked()

bool entropic::AgentEngine::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? (gh#64)

gh#64: predicate for the consecutive-failure cap.

Returns true when target matches ctx.last_failed_delegation_target and ctx.consecutive_failed_delegations >= loop_config_.max_consecutive_failed_delegations. Exposed so tests can exercise the guard without spinning a full child loop.

Parameters
ctxActive loop context.
targetProposed delegation target tier.
Returns
true if the delegation should be rejected before dispatch. @utility
Version
2.3.0

See header.

Returns
true when the target matches the last failed delegation target and the consecutive-failure cap has been reached. @req REQ-DELEG-001
Version
2.3.0

Definition at line 1161 of file engine.cpp.

◆ is_running()

bool entropic::AgentEngine::is_running ( ) const
inline

Whether a top-level run_turn is currently in progress.

Used by the facade to reject entropic_queue_user_message with ENTROPIC_ERROR_INVALID_STATE when there is no in-flight turn to "queue behind." Thread-safe (atomic load).

Returns
true while a top-level run_turn is executing. @utility
Version
2.1.10

Definition at line 722 of file engine.h.

◆ isolation_unsafe_tools()

std::vector< std::string > entropic::AgentEngine::isolation_unsafe_tools ( const LoopContext &  ctx,
const std::string &  target_tier 
)

Child-visible external tools that break the isolation claim.

External tools a sandboxed child could write through (gh#160).

Empty when isolation is off (nothing is being claimed), when no resolver is wired, or when every reachable external tool declares readOnlyHint: true.

Parameters
ctxParent loop context (supplies the session key).
target_tierTier the delegation targets.
Returns
Offending fully-qualified tool names. @dg_internal
Version
2.13.0
Parameters
ctxParent loop context (session key).
target_tierTier the delegation targets.
Returns
Offending fully-qualified tool names; empty when safe. @req REQ-DELEG-005
Version
2.13.0

Definition at line 3459 of file engine.cpp.

◆ last_loop_metrics()

LoopMetrics entropic::AgentEngine::last_loop_metrics ( ) const

Get metrics from the most recent completed run.

Metrics from the most recent completed run — see header (gh#158).

Returns a copy of the LoopMetrics snapped at the end of the last call to run() or run_turn(). Zero-initialized before any run has completed. (P2-15)

gh#158 (v2.13.0): the copy is taken under metrics_mutex_. "Returns a copy" was never sufficient on its own — LoopMetrics is a multi-field struct, so an unlocked copy taken while a finishing run assigns it reads a TORN snapshot (new iterations, old tokens_used). Under per-handle serialization that write could not overlap a read from the consumer's thread often enough to matter; with keyed runs it can.

Returns
LoopMetrics from last run. @utility
Version
2.13.0
Returns
A copy of last_metrics_, taken under metrics_mutex_. @utility
Version
2.13.0

Definition at line 581 of file engine.cpp.

◆ loop_config()

const LoopConfig & entropic::AgentEngine::loop_config ( ) const
inline

Get loop configuration.

Returns
Const reference to loop config. @utility
Version
2.0.1

Definition at line 421 of file engine.h.

◆ message_count()

size_t entropic::AgentEngine::message_count ( ) const

Get conversation message count.

TOTAL over keys since gh#158 (v2.13.0): an active session key that is not in the map answers 0. It used to .at(), and both this and get_messages() are reached from the C ABI, where an escaping std::out_of_range is a std::terminate.

Returns
Number of messages; 0 when the active session is unknown.
Version
2.13.0

TOTAL over keys (gh#158): an active key that is not in the map answers 0 rather than throwing. .at() here reached the C ABI through entropic_context_count, where an escaping std::out_of_range is a std::terminate — the host dies because it asked how long a conversation was. Two ordinary sequences produce an absent key: dropping the session that is still the active one, and a concurrent run publishing its key (see set_active_session).

Returns
Number of messages, or 0 when the active session is unknown. @dg_internal
Version
2.13.0 [reviewed]

Definition at line 4248 of file engine.cpp.

◆ message_count_for()

std::size_t entropic::AgentEngine::message_count_for ( const std::string &  key) const

Message count for a named session.

Message count for a named session — see header.

Parameters
keySession key.
Returns
Count, or 0 when the key is unknown. @utility
Version
2.12.0
Parameters
keySession key.
Returns
Count, or 0 when the key is unknown. @dg_internal
Version
2.13.0

Definition at line 4278 of file engine.cpp.

◆ messages_for()

std::vector< Message > entropic::AgentEngine::messages_for ( const std::string &  key) const

Messages held by a named session.

Messages held by a named session — see header.

Returns BY VALUE, unlike the legacy get_messages(). A keyed entry can be erased by drop_session, and handing out a reference into an erasable node is a use-after-free waiting for a later refactor. The copy is a few thousand short strings on a path that runs once per turn, against a turn measured in seconds.

Parameters
keySession key.
Returns
That session's messages; empty when the key is unknown. @req REQ-LOOP-001
Version
2.12.0
Parameters
keySession key.
Returns
That session's messages; empty when the key is unknown. @dg_internal
Version
2.13.0

Definition at line 4264 of file engine.cpp.

◆ pause()

void entropic::AgentEngine::pause ( )

Pause generation (thread-safe).

Pause generation.

Version
1.8.4

@req REQ-LOOP-006

Version
1.8.4

Definition at line 1396 of file engine.cpp.

◆ per_tier_metrics()

std::unordered_map< std::string, LoopMetrics > entropic::AgentEngine::per_tier_metrics ( ) const

Per-tier aggregated metrics since engine start.

Per-tier aggregated metrics — see header (gh#158).

Keys are tier names ("lead", "eng", etc.). Values accumulate iterations/tool_calls/tokens_used/errors and sum duration_ms across every run_loop entered with that locked_tier. Empty map before any run. (P2-15 follow-up, 2.0.6-rc16.2)

gh#158 (v2.13.0): copied under metrics_mutex_. This one was the sharper of the two — entropic_metrics_json copied the map while a concurrent run did per_tier_metrics_[tier], and an insert that rehashes relocates every bucket under the copy's iterators. Not a torn number: undefined behaviour.

Returns
Copy of the per-tier metrics map. @utility
Version
2.13.0
Returns
A copy of the per-tier map, taken under metrics_mutex_. @utility
Version
2.13.0

Definition at line 593 of file engine.cpp.

◆ prepare_next_turn()

bool entropic::AgentEngine::prepare_next_turn ( std::vector< Message > &  pending)

Pull the next queued user message into pending (gh#40).

Extracted from run_turn's drain loop. Pops one queued message, fires ON_QUEUE_CONSUMED, and replaces pending with it.

Parameters
pendingOut: cleared and set to the next user turn.
Returns
true if a queued message was dequeued; false if empty. @dg_internal
Version
2.3.7
Parameters
pendingOut: cleared and set to the next user turn.
Returns
true if a queued message was dequeued; false if empty. @dg_internal
Version
2.3.7

Definition at line 4024 of file engine.cpp.

◆ queue_user_message()

bool entropic::AgentEngine::queue_user_message ( const std::string &  message)

Append a user message to the mid-gen queue.

Enqueue a user message subject to the configured cap.

Bounded FIFO. Enforces LoopConfig::message_queue_capacity. Drained between top-level run_turn invocations from inside run_turn itself — never at child-delegation boundaries.

Parameters
messageUser input to enqueue.
Returns
true if enqueued; false if the queue is at capacity. @threadsafety Thread-safe.
Version
2.1.10

@dg_internal

Version
2.1.10

Definition at line 4388 of file engine.cpp.

◆ reset_interrupt()

void entropic::AgentEngine::reset_interrupt ( )

Reset interrupt flag for next run.

Reset interrupt flag.

Version
1.8.4

@req REQ-LOOP-006

Version
2.13.0

Definition at line 1373 of file engine.cpp.

◆ resolve_session_root()

std::filesystem::path entropic::AgentEngine::resolve_session_root ( const std::string &  session_key)

Resolve the root a session's tools operate in (gh#160).

THE seam: sandbox roots, sandbox restore targets and (gh#166) workspace roots all come from here. Falls back to get_repo_dir() when the facade has not injected a resolver — which is what every unit test that builds a bare AgentEngine gets.

Parameters
session_keyCaller-scoped session key ("" = default).
Returns
Root directory, or empty when none resolves.
Version
2.13.0
Parameters
session_keyCaller-scoped session key.
Returns
The facade's answer, else the configured/CWD project dir. @req REQ-DELEG-002 @req REQ-DELEG-005
Version
2.13.0

Definition at line 3422 of file engine.cpp.

◆ run()

std::vector< Message > entropic::AgentEngine::run ( std::vector< Message >  messages,
const std::string &  tier_override = "" 
)

Run the engine on a set of messages.

Run the engine on initial messages.

Parameters
messagesInitial messages (system + user).
tier_overridegh#99: if non-empty, lock this run to the named tier (skips routing) so its grammar/samplers apply; empty routes.
Returns
Final messages including all generated content.
Version
2.8.0
Parameters
messagesSystem + user messages.
tier_overridegh#99: if non-empty, lock the run to this tier (lock_tier_if_needed honors a pre-set locked_tier and skips routing).
Returns
Final messages. @req REQ-LOOP-001 @req REQ-LOOP-002 @req REQ-COMPACT-002 @req REQ-IDEN-001
Version
2.13.0

Definition at line 471 of file engine.cpp.

◆ run_cancel_flag()

std::atomic< bool > & entropic::AgentEngine::run_cancel_flag ( )

The cancel flag of the run executing on THIS thread (gh#158).

The cancel flag of this thread's run — see header (gh#158).

Handed to paths that take a std::atomic<bool>& cancel token — entropic_run_batch is the one that had a LOCAL flag nobody could ever set, which is why it was uninterruptible.

Falls back to the handle-wide interrupt flag when no run is claimed on this thread, so the reference is always valid.

Returns
Reference to this run's cancel flag. @req REQ-LOOP-006
Version
2.13.0
Returns
Reference to this run's cancel flag. @dg_internal
Version
2.13.0

Definition at line 3764 of file engine.cpp.

◆ run_drain_loop()

std::vector< Message > entropic::AgentEngine::run_drain_loop ( std::string  pending,
const std::string &  tier_override 
)

Shared drain loop for run_turn / run_turn_as (gh#99).

Appends pending as a user turn, runs the agentic loop under tier_override ("" = route), then drains any mid-generation queued user messages as further turns. Extracted so both entry points stay under the SLOC gate.

Parameters
pendingFirst user turn for this call.
tier_overrideTier to lock the run to ("" = route).
Returns
Result messages from the final turn. @dg_internal
Version
2.8.0
Parameters
pendingFirst user turn for this call.
tier_overrideTier to lock the run to ("" = route).
Returns
Result messages from the final turn. @dg_internal
Version
2.12.0

Definition at line 3954 of file engine.cpp.

◆ run_loop()

void entropic::AgentEngine::run_loop ( LoopContext &  ctx,
bool  inherit_interrupt = false 
)

Run the engine loop on a pre-built context.

Used by DelegationManager for child loops. Public so the delegation manager (same .so) can invoke it.

gh#81 (v2.4.3): inherit_interrupt controls whether the pre-existing interrupt flag is cleared at entry. Top-level turns clear it (a fresh turn starts un-interrupted). Delegation child loops pass inherit_interrupt=true so a parent interrupt raised before/at dispatch is NOT cleared — "stop the engine" must stop children too, not reset on each nested loop.

Parameters
ctxLoop context to execute.
inherit_interruptWhen true, do not reset the interrupt flag at entry (child loops inherit the parent's state).
Version
2.4.3
Parameters
ctxLoop context to execute.
inherit_interruptWhen true, do not reset the interrupt flag. @req REQ-LOOP-001 @req REQ-LOOP-006 @req REQ-COMPACT-002 @req REQ-IDEN-001
Version
2.13.0

Definition at line 408 of file engine.cpp.

◆ run_streaming() [1/2]

int entropic::AgentEngine::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).

Same as run_turn but with streaming token output. Owns the StreamThinkFilter, cancel polling, and session logger wiring.

Parameters
inputUser input string.
on_tokenConsumer token callback (receives filtered UTF-8).
user_dataConsumer callback context.
cancel_flagPolled per-token, nullable. A set flag stops THIS run only (v2.14.0, gh#205), never other sessions' runs.
tierTier or identity to lock this turn to, with the semantics of run_turn_as(); "" (the default) routes as usual.
Returns
0 on success, 1 if cancelled, 2 on error.
Version
2.14.0
Parameters
inputUser input.
on_tokenConsumer callback (filtered, UTF-8 aligned).
user_dataConsumer context.
cancel_flagPolled per-token, nullable.
tierTier or identity to lock this turn to; "" routes as usual (gh#205, v2.14.0).
Returns
0=OK, 1=cancelled, 2=error. @req REQ-LOOP-001 @req REQ-LOOP-008
Version
2.14.2

Definition at line 4119 of file engine.cpp.

◆ run_streaming() [2/2]

int entropic::AgentEngine::run_streaming ( std::vector< Message >  new_messages,
TokenCallback  on_token,
void *  user_data,
int *  cancel_flag 
)

Streaming conversation turn from a pre-built message list (gh#37).

Multimodal-aware streaming run_turn overload (gh#37, v2.1.8).

Multimodal-aware streaming overload. Same content_parts preservation semantics as run_turn(vector<Message>), with token callback wiring identical to the single-string streaming variant.

Parameters
new_messagesMessages to add this turn.
on_tokenConsumer token callback (filtered UTF-8).
user_dataConsumer callback context.
cancel_flagPolled per-token, nullable.
Returns
0 on success, 1 if cancelled, 2 on error.
Version
2.1.8

Mirrors the single-string streaming variant — same stream filter, cancel polling, session logger wiring — but consumes a pre-built message list with content_parts preserved.

Parameters
new_messagesMessages to add this turn.
on_tokenFiltered token callback.
user_dataConsumer context.
cancel_flagPer-token cancel poll, nullable.
Returns
0=OK, 1=cancelled, 2=error. @req REQ-LOOP-001 @req REQ-LOOP-008
Version
2.14.2

Definition at line 4189 of file engine.cpp.

◆ run_turn() [1/2]

std::vector< Message > entropic::AgentEngine::run_turn ( const std::string &  input)

Run a single conversation turn (stateful).

Manages conversation history internally. Appends user message, runs the agentic loop, appends result messages.

Parameters
inputUser input string.
Returns
Full result messages from engine.
Version
2.0.2

gh#40 (v2.1.10): after the agent loop reaches top-level COMPLETE, drains any messages enqueued mid-generation via queue_user_message as additional turns under the same call. gh#99 (v2.8.0): the drain loop is shared with run_turn_as via run_drain_loop.

Parameters
inputUser input string.
Returns
Result messages from engine. @req REQ-LOOP-001
Version
2.13.0

Definition at line 3782 of file engine.cpp.

◆ run_turn() [2/2]

std::vector< Message > entropic::AgentEngine::run_turn ( std::vector< Message >  new_messages)

Run a single conversation turn from a pre-built message list (gh#37).

Run a stateful turn, draining any queued user messages (gh#40).

Multimodal-aware overload. Each message in new_messages is appended to the engine's conversation history with its content_parts preserved (no string flattening). The agentic loop runs over the full conversation; replies are appended to history and returned.

If the conversation is currently empty AND none of new_messages carries role == "system", the engine prepends its configured system_prompt_ first — matching the single-string overload's behavior.

Parameters
new_messagesMessages to add this turn (typically one user message; may include a system message on first turn).
Returns
Full result messages from the engine loop.
Version
2.1.8
Parameters
new_messagesMessages to add this turn.
Returns
Full result messages from the engine loop. @req REQ-LOOP-001
Version
2.12.0-rc1

Definition at line 4043 of file engine.cpp.

◆ run_turn_as()

std::vector< Message > entropic::AgentEngine::run_turn_as ( const std::string &  tier,
const std::string &  input 
)

Run a single turn under a named tier's grammar/identity (gh#99).

Run one turn under a named tier's grammar/identity (gh#99).

Per-call tier selection on the shared resident model: seeds the tier's system prompt (from tier_info_) and locks the run to tier so its grammar + samplers apply — no 2nd model load, no reconfigure. Mirrors the delegation precedent (a child LoopContext with locked_tier + the tier's system prompt), scoped to one top-level call.

Parameters
tierTier name to run this call under.
inputUser input string.
Returns
Full result messages from the engine.
Version
2.8.0

The tier's grammar + samplers apply to THIS call (via the tier_override that pre-locks the tier, skipping routing). The tier's system prompt is seeded only when the conversation is empty (the first call on a fresh handle) — on a stateful handle that interleaves tiers, later calls switch grammar per call but keep the existing system prompt + accumulated history. For isolated per-kind runs (e.g. distinct game-agent identities), clear context between calls or use a fresh handle.

Parameters
tierTier to lock this call to.
inputUser input string.
Returns
Result messages. @req REQ-IDEN-001
Version
2.12.0

Definition at line 3826 of file engine.cpp.

◆ sandbox_for_session()

SandboxManager * entropic::AgentEngine::sandbox_for_session ( const std::string &  session_key)

Sandbox manager for a session, or nullptr when isolation is off (gh#160).

Sandbox manager for a session, or nullptr when isolation is off.

Public for the same reason is_delegation_cycle is: it is the observable decision point of the isolation wiring, and a test that cannot see it can only assert on a real model run.

Parameters
session_keySession the delegation belongs to.
Returns
Manager rooted at the session's root, or nullptr when delegation.isolation is none or no root resolves. @dg_internal
Version
2.13.0
Parameters
session_keySession the delegation belongs to.
Returns
Manager rooted at the session's root, else nullptr. @req REQ-DELEG-005
Version
2.13.0

Definition at line 3443 of file engine.cpp.

◆ seconds_since_last_activity()

int64_t entropic::AgentEngine::seconds_since_last_activity ( ) const

gh#35: seconds since the engine last serviced a run().

gh#35: idle accessor.

Updated at the entry of every run()/run_turn() call. Hosts that want an idle-exit policy poll this and tear down the engine when the value exceeds their threshold. Returned as int64 (epoch seconds delta) so consumers can compare against any unit.

Returns
Seconds since last activity. Returns 0 if no run has ever happened (no activity to be idle relative to). @utility
Version
2.3.0

See header. @utility

Version
2.3.0

Definition at line 1196 of file engine.cpp.

◆ seed_system_prompt()

void entropic::AgentEngine::seed_system_prompt ( const std::vector< Message > &  new_messages)

Prepend the configured system prompt if this turn needs it.

Multimodal-aware run_turn overload (gh#37, v2.1.8).

Extracted from run_turn to keep it knots-clean. Seeds conversation_ with system_prompt_ only when the conversation is empty and the caller didn't supply its own system message.

Parameters
new_messagesThe messages the caller is adding this turn. @dg_internal
Version
2.3.7

Takes a pre-built list of messages and preserves their content_parts end-to-end (no string flattening). Each input message is appended verbatim to the engine's conversation history before the agent loop runs. If the conversation is empty and the caller did not supply a system message, the engine's configured system_prompt_ is prepended first — matching the single-string overload's first-turn behavior.

Parameters
new_messagesMessages to add this turn.
Returns
Result messages from the loop. @dg_internal
Version
2.1.10

Prepend the configured system prompt if this turn needs it.

Parameters
new_messagesThe messages the caller is adding this turn. @dg_internal
Version
2.13.0

Definition at line 4000 of file engine.cpp.

◆ seed_system_prompt_for_tier()

void entropic::AgentEngine::seed_system_prompt_for_tier ( const std::string &  tier)

Seed a tier's system prompt on an empty conversation (gh#99).

Pushes tier_info_[tier].system_prompt as the system message when the conversation is empty; falls back to the global system_prompt_ when the tier carries no info.

Parameters
tierTier whose system prompt to seed. @dg_internal
Version
2.8.0

Precedence: the session's workspace prompt for the tier (gh#179, v2.14.0), then tier_info_[tier].system_prompt, then the session's untiered prompt. No-op once the conversation has started — like run_turn's first-turn seeding, the system prompt is NOT re-seeded mid-session when a later run_turn_as names a different tier (the grammar/samplers still switch; only the prompt persists). See run_turn_as.

Parameters
tierTier whose system prompt to seed. @req REQ-IDEN-001
Version
2.14.0

Definition at line 3930 of file engine.cpp.

◆ session_interrupted()

bool entropic::AgentEngine::session_interrupted ( const std::string &  key) const

Whether a named session's in-flight run carries an interrupt.

Whether a session's in-flight run carries an interrupt (gh#158).

Parameters
keySession key.
Returns
true when that run exists and is flagged. @utility
Version
2.13.0
Parameters
keySession key.
Returns
true when that run exists and is flagged. @dg_internal
Version
2.13.0

Definition at line 3751 of file engine.cpp.

◆ session_keys()

std::vector< std::string > entropic::AgentEngine::session_keys ( ) const

Keys of every session the engine currently holds.

Keys of every session the engine holds — see header.

Returns
Session keys, unordered. @utility
Version
2.12.0
Returns
Session keys, unordered. @dg_internal
Version
2.13.0

Definition at line 4318 of file engine.cpp.

◆ session_system_prompt()

std::string entropic::AgentEngine::session_system_prompt ( const std::string &  session) const

The untiered system prompt a fresh conversation in session would be seeded with (gh#179).

The untiered prompt a fresh conversation in session gets (gh#179).

Parameters
sessionSession key.
Returns
The bound workspace's default prompt when it has one, else the handle's system prompt.
Version
2.14.0
Parameters
sessionSession key.
Returns
The workspace's default prompt when the session is bound to a workspace that has one, else the handle's system prompt. @req REQ-MCP-027
Version
2.14.0

Definition at line 3911 of file engine.cpp.

◆ set_active_session()

void entropic::AgentEngine::set_active_session ( const std::string &  key)

Bind this turn to a caller-scoped session (gh#144, v2.12.0).

Bind this turn to a caller-scoped session — see header.

"" is the default session and reproduces pre-2.12.0 behaviour exactly. The key is OPAQUE to the engine — a consumer picks whatever identifies a caller for it (a canonical repository path, a hash), which is why two callers may deliberately share one by using the same string.

Distinct from LoopContext::conversation_id, which is a storage FK minted fresh per run() and is neither caller-supplied nor stable, and from the per-handle log scope. One word, one meaning.

gh#158 (v2.13.0): the binding is published to the CALLING THREAD as well as to the handle. Two concurrent runs each need their own answer to "which session am I", and a single member field can only hold one. The member remains the answer for a thread that never bound a session, which is what keeps the legacy unkeyed accessors behaving as they did.

Parameters
keySession key for the turn about to run. @req REQ-LOOP-001
Version
2.13.0

The conversation entry is created BEFORE the key is published, and that order is load-bearing. Publishing first left a window in which another thread's unkeyed accessor resolved a key that was not yet in conversations_; both of those accessors then indexed the map with .at() and threw std::out_of_range out of a C entry point, aborting the host. The accessors are total now as well, so this ordering is the belt to their braces rather than the only guard.

Parameters
keySession key for the turn about to run. @dg_internal
Version
2.13.0 [reviewed]

Definition at line 3596 of file engine.cpp.

◆ set_callbacks()

void entropic::AgentEngine::set_callbacks ( const EngineCallbacks &  callbacks)

Set callback functions for loop events.

Parameters
callbacksCallback configuration.
Version
1.8.4
Parameters
callbacksCallback configuration. @dg_internal
Version
1.8.4

Definition at line 167 of file engine.cpp.

◆ set_concurrent_sessions()

void entropic::AgentEngine::set_concurrent_sessions ( bool  enabled)

Allow runs on DIFFERENT session keys to proceed together.

Allow distinct session keys to run together — see header.

Why this defaults ON, and what turning it off buys
Per-key runs are only safe once every piece of per-handle mutable state a turn touches is either per-run or locked. That audit is recorded in decision #66 of docs/architecture-cpp.md, and it is COMPLETE — which is the only reason the default moved. Passing false restores v2.12.0 semantics exactly (a second run on any key is refused), so a consumer who hits a concurrency defect in the field has a one-line escape hatch instead of a version pin.

Config key: concurrent_sessions: false.

Parameters
enabledtrue to allow concurrent distinct-key runs. @req REQ-LOOP-009
Version
2.13.0 [reviewed]
Parameters
enabledtrue to allow concurrent distinct-key runs. @dg_internal
Version
2.13.0

Definition at line 3690 of file engine.cpp.

◆ set_delegation_callbacks()

void entropic::AgentEngine::set_delegation_callbacks ( ent_decision_t(*)(const ent_delegation_request_t *, void *)  on_start,
ent_decision_t(*)(const ent_delegation_result_t *, void *)  on_complete,
void *  user_data 
)

Register delegation start/complete callbacks (gh#29, v2.1.5).

Replaces the pre-2.1.5 silent auto-merge-to-parent behavior. The engine stores these C-style function pointers and forwards them into every DelegationManager it constructs (one per pending delegation or pipeline). Null callbacks are honored: on_start null = always ACCEPT; on_complete null = default-deny (write patch to ~/.entropic/sandbox/<session>/pending/<id>.patch).

Parameters
on_startPre-delegation gate (nullable clears).
on_completePost-delegation result (nullable clears).
user_dataForwarded to both callbacks.
Version
2.1.5
Parameters
on_startPre-delegation gate (nullable).
on_completePost-delegation result (nullable).
user_dataForwarded to both callbacks. @req REQ-DELEG-002
Version
2.1.6

Definition at line 241 of file engine.cpp.

◆ set_dir_swap()

void entropic::AgentEngine::set_dir_swap ( ScopedSandbox::SwapDirFn  swap_fn,
void *  user_data 
)

Install the directory-swap callback used by sandboxing.

Install the tool-directory swap callback (gh#160).

gh#160: DelegationManager::set_dir_swap existed from v2.1.5 and had NO production caller, so every ScopedSandbox took the non-sandboxed branch and children wrote straight into the user's tree. The engine now holds the callback and hands it to every DelegationManager it builds.

Parameters
swap_fnSwap callback (nullptr disables sandbox entry).
user_dataForwarded to the callback.
Version
2.13.0
Parameters
swap_fnSwap callback (nullptr disables sandbox entry).
user_dataForwarded to the callback. @dg_internal
Version
2.13.0

Definition at line 3389 of file engine.cpp.

◆ set_external_interrupt()

void entropic::AgentEngine::set_external_interrupt ( void(*)(void *user_data)  cb,
void *  user_data 
)

Register a callback invoked alongside interrupt().

Register external transport interrupt callback.

Used to propagate Ctrl+C into external MCP transports so in-flight tool calls do not run to completion. Facade wires this to ServerManager::interrupt_external_tools(). (P1-10, 2.0.6-rc16)

Parameters
cbCallback (nullable).
user_dataForwarded to cb.
Version
2.0.6-rc16

Facade wires this to ServerManager::interrupt_external_tools so AgentEngine::interrupt() unwinds tool dispatches within ~100ms. (P1-10, 2.0.6-rc16)

Parameters
cbCallback (nullable).
user_dataForwarded to cb. @req REQ-LOOP-006
Version
2.0.6-rc16

Definition at line 1344 of file engine.cpp.

◆ set_external_reset()

void entropic::AgentEngine::set_external_reset ( void(*)(void *user_data)  cb,
void *  user_data 
)

Register the external transport interrupt-release callback.

Register external transport interrupt-release callback.

gh#150: the counterpart to set_external_interrupt(). The facade wires this to ServerManager::clear_external_tool_interrupts so reset_interrupt() releases the transports it interrupted. Without it an interrupt was permanent, because the engine cleared only its own flag.

Parameters
cbCallback (nullable).
user_dataForwarded to cb. @req REQ-LOOP-006
Version
2.12.1

Facade wires this to ServerManager::clear_external_tool_interrupts so AgentEngine::reset_interrupt() releases what interrupt() suppressed. (gh#150)

Parameters
cbCallback (nullable).
user_dataForwarded to cb. @req REQ-LOOP-006
Version
2.12.1

Definition at line 1362 of file engine.cpp.

◆ set_handoff_rules()

void entropic::AgentEngine::set_handoff_rules ( const std::unordered_map< std::string, std::vector< std::string > > &  rules)

Store handoff rules for tier delegation.

Store handoff rules.

Parameters
rulesMap of source tier → valid target tiers.
Version
2.0.2
Parameters
rulesSource tier → valid targets. @req REQ-IDEN-003 @req REQ-IDEN-001
Version
2.0.2

Definition at line 4590 of file engine.cpp.

◆ set_hooks()

void entropic::AgentEngine::set_hooks ( const HookInterface &  hooks)

Set the hook dispatch interface.

Parameters
hooksHook dispatch interface (wired by facade).
Version
1.9.1
Parameters
hooksHook dispatch interface. @req REQ-HOOK-002
Version
1.9.1

Definition at line 210 of file engine.cpp.

◆ set_message_queue_capacity()

void entropic::AgentEngine::set_message_queue_capacity ( int  cap)

Set the runtime capacity of the mid-gen queue.

Update the runtime cap (in-place on LoopConfig).

If cap is less than the current depth, excess pending messages are kept (no truncation) but no new enqueues succeed until the queue drains below the new cap. cap of 0 disables enqueue while leaving the queue otherwise functional.

Parameters
capNew capacity. @threadsafety Thread-safe.
Version
2.1.10

@dg_internal

Version
2.1.10

Definition at line 4431 of file engine.cpp.

◆ set_project_dir()

void entropic::AgentEngine::set_project_dir ( const std::filesystem::path &  project_dir)

Set the configured project directory (gh#31, v2.1.6).

Store the project_dir resolved by entropic_configure_dir.

The facade calls this from entropic_configure_dir after the layered config loader has resolved the project root. get_repo_dir() uses this value in preference to std::filesystem::current_path(), so consumers whose launcher cwd differs from the target project (the common case for wrapper CLIs and IDE plugins) still snapshot the right tree into the sandbox.

Pre-2.1.6 the engine used CWD unconditionally, silently ignoring the project_dir argument to entropic_configure_dir. Setting an empty path resets the override so get_repo_dir() falls back to CWD (preserves the no-configure-dir caller's behavior).

Parameters
project_dirProject root (empty resets to CWD fallback). @threadsafety Serialized per-handle via the facade's api_mutex.
Version
2.1.6

gh#31 (v2.1.6). See engine.h for rationale. Resets the cache so a subsequent get_repo_dir() call picks up the new value even if a previous lookup already settled on the CWD fallback.

Parameters
project_dirProject root (empty resets to CWD fallback). @dg_internal
Version
2.13.0

Definition at line 3136 of file engine.cpp.

◆ set_queue_observer()

void entropic::AgentEngine::set_queue_observer ( void(*)(const char *, size_t, void *)  observer,
void *  user_data 
)

Register an observer that fires when a queued user message is consumed and seeded as the next turn.

Persistent slot setter; survives set_callbacks() shuffles.

Persistent across set_callbacks() reassignments — the streaming entry points overwrite the EngineCallbacks struct per-call, so the queue observer needs a dedicated slot to survive both streaming and non-streaming runs.

Parameters
observerCallback (consumed_text, remaining_depth, ud). Pass nullptr to clear.
user_dataForwarded to observer. @threadsafety Thread-safe.
Version
2.1.10

@dg_internal

Version
2.1.10

Definition at line 4470 of file engine.cpp.

◆ set_relay_single_delegate()

void entropic::AgentEngine::set_relay_single_delegate ( const std::string &  name)

Mark a tier as relay-on-single-delegate.

When this tier is the active (lead) tier and exactly one delegate completes successfully, the delegate's summary is used as the final output without lead re-generating. Avoids redundant re-synthesis of already user-ready delegate responses.

Parameters
nameTier name (typically "lead").
Version
2.0.11
Parameters
nameTier name. @req REQ-DELEG-003
Version
2.0.11

Definition at line 4579 of file engine.cpp.

◆ set_session_logger()

void entropic::AgentEngine::set_session_logger ( SessionLogger *  log)

Set session logger for model transcript logging.

Parameters
loggerNon-owning pointer (nullable). Must outlive engine.
Version
2.0.2
Parameters
logNon-owning pointer (nullable). @dg_internal
Version
2.0.2

Definition at line 3516 of file engine.cpp.

◆ set_session_messages()

bool entropic::AgentEngine::set_session_messages ( const std::string &  key,
std::vector< Message >  messages 
)

Replace one session's conversation wholesale (gh#165, v2.13.0).

Replace one session's conversation wholesale (gh#165) — see header.

The write counterpart entropic_session_context_get never had, so a session could be read out but not restored: a host that stopped the engine to free VRAM lost every conversation, and the only way to put messages back — entropic_run_session — RUNS a turn per message, re-executing the whole agentic loop including tool calls.

Refuses the session that is CURRENTLY RUNNING. Every other session stays mutable mid-run: the restriction is about the conversation this turn is appending to, not about the handle being busy.

Parameters
keySession key; "" is the default session.
messagesReplacement conversation.
Returns
true when the session was replaced; false when a run on that key is in flight and the conversation was left untouched. @req REQ-LOOP-010
Version
2.13.0

Refuses the RUNNING session and only that one. "Busy handle" would be the wrong rule: the conversation a turn appends to is the one that must not be swapped under it, and every other session is inert from that turn's point of view.

Parameters
keySession key.
messagesReplacement conversation.
Returns
true when replaced; false when a run on that key is in flight. @req REQ-LOOP-010 @dg_internal
Version
2.13.0

Definition at line 4341 of file engine.cpp.

◆ set_session_root_interface()

void entropic::AgentEngine::set_session_root_interface ( const SessionRootInterface &  iface)

Inject the session-root / tool-reach seam (gh#160, v2.13.0).

Install the facade's session-root seam (gh#160).

The facade owns the ServerManager and therefore the only truthful answer to "which directory do this session's tools resolve against". Without this the engine snapshotted its own repo_dir while the servers worked somewhere else, and delegation patches came out empty — the gh#160 report.

Parameters
ifaceResolver callbacks (a default-constructed value clears the wiring and restores the get_repo_dir() fallback).
Version
2.13.0
Parameters
ifaceResolver callbacks. @dg_internal
Version
2.13.0

Definition at line 3376 of file engine.cpp.

◆ set_state_observer()

void entropic::AgentEngine::set_state_observer ( void(*)(int state, void *user_data)  observer,
void *  user_data 
)

Register a persistent state-transition observer.

Wire the persistent state-observer slot.

The legacy path (EngineCallbacks::on_state_change) is wiped for the duration of run_streaming because that method replaces the full callback struct to install its token sink. This persistent slot survives every set_callbacks() shuffle so consumers (notably the external MCP bridge that the entropic_set_state_observer docstring names) actually see transitions during streaming runs.

Fires alongside the legacy on_state_change slot — neither supersedes the other. Pass nullptr to clear.

Parameters
observerState-change callback.
user_dataForwarded to observer. @threadsafety Thread-safe.
Version
2.1.10

Forwarded to ResponseGenerator so the PAUSED transition that ResponseGenerator emits during handle_pause also reaches the persistent slot. The legacy EngineCallbacks::on_state_change remains supported in parallel for in-tree callers (tests etc.).

@req REQ-LOOP-001

Version
2.1.10

Definition at line 4488 of file engine.cpp.

◆ set_storage()

void entropic::AgentEngine::set_storage ( const StorageInterface &  storage)

Set the storage interface for persistence.

Parameters
storageStorage callbacks (wired by facade). Nullable — engine works without storage (in-memory only mode).
Version
1.8.8
Parameters
storageStorage callbacks (nullable). @dg_internal
Version
1.8.8

Definition at line 199 of file engine.cpp.

◆ set_stream_observer()

void entropic::AgentEngine::set_stream_observer ( TokenCallback  observer,
void *  user_data 
)

Set the global stream observer.

Fires for every token from every generation path — batch entropic_run, entropic_run_streaming, and delegate child-loop generations. Persists across per-call EngineCallbacks reassignment.

Parameters
observerToken callback (nullable clears).
user_dataForwarded to observer.
Version
2.0.6-rc16

Delegates to ResponseGenerator which owns the choke point for every generation path (streaming, batch, and child-loop delegations).

Parameters
observerToken callback (nullable).
user_dataForwarded to observer. @dg_internal
Version
2.0.6-rc16

Definition at line 228 of file engine.cpp.

◆ set_system_prompt()

void entropic::AgentEngine::set_system_prompt ( const std::string &  prompt)

Set the system prompt for conversation state.

Parameters
promptAssembled system prompt string.
Version
2.0.2

gh#158 (v2.13.0): under prompt_mutex_. The setter runs on the API thread (which holds api_mutex) and every reader runs on a run thread (which, since gh#109, holds nothing) — so api_mutex never made this pair safe, and keyed runs add a second concurrent reader.

Parameters
promptAssembled system prompt. @dg_internal
Version
2.13.0

Definition at line 3491 of file engine.cpp.

◆ set_tier_info()

void entropic::AgentEngine::set_tier_info ( const std::string &  name,
const ChildContextInfo &  info 
)

Store pre-resolved tier context info.

Called at configure time. The engine uses this data for delegation instead of external TierResolutionInterface callbacks.

Parameters
nameTier name.
infoPre-resolved context info (system prompt, tools, etc.).
Version
2.0.2
Parameters
nameTier name.
infoContext info. @req REQ-IDEN-001
Version
2.0.2

Definition at line 4526 of file engine.cpp.

◆ set_tier_resolution()

void entropic::AgentEngine::set_tier_resolution ( const TierResolutionInterface &  tier_res)

Set the tier resolution interface for delegation.

Set tier resolution interface for delegation.

Parameters
tier_resTier resolution callbacks (wired by facade).
Version
1.8.6
Parameters
tier_resTier resolution callbacks. @req REQ-IDEN-001
Version
1.8.6

Definition at line 188 of file engine.cpp.

◆ set_tool_executor()

void entropic::AgentEngine::set_tool_executor ( const ToolExecutionInterface &  tool_exec)

Set the tool execution interface.

Parameters
tool_execTool execution interface (wired by facade).
Version
1.8.5
Parameters
tool_execTool execution interface. @dg_internal
Version
1.8.5

Definition at line 177 of file engine.cpp.

◆ set_validation_provider()

void entropic::AgentEngine::set_validation_provider ( char *(*)(void *)  provider,
void *  user_data 
)

Register a JSON provider for the validation block in ON_COMPLETE hook context.

Register validation JSON provider for ON_COMPLETE context.

The callback returns a malloc'd JSON object describing the validator's most recent result: {ran, verdict, violations, revisions_applied} The engine copies and frees the returned buffer. NULL return or nullptr callback means no validation block is emitted. (E3, 2.0.6-rc17)

Parameters
providerJSON builder (nullable clears).
user_dataForwarded to provider.
Version
2.0.6-rc17
Parameters
providerJSON builder callback (nullable).
user_dataForwarded to provider. @req REQ-DELEG-003
Version
2.0.6-rc17

Definition at line 270 of file engine.cpp.

◆ set_workspace_prompts()

void entropic::AgentEngine::set_workspace_prompts ( const std::string &  workspace,
WorkspacePrompts  prompts 
)

Register (or replace) one workspace's assembled prompts.

Register (or replace) one workspace's assembled prompts (gh#179).

Takes effect for every session bound to workspace whose conversation has not started; a started conversation keeps the system message it was seeded with.

Parameters
workspaceWorkspace name.
promptsAssembled prompts.
Version
2.14.0
Parameters
workspaceWorkspace name.
promptsAssembled prompts. @req REQ-MCP-027
Version
2.14.0

Definition at line 3844 of file engine.cpp.

◆ tier_requires_explicit_completion()

bool entropic::AgentEngine::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 turn.

Check if a tier contractually requires explicit completion.

Exposed for unit tests. (P1-6, 2.0.6-rc16)

Parameters
tierTier name.
Returns
true if the tier has explicit_completion=true. @utility
Version
2.0.6-rc16

Delegates to the TierResolutionInterface, falling back to false when no resolver is wired (preserves legacy behavior in tests that omit tier metadata).

Parameters
tierTier name.
Returns
true if the tier's explicit_completion flag is set. @req REQ-IDEN-001
Version
2.0.6-rc16.1

Definition at line 1124 of file engine.cpp.

◆ tier_resolution()

const TierResolutionInterface & entropic::AgentEngine::tier_resolution ( ) const

Get the tier resolution interface.

Returns
Tier resolution interface reference.
Version
1.8.6
Returns
Tier resolution interface. @req REQ-IDEN-001
Version
1.8.6

Definition at line 282 of file engine.cpp.

◆ tier_system_prompt()

const std::string & entropic::AgentEngine::tier_system_prompt ( const std::string &  name) const

A tier's resolved system prompt (gh#98).

Backs the batch entry point, which builds each request's messages with its tier's system prompt so same-tier requests share a prompt prefix.

Parameters
nameTier name.
Returns
The tier's system prompt, or "" if the tier is unknown.
Version
2.8.0
Parameters
nameTier name.
Returns
The tier's system prompt, or "" if unknown. @req REQ-IDEN-001
Version
2.8.0

Definition at line 4566 of file engine.cpp.

◆ try_begin_turn() [1/2]

bool entropic::AgentEngine::try_begin_turn ( )
inline

Claim a turn for the session bound to THIS thread (gh#158).

The no-argument form every pre-gh#158 call site already uses. It resolves to whatever set_active_session published on this thread, so run_turn's internal "claim only if the caller has not already" probe asks about the right session rather than always about "".

Returns
As try_begin_turn(key). @req REQ-API-009
Version
2.13.0

Definition at line 767 of file engine.h.

◆ try_begin_turn() [2/2]

bool entropic::AgentEngine::try_begin_turn ( const std::string &  key)

Try to claim one turn for a named session (gh#144 / gh#158).

Claim one turn for a named session — see header (gh#158).

What the claim costs
gh#144 made it a compare-exchange on running_flag_ — deliberately NOT a mutex, because gh#109 removed api_mutex from every run entry point so a long turn could not block entropic_interrupt() from another thread. gh#158 keys the claim, which needs a map, which needs a lock — but runs_mutex_ is held only for the O(1) insert and is NEVER held across a decode, a prefill or a tool call. That is the property gh#109 actually protects; a lock held for nanoseconds does not violate it, whereas api_mutex (held for the whole turn) did.
What the key changes
Two runs on the SAME key are always a genuine conflict — they share one conversation — so the second is refused whatever the configuration. Two runs on DIFFERENT keys proceed together unless set_concurrent_sessions(false) has been called; with the kill switch thrown the guard is handle-exclusive again and v2.12.0 semantics hold byte for byte.
Parameters
keySession key to claim; "" is the default session.
Returns
true when this caller now owns the turn and MUST call end_turn(key); false when the claim is refused, in which case the caller owns nothing and must not release. @req REQ-API-009 @req REQ-LOOP-009
Version
2.13.0 [reviewed]
Parameters
keySession key to claim.
Returns
true when this caller now owns the turn. @dg_internal
Version
2.13.0

Definition at line 3614 of file engine.cpp.

◆ user_message_queue_depth()

size_t entropic::AgentEngine::user_message_queue_depth ( ) const

Snapshot of the queue depth.

Read queue depth under the queue mutex.

@threadsafety Thread-safe.

Version
2.1.10

@dg_internal

Version
2.1.10

Definition at line 4407 of file engine.cpp.

Member Data Documentation

◆ MAX_DELEGATION_DEPTH

constexpr int entropic::AgentEngine::MAX_DELEGATION_DEPTH = 2
staticconstexpr

Max delegation nesting depth (0=root, 1=child, 2=max).

Version
1.8.6

Definition at line 69 of file engine.h.


The documentation for this class was generated from the following files: