fissible/verdict-console
The Artisan console companion for Fissible Verdict. It adds CLI commands to inspect, toggle, and manage Laravel feature flags, letting you check rollout status, adjust targeting, and keep environments in sync from your terminal. Ideal for local debugging, CI, and deployments.
This package is the operator-facing half of a human-in-the-loop approval system: Verdict governs agent behavior, and fissible/verdict-console captures approval pauses, exposes them to an operator UI, and resumes the agent after a decision. It is early-stage software (0.x, low adoption), so treat the source and release notes as the primary documentation.
Minimal path to first value:
Install it alongside your Laravel AI/Verdict stack:
composer require fissible/verdict-console
Pin an exact version in composer.json. In this 0.x line, the minor version is the breaking-change boundary.
Run the package installer or manually publish its config, migrations, and routes. Check the package service provider for the actual publish tags and route registration—do not assume file names from this assessment.
Migrate:
php artisan migrate
Register your agent(s) in the console’s resumable-agent registry. Implement ResumableAgents, including the v0.12.0 requirement:
public function versionFor(string $key): ?string
{
// Return an opaque token that reflects what resolve() would rebuild.
// Return null to decline versioning for this agent.
}
The registry can also accept a host-supplied version token per registration and return it without running host factories or matchers.
Configure the operator UI’s authorization. The console is an approval surface, so decide who may approve, reject, and inspect conversations before exposing routes.
First use case: put a Verdict approval gate around a consequential tool call. Run the agent normally. When the pause occurs, confirm the approval appears in the operator UI, approve or reject it, and verify the agent resumes with the expected participant and conversation state.
Where to look first:
src/Contracts/ResumableAgents and related registry code for registration and versioning.ParticipantUnresolvable, the ConversationParticipants contract, and the design notes around §6.3 for identity behavior.Approval-gated tool execution. The core workflow is: agent attempts a tool call → Verdict issues an approval receipt and pauses execution → the console ingests the pause → an operator acts in the UI → the agent resumes or is rejected. Keep the approval decision handler idempotent and log the receipt/pause identifier. Do not treat “tool requested” as “tool executed”; the tool remains unexecuted until the flow completes.
Resumable agent registration. Use the registry as the single place that knows how to rebuild an agent from a stored key. versionFor() should return a token that tracks what resolve() would currently rebuild. Exact equality compares declarations for the same key only; it does not verify semantic equivalence, ordering, or compatibility. Returning null means “unversioned/incomparable,” not “same as anything.”
A practical pattern:
final class AgentRegistry implements ResumableAgents
{
public function resolve(string $key): object
{
// Rebuild the agent for this key.
}
public function versionFor(string $key): ?string
{
// Hash the agent class, prompt version, tool set, model, etc.
// Must change whenever resolve() would produce a meaningfully different agent.
}
}
Participant-bound pauses. A pause captured for a participant must be resumed as that participant, never under an identity the host cannot reproduce. Ingestion-time checks enforce this; resolution-time fidelity depends on your host resolver. If you use conversation participants, implement the ConversationParticipants contract carefully and keep strict type/key comparisons intact.
Streaming adapters. If you expose a chat adapter, use ChatService::stream($user, $conversationId, $prompt) rather than duplicating authorization and ownership checks. The returned ChatStream is lazy and single-consumption. Important operational pattern:
turn() only after full exhaustion.Error events to the client and propagate Laravel AI’s terminal exception.A Verdict-gated pause arrives as the ToolApprovalRequest event with a receipt issued and the tool unexecuted. Because console ingestion and persistence land only when the iterator is exhausted, an adapter that breaks early can leave the approval invisible or the conversation inconsistent.
Operator UI integration. Wire approvals into your existing operations surface rather than building a second approval queue. Typical pattern: notify the responsible operator/team, deep-link to the console approval record, record who acted and why, then dispatch resume processing as a queued job. Keep business policy in your application; use the console for the human decision and audit trail.
Testing pattern. Bind a fake ResumableAgents implementation in tests, assert that versionFor() is called, simulate approval pauses, and exercise resume with the same participant identity. For streaming, add tests that exhaust the stream, test turn() before/during/after an early break, and assert that persistence happens only on completion. Also test mid-stream transport failures and confirm the Error event plus terminal exception path.
versionFor() method. Pin the package version and read every minor release note before upgrading. Custom ResumableAgents implementations must be updated when the contract changes.versionFor() must track resolve(). A stale or overly stable token can make incompatible agent reconstructions look identical. Conversely, null is incomparable and will not match another token. There is no verified equivalence or compatibility claim behind the comparison.ParticipantUnresolvable. Resolve participants from durable storage.turn() refuses before exhaustion, during iteration, after an abandoning break, and on re-iteration. Because ingestion and conversation persistence are deferred until exhaustion, an early break is not just a UI problem—it can strand an approval.Error event and then propagate Laravel AI’s terminal exception. Catch at the adapter boundary, surface a useful message, and do not assume partial persistence occurred.versionFor() returns the expected token, the pause receipt was ingested, the operator decision was persisted, the resume job used the correct participant, and the queue worker is running. Log the agent key, conversation key, receipt ID, and participant identity on both pause and resume.ResumableAgents, config overrides, the ConversationParticipants contract, and adapter-level stream consumption. Avoid patching core authorization seams or duplicating ownership checks outside ChatService.How can I help you explore Laravel packages today?