Skip to content

bearaujus/blmstudio

Repository files navigation

blmstudio

Go Reference Go Report Card License

A Go client for LM Studio's local server — chat, stream, embed, and manage AI models running on your own machine. Fully compatible with any OpenAI-format endpoint too.


Quick start

package main

import (
    "context"
    "fmt"

    "github.com/bearaujus/blmstudio"
)

func main() {
    client := blmstudio.New() // connects to http://localhost:1234 by default

    resp, err := client.ChatCompletions(context.Background(), &blmstudio.ChatCompletionRequest{
        Model: "lmstudio-community/meta-llama-3-8b-instruct",
        Messages: []blmstudio.Message{
            {Role: blmstudio.RoleUser, Content: "Hello, world!"},
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.Choices[0].Message.Content)
}

Examples

Ready-to-run examples are in the examples/ folder.

Example What it shows
examples/chat Single-turn chat (non-streaming)
examples/streaming Token-by-token streaming chat
examples/embed Batch embeddings + cosine similarity

Every example reads provider config from environment variables so you can switch between LM Studio, OpenAI, or any compatible endpoint without touching code:

# 🏠 LM Studio (local) — default, no env vars needed
LM_MODEL=lmstudio-community/meta-llama-3-8b-instruct go run examples/chat/main.go

# ☁️  OpenAI
LM_BASE_URL=https://api.openai.com LM_API_KEY=sk-... LM_MODEL=gpt-4o-mini go run examples/chat/main.go

# 🔀 Streaming
LM_MODEL=lmstudio-community/meta-llama-3-8b-instruct go run examples/streaming/main.go

# 🔢 Embeddings
LM_EMBED_MODEL=nomic-ai/nomic-embed-text-v1.5 go run examples/embed/main.go

Installation

go get github.com/bearaujus/blmstudio

Requires Go 1.21+. No C dependencies. No external runtime packages.


Configuration

All options are set at construction time via functional options:

client := blmstudio.New(
    blmstudio.WithBaseURL("http://localhost:1234"), // default
    blmstudio.WithAPIToken("your-api-key"),         // optional
    blmstudio.WithTimeout(2*time.Minute),           // default: 5 min
)
Option Default Description
WithBaseURL(url) http://localhost:1234 Server base URL. Trailing slashes stripped.
WithAPIToken(token) "" (no auth) Sets Authorization: Bearer <token>.
WithHTTPClient(hc) built-in Supply your own *http.Client (proxies, TLS, etc.).
WithTimeout(d) 5 * time.Minute Overrides the HTTP timeout.

API reference

Client

func New(opts ...Option) Client

Returns a thread-safe Client. Create once and share across goroutines.


Native chat — /api/v1/chat

Chat(ctx, *ChatRequest) (*ChatResponse, error)
ChatStream(ctx, *ChatRequest) (*StreamReader[ChatStreamEvent], error)

OpenAI chat completions — /v1/chat/completions

ChatCompletions(ctx, *ChatCompletionRequest) (*ChatCompletionResponse, error)
ChatCompletionsStream(ctx, *ChatCompletionRequest) (*StreamReader[ChatCompletionChunk], error)

Supports: Model, Messages, Temperature, TopP, MaxTokens, Tools, ToolChoice, ResponseFormat, Stop, N, FrequencyPenalty, PresencePenalty.


Text completions (legacy) — /v1/completions

TextCompletions(ctx, *TextCompletionRequest) (*TextCompletionResponse, error)
TextCompletionsStream(ctx, *TextCompletionRequest) (*StreamReader[TextCompletionChunk], error)

Embeddings — /v1/embeddings

Embed(ctx, *EmbeddingRequest) (*EmbeddingResponse, error)
// Single string
req := &blmstudio.EmbeddingRequest{
    Model: "nomic-ai/nomic-embed-text-v1.5",
    Input: blmstudio.NewEmbeddingStringInput("hello"),
}

// Batch
req := &blmstudio.EmbeddingRequest{
    Model: "nomic-ai/nomic-embed-text-v1.5",
    Input: blmstudio.NewEmbeddingStringsInput([]string{"hello", "world"}),
}

resp, _ := client.Embed(ctx, req)
fmt.Printf("%d-dim vector\n", len(resp.Data[0].Embedding))

Model management — /api/v1/models

ListModels(ctx) (*ListModelsResponse, error)
IsModelRunning(ctx, model string) error            // nil = running
LoadModel(ctx, *LoadModelRequest) (*LoadModelResponse, error)
UnloadModel(ctx, instanceID string) (*UnloadModelResponse, error)
DownloadModel(ctx, model string) (*DownloadModelResponse, error)
GetDownloadStatus(ctx, jobID string) (*DownloadStatusResponse, error)
ListOpenAIModels(ctx) (*OpenAIListModelsResponse, error)

Streaming

All streaming methods return *StreamReader[T]. Always defer Close().

stream, err := client.ChatCompletionsStream(ctx, req)
if err != nil { ... }
defer stream.Close()

for stream.Next() {
    chunk := stream.Event()
    for _, choice := range chunk.Choices {
        fmt.Print(choice.Delta.Content)
    }
}
if err := stream.Err(); err != nil { ... }

Feature matrix

Feature Native /api/v1 OpenAI /v1
Chat (non-streaming) Chat ChatCompletions
Chat (streaming) ChatStream ChatCompletionsStream
Text completions TextCompletions / Stream
Embeddings Embed
List models (rich) ListModels ListOpenAIModels
Load / unload model
Download model
Check if running IsModelRunning

Error handling

Sentinel errors

Error When returned
ErrEmptyPrompt Chat* / TextCompletion* with no messages
ErrEmptyText Embed with no input
ErrModelNotFound IsModelRunning when model is not loaded
ErrEmptyModel LoadModel / DownloadModel with empty model ID
ErrEmptyInstanceID UnloadModel with empty instance ID
ErrEmptyJobID GetDownloadStatus with empty job ID

API errors (HTTP 4xx / 5xx)

_, err := client.ChatCompletions(ctx, req)
if err != nil {
    if ae, ok := blmstudio.IsAPIError(err); ok {
        fmt.Printf("HTTP %d: %s\n", ae.StatusCode, ae.Message)
        // ae.RawBody contains the full response for debugging
    }
    // sentinel errors still work with errors.Is:
    if errors.Is(err, blmstudio.ErrEmptyPrompt) { ... }
}

LM Studio setup

  1. Download and install LM Studio.
  2. Open the Discover tab, find a model (e.g. meta-llama-3-8b-instruct), and download it.
  3. Go to the Developer tab → click Start Server (default port: 1234).
  4. (Optional) Enable Authentication and copy the API key — pass it via WithAPIToken.

CLI alternative (headless / CI):

lms server start
lms get lmstudio-community/meta-llama-3-8b-instruct
lms load lmstudio-community/meta-llama-3-8b-instruct

Architecture

┌──────────────────────────────────────────────────────┐
│                   blmstudio.Client                   │  ← public interface
│                                                      │
│  Chat / ChatStream              /api/v1/chat         │
│  ChatCompletions / Stream       /v1/chat/completions │
│  TextCompletions / Stream       /v1/completions      │
│  Embed                          /v1/embeddings       │
│  ListModels / Load / Unload     /api/v1/models       │
│  ListOpenAIModels               /v1/models           │
└────────────────────────┬─────────────────────────────┘
                         │
            ┌────────────▼────────────┐
            │     *client (private)   │  doJSON / doStream
            │  baseURL · apiToken     │
            │  *http.Client           │
            └────────────┬────────────┘
                         │ HTTP / SSE
            ┌────────────▼────────────┐
            │    LM Studio Server     │  http://localhost:1234
            │   (or any OAI proxy)    │
            └─────────────────────────┘

StreamReader[T]  (stream.go)
  ├── ChatStream              → StreamReader[ChatStreamEvent]
  ├── ChatCompletionsStream   → StreamReader[ChatCompletionChunk]
  └── TextCompletionsStream   → StreamReader[TextCompletionChunk]

Contributing

See CONTRIBUTING.md for dev setup, branch naming, commit format, and how to add new endpoints or providers.


License

MIT

About

Go client for LM Studio — chat, stream, and embed with local AI models. Works with any OpenAI-compatible endpoint.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages