Revision history for Langertha-Knarr

1.100     2026-04-26 20:36:43Z

    - Langertha floor 0.500 — for ToolCall/Usage value objects,
      capability registry, and chat_f named-args entry point.

    - New Langertha::Knarr::Response value object: single shape every
      handler returns and every protocol formatter consumes. Carries
      content, model, usage (Langertha::Usage), tool_calls
      (ArrayRef[Langertha::ToolCall]), finish_reason, raw. coerce()
      upgrades legacy returns (bare string, {content,model} hashref,
      Langertha::Response) so handlers can hand back whatever is
      convenient and the dispatcher normalizes once at the boundary.
      11 blessed/ref-HASH triplets across the handler/decorator/protocol
      tree replaced with a single typed call site.

    - Generation parameters now reach the engine. Handler::Engine and
      Handler::Router call $engine->chat_f(messages=>..., tools=>...,
      tool_choice=>..., response_format=>..., temperature=>...,
      max_tokens=>...) instead of the old simple_chat_f(@msgs) which
      silently dropped everything. Knarr::Request gained chat_f_args($engine)
      that builds the named-arg list capability-aware (consults
      $engine->supports($cap) so unsupported params are dropped before
      reaching engines that would reject them).

    - Knarr::Request gained tool_choice and response_format as
      first-class attributes; OpenAI/Anthropic/Ollama parsers populate
      them from the wire body.

    - Tool calls are surfaced in proxy responses. Configured (non-
      passthrough) routes that produce tool_calls now serialize them
      into OpenAI message.tool_calls (with finish_reason: tool_calls),
      Anthropic content[] tool_use blocks (stop_reason adapts), and
      Ollama message.tool_calls. Previous behaviour: silently dropped.

    - Real usage in proxy responses. When the engine reports a
      Langertha::Usage, OpenAI / Anthropic / Ollama formatters serialize
      via to_openai_format / to_anthropic_format / to_ollama_format
      instead of emitting hardcoded zeros. Tracing's end_trace gets the
      Usage object too — Langfuse generations now carry real token
      counts.

    - Tracing flush is async via Net::Async::HTTP. The previous
      LWP::UserAgent call blocked the IO::Async event loop on every
      end_trace; the new flush fires the request and returns
      immediately, with a warn-on-fail logger attached.

    - Streaming pump consolidated into Knarr::Stream::from_callback.
      Removes ~50 lines of duplicated queue/pending/finished/error
      bookkeeping from Handler::Engine and Handler::Router.

    - supports()-aware streaming detection. The old
      $engine->can('simple_chat_stream_realtime_f') heuristic now
      defers to $engine->supports('streaming') when available
      (Langertha 0.500+) and falls back to the can()-check for older
      engines.

    - Dead steerboard attribute removed from all six Protocol classes
      (never read), and Knarr.pm no longer threads $self into
      protocol-object construction. Knarr::PSGI's constructor argument
      renamed steerboard => knarr.

    - 'steerboard' string fallbacks replaced with 'unknown' (model
      default) and 'knarr-code' / 'knarr-raider' (handler defaults).

    - Removed unused handle_embedding_f / handle_transcription_f stubs
      from the Handler role (no protocol parser, no test, no caller —
      revisit when a concrete embedding/transcription routing strategy
      exists).

    - Tests grew from 343 to 360. New: t/15_response.t (value-object
      contract), t/25_chat_f_params.t (param forwarding + capability
      gating + tool_calls survival through Engine handler),
      t/26_tool_calls_routing.t (OpenAI/Anthropic/Ollama formatter
      output), t/27_usage_routing.t (usage serializer roundtrip).

