Skip to content

feat: backend/lemonade#70

Merged
thushan merged 12 commits intomainfrom
integration/lemonade
Oct 9, 2025
Merged

feat: backend/lemonade#70
thushan merged 12 commits intomainfrom
integration/lemonade

Conversation

@thushan
Copy link
Owner

@thushan thushan commented Oct 8, 2025

Integration of AMD enhanced Lemonade SDK.

Summary by CodeRabbit

  • New Features

    • Added native Lemonade SDK backend with proxy routing and OpenAI-compatible model listings; Lemonade recognised as a provider. Model catalogue and API responses now surface Lemonade metadata (checkpoint, recipe) and include Lemonade in backend examples/headers.
  • Documentation

    • New Lemonade SDK API reference and integration guide; updates across Quick Start, Overview, FAQ, integrations and navigation to include Lemonade, SGLang and LiteLLM. Clarified backend "type" references with links to endpoint configuration.

add tests

fix parser missing model naming

fix format issues

add devstral for parser

update tests

adds converter

if no aliases, use the default in converter

add tests to converter

add to factory and update tests

add to parsers, fix tests
fix test properly

lm parser test failures

finalise parser branch and fix up linting
update tests

lint fixes refactoring unifier
re-review and adjusting of all docs.
@thushan thushan added the llm-backend Issue is about an LLM Backend, provider or type. (Eg. Ollama, vllm) label Oct 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 8, 2025

Walkthrough

Adds native Lemonade backend support across config, docs, converters, registry parsers, unifier, handlers/routes, constants and tests. Introduces Lemonade types, parser, converter and profile, registers the converter, adds provider constants and metadata fields (checkpoint, recipe), and updates site navigation and documentation.

Changes

Cohort / File(s) Summary
Config: discovery & profiles
config/config.yaml, config/profiles/README.md, config/profiles/lemonade.yaml
Documentation comments added to discovery; profiles/README.md updated to include lemonade and sglang response_format options; new lemonade.yaml profile added.
Core domain & identifiers
internal/core/constants/providers.go, internal/core/domain/model.go, internal/core/domain/profile.go, internal/version/version.go
Adds ProviderTypeLemonade/display constant; adds Checkpoint and Recipe to ModelDetails; adds ProfileLemonade; lists lemonade in SupportedBackends.
Converter: factory and Lemonade
internal/adapter/converter/factory.go, internal/adapter/converter/lemonade_converter.go, internal/adapter/converter/factory_test.go, internal/adapter/converter/lemonade_converter_test.go
Registers NewLemonadeConverter(); implements LemonadeConverter (model→Lemonade response conversion, checkpoint/recipe handling); updates converter tests and adds comprehensive Lemonade tests and benchmark.
Registry profile and parser
internal/adapter/registry/profile/lemonade.go, internal/adapter/registry/profile/lemonade_parser.go, internal/adapter/registry/profile/lemonade_parser_test.go, internal/adapter/registry/profile/parsers.go
Adds LemonadeResponse/LemonadeModel types; implements lemonadeParser to convert Lemonade API responses to domain.ModelInfo (publisher extraction, format inference from recipe); adds tests and parser dispatch case.
Unifier adjustments
internal/adapter/unifier/default_unifier.go
Extracts applyModelDetails and applyModelInfo helpers; maps Checkpoint and Recipe into model metadata.
App handlers and routing
internal/app/handlers/handler_common.go, internal/app/handlers/handler_provider_common.go, internal/app/handlers/handler_provider_compatibility_test.go, internal/app/handlers/handler_provider_models_test.go, internal/app/handlers/server_routes.go
Adds lemonade to supported static providers and OpenAI-compatible minimal profiles (test path); adds static Lemonade routes (models proxy and API paths); updates compatibility and models tests.
Docs: API Reference (Lemonade)
docs/content/api-reference/lemonade.md, docs/content/api-reference/overview.md
New Lemonade API reference, overview updates (adds lemonade, litellm, new header X-Olla-Routing-Reason); docs-only changes.
Docs: Integrations and backend pages
docs/content/integrations/backend/lemonade.md, docs/content/integrations/backend/*, docs/content/integrations/overview.md, docs/mkdocs.yml
Adds Lemonade backend integration page; restructures integrations overview into a table including lemonade; clarifies Type links; updates site navigation.
Docs: Site content updates
docs/content/index.md, docs/content/faq.md, docs/content/getting-started/quickstart.md, docs/content/concepts/overview.md, docs/content/configuration/overview.md
Site-wide textual updates referencing Lemonade and SGLang, keywords and supported-backend lists; small config docs link change.
README
readme.md
Update badges/listing to reflect Lemonade SDK native support and related label tweaks.
Misc constants & registry glue
internal/core/constants/llm.go, internal/adapter/registry/...
Adds recipe format constants (llamacpp, flm, gguf, onnx) and wires parser dispatch to include Lemonade.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Olla as Olla Proxy
  participant Lemonade as Lemonade Backend

  rect rgb(240,248,255)
    note over Client,Olla: Model listing (normalised OpenAI-format)
    Client->>Olla: GET /olla/lemonade/api/v1/models
    Olla->>Lemonade: GET /api/v1/models
    Lemonade-->>Olla: 200 JSON (Lemonade models)
    Olla->>Olla: Parse LemonadeResponse → domain.ModelInfo → convert to OpenAI-format (preserve checkpoint/recipe)
    Olla-->>Client: 200 JSON (object=list, data=[...]) + X-Olla-* headers
  end

  rect rgb(245,255,240)
    note over Client,Olla: Proxyed inference
    Client->>Olla: POST /olla/lemonade/v1/chat/completions
    Olla->>Lemonade: POST /v1/chat/completions (forwarded)
    Lemonade-->>Olla: Stream/JSON response
    Olla-->>Client: Stream/JSON + X-Olla-Request-ID, X-Olla-Backend-Type=lemonade
  end

  rect rgb(255,250,240)
    note over Olla,Lemonade: Health & status checks
    Olla->>Lemonade: GET /healthz
    Lemonade-->>Olla: 200 OK
    Olla->>Olla: Update endpoint status/registry
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement, documentation

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly indicates the addition of the Lemonade backend feature, which is the primary change in this pull request. It is concise and directly related to the integration of the AMD-enhanced Lemonade SDK. Team members reviewing history will understand that this PR introduces support for the Lemonade backend.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch integration/lemonade

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
internal/app/handlers/handler_provider_models_test.go (1)

210-235: Consider consolidating duplicate test cases.

Both lemonade_native_format and lemonade_openai_format test cases are identical—they use the same handler (genericProviderModelsHandler("lemonade", "openai")), same expected format ("openai"), and same assertions. Since Lemonade doesn't have a native format distinct from OpenAI, one test case would suffice.

Apply this diff to remove the duplicate test case:

-		{
-			name:           "lemonade_openai_format",
-			endpoint:       "/olla/lemonade/v1/models",
-			handler:        app.genericProviderModelsHandler("lemonade", "openai"),
-			expectedFormat: "openai",
-			checkResponse: func(t *testing.T, body []byte) {
-				var response converter.OpenAIModelResponse
-				require.NoError(t, json.Unmarshal(body, &response))
-				assert.Equal(t, "list", response.Object)
-				assert.Len(t, response.Data, 1)
-				assert.Equal(t, "Qwen2.5-0.5B-Instruct-CPU", response.Data[0].ID)
-			},
-		},
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 444e577 and 6748a50.

📒 Files selected for processing (37)
  • config/config.yaml (1 hunks)
  • config/profiles/README.md (2 hunks)
  • config/profiles/lemonade.yaml (1 hunks)
  • docs/content/api-reference/lemonade.md (1 hunks)
  • docs/content/api-reference/overview.md (3 hunks)
  • docs/content/concepts/overview.md (1 hunks)
  • docs/content/configuration/overview.md (1 hunks)
  • docs/content/faq.md (1 hunks)
  • docs/content/getting-started/quickstart.md (2 hunks)
  • docs/content/index.md (3 hunks)
  • docs/content/integrations/backend/lemonade.md (1 hunks)
  • docs/content/integrations/backend/litellm.md (1 hunks)
  • docs/content/integrations/backend/lmstudio.md (1 hunks)
  • docs/content/integrations/backend/ollama.md (1 hunks)
  • docs/content/integrations/backend/sglang.md (1 hunks)
  • docs/content/integrations/backend/vllm.md (1 hunks)
  • docs/content/integrations/overview.md (1 hunks)
  • docs/mkdocs.yml (2 hunks)
  • internal/adapter/converter/factory.go (1 hunks)
  • internal/adapter/converter/factory_test.go (3 hunks)
  • internal/adapter/converter/lemonade_converter.go (1 hunks)
  • internal/adapter/converter/lemonade_converter_test.go (1 hunks)
  • internal/adapter/registry/profile/lemonade.go (1 hunks)
  • internal/adapter/registry/profile/lemonade_parser.go (1 hunks)
  • internal/adapter/registry/profile/lemonade_parser_test.go (1 hunks)
  • internal/adapter/registry/profile/parsers.go (1 hunks)
  • internal/adapter/unifier/default_unifier.go (1 hunks)
  • internal/app/handlers/handler_common.go (1 hunks)
  • internal/app/handlers/handler_provider_common.go (1 hunks)
  • internal/app/handlers/handler_provider_compatibility_test.go (2 hunks)
  • internal/app/handlers/handler_provider_models_test.go (6 hunks)
  • internal/app/handlers/server_routes.go (1 hunks)
  • internal/core/constants/providers.go (2 hunks)
  • internal/core/domain/model.go (1 hunks)
  • internal/core/domain/profile.go (1 hunks)
  • internal/version/version.go (1 hunks)
  • readme.md (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
internal/app/handlers/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Set response headers on proxy responses: X-Olla-Endpoint, X-Olla-Model, X-Olla-Backend-Type, X-Olla-Request-ID, X-Olla-Response-Time

Files:

  • internal/app/handlers/handler_provider_models_test.go
  • internal/app/handlers/handler_provider_common.go
  • internal/app/handlers/handler_provider_compatibility_test.go
  • internal/app/handlers/server_routes.go
  • internal/app/handlers/handler_common.go
{internal,pkg}/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Include Go benchmarks (Benchmark* functions) for critical paths, proxy engine comparisons, pooling efficiency, and circuit breaker behaviour

Files:

  • internal/app/handlers/handler_provider_models_test.go
  • internal/app/handlers/handler_provider_compatibility_test.go
  • internal/adapter/converter/factory_test.go
  • internal/adapter/converter/lemonade_converter_test.go
  • internal/adapter/registry/profile/lemonade_parser_test.go
🧠 Learnings (2)
📚 Learning: 2025-09-23T08:30:20.366Z
Learnt from: CR
PR: thushan/olla#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T08:30:20.366Z
Learning: Applies to internal/app/handlers/*.go : Set response headers on proxy responses: `X-Olla-Endpoint`, `X-Olla-Model`, `X-Olla-Backend-Type`, `X-Olla-Request-ID`, `X-Olla-Response-Time`

Applied to files:

  • docs/content/api-reference/overview.md
  • docs/content/index.md
📚 Learning: 2025-09-23T08:30:20.366Z
Learnt from: CR
PR: thushan/olla#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T08:30:20.366Z
Learning: Applies to config/profiles/{ollama,lmstudio,litellm,openai,vllm}.yaml : Provider-specific profiles must reside under `config/profiles/` with the specified filenames

Applied to files:

  • docs/content/concepts/overview.md
🧬 Code graph analysis (10)
internal/app/handlers/handler_provider_models_test.go (3)
internal/core/domain/endpoint.go (1)
  • StatusHealthy (52-52)
internal/core/domain/model.go (1)
  • ModelInfo (28-35)
internal/adapter/converter/openai_converter.go (1)
  • OpenAIModelResponse (11-14)
internal/app/handlers/handler_provider_common.go (1)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/adapter/converter/factory.go (1)
internal/adapter/converter/lemonade_converter.go (1)
  • NewLemonadeConverter (23-27)
internal/adapter/unifier/default_unifier.go (1)
internal/core/domain/model.go (2)
  • ModelDetails (11-26)
  • ModelInfo (28-35)
internal/adapter/registry/profile/lemonade_parser.go (2)
internal/core/domain/model.go (2)
  • ModelInfo (28-35)
  • ModelDetails (11-26)
internal/adapter/registry/profile/lemonade.go (1)
  • LemonadeResponse (11-14)
internal/adapter/registry/profile/parsers.go (1)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/adapter/converter/lemonade_converter.go (5)
internal/adapter/registry/profile/lemonade.go (2)
  • LemonadeResponse (11-14)
  • LemonadeModel (17-27)
internal/adapter/converter/base_converter.go (2)
  • BaseConverter (8-10)
  • NewBaseConverter (13-17)
internal/core/ports/model_converter.go (2)
  • ModelResponseConverter (10-15)
  • ModelFilters (18-23)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/core/domain/unified_model.go (1)
  • UnifiedModel (15-31)
internal/app/handlers/server_routes.go (1)
internal/core/constants/providers.go (2)
  • ProviderTypeLemonade (5-5)
  • ProviderTypeOpenAI (7-7)
internal/adapter/converter/lemonade_converter_test.go (6)
internal/adapter/converter/lemonade_converter.go (2)
  • NewLemonadeConverter (23-27)
  • LemonadeConverter (18-20)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/core/domain/unified_model.go (3)
  • UnifiedModel (15-31)
  • AliasEntry (9-12)
  • SourceEndpoint (34-44)
internal/core/ports/model_converter.go (1)
  • ModelFilters (18-23)
internal/adapter/registry/profile/lemonade.go (2)
  • LemonadeResponse (11-14)
  • LemonadeModel (17-27)
internal/adapter/converter/base_converter.go (2)
  • BaseConverter (8-10)
  • NewBaseConverter (13-17)
internal/app/handlers/handler_common.go (1)
internal/core/constants/providers.go (3)
  • ProviderTypeLemonade (5-5)
  • ProviderTypeLMStudio (6-6)
  • ProviderTypeOllama (4-4)
🪛 markdownlint-cli2 (0.18.1)
docs/content/api-reference/lemonade.md

24-24: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


186-186: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


209-209: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


256-256: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


263-263: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/content/integrations/backend/lemonade.md

167-167: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


318-318: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


541-541: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cross-Platform Build Validation (windows-latest)
🔇 Additional comments (47)
config/profiles/README.md (1)

20-20: LGTM!

The documentation additions for Lemonade SDK integration are clear and consistent with the existing profile documentation structure.

Also applies to: 133-133

config/config.yaml (1)

73-74: LGTM!

The documentation reference improves usability by pointing users to endpoint configuration details.

docs/content/integrations/backend/sglang.md (2)

16-16: Verify the version downgrade.

The "Since" version changed from v0.1.0 to v0.0.19, which represents a backwards version change. Please confirm this is intentional and not a documentation error.


20-20: LGTM!

Adding the hyperlink to endpoint configuration improves documentation consistency and usability.

docs/content/integrations/backend/vllm.md (1)

20-20: LGTM!

The hyperlink addition improves documentation consistency across backend integrations.

docs/content/integrations/backend/litellm.md (1)

20-20: LGTM!

The hyperlink addition maintains consistency with other backend integration documentation.

docs/content/integrations/backend/ollama.md (1)

20-20: LGTM!

The hyperlink addition aligns with the documentation pattern used across other backend integrations.

docs/content/integrations/backend/lmstudio.md (1)

20-20: LGTM!

The hyperlink addition improves navigation and maintains documentation consistency.

internal/app/handlers/handler_provider_common.go (1)

45-45: LGTM!

Adding Lemonade to the test scenario's minimal OpenAI-compatible profile set is consistent with the PR's objective of integrating Lemonade SDK support. The placement within the test-only branch (when profileFactory is nil) is appropriate.

config/profiles/lemonade.yaml (1)

1-260: Comprehensive profile definition for Lemonade SDK.

The profile is well-structured and covers all necessary aspects: routing, API compatibility, model management, resource requirements, and security considerations. The inclusion of hardware acceleration details (CPU, GPU, NPU) and multiple backend support (oga-cpu, oga-npu, llamacpp, etc.) aligns well with Lemonade's local inference optimisation focus.

docs/content/concepts/overview.md (1)

69-69: LGTM!

The documentation update correctly reflects the addition of SGLang, Lemonade SDK, and LiteLLM to the list of pre-configured profiles.

internal/adapter/converter/factory.go (1)

24-24: LGTM!

The Lemonade converter registration follows the established pattern for other providers and aligns with the factory's registration approach.

internal/adapter/registry/profile/parsers.go (1)

23-24: LGTM!

The parser registration for Lemonade follows the established pattern for other providers and correctly references the provider type constant.

docs/mkdocs.yml (1)

157-157: LGTM!

The navigation entries for Lemonade SDK documentation are correctly placed in both the Backends and Provider APIs sections, maintaining consistency with other providers.

Also applies to: 179-179

internal/core/constants/providers.go (1)

5-5: LGTM!

The provider constants for Lemonade follow the established naming conventions and are correctly placed among the existing provider definitions.

Also applies to: 14-14

docs/content/faq.md (1)

13-13: LGTM!

The FAQ update correctly includes the newly supported backends (vLLM, SGLang, Lemonade SDK, LiteLLM) in the product description.

docs/content/getting-started/quickstart.md (1)

3-4: LGTM!

The quickstart guide has been appropriately updated to include the new backends in the description, keywords, and recommended next steps section.

Also applies to: 227-227

internal/version/version.go (1)

34-34: LGTM!

The addition of "lemonade" to the SupportedBackends list is correct and maintains alphabetical ordering.

internal/core/domain/profile.go (1)

5-5: LGTM!

The ProfileLemonade constant is correctly defined and follows the established naming convention.

docs/content/configuration/overview.md (1)

206-210: LGTM!

The documentation improvements enhance discoverability by linking to the integrations overview, making it easier for users to understand supported backend types.

internal/app/handlers/handler_provider_compatibility_test.go (2)

57-62: LGTM!

The test case correctly validates that the OpenAI provider accepts Lemonade endpoints, which is appropriate given Lemonade's OpenAI-compatible API.


120-138: LGTM!

The test coverage for the Lemonade provider is comprehensive, including both positive cases (accepts lemonade) and negative cases (rejects ollama and vllm). This follows the established testing pattern.

internal/app/handlers/handler_common.go (1)

82-84: LGTM!

The addition of Lemonade to the staticProviders map is correct and maintains alphabetical ordering. This ensures Lemonade is recognised as a valid provider type.

internal/adapter/converter/factory_test.go (3)

23-27: LGTM!

The test cases correctly validate that the converter factory returns the appropriate converters for lemonade, sglang, and vllm formats.


52-55: LGTM!

The error message assertions ensure that unsupported format errors properly list lemonade and sglang as valid options.


60-74: LGTM!

The test correctly validates that the supported formats count increased to 7 and that lemonade is properly registered in the format map.

docs/content/index.md (4)

3-4: LGTM!

The documentation metadata is correctly updated to include Lemonade SDK and SGLang in the description and keywords.


20-20: LGTM!

The badge correctly reflects native Lemonade support, upgraded from OpenAI-compatible status. This accurately represents the PR's integration of native Lemonade SDK support.


27-27: LGTM!

The routing description accurately reflects the addition of Lemonade SDK (AMD Ryzen AI) and SGLang (with RadixAttention) as supported backends.


98-98: LGTM!

The Backend-Type response header documentation correctly includes lemonade in the list of supported backend types.

internal/core/domain/model.go (1)

23-24: Approve Checkpoint and Recipe additions

The new optional Checkpoint and Recipe fields are correctly defined and fully integrated in parsing, conversion, and registry logic, with comprehensive tests covering all scenarios.

docs/content/api-reference/overview.md (4)

17-18: LGTM! Playful reminder enhances user experience.

The mnemonic "4 OLLA" is a clever way to help users remember the port number. This adds personality to the documentation while serving a practical purpose.


67-72: LGTM! Lemonade SDK section properly documented.

The new section follows the established pattern for other backend API sections. The description correctly highlights ONNX and GGUF model support with hardware acceleration, aligning with Lemonade's capabilities.


108-108: LGTM! Backend type examples properly updated.

The addition of lemonade and litellm to the examples correctly reflects the expanded backend support.


112-112: X-Olla-Routing-Reason header is implemented
The header is set in internal/adapter/proxy/core/common.go (lines 184–190) when stats.RoutingDecision.Reason is non-empty.

docs/content/integrations/overview.md (1)

13-25: LGTM! Table structure improves documentation clarity.

The structured table provides better visibility of backend types and descriptions compared to the previous bullet list. The addition of Lemonade SDK and OpenAI Compatible entries is well-documented and consistent with other backend entries.

The note about using the type in Endpoint Configurations is helpful for users.

internal/app/handlers/handler_provider_models_test.go (2)

33-33: LGTM! Lemonade test setup follows existing patterns.

The lemonade endpoint and model registration follows the established pattern used for other providers (ollama, lmstudio, openai, vllm). The single test model "Qwen2.5-0.5B-Instruct-CPU" aligns with Lemonade's naming conventions.

Also applies to: 64-70, 87-87, 93-93


183-194: LGTM! Expected model count and assertions properly updated.

The comment correctly explains that the openai provider accepts models from all OpenAI-compatible endpoints (ollama, lmstudio, openai, vllm, and lemonade). The updated count from 5 to 6 and the assertion for "Qwen2.5-0.5B-Instruct-CPU" are correct.

internal/app/handlers/server_routes.go (1)

181-188: LGTM! Lemonade static provider follows established patterns.

The static provider entry for Lemonade is consistent with other providers (SGLang, vLLM). The routes correctly configure:

  • Model discovery endpoints (api/v1/models and v1/models) using OpenAI format
  • Proxy route for forwarding requests to the backend

The structure aligns with the new backend integration requirements.

internal/adapter/unifier/default_unifier.go (3)

357-372: LGTM! Refactoring improves code organisation.

The extraction of detail transfer logic into applyModelDetails and applyModelInfo helpers improves readability and maintainability. The centralised return site makes the function flow clearer.


374-421: LGTM! Checkpoint and Recipe metadata properly handled.

The applyModelDetails helper correctly transfers all ModelDetails fields to the Model and its metadata, including the new Checkpoint and Recipe fields (lines 415-420). The logic for handling family selection (Family vs. Families) is preserved.


423-434: LGTM! Top-level ModelInfo fields properly transferred.

The applyModelInfo helper correctly transfers Type, Description, and LastSeen from ModelInfo to Model metadata.

readme.md (2)

10-14: LGTM! Provider badges accurately reflect backend support.

The badges correctly represent:

  • LiteLLM as native support
  • Lemonade SDK as native support with AMD Ryzen AI optimisation
  • LM Deploy as OpenAI-compatible

The visual hierarchy helps users quickly understand the integration types.


81-81: LGTM! Lemonade SDK table entry provides comprehensive information.

The table entry clearly describes Lemonade SDK as AMD's local inference solution with specific hardware optimisations (AMD Ryzen AI NPU, IGPU via DirectML, and CPU) and supported model formats (ONNX and GGUF).

internal/adapter/registry/profile/lemonade.go (1)

1-27: LGTM! Data contracts are well-defined and documented.

The Lemonade data structures are clean and follow established patterns:

  • LemonadeResponse matches OpenAI-compatible list format
  • LemonadeModel extends OpenAI fields with Lemonade-specific metadata
  • Inline documentation clearly distinguishes standard vs. Lemonade-specific fields
  • Checkpoint and Recipe fields are properly documented with examples

The structure aligns with the API reference documentation (line 7 reference is helpful).

internal/adapter/registry/profile/lemonade_parser.go (2)

13-83: Parser implementation is well-structured with intelligent metadata extraction.

The Parse method correctly:

  • Handles empty input gracefully (lines 14-16)
  • Skips models with empty IDs (lines 27-29)
  • Extracts creation time and maps to ModifiedAt (lines 42-46)
  • Stores Checkpoint metadata (lines 50-52)
  • Extracts Publisher from checkpoint path (lines 56-59)—clever use of HuggingFace path convention
  • Stores Recipe and infers Format via helper (lines 64-73)
  • Only applies details when present (lines 75-77)

The logic is clean and follows established patterns from other parsers in the codebase.


85-95: LGTM! Format inference maps recipes to model formats correctly.

The inferFormatFromRecipe helper provides intelligent mapping:

  • oga-* recipes → ONNX format
  • llamacpp and flm recipes → GGUF format

This enables proper routing and compatibility checking based on the inference engine. The implementation is straightforward and maintainable.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6748a50 and 9cb11c9.

📒 Files selected for processing (5)
  • config/profiles/lemonade.yaml (1 hunks)
  • internal/adapter/converter/lemonade_converter_test.go (1 hunks)
  • internal/adapter/registry/profile/lemonade_parser.go (1 hunks)
  • internal/adapter/registry/profile/lemonade_parser_test.go (1 hunks)
  • internal/core/constants/llm.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • config/profiles/lemonade.yaml
  • internal/adapter/registry/profile/lemonade_parser.go
  • internal/adapter/registry/profile/lemonade_parser_test.go
🧰 Additional context used
📓 Path-based instructions (1)
{internal,pkg}/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Include Go benchmarks (Benchmark* functions) for critical paths, proxy engine comparisons, pooling efficiency, and circuit breaker behaviour

Files:

  • internal/adapter/converter/lemonade_converter_test.go
🧬 Code graph analysis (1)
internal/adapter/converter/lemonade_converter_test.go (6)
internal/adapter/converter/lemonade_converter.go (2)
  • NewLemonadeConverter (23-27)
  • LemonadeConverter (18-20)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/core/domain/unified_model.go (3)
  • UnifiedModel (15-31)
  • AliasEntry (9-12)
  • SourceEndpoint (34-44)
internal/core/ports/model_converter.go (1)
  • ModelFilters (18-23)
internal/adapter/registry/profile/lemonade.go (2)
  • LemonadeResponse (11-14)
  • LemonadeModel (17-27)
internal/adapter/converter/base_converter.go (2)
  • BaseConverter (8-10)
  • NewBaseConverter (13-17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cross-Platform Build Validation (windows-latest)
🔇 Additional comments (1)
internal/adapter/converter/lemonade_converter_test.go (1)

463-500: LGTM! Past issue resolved.

The benchmark correctly uses strconv.Itoa(i) (Lines 470, 472, 476) to convert integers to strings, addressing the issue flagged in the previous review. The benchmark is well-structured with a large dataset, memory allocation reporting, and proper validation.

Comment on lines +257 to +278
func TestLemonadeConverter_ConvertToFormat_OwnerFromModelID(t *testing.T) {
converter := NewLemonadeConverter()

model := &domain.UnifiedModel{
ID: "test-model",
Aliases: []domain.AliasEntry{
{Name: "custom-org/test-model", Source: constants.ProviderTypeLemonade},
},
}

result, err := converter.ConvertToFormat([]*domain.UnifiedModel{model}, ports.ModelFilters{})

require.NoError(t, err)
response, ok := result.(profile.LemonadeResponse)
require.True(t, ok)

require.Len(t, response.Data, 1)
lemonadeModel := response.Data[0]

// Owner should be extracted from model ID with slash
assert.Equal(t, "custom-org", lemonadeModel.OwnedBy)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify misleading comment about owner extraction.

Line 277's comment states "Owner should be extracted from model ID with slash", but the test extracts the owner from the alias ("custom-org/test-model" on Line 263), not the model ID ("test-model" on Line 261). The comment should clarify that the owner comes from the alias.

Apply this diff to clarify the comment:

-	// Owner should be extracted from model ID with slash
+	// Owner should be extracted from the alias name with slash
 	assert.Equal(t, "custom-org", lemonadeModel.OwnedBy)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func TestLemonadeConverter_ConvertToFormat_OwnerFromModelID(t *testing.T) {
converter := NewLemonadeConverter()
model := &domain.UnifiedModel{
ID: "test-model",
Aliases: []domain.AliasEntry{
{Name: "custom-org/test-model", Source: constants.ProviderTypeLemonade},
},
}
result, err := converter.ConvertToFormat([]*domain.UnifiedModel{model}, ports.ModelFilters{})
require.NoError(t, err)
response, ok := result.(profile.LemonadeResponse)
require.True(t, ok)
require.Len(t, response.Data, 1)
lemonadeModel := response.Data[0]
// Owner should be extracted from model ID with slash
assert.Equal(t, "custom-org", lemonadeModel.OwnedBy)
}
func TestLemonadeConverter_ConvertToFormat_OwnerFromModelID(t *testing.T) {
converter := NewLemonadeConverter()
model := &domain.UnifiedModel{
ID: "test-model",
Aliases: []domain.AliasEntry{
{Name: "custom-org/test-model", Source: constants.ProviderTypeLemonade},
},
}
result, err := converter.ConvertToFormat([]*domain.UnifiedModel{model}, ports.ModelFilters{})
require.NoError(t, err)
response, ok := result.(profile.LemonadeResponse)
require.True(t, ok)
require.Len(t, response.Data, 1)
lemonadeModel := response.Data[0]
// Owner should be extracted from the alias name with slash
assert.Equal(t, "custom-org", lemonadeModel.OwnedBy)
}
🤖 Prompt for AI Agents
internal/adapter/converter/lemonade_converter_test.go around lines 257 to 278:
the inline comment on line 277 incorrectly states the owner is extracted from
the model ID; update that comment to state the owner is extracted from the alias
value (e.g., "custom-org/test-model") which contains the slash, so change the
comment to clarify the owner comes from the alias rather than the model.ID.

Comment on lines 3 to 5
const (
BackendLlamaCpp = "llamacpp"
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify the constant's purpose and naming.

The PR is focused on Lemonade backend integration, but this file introduces a BackendLlamaCpp constant. Based on the Lemonade implementation, "llamacpp" appears to be a recipe/inference engine type rather than a backend. This raises two concerns:

  1. Is this constant intended for Lemonade's recipe field or for a separate LlamaCpp backend?
  2. If it's for recipes, should it be named RecipeLlamaCpp instead of BackendLlamaCpp for clarity?

Run the following script to verify how this constant is used:


🏁 Script executed:

#!/bin/bash
# Description: Check usage of BackendLlamaCpp constant across the codebase

# Search for references to BackendLlamaCpp
rg -nP --type=go -C3 'BackendLlamaCpp'

# Search for "llamacpp" string literals to understand context
rg -nP --type=go -C3 '"llamacpp"'

Length of output: 6080


Rename BackendLlamaCpp to RecipeLlamaCpp
Update internal/core/constants/llm.go (and its references in the Lemonade parser) so the constant reflects its use as a recipe type.

- const BackendLlamaCpp = "llamacpp"
+ const RecipeLlamaCpp  = "llamacpp"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In internal/core/constants/llm.go around lines 3 to 5, the constant
BackendLlamaCpp should be renamed to RecipeLlamaCpp to reflect its role as a
recipe type; update the constant name in this file and then find and replace all
references across the codebase (including the Lemonade parser) to use
RecipeLlamaCpp, update any tests or switch/case branches that match on the old
name, and ensure import paths and compilation by running a full build and tests
after renaming.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
internal/adapter/converter/lemonade_converter_test.go (1)

276-277: Correct the alias ownership comment.

The owner is derived from the Lemonade alias (custom-org/test-model), not from the unified model ID, so this note misleads future maintainers. Please update the comment to reflect the alias source.

🧹 Nitpick comments (3)
internal/core/constants/llm.go (3)

7-7: Consider consistent casing for acronyms.

The constant RecipeOnnx uses mixed case (Onnx), whilst RecipeFLM and RecipeGGUF use all-caps for their acronyms. If ONNX is an acronym (Open Neural Network Exchange), consider using all-caps for consistency with Go conventions.

Apply this diff for consistent acronym casing:

-	RecipeOnnx     = "onnx"
+	RecipeONNX     = "onnx"

Note: This would require updating all references to RecipeOnnx throughout the codebase.


3-8: Add documentation for the constants.

Consider adding package-level and constant-level documentation to explain the purpose of these recipe constants and their relationship to the Lemonade backend integration. This improves maintainability and helps developers understand usage context.

Example documentation:

+// Package constants defines shared constant values used across the application,
+// including LLM backend recipe identifiers for format detection and conversion.
 package constants

+// Recipe constants define supported Lemonade backend inference engine formats.
+// These are used during model metadata parsing and format detection.
 const (
+	// RecipeLlamaCpp represents the llama.cpp inference engine format
 	RecipeLlamaCpp = "llamacpp"
+	// RecipeFLM represents the FLM (Fast Language Model) format
 	RecipeFLM      = "flm"
+	// RecipeGGUF represents the GGUF (GPT-Generated Unified Format) format
 	RecipeGGUF     = "gguf"
+	// RecipeOnnx represents the ONNX (Open Neural Network Exchange) format
 	RecipeOnnx     = "onnx"
 )

3-8: Consider using a custom type for type safety.

Defining a custom Recipe type would provide compile-time type safety, prevent accidental misuse, and enable attaching methods for validation or conversion logic in the future.

Example refactor with custom type:

+// Recipe represents a Lemonade backend inference engine format identifier.
+type Recipe string
+
+// Recipe constants define supported Lemonade backend formats.
 const (
-	RecipeLlamaCpp = "llamacpp"
-	RecipeFLM      = "flm"
-	RecipeGGUF     = "gguf"
-	RecipeOnnx     = "onnx"
+	RecipeLlamaCpp Recipe = "llamacpp"
+	RecipeFLM      Recipe = "flm"
+	RecipeGGUF     Recipe = "gguf"
+	RecipeOnnx     Recipe = "onnx"
 )

This would require updating function signatures that accept or return these values to use the Recipe type instead of string.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cb11c9 and 203ce4a.

📒 Files selected for processing (3)
  • internal/adapter/converter/lemonade_converter_test.go (1 hunks)
  • internal/adapter/registry/profile/lemonade_parser.go (1 hunks)
  • internal/core/constants/llm.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/adapter/registry/profile/lemonade_parser.go
🧰 Additional context used
📓 Path-based instructions (1)
{internal,pkg}/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Include Go benchmarks (Benchmark* functions) for critical paths, proxy engine comparisons, pooling efficiency, and circuit breaker behaviour

Files:

  • internal/adapter/converter/lemonade_converter_test.go
🧬 Code graph analysis (1)
internal/adapter/converter/lemonade_converter_test.go (6)
internal/adapter/converter/lemonade_converter.go (2)
  • NewLemonadeConverter (23-27)
  • LemonadeConverter (18-20)
internal/core/constants/providers.go (1)
  • ProviderTypeLemonade (5-5)
internal/core/domain/unified_model.go (3)
  • UnifiedModel (15-31)
  • AliasEntry (9-12)
  • SourceEndpoint (34-44)
internal/core/ports/model_converter.go (1)
  • ModelFilters (18-23)
internal/adapter/registry/profile/lemonade.go (2)
  • LemonadeResponse (11-14)
  • LemonadeModel (17-27)
internal/adapter/converter/base_converter.go (2)
  • BaseConverter (8-10)
  • NewBaseConverter (13-17)
🔇 Additional comments (1)
internal/core/constants/llm.go (1)

1-8: Previous feedback addressed: constant renamed appropriately.

The previous review comment suggested renaming BackendLlamaCpp to RecipeLlamaCpp to better reflect its role as a recipe type rather than a backend identifier. This feedback has been properly addressed in the current implementation.

@thushan thushan merged commit 8ad09fd into main Oct 9, 2025
8 checks passed
@thushan thushan deleted the integration/lemonade branch October 9, 2025 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llm-backend Issue is about an LLM Backend, provider or type. (Eg. Ollama, vllm)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant