NAME

Langertha::Role::ThinkTag - Configurable think tag filtering for reasoning models

VERSION

version 0.202

SYNOPSIS

# Think tag filter is enabled by default on all engines.
# <think> tags are automatically stripped and thinking preserved:
my $response = $engine->simple_chat('Explain quantum computing');
say $response;                  # clean answer text
say $response->thinking;        # chain-of-thought (if any)

# For APIs with native reasoning (DeepSeek, Anthropic, Gemini),
# thinking is extracted from the API response automatically —
# no tag filtering needed.

# Custom tag name (e.g. for models using <reasoning> tags):
my $engine = Langertha::Engine::vLLM->new(
    url       => $vllm_url,
    model     => 'my-reasoning-model',
    think_tag => 'reasoning',
);

# Disable filtering if you want raw output:
my $engine = Langertha::Engine::OpenAI->new(
    api_key          => $key,
    think_tag_filter => 0,
);

DESCRIPTION

This role provides automatic filtering of <think> tags from LLM responses. Many reasoning models (DeepSeek R1, QwQ, Hermes with reasoning enabled) emit chain-of-thought reasoning wrapped in <think> tags inline with their response text. This role strips those tags and preserves the thinking content on the "thinking" in Langertha::Response attribute.

Composed into Langertha::Role::Chat, so every engine gets it automatically. The filter handles both closed pairs (<think>...</think>) and unclosed tags where the model stopped mid-thought.

For APIs that provide reasoning content natively (DeepSeek reasoning_content, Anthropic thinking blocks, Gemini thought parts), the thinking is extracted directly from the API response — no tag filtering needed.

think_tag

The XML tag name used for thinking content. Defaults to think. Some models may use different tag names (e.g. reasoning).

think_tag_filter

When true, <think>...</think> blocks are stripped from response text. The thinking content is preserved on the "thinking" in Langertha::Response attribute for inspection. Defaults to 1 (enabled). Set to 0 to pass think tags through unmodified.

filter_think_content

my ($filtered_text, $thinking) = $engine->filter_think_content($text);

Strips <think>...</think> blocks from $text. Handles both closed pairs and unclosed tags (where the model stopped mid-thought). Returns the filtered text and the extracted thinking content (or undef if none). Returns the original text unchanged when "think_tag_filter" is false.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudss.us/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.