NAME

Langertha::Knarr::PSGI - PSGI adapter for Langertha::Knarr (buffered, no streaming)

VERSION

version 1.102

SYNOPSIS

use Langertha::Knarr;
use Langertha::Knarr::PSGI;

my $knarr = Langertha::Knarr->new( handler => $handler );
my $app = Langertha::Knarr::PSGI->new( knarr => $knarr )->to_app;
# $app is now a Plack-compatible coderef

# Run with any PSGI server:
#   plackup -s Starman -p 8088 app.psgi

DESCRIPTION

Adapter that wraps a Langertha::Knarr instance and exposes it as a PSGI app, so you can deploy Knarr behind any Plack server (Starman, Twiggy, Gazelle, mod_perl, etc.) instead of running its native Net::Async::HTTP::Server loop.

Streaming responses are buffered. The PSGI streaming protocol's delayed-response form does work in theory but mixes badly with IO::Async in the same process; for honesty's sake this adapter just drives the inner stream to completion in a blocking loop and returns the full assembled body. Use the native "run" in Langertha::Knarr entry point if you need real-time streaming.

Raw passthrough works as on the native server: with a raw_passthrough handler and a router set on the Knarr, a chat request for a model the router does not configure is sent to the upstream byte for byte with the client's headers (minus the proxy key, see "auth_token" in Langertha::Knarr), and the upstream's status, headers and body come back unchanged (see "raw_passthrough" in Langertha::Knarr). A streamed passthrough answer is buffered like any other stream here; its Content-Encoding is handled as on the native server. A discovered model's 401 falls back to its engine as there, streamed or not.

One limit is the PSGI server's: it hands over a request header the client sent twice as one value joined with , (one HTTP_* key), so the upstream gets that header once, as that joined value. The native server forwards each line. The same holds for the auth headers a Langertha::Knarr::Handler::Passthrough in the handler chain forwards (forward_headers, see "forward_header_pairs" in Langertha::Knarr::Request).

Requests are authenticated exactly like on the native server: with "auth_token" in Langertha::Knarr set, every route except the A2A agent card needs the key as Authorization: Bearer or x-api-key, and a missing or wrong key gets the same 401 JSON error.

knarr

Required. The Langertha::Knarr instance to expose.

to_app

Returns the PSGI coderef.

SUPPORT

Issues

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

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

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

AUTHOR

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

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.