feat: path preservation for routing in Olla#81
Conversation
fix broken tests add proxy specific path testing move target path resolution too & update tests
yaml formatting issue (thanks vscode)
WalkthroughThis pull request introduces a path preservation feature for proxy endpoints, enabling base URL paths to be preserved during request proxying. It adds new OpenAI-compatible profiles, extends configuration types with PreservePath fields, implements centralised URL-building logic, and refactors proxy services to use the new builder. Comprehensive documentation and tests are included. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant ProxyService as Proxy Service<br/>(Olla/Sherpa)
participant URLBuilder as URL Builder<br/>(common.BuildTargetURL)
participant Endpoint as Endpoint<br/>(PreservePath flag)
participant Backend as Backend<br/>Service
Client->>ProxyService: HTTP Request<br/>/prefix/path?query=value
ProxyService->>URLBuilder: BuildTargetURL(request,<br/>endpoint, proxyPrefix)
alt PreservePath = true
URLBuilder->>Endpoint: Check PreservePath flag
Endpoint-->>URLBuilder: true
URLBuilder->>URLBuilder: Join base path<br/>+ request path
Note over URLBuilder: Result: base_path/path?query=value
else PreservePath = false
URLBuilder->>Endpoint: Check PreservePath flag
Endpoint-->>URLBuilder: false
URLBuilder->>URLBuilder: Strip proxy prefix,<br/>clean path,<br/>resolve against base
Note over URLBuilder: Result: /path?query=value
end
URLBuilder-->>ProxyService: Target URL
ProxyService->>Backend: Proxied Request
Backend-->>ProxyService: Response
ProxyService-->>Client: Response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
docs/content/troubleshooting/path-preservation.md (1)
19-23: Consider adding language specifiers to fenced code blocks.Several code blocks lack language identifiers, which would improve syntax highlighting and readability. Consider adding appropriate identifiers (e.g.,
text,plaintext, orconsolefor output examples).Apply these changes:
-``` +```text Endpoint URL: http://localhost:8080/api/v1 Client request: POST /v1/chat/completions Proxied to: http://localhost:8080/v1/chat/completions -``` +```And similarly for the other blocks at lines 31-35, 152-155, and 298-325.
Also applies to: 31-35, 152-155, 298-325
config/profiles/openai-compatible.yaml (1)
1-127: LGTM! Comprehensive OpenAI-compatible profile.The profile configuration is well-structured and covers all necessary aspects: routing, API paths, model patterns, context windows, and metrics extraction. The context patterns comprehensively cover GPT model families.
Minor: Consider adding a trailing newline at the end of the file to follow standard YAML conventions.
internal/adapter/proxy/common/url_builder.go (1)
38-38: Typo in comment."perbent-encoded" should be "percent-encoded".
Apply this diff:
- // Non-preserve mode: guard against traversal, including perbent-encoded dot segments. + // Non-preserve mode: guard against traversal, including percent-encoded dot segments.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
config/profiles/openai-compatible.yaml(1 hunks)config/profiles/openai.yaml(2 hunks)docs/content/configuration/examples.md(1 hunks)docs/content/configuration/reference.md(2 hunks)docs/content/troubleshooting/path-preservation.md(1 hunks)internal/adapter/discovery/repository.go(1 hunks)internal/adapter/proxy/common/url_builder.go(1 hunks)internal/adapter/proxy/common/url_builder_test.go(1 hunks)internal/adapter/proxy/olla/service.go(1 hunks)internal/adapter/proxy/olla/service_preserve_path_test.go(1 hunks)internal/adapter/proxy/olla/service_retry.go(1 hunks)internal/adapter/proxy/sherpa/service_preserve_path_test.go(1 hunks)internal/adapter/proxy/sherpa/service_retry.go(1 hunks)internal/config/types.go(1 hunks)internal/core/domain/endpoint.go(1 hunks)internal/integration/network_integration_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{go,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Australian English in comments and documentation
Files:
docs/content/configuration/reference.mdinternal/integration/network_integration_test.godocs/content/configuration/examples.mdinternal/adapter/proxy/olla/service_retry.gointernal/core/domain/endpoint.gointernal/adapter/proxy/common/url_builder.gointernal/adapter/discovery/repository.gointernal/adapter/proxy/sherpa/service_retry.godocs/content/troubleshooting/path-preservation.mdinternal/adapter/proxy/common/url_builder_test.gointernal/config/types.gointernal/adapter/proxy/olla/service_preserve_path_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: Write comments that explain why decisions are made rather than what the code does
Code must be formatted and linted (run fmt, lint, align) to passmake ready
Files:
internal/integration/network_integration_test.gointernal/adapter/proxy/olla/service_retry.gointernal/core/domain/endpoint.gointernal/adapter/proxy/common/url_builder.gointernal/adapter/discovery/repository.gointernal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/common/url_builder_test.gointernal/config/types.gointernal/adapter/proxy/olla/service_preserve_path_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
internal/integration/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Place integration tests under
internal/integrationas Go test files
Files:
internal/integration/network_integration_test.go
internal/adapter/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place infrastructure implementations (proxies, balancers, registries, translators, etc.) under
internal/adapter
Files:
internal/adapter/proxy/olla/service_retry.gointernal/adapter/proxy/common/url_builder.gointernal/adapter/discovery/repository.gointernal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/common/url_builder_test.gointernal/adapter/proxy/olla/service_preserve_path_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
internal/adapter/proxy/olla/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Implement Olla proxy logic under
internal/adapter/proxy/olla
Files:
internal/adapter/proxy/olla/service_retry.gointernal/adapter/proxy/olla/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
internal/core/**
📄 CodeRabbit inference engine (CLAUDE.md)
Keep domain logic (entities, interfaces, constants) within
internal/coreper Hexagonal Architecture
Files:
internal/core/domain/endpoint.go
internal/adapter/proxy/sherpa/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Implement Sherpa proxy logic under
internal/adapter/proxy/sherpa
Files:
internal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/sherpa/service_preserve_path_test.go
config/profiles/*.yaml
📄 CodeRabbit inference engine (CLAUDE.md)
Store provider-specific profiles as YAML files under
config/profiles/
Files:
config/profiles/openai-compatible.yamlconfig/profiles/openai.yaml
🧠 Learnings (5)
📚 Learning: 2025-10-22T08:11:10.879Z
Learnt from: CR
Repo: thushan/olla PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-22T08:11:10.879Z
Learning: Applies to internal/integration/**/*_test.go : Place integration tests under `internal/integration` as Go test files
Applied to files:
internal/integration/network_integration_test.gointernal/adapter/proxy/common/url_builder_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.go
📚 Learning: 2025-10-22T08:11:10.879Z
Learnt from: CR
Repo: thushan/olla PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-22T08:11:10.879Z
Learning: Applies to internal/adapter/proxy/olla/**/*.go : Implement Olla proxy logic under `internal/adapter/proxy/olla`
Applied to files:
internal/adapter/proxy/olla/service_retry.gointernal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/olla/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
📚 Learning: 2025-10-22T08:11:10.879Z
Learnt from: CR
Repo: thushan/olla PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-22T08:11:10.879Z
Learning: Applies to internal/adapter/proxy/core/**/*.go : Place shared proxy components under `internal/adapter/proxy/core`
Applied to files:
internal/adapter/proxy/olla/service_retry.gointernal/adapter/proxy/common/url_builder.gointernal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/common/url_builder_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
📚 Learning: 2025-10-22T08:11:10.879Z
Learnt from: CR
Repo: thushan/olla PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-22T08:11:10.879Z
Learning: Applies to internal/adapter/proxy/sherpa/**/*.go : Implement Sherpa proxy logic under `internal/adapter/proxy/sherpa`
Applied to files:
internal/adapter/proxy/olla/service_retry.gointernal/adapter/proxy/common/url_builder.gointernal/adapter/proxy/sherpa/service_retry.gointernal/adapter/proxy/common/url_builder_test.gointernal/adapter/proxy/sherpa/service_preserve_path_test.gointernal/adapter/proxy/olla/service.go
📚 Learning: 2025-10-22T08:11:10.879Z
Learnt from: CR
Repo: thushan/olla PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-22T08:11:10.879Z
Learning: Applies to internal/adapter/translator/**/*.go : Put API translation logic (OpenAI ↔ Provider) under `internal/adapter/translator`
Applied to files:
internal/adapter/proxy/common/url_builder_test.go
🧬 Code graph analysis (7)
internal/adapter/proxy/olla/service_retry.go (1)
internal/adapter/proxy/common/url_builder.go (1)
BuildTargetURL(20-63)
internal/adapter/proxy/common/url_builder.go (2)
internal/core/domain/endpoint.go (1)
Endpoint(19-40)internal/util/request.go (1)
StripPrefix(74-83)
internal/adapter/proxy/sherpa/service_retry.go (1)
internal/adapter/proxy/common/url_builder.go (1)
BuildTargetURL(20-63)
internal/adapter/proxy/common/url_builder_test.go (2)
internal/core/domain/endpoint.go (1)
Endpoint(19-40)internal/adapter/proxy/common/url_builder.go (1)
BuildTargetURL(20-63)
internal/adapter/proxy/olla/service_preserve_path_test.go (3)
internal/core/domain/endpoint.go (1)
Endpoint(19-40)internal/adapter/proxy/olla/service.go (1)
Service(65-85)internal/adapter/proxy/config/unified.go (2)
OllaConfig(117-124)BaseProxyConfig(43-51)
internal/adapter/proxy/sherpa/service_preserve_path_test.go (6)
internal/core/domain/endpoint.go (1)
Endpoint(19-40)internal/core/ports/proxy.go (1)
RequestStats(46-69)internal/adapter/proxy/olla/service.go (1)
Service(65-85)internal/adapter/proxy/core/base.go (2)
NewBaseProxyComponents(63-78)BaseProxyComponents(48-60)pkg/pool/lite_pool.go (1)
NewLitePool(44-68)internal/adapter/proxy/core/retry.go (1)
NewRetryHandler(28-33)
internal/adapter/proxy/olla/service.go (1)
internal/adapter/proxy/common/url_builder.go (1)
BuildTargetURL(20-63)
🪛 LanguageTool
docs/content/troubleshooting/path-preservation.md
[duplication] ~144-~144: Possible typo: you repeated a word.
Context: ...sts fail when endpoint is behind an API gateway - Gateway returns routing errors - Direct endpoin...
(ENGLISH_WORD_REPEAT_RULE)
🪛 markdownlint-cli2 (0.18.1)
docs/content/troubleshooting/path-preservation.md
19-19: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
152-152: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
298-298: 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). (2)
- GitHub Check: test (1.24)
- GitHub Check: Cross-Platform Build Validation (windows-latest)
🔇 Additional comments (16)
internal/integration/network_integration_test.go (1)
1-1: LGTM! Package declaration now aligns with directory structure.The package name now correctly matches the
internal/integrationdirectory path, following Go conventions.config/profiles/openai.yaml (2)
1-5: LGTM! Profile metadata clarifies intent.The renaming from
openai-compatibletoopenaiand the updated display name/description better reflect that this is the default OpenAI profile. The comments appropriately reference the separateopenai-compatible.yamlfor alternative routing.Also applies to: 11-12
52-69: LGTM! Future-proof model context patterns added.The expanded context patterns for GPT-5, GPT-4.1, and GPT-4o families provide forward compatibility. The context window sizes appear reasonable based on the model family tiers (thinking variant at 400K, GPT-4.1 up to 1M tokens).
internal/core/domain/endpoint.go (1)
39-39: LGTM! PreservePath field added to domain model.The new boolean field correctly extends the Endpoint entity to support path preservation behaviour. Public visibility is appropriate for a domain field that's propagated from configuration and used by proxy services.
internal/adapter/proxy/sherpa/service_retry.go (1)
59-59: LGTM! Centralised URL construction improves consistency.Delegating target URL construction to
common.BuildTargetURLeliminates code duplication and ensures path preservation behaviour is handled consistently across proxy implementations. The refactor respects the endpoint's PreservePath configuration.internal/config/types.go (1)
110-110: LGTM! Configuration field properly defined.The PreservePath field is correctly added with appropriate YAML tag
preserve_path. The boolean type with zero-value default (false) matches the documented default behaviour, ensuring backward compatibility.docs/content/configuration/reference.md (2)
240-240: LGTM! Feature thoroughly documented.The
preserve_pathfield is well-documented with clear explanation of default vs path-preserving behaviour. The use cases (Docker Model Runner, API gateways, path-based routing) provide practical guidance for when to enable this feature.Also applies to: 256-280
287-297: LGTM! Examples demonstrate feature usage clearly.The example configuration shows both use cases: Docker Model Runner with
preserve_path: trueand standard endpoint withpreserve_path: false(default). The inline comments explain the reasoning, making it easy for users to understand when to use each setting.internal/adapter/proxy/olla/service.go (1)
462-464: LGTM! Refactor delegates to shared URL builder.The buildTargetURL method now delegates to
common.BuildTargetURL, eliminating code duplication whilst maintaining encapsulation. This ensures consistent path preservation behaviour across Olla and Sherpa proxy implementations.internal/adapter/proxy/olla/service_retry.go (1)
67-68: LGTM! Centralised URL building logic.The refactor to use
common.BuildTargetURLproperly centralises the URL construction logic and respects thepreserve_pathconfiguration. The comment clearly explains the intent.docs/content/configuration/examples.md (1)
350-446: LGTM! Comprehensive documentation for path preservation.The examples clearly demonstrate the
preserve_pathfeature across realistic scenarios (Docker Model Runner, API gateways, microservices). The structure aligns well with existing documentation patterns.internal/adapter/discovery/repository.go (1)
178-178: LGTM! Proper field propagation.The
PreservePathfield is correctly propagated from configuration to the endpoint instance, consistent with other field assignments.internal/adapter/proxy/common/url_builder_test.go (1)
1-764: LGTM! Excellent test coverage.This comprehensive test suite properly validates the URL building logic across multiple dimensions:
- Backward compatibility with existing behavior
- Path preservation modes
- Edge cases (double slashes, path traversal, encoding)
- Query string handling
- Real-world provider configurations
- Performance benchmarks
The tests are well-structured, use parallel execution, and cover security concerns.
internal/adapter/proxy/olla/service_preserve_path_test.go (1)
1-739: LGTM! Comprehensive service-level tests.The test suite properly validates the Olla service's URL building behavior, complementing the lower-level
url_buildertests. Good coverage of preserve_path modes, edge cases, and real-world provider scenarios.internal/adapter/proxy/sherpa/service_preserve_path_test.go (1)
1-690: LGTM! Excellent integration tests.The test suite validates Sherpa's path preservation through end-to-end HTTP proxying using a mock backend server. This approach effectively verifies that the URL building logic works correctly in the full proxy flow. The helper functions and mock implementations are clean and appropriate.
internal/adapter/proxy/common/url_builder.go (1)
20-87: LGTM! Well-designed URL building logic.The implementation properly handles:
- Path preservation mode with correct joining of base and request paths
- Security: Guards against path traversal (including encoded variants)
- Performance: Optimizes common cases with fast paths
- Query parameter preservation across all modes
The helper functions are efficient and the overall logic is sound.
This PR addresses a few things that was raised in #80 around the use of Docker Model Runner and Olla.
This PR adds
preserve_pathto the endpoint config so we can map cleanly (and also support existing endpoints).Summary by CodeRabbit
Release Notes
New Features
Documentation