NAME

Langertha::Knarr::Protocol::Ollama - Ollama-compatible wire protocol (/api/chat, /api/generate, /api/tags, /api/version, /api/show) for Knarr

VERSION

version 1.102

DESCRIPTION

Implements the Ollama wire format on top of Langertha::Knarr::Protocol. Loaded by default.

  • POST /api/chat, POST /api/generate — chat with NDJSON streaming; /api/generate answers in Ollama's generate shape, the text on response instead of message (see "format_chat_response")

  • GET /api/tags — model listing

  • GET /api/version — version probe, answered with Ollama's shape {"version":"x.y.z"} and the Ollama version Knarr claims compatibility with ("ollama_compat_version" in Langertha::Knarr), not Knarr's own version

  • POST /api/show — model details for a listed model (see "format_show_response"); model or the legacy name in the body, 400 without one, Ollama's 404 {"error":"model 'x' not found"} for a model Knarr does not list

The client's Authorization header is kept as forward_headers, like the OpenAI and Anthropic protocols do, so a Langertha::Knarr::Handler::Passthrough in the handler chain reaches an authenticated remote Ollama with it.

Streaming uses newline-delimited JSON (NDJSON) rather than SSE — the Content-Type is application/x-ndjson and each chunk is a single JSON object per line. The final chunk has done: true.

reasoning

The Langertha::Knarr::Reasoning that maps the body's think (a boolean or a level string) onto the request's reasoning_effort. Pass your own to override the level think: true maps to.

format_chat_response

my ($status, $headers, $body) = $proto->format_chat_response( $response, $request );

The non-streaming answer: model, created_at, done, done_reason and the usage counters (prompt_eval_count, eval_count, ...) when the backend reported usage. A /api/chat request gets the text on message (with tool_calls), a /api/generate request on response, as Ollama answers it -- streaming alike, where every chunk carries its piece on message.content or response and the final {"done": true} line an empty one, with the usage counters when the backend reported usage.

format_error_response

my ($status, $headers, $body) = $proto->format_error_response( 404, "model 'x' not found" );

Ollama's error answer: {"error":"..."} with a plain string, not the {"error":{"message":...}} object of the OpenAI wire.

format_show_response

my ($status, $headers, $body) = $proto->format_show_response( $model, {
    capabilities   => [ 'completion', 'tools' ],
    context_length => 131072,   # optional
} );

The POST /api/show answer for a model Knarr serves (k29). Only what Knarr knows is claimed: capabilities as given, model_info with general.architecture (knarr) and knarr.context_length when a context length is known -- the pair VS Code Copilot reads, {} otherwise -- and empty details, template and parameters, since there are no local weights, template or Modelfile behind a routed model.

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.