package loop import ( "log/slog" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/agent" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/guardrail" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/persist" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/tool" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace" ) // Options configures a Loop. All fields are optional and nil is tolerated until // the step that actually needs the field: the agent is required for Run (Run // returns ErrNilAgent otherwise); a missing tool dispatcher causes a requested // call to be fed back as an error; a missing retriever/persona skips memory // injection; a missing extractor/store skips the memory hook; a missing // checkpoint skips persistence; a missing tracer skips tracing. type Options struct { // Agent is the loop's execution unit: an instruction string plus a backend // adapter, an optional tool dispatcher and optional guardrails. Agent *agent.Agent // Tools is the tool dispatcher used to execute model-requested calls. When // nil the loop falls back to the agent's own dispatcher (if any). Tools *tool.Dispatcher // Memory is the long-term memory store used to persist extracted items. Memory *memory.Store // Retriever injects relevant memories into the first-turn context. Retriever *memory.Retriever // WorkingMemory is the per-session sliding window, provided for the // orchestrator to inspect; the loop does not mutate it. WorkingMemory *memory.WorkingMemory // Extractor derives memory items to persist after every step. Extractor memory.Extractor // Checkpoint persists a durable snapshot of the loop state at every step. Checkpoint *persist.Store // Tracer emits a structured span for every step, LLM call and tool call. Tracer *trace.Tracer // Guards validates request/response payloads on the streaming path, where // RunStep is bypassed. On the non-streaming path the agent runs its own // guardrails inside RunStep. Guards *guardrail.Pipeline // PersonaID scopes memory retrieval and extraction. Blank skips both. PersonaID string // MaxRounds is the tool-loop upper bound. Non-positive selects // DefaultMaxRounds (8). MaxRounds int // OnStream, when non-nil, switches the loop to the streaming path: the model // adapter's ChatStream is driven directly and each structured stream event is // forwarded to this callback (model.StreamEvent), so the frontend can render // body text, tool calls and (eventually) reasoning segments independently. OnStream func(model.StreamEvent) // Log is the base logger. Nil is replaced with a discard logger tagged with // source "runtime/loop". Log *slog.Logger }