Update readme & use provided logging package
This commit is contained in:
parent
a2524a1d05
commit
12a98d6940
2 changed files with 54 additions and 9 deletions
30
README.md
30
README.md
|
|
@ -100,6 +100,7 @@ You can configure OpenCode using environment variables:
|
||||||
| `AZURE_OPENAI_ENDPOINT` | For Azure OpenAI models |
|
| `AZURE_OPENAI_ENDPOINT` | For Azure OpenAI models |
|
||||||
| `AZURE_OPENAI_API_KEY` | For Azure OpenAI models (optional when using Entra ID) |
|
| `AZURE_OPENAI_API_KEY` | For Azure OpenAI models (optional when using Entra ID) |
|
||||||
| `AZURE_OPENAI_API_VERSION` | For Azure OpenAI models |
|
| `AZURE_OPENAI_API_VERSION` | For Azure OpenAI models |
|
||||||
|
| `LOCAL_ENDPOINT` | For self-hosted models |
|
||||||
| `SHELL` | Default shell to use (if not specified in config) |
|
| `SHELL` | Default shell to use (if not specified in config) |
|
||||||
|
|
||||||
### Shell Configuration
|
### Shell Configuration
|
||||||
|
|
@ -566,6 +567,35 @@ The AI assistant can access LSP features through the `diagnostics` tool, allowin
|
||||||
|
|
||||||
While the LSP client implementation supports the full LSP protocol (including completions, hover, definition, etc.), currently only diagnostics are exposed to the AI assistant.
|
While the LSP client implementation supports the full LSP protocol (including completions, hover, definition, etc.), currently only diagnostics are exposed to the AI assistant.
|
||||||
|
|
||||||
|
## Using a self-hosted model provider
|
||||||
|
|
||||||
|
OpenCode can also load and use models from a self-hosted (OpenAI-like) provider.
|
||||||
|
This is useful for developers who want to experiment with custom models.
|
||||||
|
|
||||||
|
### Configuring a self-hosted provider
|
||||||
|
|
||||||
|
You can use a self-hosted model by setting the `LOCAL_ENDPOINT` environment variable.
|
||||||
|
This will cause OpenCode to load and use the models from the specified endpoint.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LOCAL_ENDPOINT=http://localhost:1235/v1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring a self-hosted model
|
||||||
|
|
||||||
|
You can also configure a self-hosted model in the configuration file under the `agents` section:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"agents": {
|
||||||
|
"coder": {
|
||||||
|
"model": "local.granite-3.3-2b-instruct@q8_0",
|
||||||
|
"reasoningEffort": "high"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package models
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -11,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/opencode-ai/opencode/internal/logging"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ func init() {
|
||||||
if endpoint := os.Getenv("LOCAL_ENDPOINT"); endpoint != "" {
|
if endpoint := os.Getenv("LOCAL_ENDPOINT"); endpoint != "" {
|
||||||
localEndpoint, err := url.Parse(endpoint)
|
localEndpoint, err := url.Parse(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Debug("Failed to parse local endpoint",
|
logging.Debug("Failed to parse local endpoint",
|
||||||
"error", err,
|
"error", err,
|
||||||
"endpoint", endpoint,
|
"endpoint", endpoint,
|
||||||
)
|
)
|
||||||
|
|
@ -44,7 +44,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(models) == 0 {
|
if len(models) == 0 {
|
||||||
slog.Debug("No local models found",
|
logging.Debug("No local models found",
|
||||||
"endpoint", endpoint,
|
"endpoint", endpoint,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
@ -77,7 +77,7 @@ type localModel struct {
|
||||||
func listLocalModels(modelsEndpoint string) []localModel {
|
func listLocalModels(modelsEndpoint string) []localModel {
|
||||||
res, err := http.Get(modelsEndpoint)
|
res, err := http.Get(modelsEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Debug("Failed to list local models",
|
logging.Debug("Failed to list local models",
|
||||||
"error", err,
|
"error", err,
|
||||||
"endpoint", modelsEndpoint,
|
"endpoint", modelsEndpoint,
|
||||||
)
|
)
|
||||||
|
|
@ -85,7 +85,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
slog.Debug("Failed to list local models",
|
logging.Debug("Failed to list local models",
|
||||||
"status", res.StatusCode,
|
"status", res.StatusCode,
|
||||||
"endpoint", modelsEndpoint,
|
"endpoint", modelsEndpoint,
|
||||||
)
|
)
|
||||||
|
|
@ -93,7 +93,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
|
||||||
|
|
||||||
var modelList localModelList
|
var modelList localModelList
|
||||||
if err = json.NewDecoder(res.Body).Decode(&modelList); err != nil {
|
if err = json.NewDecoder(res.Body).Decode(&modelList); err != nil {
|
||||||
slog.Debug("Failed to list local models",
|
logging.Debug("Failed to list local models",
|
||||||
"error", err,
|
"error", err,
|
||||||
"endpoint", modelsEndpoint,
|
"endpoint", modelsEndpoint,
|
||||||
)
|
)
|
||||||
|
|
@ -103,7 +103,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
|
||||||
for _, model := range modelList.Data {
|
for _, model := range modelList.Data {
|
||||||
if strings.HasSuffix(modelsEndpoint, lmStudioBetaModelsPath) {
|
if strings.HasSuffix(modelsEndpoint, lmStudioBetaModelsPath) {
|
||||||
if model.Object != "model" || model.Type != "llm" {
|
if model.Object != "model" || model.Type != "llm" {
|
||||||
slog.Debug("Skipping unsupported LMStudio model",
|
logging.Debug("Skipping unsupported LMStudio model",
|
||||||
"endpoint", modelsEndpoint,
|
"endpoint", modelsEndpoint,
|
||||||
"id", model.ID,
|
"id", model.ID,
|
||||||
"object", model.Object,
|
"object", model.Object,
|
||||||
|
|
@ -125,7 +125,7 @@ func loadLocalModels(models []localModel) {
|
||||||
model := convertLocalModel(m)
|
model := convertLocalModel(m)
|
||||||
SupportedModels[model.ID] = model
|
SupportedModels[model.ID] = model
|
||||||
|
|
||||||
if i == 1 || m.State == "loaded" {
|
if i == 0 || m.State == "loaded" {
|
||||||
viper.SetDefault("agents.coder.model", model.ID)
|
viper.SetDefault("agents.coder.model", model.ID)
|
||||||
viper.SetDefault("agents.summarizer.model", model.ID)
|
viper.SetDefault("agents.summarizer.model", model.ID)
|
||||||
viper.SetDefault("agents.task.model", model.ID)
|
viper.SetDefault("agents.task.model", model.ID)
|
||||||
|
|
@ -150,7 +150,19 @@ func convertLocalModel(model localModel) Model {
|
||||||
var modelInfoRegex = regexp.MustCompile(`(?i)^([a-z0-9]+)(?:[-_]?([rv]?\d[\.\d]*))?(?:[-_]?([a-z]+))?.*`)
|
var modelInfoRegex = regexp.MustCompile(`(?i)^([a-z0-9]+)(?:[-_]?([rv]?\d[\.\d]*))?(?:[-_]?([a-z]+))?.*`)
|
||||||
|
|
||||||
func friendlyModelName(modelID string) string {
|
func friendlyModelName(modelID string) string {
|
||||||
match := modelInfoRegex.FindStringSubmatch(modelID)
|
mainID := modelID
|
||||||
|
tag := ""
|
||||||
|
|
||||||
|
if slash := strings.LastIndex(mainID, "/"); slash != -1 {
|
||||||
|
mainID = mainID[slash+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if at := strings.Index(modelID, "@"); at != -1 {
|
||||||
|
mainID = modelID[:at]
|
||||||
|
tag = modelID[at+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
match := modelInfoRegex.FindStringSubmatch(mainID)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
return modelID
|
return modelID
|
||||||
}
|
}
|
||||||
|
|
@ -186,6 +198,9 @@ func friendlyModelName(modelID string) string {
|
||||||
if label != "" {
|
if label != "" {
|
||||||
parts = append(parts, label)
|
parts = append(parts, label)
|
||||||
}
|
}
|
||||||
|
if tag != "" {
|
||||||
|
parts = append(parts, tag)
|
||||||
|
}
|
||||||
|
|
||||||
return strings.Join(parts, " ")
|
return strings.Join(parts, " ")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue