# Strategy Internals
You want to extend strategy behavior without breaking machine/runtime contracts.
After this guide, you can safely modify strategy adapters and preserve signal/directive semantics.
## Strategy Modules
- `Jido.AI.Reasoning.ReAct.Strategy`
- `Jido.AI.Reasoning.ChainOfThought.Strategy`
- `Jido.AI.Reasoning.AlgorithmOfThoughts.Strategy`
- `Jido.AI.Reasoning.TreeOfThoughts.Strategy`
- `Jido.AI.Reasoning.GraphOfThoughts.Strategy`
- `Jido.AI.Reasoning.TRM.Strategy`
- `Jido.AI.Reasoning.Adaptive.Strategy`
Each strategy acts as a thin adapter around a state machine and implements:
- `action_spec/1`
- `signal_routes/1`
- `snapshot/2`
- `init/2`
- `cmd/3`
## Extension Pattern
1. Add new action atom and schema in `@action_specs`.
2. Route incoming signal in `signal_routes/1`.
3. Translate to machine message in instruction processing.
4. Lift machine directives into runtime directives.
5. Keep state updates inside strategy state (`__strategy__`).
## Example: New Strategy Signal Route
```elixir
@impl true
def signal_routes(_ctx) do
[
{"ai.react.query", {:strategy_cmd, @start}},
{"ai.llm.response", {:strategy_cmd, @llm_result}},
{"ai.request.error", {:strategy_cmd, @request_error}}
]
end
```
## Failure Mode: Contract Drift Between Strategy And Machine
Symptom:
- machine receives unknown event shape
- request never completes
Fix:
- keep translation layer explicit and typed
- update both strategy instruction mapping and machine update clauses together
## Defaults You Should Know
- most strategies default model alias to `:fast` (resolved via `Jido.AI.resolve_model/1`)
- request error routing is standardized via `ai.request.error`
- Adaptive delegates to selected strategy and can re-evaluate on new prompts
## Algorithm-of-Thoughts Specific Internals
`Jido.AI.Reasoning.AlgorithmOfThoughts.Strategy` is single-query by design:
- one `Directive.LLMStream` call per request
- machine flow is `idle -> exploring -> completed/error`
- query signal is `ai.aot.query`
- plugin run signal is `reasoning.aot.run`
AoT result contract is structured:
- `answer`
- `found_solution?`
- `first_operations_considered`
- `backtracking_steps`
- `raw_response`
- `usage`
- `termination` (`reason`, `status`, `duration_ms`)
- `diagnostics`
## Tree-of-Thoughts Specific Internals
`Jido.AI.Reasoning.TreeOfThoughts.Strategy` now enforces a structured result contract from the machine:
- `snapshot.result` is a map (best/candidates/termination/tree/usage/diagnostics)
- CLI adapters should project `result.best.content` for human-readable answer text
- full structured payload should be preserved in metadata (`tot_result`)
ToT parser flow is JSON-first with regex fallback:
1. Parse strict JSON for generation/evaluation outputs
2. Fallback to regex parsing
3. Retry once (configurable) with repair prompt
4. Emit structured diagnostics on terminal parse failure
ToT tool orchestration is strategy-managed:
- `ai.tool.result` signals (including error envelopes) are routed back into the strategy
- machine progression pauses during tool rounds
- tool effects are applied in original tool-call order after the round is complete
- follow-up LLM calls are issued with assistant tool-call + tool messages
- follow-up tool messages preserve original tool-call order
- round trips are bounded by `max_tool_round_trips`
## Tool Context State Snapshot Contract
For tool-executing strategy paths, action context includes a state snapshot under:
- `:state` (canonical, core Jido-compatible)
Current behavior by strategy:
- ReAct: snapshot is injected at request start and refreshed between tool rounds after applying allowed `StateOp` effects in deterministic tool-call order.
- ToT: snapshot is injected into each `Directive.ToolExec` context when the tool round is started.
- Adaptive: inherits this behavior when delegating to ReAct/ToT.
This key is runtime-managed and overrides same-named entries from user `tool_context`.
## ReAct Context Projection Internals
ReAct now uses explicit separation between core event log and LLM projection:
- Core append-only log: `agent.state[:__thread__]` (`Jido.Thread`)
- ReAct materialized view: `agent.state[:__strategy__].context` (`Jido.AI.Context`)
Canonical ReAct control surface:
- `ai.react.context.modify`
- `ai.react.steer`
- `ai.react.inject`
Core thread entries emitted by ReAct:
- `:ai_message` for user/assistant/tool message lifecycle
- `:ai_context_operation` for context operations (`replace`, `switch`)
Pending-input semantics:
- active runs own a per-run `Jido.AI.PendingInputServer`
- `ai.react.steer` and `ai.react.inject` synchronously enqueue user-style input there
- enqueue success means the input is queued for best-effort delivery, not durably accepted
- queued input is not appended to the core thread on enqueue
- runtime emits `:input_injected` only when it drains queued input into `run_context`
- strategy appends a user `:ai_message` only on `:input_injected`, so undrained input is not persisted
- if a run fails, is cancelled, or exits before drain, queued input is dropped
- `:request_completed` is emitted only after the runtime confirms the pending-input queue is empty and sealed
Deferred semantics:
- If a run is active, context operations are stored as `pending_context_op`
- Deferred op is applied after terminal event (`completed`, `failed`, `cancelled`, worker-exit failure)
Projection semantics:
- ReAct projects lane-specific context using `context_ref`
- Projection starts from latest `replace` anchor and folds subsequent `ai_message` entries
See full model: [Thread-Context Projection Model](thread_context_projection_model.md)
## When To Use / Not Use
Use this when:
- adding strategy features or new control signals
Do not use this when:
- you only need tool definitions or plugin-level changes
## Next
- [Architecture And Runtime Flow](architecture_and_runtime_flow.md)
- [Directives Runtime Contract](directives_runtime_contract.md)
- [Configuration Reference](configuration_reference.md)