Chorus

 view release on metacpan or  search on metacpan

lib/Chorus/Expert.pm  view on Meta::CPAN


=item * C<BOARD> -- the shared frame, accessible as C<< $agent->BOARD >>.

=item * C<EXPERT> -- a back-reference to this expert instance.

=back

  $xprt->register($agent1, $agent2, $agent3);

Agents are stored in registration order, which determines the order in which
C<process()> calls their C<loop()> method.

The termination agent (the one that calls C<solved()>) should be registered
B<last>.

=head2 debug

Enables verbose output to STDERR for the main process loop.

  $xprt->debug(1);   # enable
  $xprt->debug(0);   # disable

=head2 process

Runs the pipeline.

  my $ok = $xprt->process();           # no input
  my $ok = $xprt->process($something); # $something available as $agent->BOARD->INPUT

The main loop iterates over all registered agents in order, calling C<loop()>
on each one, until C<BOARD->{SOLVED}> or C<BOARD->{FAILED}> is set.  It respects
C<_REPLAY> and C<_REPLAY_ALL> signals from the agents.

An agent tagged with C<_LOCK_UNTIL_STABLE> is skipped when any earlier agent in
the current iteration has already succeeded (C<_SUCCES> is true).  This allows
priority-based sequencing without explicit coupling.

If C<_MAX_ITER> full iterations complete without termination, a warning is emitted
and C<process()> returns C<undef>.

Returns C<1> if C<SOLVED>, C<undef> if C<FAILED> or if C<_MAX_ITER> is exceeded.

=head2 _LOCK_UNTIL_STABLE

An optional flag set directly on an agent frame:

  $agent->{_LOCK_UNTIL_STABLE} = 'Y';

When C<_LOCK_UNTIL_STABLE> is set on agent N, C<process()> skips that agent in
the current iteration if B<any> earlier agent has already succeeded
(C<_SUCCES> is true on that agent).  This implements priority-based sequencing:
earlier agents are given another full pass before the locked agent is allowed
to run.

Typical use: a "global cleanup" or "conformity check" agent that should only
run once all upstream agents have stabilised for the current cycle.

=head2 _REPLAY and _REPLAY_ALL

These flags are set by the corresponding engine methods and are handled
transparently by C<process()>.

=over 4

=item C<_REPLAY>

Set by C<< $agent->replay() >>.  C<process()> re-runs C<loop()> on the same
agent immediately (inner C<do/while> loop), without advancing to the next agent.

=item C<_REPLAY_ALL>

Set by C<< $agent->replay_all() >>.  C<process()> restarts the outer agent loop
from the beginning — all agents are iterated again from agent 1.

=back

Both flags are automatically deleted by C<process()> before the re-run, so they
fire exactly once per call.

=head1 BOARD

Every agent registered with C<register()> receives a reference to a shared
L<Chorus::Frame> called B<BOARD>.  Access it from inside any rule:

  my $board = $agent->BOARD;

=head2 Reserved slots

=over 4

=item C<SOLVED>

Set to C<'Y'> by C<< $agent->solved() >>.  Causes C<process()> to return C<1>
immediately after the current C<loop()> call finishes.  Deleted by C<process()>
before returning.

=item C<FAILED>

Set to C<'Y'> by C<< $agent->failed() >>.  Causes C<process()> to return
C<undef> immediately.  Deleted by C<process()> before returning.

=item C<INPUT>

Set by C<process($input)> before the main loop starts.  Holds the raw input
value passed to the pipeline.

  my $input = $agent->BOARD->INPUT;

=back

=head2 Custom slots for inter-agent communication

Any other slot can be freely written and read by agents to exchange state that
does not belong to individual domain frames:

  # In agent 1's _APPLY:
  $agent->BOARD->set('phase', 'enrichment');

  # In agent 2's _APPLY:
  my $phase = $agent->BOARD->phase;    # 'enrichment'



( run in 2.450 seconds using v1.01-cache-2.11-cpan-600a1bdf6e4 )