Claude-Agent

 view release on metacpan or  search on metacpan

lib/Claude/Agent.pm  view on Meta::CPAN

=head1 EXPORTED FUNCTIONS

=head2 query

    my $iter = query(
        prompt  => $prompt,
        options => $options,
        loop    => $loop,      # optional, for async integration
    );

Creates a new query and returns an iterator for streaming messages.

=head3 Arguments

=over 4

=item * prompt - The prompt string to send to Claude

=item * options - A L<Claude::Agent::Options> object (optional)

=item * loop - An L<IO::Async::Loop> object (optional, for async integration)

lib/Claude/Agent/Options.pm  view on Meta::CPAN


    # Structured output
    'output_format?',                         # JSON schema for structured outputs

    # Settings sources
    'setting_sources?' => ArrayRef[Str],     # 'user', 'project', 'local'

    # Sandbox settings
    'sandbox?',                               # Sandbox configuration

    # Include partial messages during streaming
    'include_partial_messages?' => Bool,

    # Continue conversation from previous messages
    'continue_conversation?' => Bool,

    # Query timeout in seconds (default 600 = 10 minutes)
    'query_timeout?' => Int,

    # Dry-run mode - preview tool calls without executing writes
    'dry_run?' => Bool,

lib/Claude/Agent/Options.pm  view on Meta::CPAN


ArrayRef specifying which settings files to load. Valid values:
'user', 'project', 'local'.

=head2 sandbox

Sandbox configuration settings.

=head2 include_partial_messages

Boolean. If true, include partial messages during streaming.

=head2 continue_conversation

Boolean. If true, continue from previous conversation messages.

=head2 query_timeout

Timeout in seconds for the C<next()> method to wait for messages.
Defaults to 600 seconds (10 minutes). Set to a lower value for
interactive applications, or higher for complex long-running queries.

lib/Claude/Agent/Query.pm  view on Meta::CPAN

    '_hook_executor==.',                            # Hook executor for Perl callbacks
    '_pending_tool_uses==.' => sub { {} },          # Track tool uses awaiting results
    '_processing_message==.' => sub { 0 },           # Guard against concurrent message processing
    '_cleaned_up==.' => sub { 0 },                     # Track if cleanup() has been called
    '_jsonl==.' => sub {
        JSON::Lines->new(
            utf8     => 1,
            error_cb => sub {
                my ($action, $error, $data) = @_;
                # Only log at trace level since parse errors are common
                # with streaming JSON and partial data
                $log->trace("JSON::Lines $action error: $error");
                return;
            },
        )
    };

use IO::Async::Loop;
use IO::Async::Process;
use Future;
use Future::AsyncAwait;

lib/Claude/Agent/Query.pm  view on Meta::CPAN

        # This catches any escape sequences not matched above
        $sanitized_prompt =~ s/\x1b.//g;

        # Ultimate safety: strip any remaining bare ESC (0x1B) bytes entirely
        # This handles edge cases with multi-byte sequences in exotic terminal emulators
        $sanitized_prompt =~ s/\x1b//g;

        push @cmd, '--print', '--', $sanitized_prompt;
    }
    else {
        # For streaming input (async generator), use stream-json input format
        push @cmd, '--input-format', 'stream-json';
    }

    return @cmd;
}

sub _start_process {
    my ($self) = @_;

    my @cmd = $self->_build_command();

lib/Claude/Agent/Query.pm  view on Meta::CPAN

    $self->_process($process);
    $self->_stdin($process->stdin);
    $self->_loop->add($process);

    # For --print mode, prompt is in argv, stdin can be closed
    if (!ref($self->prompt)) {
        $self->_loop->later(sub {
            $self->_stdin->close_when_empty if $self->_stdin;
        });
    }
    # For ref prompts (streaming input), caller will send messages via send_user_message
    return;
}

sub _handle_line {
    my ($self, $line) = @_;

    return unless defined $line && length $line;

    # Use JSON::Lines decode method for single line
    my @decoded = $self->_jsonl->decode($line);

lib/Claude/Agent/Query.pm  view on Meta::CPAN

    my $msg = $self->_jsonl->encode([{ type => 'interrupt' }]);
    return unless defined $msg && length $msg;
    $self->_stdin->write($msg);
    return;
}

=head2 send_user_message

    $query->send_user_message("Continue with the next step");

Send a follow-up user message during streaming.

=cut

sub send_user_message {
    my ($self, $content) = @_;

    return unless $self->_stdin && !$self->_finished;

    my $msg = $self->_jsonl->encode([{
        type    => 'user',

lib/Claude/Agent/Query.pm  view on Meta::CPAN

        $log->debug(sprintf("send_user_message write error: %s", $_));
        $result = 0;
    };
    return $result;
}

=head2 set_permission_mode

    $query->set_permission_mode('acceptEdits');

Change permission mode during streaming.

=cut

sub set_permission_mode {
    my ($self, $mode) = @_;

    return unless $self->_stdin && !$self->_finished;

    my $msg = $self->_jsonl->encode([{
        type            => 'set_permission_mode',



( run in 0.843 second using v1.01-cache-2.11-cpan-140bd7fdf52 )