1.001     2026-04-12 22:22:19Z

    - Raw passthrough: unconfigured models are now piped 1:1 as raw
      HTTP bytes to the upstream API. All protocol metadata (tool_use,
      usage, cache_control, stop_reason, content block indices) is
      preserved. Client auth headers are forwarded transparently.

    - Langfuse tracing for passthrough requests: every raw passthrough
      call creates a Langfuse trace with model, protocol, and timing.

    - 'knarr container' is now a deprecated alias for
      'knarr start --from-env'. The --from-env flag builds config from
      environment variables when no config file is found.

    - --port is now repeatable: -p 8080 -p 11434 binds multiple ports.
      --host defaults to 0.0.0.0.

    - KNARR_DEBUG=1 environment variable enables verbose logging
      (equivalent to --verbose / -v).

    - Logging always active: Log::Any::Adapter::Stderr is now always
      set (warning level by default, trace level with --verbose).
      Errors in request handling are logged to stderr.

    - Anthropic system prompt: handle array-of-content-blocks format
      sent by Claude Code (was: only plain string).

    - Removed route_model from Handler role — decorator chain
      (Tracing, RequestLog) is no longer bypassed.

    - Dockerfile rewritten: cpm instead of cpanm, cpanfile-based
      installation, non-root user, Docker-cache-friendly layers.

    - Bump Langertha floor to 0.401.

    - Added IO::Async::SSL to cpanfile (required for HTTPS passthrough).

    - Test suite expanded to 343 tests. New coverage:
        * Raw passthrough with mock Langfuse tracing
        * Passthrough with and without tracing enabled

    - Documentation updated: CLAUDE.md, README.md, bin/knarr POD
      reflect new architecture, --from-env, repeatable --port,
      KNARR_DEBUG, raw passthrough behavior.

1.000     2026-04-10 00:00:20Z

    - MAJOR REWRITE. Mojolicious is gone; the new core is built on
      IO::Async + Net::Async::HTTP::Server + Future::AsyncAwait for
      native async streaming and seamless integration with Langertha
      engines. Existing knarr.yaml configs and the knarr CLI commands
      (start, container, models, check, init) keep working.

    - Six wire protocols loaded by default on every listening port:
      OpenAI (/v1/chat/completions, /v1/models, SSE), Anthropic
      (/v1/messages, named-event SSE), Ollama (/api/chat, /api/tags,
      NDJSON streaming), A2A (Google Agent2Agent JSON-RPC at / with
      /.well-known/agent.json discovery), ACP (BeeAI/IBM /agents,
      /runs), and AG-UI (CopilotKit /awp event stream).

    - Pluggable Handler architecture replaces the old Knarr::Proxy
      classes:
        Knarr::Handler::Router        — model→engine via Knarr::Router
        Knarr::Handler::Engine        — single Langertha engine wrapper
        Knarr::Handler::Raider        — per-session Langertha::Raider
        Knarr::Handler::Code          — coderef-backed for tests/fakes
        Knarr::Handler::Passthrough   — raw HTTP forward to upstream
        Knarr::Handler::A2AClient     — consume remote A2A agents
        Knarr::Handler::ACPClient     — consume remote ACP agents
        Knarr::Handler::Tracing       — Langfuse tracing decorator
        Knarr::Handler::RequestLog    — JSONL request logging decorator

    - Langfuse tracing and per-request JSONL logging restored as
      decorator handlers and auto-mounted by knarr start / knarr
      container when their respective config sections are present.

    - Multi-listen restored: the listen attribute is always an
      arrayref (default composed from host + port), supports any
      number of host:port entries. knarr container binds 8080 +
      11434 simultaneously so existing Ollama clients work without
      reconfiguration.

    - proxy_api_key authentication enforced by the new dispatcher.
      Clients must present 'Authorization: Bearer <token>' or
      'x-api-key: <token>' when KNARR_API_KEY (or yaml proxy_api_key)
      is set. The /.well-known/agent.json discovery route stays
      anonymous.

    - PSGI adapter (Knarr::PSGI) for deploying behind any Plack
      server (Starman, Twiggy, mod_perl, ...). Streaming is buffered
      in this mode; use the native server for real-time streaming.

    - Universal protocol translator pattern: an OpenAI-fronted Knarr
      with a Handler::A2AClient backend exposes a remote A2A agent to
      OpenAI clients (and similarly for ACP).

    - Drops the Knarr namespace facades for Langertha utility code
      (Knarr::Metrics, Knarr::Input, Knarr::Output, Knarr::Input::Tools,
      Knarr::Output::Tools). Use Langertha::Usage / Tool / ToolCall /
      ToolChoice / Pricing / Cost / UsageRecord directly from
      Langertha core.

    - cpanfile drops Mojolicious, Test::Mojo, MooseX::Role::Parameterized,
      HTTP::Message, File::ShareDir::ProjectDistDir; adds IO::Async,
      Net::Async::HTTP, Net::Async::HTTP::Server, Future::AsyncAwait,
      Moose, Path::Tiny (test), Capture::Tiny (test).

    - Bump Langertha floor to 0.400 for the new value object API.

    - dist.ini sets irc = #langertha (on irc.perl.org).

    - Test suite expanded from 200 to 320 unit tests + author POD
      syntax. New coverage:
        * end-to-end live streaming for Anthropic / A2A / ACP / AG-UI
          (OpenAI and Ollama already covered)
        * Handler::Passthrough sync + streaming through a real backend
        * Handler::Router with passthrough fallback
        * Multi-listen on real sockets
        * Tracing and RequestLog decorators
        * CLI smoketest for knarr models / check / init
        * proxy_api_key auth enforcement

