Core Concepts
AI as Actor
AI as an actor, not the controller
Loop Engine treats AI the same way it treats humans and automation: as an attributed actor constrained by transitions and guards.
What AI can do
- inspect loop state in your application layer
- recommend transitions with evidence
- execute transitions where
allowedActorsincludesai-agent
What AI cannot do
- bypass
allowedActors - bypass hard guards
- modify loop definitions at runtime
- execute indefinitely if circuit-breaker constraints block it
AIAgentActor shape
1interface AIAgentActor extends ActorRef {2 type: "ai-agent"3 agentId: string4 gatewaySessionId: string5 recommendedBy?: string6}AI submission flow
1"cmt">// @no-typecheck2"cmt">// F-38: canonical `AIAgentActor` + submission types are being realigned in SR-024; this block stays illustrative.3import { actorId, transitionId } from '@loop-engine/core'4import { canActorExecuteTransition, buildActorEvidence, type AIAgentActor } from '@loop-engine/actors'5 6const agent: AIAgentActor = {7 type: 'ai-agent',8 id: actorId('agent:demand-forecaster'),9 agentId: 'claude-3-5-sonnet',10 gatewaySessionId: session.id11}12 13const auth = canActorExecuteTransition(agent, transition)14if (auth.authorized) {15 const evidence = buildActorEvidence(agent, {16 ai_confidence: 0.94,17 ai_reasoning: 'Stock level below reorder point; lead time elevated',18 recommended_qty: 50019 })20 21 await engine.transition({22 aggregateId,23 transitionId: transitionId('trigger_po'),24 actor: { type: agent.type, id: String(agent.id) },25 evidence26 })27}Provider implementations
The actor contract stays constant across providers. Only SDK wiring changes.
1"cmt">// Anthropic path (Claude)2const claudeActor: AIAgentActor = {3 type: "ai-agent",4 id: actorId("agent:demand-forecaster"),5 agentId: "claude-sonnet-4-20250514",6 gatewaySessionId: "claude-session-123"7}8 9"cmt">// OpenAI path (GPT-4o)10const openAiActor: AIAgentActor = {11 type: "ai-agent",12 id: actorId("agent:demand-forecaster"),13 agentId: "gpt-4o",14 gatewaySessionId: "openai-session-123"15}Anthropic and OpenAI both submit through the same transition path and evidence schema:
ai_confidenceai_reasoningrecommended_actionrecommended_qty
Safety constraints
- Confidence
0.58onrecommend_replenishmentreturnsguard_failedand holds state atAI_ANALYSIS. - Confidence
0.82passesconfidence_thresholdand advances toPENDING_BUYER_APPROVAL. - AI attempts on
approve_replenishmentare rejected when transitionallowedActorsis["human"].
Deep-dive example
The full dual-provider walkthrough is in /docs/examples/ai-replenishment, with source links for both provider adapters:
Available AI adapters
| Package | Models |
|---|---|
| @loop-engine/adapter-anthropic | Claude (claude-opus-4-6, claude-sonnet-4-6) |
| @loop-engine/adapter-openai | OpenAI (gpt-4o, o-series) |
| @loop-engine/adapter-grok | Grok (grok-3, grok-2) via xAI |
| @loop-engine/adapter-gemini | Gemini (gemini-1.5-pro, gemini-2.0-flash) |
| @loop-engine/adapter-perplexity | Perplexity Sonar (sonar, sonar-pro, …) — ToolAdapter with citations for research steps |
The Perplexity package implements ToolAdapter.invoke() (text + citations), not the actor createSubmission flow. Use it where you need grounded retrieval inside a loop; use the actor adapters above for structured signal decisions.