llm.Parse(spec) resolves model strings into ready-to-use *Model objects in one call. Supports "openai/gpt-4o", "openai/gpt-4o:high" (with reasoning suffix), Ollama-style tags like "ollama/qwen3:30b", static aliases, dynamic resolvers, and named targets via LLM_X env var DSNs.
Extensible Registry type with RegisterProvider, RegisterAlias, and RegisterResolver methods. A DefaultRegistry is pre-populated with all built-in providers (including the new foreman entry). Package-level convenience functions delegate to DefaultRegistry.
Foreman constructor for targeting foreman daemons (private authenticated Ollama endpoints with queuing/observability).
LLM_X DSN env vars enable named multi-instance targets without code changes: LLM_M5=foreman://token@host lets callers write llm.Parse("m5/qwen3:30b").
Spec format
spec = alias | provider "/" model | envname "/" model
alias = registered name (e.g., "fast", "thinking")
provider = registered provider (e.g., "openai", "foreman")
envname = name resolved via LLM_{UPPER(name)} env var DSN
model = everything after the first "/"
Optional ":low"/":medium"/":high" reasoning suffix on any spec.
Ollama tags like ":30b" are preserved (not consumed as reasoning).
mort migration (registering tier aliases as resolvers, lane-wrapped factories via RegisterProvider) is a separate PR.
Test plan
go build ./... passes
go vet ./... clean
go test -race -count=1 ./... all pass (18 new test cases in parse_test.go)
go mod tidy + no diff on go.mod/go.sum
Backward compat: Providers() and ProviderByName() still work, now include foreman
## Summary
- **`llm.Parse(spec)`** resolves model strings into ready-to-use `*Model` objects in one call. Supports `"openai/gpt-4o"`, `"openai/gpt-4o:high"` (with reasoning suffix), Ollama-style tags like `"ollama/qwen3:30b"`, static aliases, dynamic resolvers, and named targets via `LLM_X` env var DSNs.
- **Extensible `Registry`** type with `RegisterProvider`, `RegisterAlias`, and `RegisterResolver` methods. A `DefaultRegistry` is pre-populated with all built-in providers (including the new `foreman` entry). Package-level convenience functions delegate to `DefaultRegistry`.
- **`Foreman` constructor** for targeting foreman daemons (private authenticated Ollama endpoints with queuing/observability).
- **`LLM_X` DSN env vars** enable named multi-instance targets without code changes: `LLM_M5=foreman://token@host` lets callers write `llm.Parse("m5/qwen3:30b")`.
## Spec format
```
spec = alias | provider "/" model | envname "/" model
alias = registered name (e.g., "fast", "thinking")
provider = registered provider (e.g., "openai", "foreman")
envname = name resolved via LLM_{UPPER(name)} env var DSN
model = everything after the first "/"
Optional ":low"/":medium"/":high" reasoning suffix on any spec.
Ollama tags like ":30b" are preserved (not consumed as reasoning).
```
## DSN format (for `LLM_X` env vars)
```
scheme://[token@]host[/path]
```
Examples:
- `LLM_M5=foreman://[email protected]`
- `LLM_LOCAL=ollama://localhost:11434`
## Extension points
| Method | Purpose |
|---|---|
| `RegisterProvider(info)` | Add or replace a provider factory |
| `RegisterAlias(name, spec)` | Static alias ("fast" -> "openai/gpt-4o-mini") |
| `RegisterResolver(res)` | Dynamic resolver (DB-backed tiers, remote config) |
## Follow-up
mort migration (registering tier aliases as resolvers, lane-wrapped factories via RegisterProvider) is a separate PR.
## Test plan
- [x] `go build ./...` passes
- [x] `go vet ./...` clean
- [x] `go test -race -count=1 ./...` all pass (18 new test cases in parse_test.go)
- [x] `go mod tidy` + no diff on go.mod/go.sum
- [x] Backward compat: `Providers()` and `ProviderByName()` still work, now include foreman
Introduces llm.Parse(spec) backed by an extensible Registry that resolves
model strings like "openai/gpt-4o", aliases like "fast", and named targets
like "m5/qwen3:30b" (via LLM_M5 env var DSNs) into ready-to-use *Model
objects. Extension points: RegisterProvider, RegisterAlias, RegisterResolver.
Adds Foreman constructor and sentinel errors ErrAliasLoop, ErrUnknownProvider,
ErrInvalidDSN.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The previous CI fix commits stored the workflow file as a literal base64
string instead of decoded YAML, so Gitea could not parse it as a valid
workflow and no CI runs triggered. This writes the correct YAML content.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
llm.Parse(spec)resolves model strings into ready-to-use*Modelobjects in one call. Supports"openai/gpt-4o","openai/gpt-4o:high"(with reasoning suffix), Ollama-style tags like"ollama/qwen3:30b", static aliases, dynamic resolvers, and named targets viaLLM_Xenv var DSNs.Registrytype withRegisterProvider,RegisterAlias, andRegisterResolvermethods. ADefaultRegistryis pre-populated with all built-in providers (including the newforemanentry). Package-level convenience functions delegate toDefaultRegistry.Foremanconstructor for targeting foreman daemons (private authenticated Ollama endpoints with queuing/observability).LLM_XDSN env vars enable named multi-instance targets without code changes:LLM_M5=foreman://token@hostlets callers writellm.Parse("m5/qwen3:30b").Spec format
DSN format (for
LLM_Xenv vars)Examples:
LLM_M5=foreman://[email protected]LLM_LOCAL=ollama://localhost:11434Extension points
RegisterProvider(info)RegisterAlias(name, spec)RegisterResolver(res)Follow-up
mort migration (registering tier aliases as resolvers, lane-wrapped factories via RegisterProvider) is a separate PR.
Test plan
go build ./...passesgo vet ./...cleango test -race -count=1 ./...all pass (18 new test cases in parse_test.go)go mod tidy+ no diff on go.mod/go.sumProviders()andProviderByName()still work, now include foreman