Repository navigation
Releases: laragentic/agents
Release list
v0.8.1
Bug Fix
String-based PausesLoop detection for SDK-resolved tool results
The Prism gateway stringifies all tool results before they reach the agentic loop, so instanceof PausesLoop checks never matched for SDK-resolved tools. This caused loops to continue iterating instead of pausing when a tool returned a PausesLoop signal.
Changes
- Added
MARKER_KEYconstant toPausesLoopcontract — implementations must include this key in their__toString()output - Created
PauseSignal::isSignal()static helper for string-based detection (mirrorsAskHumanSignal::isSignal()) - Updated both
ReActLoopandPlanExecuteLoopto detect pauses viainstanceof || PauseSignal::isSignal() LoopResult::$pauseSignalandPlanResult::$pauseSignalare now?string(stringified JSON) instead of?PausesLooponPausecallbacks now receivestring $signalas the first argument
Migration
If you have onPause callbacks, update the first parameter type from PausesLoop to string:
// Before
->onPause(function (PausesLoop $signal, ...) { ... })
// After
->onPause(function (string $signal, ...) { ... })If you have custom PausesLoop implementations, include the marker in __toString():
public function __toString(): string
{
return json_encode([
self::MARKER_KEY => true,
// ... your payload
]);
}v0.8.0
What's New
PausesLoop Support in PlanExecuteLoop
The PlanExecuteLoop now correctly detects and handles PausesLoop tool results during step execution. Previously, only the ReActLoop supported pausing when a tool required human interaction (e.g. an SDK app rendering an interactive iframe). This caused the plan-execute loop to keep running through remaining steps instead of pausing and waiting for user input.
The Problem
When using Plan & Execute mode with SDK app tools (like a Stamp Duty Calculator), the loop would:
- Execute the SDK app tool in step 1 — returning an iframe render payload
- Not pause — continue to steps 2, 3, 4... repeating the same instructions
- Eventually hit max steps, never rendering the interactive tool for the user
The Fix
Both planExecute() and planExecuteStream() now scan toolResults for PausesLoop instances (alongside the existing AskHumanSignal scan). When detected, the loop:
- Records the completed step and fires
afterStepcallback - Calculates deferred steps (remaining plan steps not yet executed)
- Fires the
pausecallback with the signal, deferred steps, step number, and response - Returns a
PlanResultwithpauseSignalanddeferredSteps
New APIs on PlanResult
pauseSignal— thePausesLoopinstance that caused the pause (nullwhen not paused)deferredSteps—list<string>of plan step descriptions not yet executedpaused()— returnstruewhen the loop was paused by aPausesLooptool resultcompleted()— now returnsfalsewhen paused (in addition toaskedHumanandreachedMaxSteps)
Usage
No code changes required — if your agent already uses PlanExecuteLoop with tools that implement PausesLoop, the loop will now correctly pause and return the signal.
$result = $agent->planExecute('Calculate stamp duty for NSW');
if ($result->paused()) {
// Emit the SDK render event to the frontend
$payload = json_decode((string) $result->pauseSignal, true);
// Remaining steps the agent needs to complete after user interaction
$deferred = $result->deferredSteps; // ['Record result', 'Advise client']
}Full Changelog: v0.7.0...v0.8.0
v0.7.0
What's New
Skill Tool Restrictions
Skills can now specify which tools an agent should use via the toolIds parameter on Skill. This enables agents to filter their available tools based on active skill restrictions.
New APIs
Skill::$toolIds—array<string>constructor parameter specifying allowed tool identifiersSkill::hasToolRestrictions()— returnstruewhen the skill restricts tool usageHasAgentSkills::allowedToolIds()— returns the union of tool IDs from all loaded skills (empty when no restrictions apply)
Prompt Enhancement
When a loaded skill has toolIds set, the enhanced prompt now includes a "Preferred tools for this skill" section listing the allowed tools, guiding the LLM toward the correct tool set.
Usage
$skill = new Skill(
metadata: $metadata,
instructions: 'Analyse contracts...',
path: '',
toolIds: ['sdk_contract_review', 'sdk_llm', 'sdk_docs_create'],
);
// In your agent's tools() method:
$allowedIds = $this->allowedToolIds();
// Filter tools based on $allowedIds when non-emptyFull Changelog: v0.6.2...v0.7.0
v0.6.2
Bug Fix
- Fixed PausesLoop detection in SDK-resolved tool results: When the Laravel AI SDK resolves tool calls internally (via the Prism gateway), the ReAct loop's ACTION phase is skipped. Previously, only
AskHumanSignalwas scanned in these SDK-resolved results —PausesLoopsignals were missed entirely. This caused both SDK tools (e.g. stamp duty calculator + email composer) to be executed within a singleprompt()call, instead of pausing after the first interactive tool.
What Changed
- Added
scanSdkResolvedToolResults()andscanSdkResolvedToolResultsStream()methods to theReActLooptrait - These methods scan
$response->toolResultsforPausesLoopinstances, build pause observations with deferred tool context, fireonPausecallbacks, and return aLoopResultwith the pause signal and deferred tools - Both the sync
reactLoop()and streamingreactLoopStream()paths now correctly handle PausesLoop in SDK-resolved results
v0.6.1
Added
onPause()callback — fires when a tool returns aPausesLoopresult, receiving the pause signal, deferred tool names, iteration, and responseLoopResult::$deferredTools— array of tool names the LLM requested but were not executed due to the pause- Pause observation — when the loop pauses, an observation is built and stored in the conversation history, explicitly listing which tools were executed and which were deferred. This ensures the LLM picks up remaining tools when the conversation resumes.
Changed
- The
onPausecallback replacesonLoopCompletewhen the loop pauses (previouslyloopCompletefired on pause, nowpausefires instead) CoTResultnow includespauseSignalanddeferredToolsproperties (consistent withLoopResult)
Fixed
- When the loop paused after executing an interactive tool (e.g. SDK app), the LLM had no context about deferred tools when the conversation resumed. Now the observation explicitly tells the LLM which tools still need to be called.
v0.6.0
What's New
PausesLoop contract for tools requiring human interaction
Tools that return a PausesLoop result (e.g. SDK app iframes) now cause the loop to stop executing further tools and terminate gracefully. This prevents multiple interactive tools from launching simultaneously when the LLM requests them in a single iteration.
Changes
- Add
PausesLoopmarker interface inContracts - Detect
PausesLoopresults inExecutesLoopToolsalongsideAskHumanSignal - Handle pause termination in
ReActLoopandChainOfThoughtLoop(sync + stream) - Add
pauseSignalandpaused()toLoopResult
Full Changelog: v0.5.1...v0.6.0
v0.4.0 — AskHuman: Human-in-the-Loop Clarification
What's New
AskHuman Signal System
Agents can now pause an agentic loop to ask the human for clarification before proceeding. When the LLM decides it needs more information, it calls the built-in ask_human tool — the loop terminates immediately (no second LLM iteration) and fires the onAskHuman callback.
New Classes
AskHumanSignal— signal value object carrying the question payloadHumanQuestion— individual question with type, text, and optionsQuestionType— enum:FreeText,SingleChoice,MultipleChoiceAskHumanTool— built-in tool the LLM calls; schema guides structured question construction
New Lifecycle Hook
$result = (new MyAgent)
->onAskHuman(function (AskHumanSignal $signal, int $iteration) {
broadcast(new ClarificationRequested($signal->toArray()));
})
->reactLoop('Help me build something...');
if ($result->askedHuman()) {
return response()->json($result->askHumanSignal->toArray());
}Two Question Modes
Free-text (default) — a single open question:
{ "mode": "free_text", "question": "What kind of project are you building?" }Structured — typed questions the frontend renders natively:
{
"mode": "structured",
"questions": [
{ "type": "single_choice", "question": "What is your timeline?", "options": ["1 week", "1 month", "3+ months"] },
{ "type": "free_text", "question": "Describe the core feature.", "options": [] }
]
}Works Across All Loops
onAskHuman is supported in ReActLoop, ChainOfThoughtLoop, and PlanExecuteLoop. Each result type (LoopResult, CoTResult, PlanResult) gains askedHuman() and askHumanSignal.
Full Changelog
v0.3.1 - Fix multi-loop trait collision
Bug Fix
Fatal error when composing multiple loop traits
Agents using more than one loop trait together (e.g. ReActLoop, ChainOfThoughtLoop, PlanExecuteLoop) would crash on instantiation with a PHP fatal error:
```
Trait method Laragentic\Loops\ChainOfThoughtLoop::onMaxIterationsReached has not been applied
because of collision with Laragentic\Loops\ReActLoop::onMaxIterationsReached
```
Root cause: ReActLoop and ChainOfThoughtLoop both defined 9 identical methods. PHP requires trait method collisions to be explicitly resolved in the consuming class, which isn't feasible to ask every agent author to do.
Fix: Shared methods have been extracted into two new concern traits:
Laragentic\Concerns\HasIterationCallbacks— shared iteration-phase callback registrations (onMaxIterationsReached,onIterationStart,onIterationEnd,onBeforeAction,onAfterAction)Laragentic\Concerns\ExecutesLoopTools— shared tool execution helpers (executeLoopToolCalls,executeLoopTool,resolveToolMap,formatObservation)
PHP de-duplicates traits that appear via multiple paths, so any combination of loop traits now composes cleanly.
No breaking changes
All existing public APIs are unchanged. Agents using a single loop trait are unaffected. The formatObservation() method remains overridable. ReActLoop gains a new overridable buildReActObservation() method for customising the full ReAct observation prompt (guidance text + tool results).
Upgrading
No changes required. Update your composer.json constraint to ^0.3.1 and run composer update.
Release v0.2.0 - Agent Skills System
v0.2.0 - Agent Skills System
Major release featuring the complete Agent Skills System following the
agentskills.io specification.
New Features
Agent Skills System
- Progressive disclosure with dynamic skill loading
- Manual skill loading via ->withSkill() and ->withSkills()
- Auto-resolution with intelligent relevance scoring
- Full integration with all loops (ReAct, Plan-Execute, Chain-of-Thought)
- Callback system for skill loading and resolution events
- Streaming support for real-time skill activation
- Comprehensive configuration options
Example Skills (Production-Ready)
- code-review: Security, performance, and best practices analysis
- data-analysis: Statistical analysis and insight generation
- api-testing: API validation and testing
Testing
- 53 Skills tests with 154 assertions (100% passing)
- Full integration test coverage
- Comprehensive unit test suite
Documentation
- Complete tutorial with examples and diagrams
- Skills README with quick reference
- Updated main README with Skills section
- Three production-ready example skills
All Features
Agentic Loops
- ReAct Loop (Reasoning + Acting)
- Plan-Execute Loop (Planning + Execution + Synthesis)
- Chain-of-Thought Loop (Iterative Self-Reflection)
Skills System
- Dynamic skill loading and progressive disclosure
- Auto-discovery and relevance scoring
- Integration with all loop types
Developer Experience
- Comprehensive callbacks for all loops
- Streaming support (SSE)
- Configurable limits and thresholds
- Zero-config defaults
- Full Laravel integration
For detailed usage and examples, see:
- README.md - Complete documentation
- tutorial/agent-skills-system.md - Skills tutorial
- SKILLS_README.md - Skills quick reference
v0.1.0 - Chain-of-Thought Loop
🧠 Chain-of-Thought Loop
This release introduces a new agentic loop pattern focused on deep reasoning through iterative self-reflection.
What's New
Chain-of-Thought Loop
- New trait:
ChainOfThoughtLoop- Enables progressive reasoning with confidence evaluation - Streaming support: Real-time streaming of reasoning iterations via
chainOfThoughtStream() - Self-reflection: Automatic confidence checks between reasoning cycles
- Full transparency: Shows step-by-step thinking process to users
Supporting Classes
CoTResult- Enhanced result object with reasoning metadataCoTStep- Value object for each reasoning iterationCoTPrompts- Reusable prompt templates for CoT reasoning
Lifecycle Callbacks (6 new callbacks)
onIterationStart- When reasoning iteration beginsonBeforeReasoning- Before LLM reasons through problemonAfterReasoning- After reasoning step completesonReflection- When confidence evaluation occursonLoopComplete- When agent reaches confident answeronMaxIterationsReached- When iteration limit is hit
Plus all standard action callbacks (onBeforeAction, onAfterAction)
Configuration
max_reasoning_iterations- Control iteration limits (default: 5)throw_on_max_iterations- Configure error handling- Environment variable support via
AGENTIC_COT_MAX_ITERATIONS
Documentation
- New tutorial: Streaming Chain-of-Thought Loop
- Complete code examples with backend routes and React frontend
- Comparison tables: CoT vs ReAct vs Plan-Execute
- Best practices and customization guide
- Screenshots demonstrating the UI
Tests
- Comprehensive unit tests with 20+ test cases
- Integration tests with real API calls
- 100% coverage of CoT loop logic
When to Use Chain-of-Thought
Use CoT when:
- ✅ The reasoning process needs to be visible/auditable
- ✅ You need to demonstrate understanding, not just results
- ✅ The problem requires careful, step-by-step analysis
- ✅ Users want to see "how" the agent thinks
- ✅ Confidence in the answer is critical
Quick Example
```php
use Laragentic\Loops\ChainOfThoughtLoop;
class MathAgent implements Agent, HasTools
{
use Promptable, ChainOfThoughtLoop;
public function instructions(): string
{
return 'Think step-by-step. Evaluate your confidence. '
. 'Only answer when you're certain.';
}
}
$result = (new MathAgent)->chainOfThought(
'Which train is faster and by how much?'
);
echo $result->text();
echo "Reasoning iterations: {$result->reasoningIterations}";
```
Breaking Changes
None - fully backward compatible with v0.0.2
Updated Documentation
- README updated with Chain-of-Thought section
- Tutorial links updated
- Configuration documented
- All existing tutorials updated with CoT references
Full Changelog: v0.0.2...v0.1.0