=begin pod

=head1 NAME

LLM::Character - Implementation of Character Card v3 characters & lorebooks in Raku

=head1 SYNOPSIS

=begin code :lang<raku>

use LLM::Character;
use LLM::Character::Lorebook::Matching;

# Import lorebook & characters
my $c         = LLM::Character.new;
my $lorebook  = $c.import-lorebook('t/fixtures/lorebook_minimal.json');
my $character = $c.import-character('t/fixtures/character.json');
my $pngchar   = $c.import-character('t/fixtures/Assistant.png');

# Export character & lorebook
$c.export-character($character, 'output.json');
$c.export-character-to-png($character, 'source.png', 'output.png');
$c.export-lorebook($lorebook, 'lorebook.json');
$c.export-lorebook($lorebook, 'lorebook_st.json', format => 'st');

# Get lorebook entries which match an input
my $m       = LLM::Character::Lorebook::Matching.build-matcher($lorebook.entries);
my $input   = "foo bar baz";
my @matches = $m.match($input);

=end code

=head2 STATUS

This module aims to implement the most common functionality of the Character Card V2/V3 spec, including importing and exporting SillyTavern character cards and their embedded lorebooks.

Fast aho-corasick based lorebook matching is implemented for the following:

=item Case sensitive & case insensitive matches

=item Selective matches with secondary keys

=item Constant matches

=item Regex matches with or without valid pcre flags

=item ST-style prevent recursion, delay until recursion, and exclude recursion

Not yet implemented are decorator-based matches.

=head1 EXTERNAL API

=head2 LLM::Character

=head3 .new()

Create a new instance of LLM::Character

=head3 .import-character(Str:D $file)

Imports a character from JSON or PNG at $file (the file extension must be correct)

=head3 .import-lorebook(Str:D $file)

Imports a stand-alone JSON lorebook in ST or CCv3 format from $file

=head3 .export-character(Card:D $card, Str:D $file)

Exports a character card to $file as CCv3 JSON (file must have .json extension)

=head3 .export-character-to-png(Card:D $card, Str:D $source-png, Str:D $output-png)

Exports a character card to a PNG file, embedding the CCv3 JSON as base64 in both C<ccv3> and C<chara> tEXt chunks. Requires a source PNG to use as the image.

=head3 .export-lorebook(Lorebook:D $lorebook, Str:D $file, Str :$format = 'ccv3')

Exports a lorebook to $file. Set C<:format<st>> for SillyTavern format, defaults to CCv3.

=head2 LLM::Character::Lorebook::Matching

=head3 .build-matcher(@entries, Bool :default-cs = False)

Creates a matcher based on the entries provided.

If default-cs is True, defaults to case-sensitive matching where not specified.

=head3 .match(Str:D $input, Int:D $recursion_depth = 99, Bool:D :$recursive_scanning = False)

Matches input against the specified entries.

If $recursive_scanning is True, will continue to match against newly matched entries 
up to $recursion_depth times, or until there are no more matches.

=head1 AUTHOR

=item Matt Doughty

=head1 COPYRIGHT AND LICENSE

Copyright 2025 Matt Doughty

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

=end pod