0.007     2026-03-10 20:05:00Z

  - Resolve configured engines through both `Langertha::Engine::*` and
    `LangerthaX::Engine::*` (including fully-qualified class names).
  - Add router test coverage for `LangerthaX::Engine::*` custom engines.
  - Tighten dependency minimums in cpanfile:
    `Langertha 0.307`, `Mojolicious 9.0`.
  - Update README and POD docs to describe custom engine resolution order.
  - Dockerfile: add optional `LANGERTHA_SRC` build arg to inject unreleased
    Langertha source when CPAN indexers lag.
  - dist.ini release Docker build supports optional
    `KNARR_DOCKER_BUILD_ARGS='...'` passthrough for temporary build overrides,
    including GitHub release-dist URL examples and a note against
    `/archive/refs/*` source archives for dzil dists.
  - dist.ini now uploads `Langertha-Knarr-%v.tar.gz` to GitHub releases
    (`Getty/langertha-knarr`) via `gh` during post-release hooks.
  - dist.ini now runs `${GH_BIN:-gh}` directly in separate `run_after_release`
    steps (no pre-check, no chained `&&`), so hooks use invoking-shell runtime
    environment/path.

0.005     2026-03-10 14:48:05Z

  - Add primary Knarr normalization modules (core-backed):
    `Langertha::Knarr::Input`, `Langertha::Knarr::Output`, `Langertha::Knarr::Metrics`.
  - Bump `Langertha` dependency to `>= 0.306`.

  - Add request policy hooks in `build_app`:
    - `before_request` hook to inspect/mutate/block requests before routing
    - `api_key_validator` hook for dynamic per-request key authorization
  - Add cross-format tool bridging between OpenAI and Anthropic request/response shapes
    (including `tools`, `tool_choice`, `tool_calls`, `tool_use`, and `tool_result`)
  - Add Hermes tool XML bridging:
    - Parse `<tool_call>{...}</tool_call>` into OpenAI `tool_calls`
    - Parse `<tool_call>{...}</tool_call>` into Anthropic `tool_use` blocks
  - Route OpenAI `tools` through Hermes-capable engines by normalizing tool schema
  - Extend proxy/unit/integration tests for hook behavior and tool-bridge paths

0.004     2026-03-03 05:22:38Z

  - Fix routing priority: passthrough before default engine fallback
  - Add passthrough-only mode (no API keys needed)
  - Add KNARR_TRACE_NAME / --trace-name for custom Langfuse trace names
  - Support LANGFUSE_BASE_URL env var (in addition to LANGFUSE_URL)
  - Strip quotes from env values (Docker --env-file compatibility)
  - Strip Accept-Encoding/Content-Encoding in passthrough (no gzip issues)
  - Rewrite POD: passthrough proxy as primary use case
  - Fix Langertha dependency version to 0.303
  - Fix author URL

0.001     2026-03-03 04:00:32Z

  - Initial release
  - Multi-format LLM proxy: OpenAI, Anthropic, Ollama
  - Passthrough mode with Langfuse tracing
  - Docker container mode with auto-detect from ENV
  - CLI: start, container, models, check, init
