Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bb996dc
feat(instinct#12): add FC discovery type (petersimmons1972/instinct#1…
petersimmons1972 May 22, 2026
85c1cd4
fix(olla): honor endpoint circuit breaker config
May 23, 2026
3aa0f2b
Merge pull request #5 from petersimmons1972/codex/issue-2-circuit-bre…
petersimmons1972 May 23, 2026
012e5e3
test(olla): cover breaker config override wiring
May 23, 2026
801b0a8
feat(olla): expose breaker state in endpoint status
May 23, 2026
db9a963
feat(olla): enforce allowed model aliases
May 23, 2026
0521432
Merge pull request #8 from petersimmons1972/codex/issue-2-breaker-con…
petersimmons1972 May 23, 2026
4743408
Merge pull request #9 from petersimmons1972/codex/issue-3-breaker-sta…
petersimmons1972 May 23, 2026
8306f92
Merge pull request #11 from petersimmons1972/codex/issue-4-allowed-mo…
petersimmons1972 May 23, 2026
52c0a2b
fix(unifier): infer BGE embedding capability (#14)
petersimmons1972 May 26, 2026
1f58b14
fix(status): flag degraded endpoints by success rate (#15)
petersimmons1972 May 26, 2026
c2a0f27
Expose circuit breaker and discovery status fixes (#16)
petersimmons1972 May 26, 2026
9f406ae
feat(instinct#12): add FC discovery type (petersimmons1972/instinct#1…
petersimmons1972 May 22, 2026
74b7efa
fix(olla): honor endpoint circuit breaker config
May 23, 2026
6002a49
test(olla): cover breaker config override wiring
May 23, 2026
d1c23fe
feat(olla): expose breaker state in endpoint status
May 23, 2026
6b4ec48
feat(olla): enforce allowed model aliases
May 23, 2026
1e306f6
fix(unifier): infer BGE embedding capability (#14)
petersimmons1972 May 26, 2026
7000ce5
fix(status): flag degraded endpoints by success rate (#15)
petersimmons1972 May 26, 2026
91edb9c
Expose circuit breaker and discovery status fixes (#16)
petersimmons1972 May 26, 2026
978084c
Merge pull request #25 from petersimmons1972/integration/upstream-mai…
petersimmons1972 May 26, 2026
a8ee1f0
Fix model config and discovery defaults
May 26, 2026
1416386
Merge pull request #26 from petersimmons1972/codex/p1-model-path
petersimmons1972 May 26, 2026
3e00838
fix: harden Olla model routing defaults
May 26, 2026
2307e34
docs: align OLLA env overrides documentation and add unsupported env …
Jun 5, 2026
babe871
fix(handlers): fail closed provider scoped routes (Closes #84)
Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions config/config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Olla Configuration (default)

server:
host: "localhost" # Use 0.0.0.0 to bind to all interfaces (so it's accessible externally)
port: 40114 # default port for Olla - 4-OLLA
Expand Down Expand Up @@ -106,13 +107,14 @@ discovery:
check_interval: 2s
check_timeout: 1s
- url: "http://localhost:8000"
name: "local-vllm"
name: "oblivion-gb10-vllm"
type: "vllm"
priority: 100
model_url: "/v1/models"
health_check_url: "/health"
check_interval: 5s
check_timeout: 2s
circuit_breaker_timeout: 2000s
model_discovery:
enabled: true
interval: 5m
Expand Down Expand Up @@ -140,7 +142,7 @@ model_registry:

# Discovery mode settings
discovery_timeout: 2s # Timeout for discovery refresh
discovery_refresh_on_miss: false # Refresh discovery when model not found
discovery_refresh_on_miss: true # Refresh discovery when model not found

translators:
#####
Expand Down Expand Up @@ -168,6 +170,8 @@ logging:

engineering:
show_nerdstats: false
endpoint_degraded_success_rate_threshold: 80.0
endpoint_degraded_minimum_requests: 10

# Model aliases allow mapping a single virtual model name to multiple actual model names
# across different backends. When a request arrives with an alias, olla finds endpoints
Expand Down
8 changes: 7 additions & 1 deletion config/models.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ capabilities:
- multimodal
- image-understanding

- pattern: "(^|[/_-])(bge|e5|gte|minilm|jina-embeddings?|nomic-embed|mxbai-embed|text-embedding)"
capabilities:
- embeddings
- similarity
- vector-search

# Context length categories (in tokens)
context_thresholds:
extended_context: 32000
Expand All @@ -213,4 +219,4 @@ special_rules:
- unknown
- test
- temp
- default
- default
41 changes: 34 additions & 7 deletions docs/content/configuration/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,16 @@ Debug and development features.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `show_nerdstats` | bool | `false` | Show memory stats on shutdown |
| `endpoint_degraded_success_rate_threshold` | float | `80.0` | Mark endpoints degraded when request success rate drops below this percentage |
| `endpoint_degraded_minimum_requests` | integer | `10` | Minimum endpoint request count before low success rate degradation is reported |

Example:

```yaml
engineering:
show_nerdstats: true
endpoint_degraded_success_rate_threshold: 80.0
endpoint_degraded_minimum_requests: 10
```

When enabled, displays:
Expand All @@ -731,31 +735,54 @@ When enabled, displays:

## Environment Variables

All configuration can be overridden via environment variables.

Pattern: `OLLA_<SECTION>_<KEY>` in uppercase with underscores.
Supported environment variables are listed below.

Examples:

```bash
# Server settings
OLLA_SERVER_HOST=0.0.0.0
OLLA_SERVER_PORT=8080
OLLA_SERVER_REQUEST_LOGGING=true
OLLA_SERVER_READ_TIMEOUT=45s
OLLA_SERVER_WRITE_TIMEOUT=30s
OLLA_SERVER_MAX_BODY_SIZE=25MB
OLLA_SERVER_MAX_HEADER_SIZE=2MB
OLLA_SERVER_GLOBAL_RATE_LIMIT=1000
OLLA_SERVER_PER_IP_RATE_LIMIT=100
OLLA_SERVER_RATE_BURST_SIZE=50
OLLA_SERVER_HEALTH_RATE_LIMIT=1000
OLLA_SERVER_RATE_CLEANUP_INTERVAL=5m
OLLA_SERVER_TRUST_PROXY_HEADERS=true
OLLA_SERVER_TRUSTED_PROXY_CIDRS=127.0.0.0/8,10.0.0.0/8

# Proxy settings
OLLA_PROXY_ENGINE=olla
OLLA_PROXY_LOAD_BALANCER=round-robin
OLLA_PROXY_PROFILE=auto
OLLA_PROXY_RESPONSE_TIMEOUT=600s
OLLA_PROXY_READ_TIMEOUT=120s
OLLA_PROXY_STICKY_SESSIONS_ENABLED=true

# Logging
OLLA_LOGGING_LEVEL=debug
OLLA_LOGGING_FORMAT=text

# Rate limits
OLLA_SERVER_RATE_LIMITS_GLOBAL_REQUESTS_PER_MINUTE=1000
# Model registry / translators / engine
OLLA_MODEL_REGISTRY_TYPE=memory
OLLA_MODEL_UNIFIER_ENABLED=true
OLLA_MODEL_UNIFIER_CACHE_TTL=10m
OLLA_TRANSLATORS_ANTHROPIC_ENABLED=true
OLLA_TRANSLATORS_ANTHROPIC_MAX_MESSAGE_SIZE=10485760
OLLA_TRANSLATORS_ANTHROPIC_PASSTHROUGH_ENABLED=true

# Operational
OLLA_SHOW_NERD_STATS=true
OLLA_CONFIG_FILE=config/config.yaml
```

Deprecated or unsupported variables shown in older docs (for example, `OLLA_LOG_LEVEL`, `OLLA_SERVER_REQUEST_LOGGING`,
and `OLLA_SERVER_RATE_LIMITS_*`) are intentionally unsupported by the current env override path and must not be used.

## Duration Format

Duration values use Go duration syntax:
Expand Down Expand Up @@ -885,4 +912,4 @@ Additionally, Olla's `Validate()` method catches dangerous zero or empty configu

- [Configuration Examples](examples.md) - Common configurations
- [Best Practices](practices/overview.md) - Production recommendations
- [Environment Variables](#environment-variables) - Override configuration
- [Environment Variables](#environment-variables) - Override configuration
138 changes: 138 additions & 0 deletions internal/adapter/discovery/fc_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package discovery

import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/thushan/olla/internal/config"
"github.com/thushan/olla/internal/logger"
)

// fcModelSpec mirrors the Flight Controller ModelSpec fields we care about for
// building Olla endpoint configs. Only Name and Port are required for routing.
type fcModelSpec struct {
Name string `json:"name"`
Port int `json:"port"`
Framework string `json:"framework"`
}

// fcRegistryEntry mirrors the Flight Controller RegistryEntry type returned by
// GET /registry. We only parse the fields Olla needs; extra fields are ignored.
type fcRegistryEntry struct {
Host string `json:"host"`
Models []fcModelSpec `json:"models"`
}

// FCDiscoveryPoller polls the Flight Controller /registry endpoint and reconciles
// the StaticEndpointRepository on each poll. A full replace-on-poll strategy ensures
// that endpoints removed from the FC registry are promptly evicted from Olla's rotation,
// meeting the <30s convergence acceptance criterion for petersimmons1972/instinct#12.
type FCDiscoveryPoller struct {
repo *StaticEndpointRepository
registryURL string
logger logger.StyledLogger
client *http.Client
}

// NewFCDiscoveryPoller creates a poller that syncs Olla endpoints from FC /registry.
// registryBaseURL is the FC service base URL, e.g. http://ai-fleet-controller.ai-fleet.svc.cluster.local.
func NewFCDiscoveryPoller(repo *StaticEndpointRepository, registryBaseURL string, log logger.StyledLogger) *FCDiscoveryPoller {
return &FCDiscoveryPoller{
repo: repo,
registryURL: registryBaseURL + "/registry",
logger: log,
client: &http.Client{
Timeout: 10 * time.Second,
},
}
}

// Poll fetches the FC registry and reconciles Olla's endpoint set.
// On FC unreachable: logs a warning, preserves the current endpoint set (fail-open).
// On success: fully replaces the endpoint set with the FC-derived list.
func (p *FCDiscoveryPoller) Poll(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.registryURL, nil)
if err != nil {
return fmt.Errorf("fc-discovery: build request: %w", err)
}

resp, err := p.client.Do(req)
if err != nil {
// Fail-open: preserve the existing endpoint set when FC is unreachable.
p.logger.Warn("fc-discovery: FC registry unreachable, preserving existing endpoints", "url", p.registryURL, "error", err)
return nil
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
p.logger.Warn("fc-discovery: FC registry returned non-200, preserving existing endpoints",
"url", p.registryURL, "status", resp.StatusCode)
return nil
}

var entries []fcRegistryEntry
if err := json.NewDecoder(resp.Body).Decode(&entries); err != nil {
return fmt.Errorf("fc-discovery: decode registry response: %w", err)
}

configs := fcEntriesToEndpointConfigs(entries)
if err := p.repo.LoadFromConfig(ctx, configs); err != nil {
return fmt.Errorf("fc-discovery: load endpoint configs: %w", err)
}

p.logger.Info("fc-discovery: endpoint set reconciled from FC registry",
"endpoints", len(configs))
return nil
}

// RunLoop starts a background polling loop. It polls immediately on first call, then
// at the configured interval. The loop exits when ctx is cancelled.
func (p *FCDiscoveryPoller) RunLoop(ctx context.Context, interval time.Duration) {
// Immediate first poll so Olla is populated before the ticker fires.
if err := p.Poll(ctx); err != nil {
p.logger.Warn("fc-discovery: initial poll error", "error", err)
}

ticker := time.NewTicker(interval)
defer ticker.Stop()

for {
select {
case <-ctx.Done():
p.logger.Info("fc-discovery: loop stopped")
return
case <-ticker.C:
if err := p.Poll(ctx); err != nil {
p.logger.Warn("fc-discovery: poll error", "error", err)
}
}
}
}

// fcEntriesToEndpointConfigs converts FC registry entries into Olla EndpointConfig slices.
// Each (host, model) pair becomes one endpoint at http://<host>:<port>.
// Type is always "openai" because all FC-managed containers serve the OpenAI-compatible API.
// Priority defaults to 100 (standard Olla default).
func fcEntriesToEndpointConfigs(entries []fcRegistryEntry) []config.EndpointConfig {
defaultPriority := 100
var configs []config.EndpointConfig

for _, entry := range entries {
for _, model := range entry.Models {
if model.Port == 0 {
continue // skip models without a port (incomplete CRD)
}
cfg := config.EndpointConfig{
URL: fmt.Sprintf("http://%s:%d", entry.Host, model.Port),
Name: fmt.Sprintf("%s-%s", entry.Host, model.Name),
Type: "openai",
Priority: &defaultPriority,
}
configs = append(configs, cfg)
}
}
return configs
}
Loading