mllm

package
v0.4.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2026 License: MIT Imports: 21 Imported by: 0

README

mllm

tiny ai client package

About

The mllm package is a lightweight, extensible LLM client library designed to simplify interactions with Large Language Models (LLMs) via providers such as llama.cpp or Ollama. It provides high-level abstractions for handling conversation messages, streaming responses (via a StreamBG method and configurable StreamHandler callbacks), and tool calling. The package simplifies environment-based configuration (Model, Host, API Key) and requires users to implement their own "tool runners" to execute logic based on the Tool specifications and Call arguments provided by the LLM.

Environment Runtime Config

Reads these env vars (in order):

Model: "MLLM_MODEL", "OLLAMA_MODEL", "LLM_MODEL" Host: "MLLM_HOST", "OLLAMA_HOST", "LLM_HOST" API Key (optional): "MLLM_API_KEY", "OLLAMA_API_KEY", "LLM_API_KEY"

Use DEBUG_LLM=1 to see JSON requests/responses

Host may be a full URL. Otherwise, /v1/chat/completions is added.

Model and Host are required.

Flags may target mllm.DefaultOptions to override Temperature, etc.

flag.Float64Var(mllm.DefaultOptions.Temperature,
  "temperature", *mllm.DefaultOptions.Temperature, "temperature value for ai")

Programs may bypass the environment-based configuration by various means, such as replacing mllm.Default, or creating a mllm.Client manually.

apiurl , _ := url.Parse("https://ollama.home.arpa/v1/chat/completions")
client := mllm.E{
  Host: *apiurl,
  Model: "gemma4:12b",
  Writer: os.Stdout,
}
_, err := client.Generate(context.TODO(), "", "Tell funny joke")
if err != nil {
  log.Fatalln(err)
}

Provider

Tested with llama.cpp:

export LLM_MODEL=gemma-4-E2B-it-Q4_K_M LLM_HOST=http://127.0.0.1:9931/v1/chat/completions LLM_API_KEY=some-key-here

Tested with ollama:

export LLM_MODEL=gemma4:12b LLM_HOST=http://127.0.0.1:11434/v1/chat/completions

Usage

Typical usage for TUI would be (background) streaming with a custom StreamHandler to write into a view that renders markdown.

Background

Use StreamBG to send the request, returning a chan error that is closed when stream is finished. A nil error is sent if no error occurred. The channel must be emptied.

TUI/GUI applications may use StreamBG with custom StreamHandler to stream the LLM output frames directly to a view (possibly rendering markdown at intervals), and can access cr.Done to signal other threads that the generation is finished, to save and add the message to the "conversation".

// simple orchestration loop

 client := mllm.Default() // uses env for Model and Host
 think := false
 e.Tools = mllm.Tools{searchTool,scrapeTool}

// convo is list of mllm.Message which might look familiar:
 convo := mllm.Messages{
  {Role: "system", Content: "You are a ..."}, 
  {Role: "user", Content: "what is the latest version of golang, and when will the next one be released?",
 }}

 // ChatResponse itself has a Handler method that is a StreamHandler func
 var chatResp mllm.ChatResponse
 var handlers []StreamHandler // stream handlers are called each frame/delta
 handlers = []StreamHandler{
   mllm.NewHandlerOut(os.Stderr, "THINKING:\n", "\nFINISHED THINKING\n"),
   chatResp.Handler,
   // your other handler for sending to View
 }
Chat:
 err := <- e.StreamBG(ctx, convo, think, handlers...)
 // add the "caller" to the conversation first
 convo = append(convo, chatResp.Message)
 // then, give "caller" to toolrunner, etc
 if len(chatResp.Message.ToolCalls) != 0 {
   // then, add toolout to convo
   toolout := runTools(ctx, chatResp.Message)
   convo = append(convo, toolout)
   goto Chat // go back to the generate step
 }
 finalMessage := chatResp.Message

See also: test file

Foreground

For non-streaming behavior, use msg, err := client.Get(...)

Under the hood, we still use "stream": true, but our Generate, Get, and GetMessage functions do not return until the llm is finished (same with Get function)

 client := mllm.Default() // uses env for Model and Host
 client.Tools = nil // add tools to client
 think := false
 var resp mllm.Message
 var err error
 // Get/GetMessage accepts convo and think as arguments.
 cr, err := client.Get(ctx, messages, think)
 resp = cr.Message 
 // or, use GetMessage:
 resp, err = client.GetMessage(ctx, messages, think)

 // or, for first or only message, Generate can be used 
 // Generate accepts two string arguments (system, user):
 resp, err = client.Generate(ctx, "You are a helpful assistant.", "Send golang official documentation links", think)
}

See also: test file

StreamHandler

Although it is usually not necessary, a new StreamHandler is easy to make. It might contain state. If it returns any error the stream will cut short. A StreamHandler is called very quickly, and will lag the llm stream (see example below).

import "github.com/aerth/mostly/mllm"

// as a function

func Dummy(cr mllm.ChatResponse) error {
 return nil
}

// as a method, stateful for adding each frame to it's own message copy
type X struct{Message mllm.Message, Ch chan mllm.Message}

func (x *X) Dummy(cr mllm.ChatResponse) error {
  x.Message = x.Message.Add(cr.Message) // combined
  if cr.Done {
 select {
 case x.Ch <- x.Message:
 default:
 return fmt.Errorf("GUI message channel is full")
 }
  }
 return nil
}
Tools

In this package, a Tool contains an "Exec" function (who's signature is up to you), paired with a JSON "Spec" which is a json.RawMessage. A tool Call, given by LLM, has "Arguments", (which may be an object or stringified object, or null or empty string). This package does not run tools, or care what function signature you use as tool's Exec, and therefore you must implement your own "tool runner".

An example tool runner is explainfile

See also: tool test file

Tool Exec Funcs

Example tool function signatures might include (but are in no way limited to):

func(ctx context.Context, args json.RawMessage) (string, error)

func(args map[string]any) (any, error)

func(ctx context.Context, args SomeArgumentType, other SessionData) (SomeResponseType, error)

call.ReplyTool

The call.ReplyTool helper function (for a tool runner) to wrap a tool output into text for a new message to be added to the conversation. It adds ToolCallID and ToolName, and JSON encodes the input for the new message's Content.

Example Tool

Example TimeTool implemented in Go, using a (ctx context.Context, args map[string]any) (string, error) exec func signature.

The "function": wrapper is unnecessary as this package always ensures the spec is wrapped.

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/aerth/mostly/mllm"
)

var TimeTool = mllm.Tool{
	Spec: timeSpec,
	Exec: getTime,
}

var timeSpec = json.RawMessage(`{
  "type": "function",
  "function": {
    "name": "get_time",
    "description": "get current time",
    "parameters": {
      "type": "object",
      "properties": {
        "zone": {
          "type": "string"
        }
      },
      "required": ["zone"]
    }
  }
}`)

func getTime(ctx context.Context, args map[string]any) (string, error) {
	zone, ok := args["zone"].(string)
	if !ok {
		return "", errors.New("invalid zone")
	}
	loc, err := time.LoadLocation(zone)
	if err != nil {
		return "", fmt.Errorf("load location failed: %w", err)
	}
	return time.Now().In(loc).Format(time.RFC3339), nil
}

Documentation

Overview

Package mllm is simple llm client, part of aerth/mostly project

Index

Constants

This section is empty.

Variables

View Source
var (
	DefaultThinkPre         = "Thinking:\n"
	DefaultThinkPost        = "\n... done thinking.\n"
	ThinkRequestType        = false
	StopAtFirstHandlerError = true
	ErrNoLines              = errors.New("no lines read")
	HideThink               = false
	HideTools               = false
	EnvModel                = []string{"MLLM_MODEL", "OLLAMA_MODEL", "LLM_MODEL"}
	EnvHost                 = []string{"MLLM_HOST", "OLLAMA_HOST", "LLM_HOST"}
	EnvKey                  = []string{"MLLM_API_KEY", "OLLAMA_API_KEY", "LLM_API_KEY"}
	DebugLLM2               = os.Getenv("DEBUG_LLM") == "2"
	DebugLLM                = os.Getenv("DEBUG_LLM") == "1" || DebugLLM2
	ErrNoConvo              = errors.New("no messages in conversation")
	Quiet                   = false // quiet the debug
)
View Source
var (
	DefaultOptions = Options{
		Temperature: new(1.0),
		Seed:        -1,
	}
	DefaultModel      string
	DefaultHost       string
	DefaultHTTPClient *http.Client
	ForcePath         = false
)
View Source
var (
	Errorf = stackerr.Errorf
	Slog   = slog.Default
)
View Source
var Default = func() E {
	e := NewEndpoint(nil, nil)
	return e
}

Default creates a new reusable LLM endpoint from env using NewEndpoint with no tools no options.

View Source
var DefaultChatMessageFormatter = func(cm ChatMessage) ([]Message, bool) {
	return []Message{cm.Message}, true
}

DefaultChatMessageFormatter pass through ChatMessageFormatter In a custom implementation, this might add text to Content, replace Role, or insert messages before/after.

View Source
var DefaultEmbedOptions map[string]any // nil

DefaultEmbedOptions is added to the embed requests

Untested

View Source
var DefaultFrom string
View Source
var DefaultThread = uuid.Nil()

DefaultThread for all Message.ToChatMessage calls.

Applications may use this for chat rooms, conversations, etc

View Source
var DefaultWriter io.Writer = os.Stderr

DefaultWriter added to all new endpoints

View Source
var EmbedOptions = struct {
	URL        url.URL
	Model      string            // if req.Model is empty and env is empty
	Dimensions int               // must match [vector256.VarLen]
	EnvHost    string            // the ENV_VAR to check to override [E.Host] (for when using 2 different hosts for llm,embeddings.)
	Path       string            // custom endpoint url path (default /api/embed)
	Headers    map[string]string // if different than LLM_API_KEY
}{
	Model:   "nomic-embed-text:v1.5",
	EnvHost: "LLM_EMBED_HOST",
	Path:    "/v1/embeddings",
}

EmbedOptions application-wide global options

Apart from Path, all serve as fallback if not present in request/env.

NewE custom NewEndpoint

View Source
var NoLogFlags bool
View Source
var ThreadHasher = func(v string) uuid.UUID {
	h := sha256.New()
	_, err := h.Write([]byte(v))
	if err != nil {
		panic(err.Error())
	}
	b := h.Sum(nil)
	var id uuid.UUID
	copy(id[:], b)
	return id
}

ThreadHasher for easy thread UUID by "name"

Set to 'nil' if the "--thread" flag should strictly parse UUID.

View Source
var ToolWriter = toolWriter
View Source
var ToolWriterOut io.Writer = os.Stderr

Functions

func CtxCallIndex added in v0.4.2

func CtxCallIndex(ctx context.Context) (int, bool)

func Flags added in v0.4.0

func Flags()

Flags useful for programs to use, but not necessary. If -v or -q are already flags, set NoLogFlags to true.

func L2normalize added in v0.3.4

func L2normalize[T float32 | float64](v []T) []T

L2normalize for llama.cpp to truncate dimensions

func Noop added in v0.3.2

func Noop(cr ChatResponse) error

func StderrHandler

func StderrHandler(cr ChatResponse) error

StderrHandler plain 🍔

func StdoutHandler

func StdoutHandler(cr ChatResponse) error

StdoutHandler plain 🍔

func Summary

func Summary(w io.Writer, st Stats) (err error)

Summary in well-known format

func ToMarshalers added in v0.3.2

func ToMarshalers(v ...json.Marshaler) []json.Marshaler

func ToolNames added in v0.4.10

func ToolNames(tools Tools) []string

func WithCall added in v0.4.2

func WithCall[T any](ctx context.Context, call Call[T]) context.Context

func WithCallIndex added in v0.4.2

func WithCallIndex(ctx context.Context, index int) context.Context

func WithCaller added in v0.4.2

func WithCaller(ctx context.Context, caller Message) context.Context

func WithClient added in v0.4.7

func WithClient(ctx context.Context, client E) context.Context

func WrapToolSpec added in v0.3.2

func WrapToolSpec(js json.RawMessage) ([]byte, error)

Types

type Call added in v0.3.1

type Call[T any] struct {
	ID       string      `json:"id,omitempty"`
	Index    int         `json:"index"`
	Type     string      `json:"type,omitempty"`
	Function Function[T] `json:"function"`
}

Call is for a tool-runner to decode arguments. Callers may use Call[struct{Path string}] to decode `"arguments": {"path": "foo.txt"}`

It handles the case where Arguments json object is passed as a json string.

See Call.UnmarshalJSON

func CtxCall added in v0.4.2

func CtxCall[T any](ctx context.Context) (Call[T], bool)

func (*Call[T]) FromPlain added in v0.3.2

func (c *Call[T]) FromPlain(from Call[json.RawMessage]) error

func (*Call[T]) FromRaw added in v0.3.2

func (c *Call[T]) FromRaw(js json.RawMessage) error

FromRaw attempts to decode from JSON

func (Call[T]) ReplyTool added in v0.3.2

func (c Call[T]) ReplyTool(val any) Message

func (Call[T]) ReplyToolOrError added in v0.3.2

func (c Call[T]) ReplyToolOrError(val any, err error) Message

func (*Call[T]) ToJSON added in v0.3.2

func (c *Call[T]) ToJSON() json.RawMessage

func (Call[T]) ToRaw added in v0.3.2

func (c Call[T]) ToRaw() Call[json.RawMessage]

ToRaw converts back to a js arguments

func (*Call[T]) UnmarshalJSON added in v0.3.1

func (c *Call[T]) UnmarshalJSON(b []byte) error

type CallFuncV1 added in v0.3.2

type CallFuncV1 = func(ctx context.Context, args map[string]any) (output any, err error)

CallFuncV1 is completly optional. Any function signature may be used by a custom toolrunner.

type CallFuncV1B added in v0.3.2

type CallFuncV1B = func(ctx context.Context, args json.RawMessage) (output any, err error)

CallFuncV1 is completly optional. Any function signature may be used by a custom toolrunner.

type CallFuncV1C added in v0.4.2

type CallFuncV1C = func(ctx context.Context, m Message, index int) (output any, err error)

CallFuncV1 is completly optional. Any function signature may be used by a custom toolrunner.

type Calls added in v0.3.2

type Calls[T any] []Call[T]

func (Calls[T]) ToJSON added in v0.3.2

func (c Calls[T]) ToJSON() []json.RawMessage

ToJSON used in E.Read to recombine to unparsed RawMessages

type ChatHandlerT

type ChatHandlerT interface {
	HandleChat(cr ChatResponse) error
}

type ChatMessage

type ChatMessage struct {
	MessageID uuid.UUID `gorm:"type:uuid;uniqueKey;default:null;" json:"message_id,omitempty"` // MessageID is unique identifier for this message
	Message             // Base Message
	From      string    `json:"from,omitempty" gorm:"default:null"`             // The name of user/bot who created this message
	CreatedAt time.Time `json:"created_at"`                                     // Created or received at
	Thread    uuid.UUID `json:"thread,omitempty" gorm:"type:uuid;default:null"` // Conversation thread this message belongs to

	Aux any `json:"-" gorm:"-"` // unused by this package
}

ChatMessage is a Message but with additional metadata (for a multi-participant conversation)

Is a gorm model, (without uint ID)

ChatMessage API is subject to change and not stablized yet

func NewChatMessage

func NewChatMessage(m Message, from string, thread uuid.UUID) *ChatMessage

NewChatMessage from (see also Message.ToChatMessage)

func (ChatMessage) Add added in v0.4.0

func (*ChatMessage) HandleChat added in v0.4.0

func (m *ChatMessage) HandleChat(cr ChatResponse) error

type ChatMessageFormatter

type ChatMessageFormatter = func(cm ChatMessage) ([]Message, bool)

ChatMessageFormatter may skip a message by returning false

The returned formatted messages are NEVER stored only sent

type ChatMessageWithID added in v0.3.2

type ChatMessageWithID struct {
	ID uint `json:"-" gorm:"primaryKey"` // TODO: cant json id here for [Message2.ToolCallID2] llama.cpp
	ChatMessage
}

type ChatMessages

type ChatMessages []ChatMessage

ChatMessages like Messages but with additional metadata (multiple multi-participant conversations)

func (ChatMessages) ID added in v0.4.0

func (cm ChatMessages) ID(id uuid.UUID) *ChatMessage

func (ChatMessages) IndexOf added in v0.4.0

func (cm ChatMessages) IndexOf(id uuid.UUID) int

func (ChatMessages) Roles added in v0.4.7

func (cm ChatMessages) Roles() []string

func (ChatMessages) ToMessages

func (cm ChatMessages) ToMessages() Messages

func (ChatMessages) ToMessagesFormat

func (cm ChatMessages) ToMessagesFormat(fn ChatMessageFormatter) []Message

ToMessagesFormat returns a **temporary** convo for llm to produce a single new Message The returned convo should NEVER be stored (only sent to llm) as the Content is modified by formatter.

func (ChatMessages) Top added in v0.2.5

func (cm ChatMessages) Top() ChatMessage

func (ChatMessages) TopN added in v0.2.5

func (cm ChatMessages) TopN(n int) ChatMessages

func (ChatMessages) TopP added in v0.4.0

func (cm ChatMessages) TopP() *ChatMessage

func (ChatMessages) TopRole added in v0.2.5

func (cm ChatMessages) TopRole(role string) ChatMessage

type ChatRequest

type ChatRequest struct {
	Model     string           `json:"model,omitempty"`
	Messages  []Message        `json:"messages,omitempty"`
	Stream    bool             `json:"stream"`
	Think     *Think           `json:"reasoning_effort,omitempty"` // ollama endpoint "think" but /v1/chat/completions is "thinking"
	KeepAlive int              `json:"keep_alive,omitempty"`
	Tools     []json.Marshaler `json:"tools,omitempty"`
	*Options  `gorm:"type:jsonb;serializer:json;default:null"`
}

ChatRequest sent to LLM (/v1/chat/completions or compatible)

type ChatResponse

type ChatResponse struct {
	LLMID string `json:"id,omitempty" gorm:"-"`
	//	Object string
	Model       string          `json:"model"`
	Created     json.RawMessage `json:"created,omitempty"`
	Done        bool            `json:"done"` // for stream
	DoneReason  string          `json:"done_reason,omitempty"`
	DoneReason2 string          `json:"finish_reason,omitempty" gorm:"-"` // INTERNAL do not use
	Message     Message         `json:"message"`                          // for stream, handlers
	Stats       `gorm:"embedded"`
	Choices     []Choice `json:"choices,omitempty"` // INTERNAL do not use
}

ChatResponse streamable has ChatResponse.Handler

See LMessage

Example:

var cr mllm.ChatResponse
err := <-mllm.Default().StreamBG(ctx, mllm.Messages{{Role: "user", Content: "hi"}}, false, cr.Handler)
println("Bot:", cr.Message.Content)

func (*ChatResponse) Handler

func (c *ChatResponse) Handler(in ChatResponse) error

Handler for E.StreamBG and E.Stream

SWAPS

Is a StreamHandler to gather Message

func (ChatResponse) SummaryString

func (c ChatResponse) SummaryString() string

SummaryString collects [ChatResponse.Stats] into a string

type Choice added in v0.3.1

type Choice struct {
	Index        int     `json:"index"`
	FinishReason *string `json:"finish_reason,omitempty"`
	Delta        Message `json:"delta"`
}

type Client added in v0.4.0

type Client = E

type E

type E struct {
	Host  url.URL // the LLM API (required)
	Model string  // the model name (required)

	Client  *http.Client      `json:"-"` // custom http client (optional)
	Headers map[string]string `json:"-"` // custom headers (optional)
	Tools   []json.Marshaler  // Bring your own tools (optional)
	Options *Options          // Options (optional) added to each NewRequest

	Writer       io.Writer // used in [E.Get] as StreamWriter if no StreamWriter
	StreamWriter W1        `json:"-" gorm:"-"` // used as only handler **IF no handlers given**

	PreRequest func(request *ChatRequest) error `json:"-"`

	// Handlers **added** to all requests
	Handlers []StreamHandler `json:"-"`

	//
	From     string
	ThreadID uuid.UUID
}

E (Endpoint) holds information for future requests

Writer for streaming output with ThinkPre and ThinkPost.

func CtxClient added in v0.4.7

func CtxClient(ctx context.Context) (E, bool)

func NewEndpoint

func NewEndpoint(options *Options, tools []json.Marshaler) E

NewEndpoint reads env and returns a new reusable Endpoint

See E.StreamBG or E.Stream or E.Get

func (E) AddHandlers

func (e E) AddHandlers(h ...StreamHandler) E

func (E) Do added in v0.2.3

func (e E) Do(ctx context.Context, creq ChatRequest, handlers []StreamHandler) error

Do sends a ChatRequest and streams response in E.Read

func (E) Embed added in v0.2.2

func (e E) Embed(ctx context.Context, req EmbedRequest) (*EmbedResponse, error)

Embed generates new embeddings

See NewNomicDocument and NewNomicQuery for model-specific query prefixes

func (E) Generate added in v0.4.0

func (e E) Generate(ctx context.Context, sys string, usr string, think any) (Message, error)

Generate helper, uses E.GetMessage with a new conversation.

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) Get

func (e E) Get(ctx context.Context, messages []Message, think any) (ChatResponse, error)

Get calls E.Stream and waits until finished, returning the full ChatResponse

Uses E.Stream, writes stream text to E.Writer if non-nil, returns full ChatResponse

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) GetMessage added in v0.3.1

func (e E) GetMessage(ctx context.Context, messages []Message, think any) (Message, error)

GetMessage is E.Get but only message.

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) MultiChat added in v0.4.0

func (e E) MultiChat(ctx context.Context, messages ChatMessages, think any) (ChatMessage, error)

MultiChat returns a threaded ChatMessage (from E.From in thread E.ThreadID)

For Messages input see E.MultiChat2

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) MultiChat2 added in v0.4.0

func (e E) MultiChat2(ctx context.Context, messages Messages, think any) (ChatMessage, error)

MultiChat2 returns a threaded ChatMessage (from E.From in thread E.ThreadID)

For ChatMessages input see E.MultiChat

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) NewRequest added in v0.2.3

func (e E) NewRequest(messages []Message, think any) *ChatRequest

NewRequest creates a ChatRequest adds e.Model, e.Tools, and e.Options

func (E) Read added in v0.2.2

func (e E) Read(ctx context.Context, reader *bufio.Reader, handlers ...StreamHandler) error

Read a stream, collecting for StreamHandlers, stopping immediately at first error.

Nothing is printed, only error is returned. At least one StreamHandler must be given.

NOTE: To modify Read so that, after an error, **all** stream handlers are given each frame, caller should set StopAtFirstHandlerError to false,

func (E) Stream

func (e E) Stream(ctx context.Context, messages []Message, think any, handlers ...StreamHandler) error

Stream with handlers(only) or to E.Writer, calls E.Do

Like all E methods, uses stream mode with /v1/chat/completions endpoint.

func (E) StreamBG

func (e E) StreamBG(ctx context.Context, messages []Message, think any, handlers ...StreamHandler) chan error

StreamBG uses E.Stream, closing ch after streaming is finished, sending non-nil error to the channel

func (*E) ValidateConfig

func (e *E) ValidateConfig(think any) error

func (E) WithHandlers

func (e E) WithHandlers(h ...StreamHandler) E

func (E) WithOptions

func (e E) WithOptions(options *Options) E

func (E) WithTools

func (e E) WithTools(tools ...json.Marshaler) E

func (E) WithoutTools added in v0.2.1

func (e E) WithoutTools() E

type EmbedRequest added in v0.2.2

type EmbedRequest struct {
	Model     string `json:"model"`
	Input     string `json:"input"`
	KeepAlive int    `json:"keep_alive,omitempty"`
	// Dimensions truncates the output embedding to the specified dimension.
	Dimensions int   `json:"dimensions,omitempty"`
	Truncate   *bool `json:"truncate,omitempty"`
	// Options lists model-specific options.
	Options map[string]any `json:"options,omitempty"`

	Host url.URL `json:"-"` // optional: override E.Host and LLM_EMBED_HOST env
}

EmbedRequest is the request passed to E.Embed.

func NewEmbed added in v0.2.2

func NewEmbed(s string) EmbedRequest

NewEmbed request

func NewNomicDocument added in v0.2.2

func NewNomicDocument(s string) EmbedRequest

NewNomicDocument adds `search_document: ` prefix to the given string

func NewNomicQuery added in v0.2.2

func NewNomicQuery(s string) EmbedRequest

NewNomicQuery adds `search_query: ` prefix to the given string

type EmbedResponse added in v0.2.2

type EmbedResponse struct {
	Model      string                `json:"model"`
	Embeddings []vector256.Vector256 `json:"embeddings"` // get resp.Embeddings[0]
	Data       []*struct {
		Embedding vector256.Vector256
	} `json:"data,omitempty"`
	Stats                   // limited for this endpoint
	Error   json.RawMessage `json:"error,omitempty"`
	Message json.RawMessage `json:"message,omitempty"`
}

EmbedResponse is the response from [Client.Embed].

func (*EmbedResponse) GetEmbeddings added in v0.2.2

func (e *EmbedResponse) GetEmbeddings() vector256.Vector256

GetEmbeddings extracts the search embeddings vectors

type ErrorWithResponse added in v0.2.2

type ErrorWithResponse struct {
	// contains filtered or unexported fields
}

func (ErrorWithResponse) Body added in v0.2.2

func (e ErrorWithResponse) Body() []byte

func (ErrorWithResponse) Unwrap added in v0.2.2

func (e ErrorWithResponse) Unwrap() error

Unwrap for errors.Unwrap.

type Function added in v0.3.2

type Function[T any] struct {
	Name      string `json:"name"`
	Arguments T      `json:"arguments,omitempty"`
}

func (Function[T]) ArgsToJSON added in v0.3.2

func (f Function[T]) ArgsToJSON() json.RawMessage

func (Function[T]) ArgsToMap added in v0.3.2

func (f Function[T]) ArgsToMap() map[string]any

func (Function[T]) ToJSON added in v0.3.2

func (f Function[T]) ToJSON() json.RawMessage

type LChoices added in v0.3.2

type LChoices struct {
	FinishReason string `json:"finish_reason"`
	Index        int    `json:"index"`
	Delta        LDelta `json:"delta"`
}

type LDelta added in v0.3.2

type LDelta struct{}

type LMessage added in v0.3.2

type LMessage struct {
	Choices           []LChoices `json:"choices"`
	Created           int        `json:"created"`
	ID                string     `json:"id"`
	Model             string     `json:"model"`
	SystemFingerprint string     `json:"system_fingerprint"`
	Object            string     `json:"object"`
	Timings           LTimings   `json:"timings"`
}

type LTimings added in v0.3.2

type LTimings struct {
	CacheN              int     `json:"cache_n"`
	PromptN             int     `json:"prompt_n"`
	PromptMs            float64 `json:"prompt_ms"`
	PromptPerTokenMs    float64 `json:"prompt_per_token_ms"`
	PromptPerSecond     float64 `json:"prompt_per_second"`
	PredictedN          int     `json:"predicted_n"`
	PredictedMs         float64 `json:"predicted_ms"`
	PredictedPerTokenMs float64 `json:"predicted_per_token_ms"`
	PredictedPerSecond  float64 `json:"predicted_per_second"`
}

type Message

type Message struct {
	Role       string            `json:"role,omitempty"`
	Content    string            `json:"content"`
	Reasoning  string            `json:"thinking,omitempty" gorm:"default:null"`
	ToolCalls  []json.RawMessage `json:"tool_calls,omitempty" gorm:"type:jsonb;serializer:json;default:null;"`
	ToolName   string            `json:"tool_name,omitempty" gorm:"default:null"`
	ToolCallID string            `json:"tool_call_id,omitempty" gorm:"default:null"`
	Images     [][]byte          `json:"images,omitempty" gorm:"serializer:json;type:jsonb;default:null;"`
	// contains filtered or unexported fields
}

Message from LMessage

func CtxCaller added in v0.4.2

func CtxCaller(ctx context.Context) (Message, bool)

func ReplyTool added in v0.3.2

func ReplyTool[T any](call Call[T], val any) Message

func ReplyToolOrError added in v0.3.2

func ReplyToolOrError[T any](call Call[T], val any, err error) Message

func (Message) Add

func (m Message) Add(m2 Message) Message

Add fields of c2 to c for gathering streamed chunks

Used in ChatResponse.Handler

func (Message) Equal

func (m Message) Equal(m2 Message) bool

func (Message) IsBlank added in v0.4.0

func (m Message) IsBlank() bool

IsBlank DOES NOT check m.Aux or m.Role -- see also: Message.IsEmpty

func (Message) IsEmpty

func (m Message) IsEmpty() bool

IsEmpty DOES NOT check m.Aux -- see also: Message.IsBlank

func (Message) ToChatMessage

func (m Message) ToChatMessage(from string) *ChatMessage

ToChatMessage with DefaultThread, new MessageID, new timestamp.

Should be called ONCE immediately after stream is finished.

func (Message) ToThreadMessage added in v0.3.2

func (m Message) ToThreadMessage(from string, thread uuid.UUID) *ChatMessage

type Messages

type Messages []Message

func (Messages) Top added in v0.2.5

func (m Messages) Top() Message

func (Messages) TopN added in v0.2.5

func (m Messages) TopN(n int) Messages

func (Messages) TopRole added in v0.2.5

func (m Messages) TopRole(role string) Message

type Name added in v0.3.2

type Name struct {
	Name     string `json:"name,omitempty"`
	Function struct {
		Name string `json:"name,omitempty"`
	} `json:"function"`
}

Name finder (wrapped or unwrapped) in `"type":"function"` Caller should access Name.GetName method

Used by Tool.GetName and Tools.ByName

func (Name) GetName added in v0.3.2

func (n Name) GetName() string

GetName of Tool function Spec or Call

type Options

type Options struct {
	Seed             int64    `json:"seed,omitempty"`
	Temperature      *float64 `json:"temperature,omitempty"` // 0.0 to 2.0
	NumCtx           int      `json:"num_ctx,omitempty"`
	TopP             *float64 `json:"top_p,omitempty"`             // 0.0 to 1.0
	TopK             *int     `json:"top_k,omitempty"`             // 1 to ???
	FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"` // -2.0 to 2.0
	PresencePenalty  *float64 `json:"presence_penalty,omitempty"`  // -2.0 to 2.0
	//
	Debug int `json:"-"` // internal, for printing full chatrequest before sending
}

Options for ChatRequest

type Spec added in v0.3.2

type Spec = json.RawMessage

type Stats

type Stats struct {
	LoadDuration       time.Duration `json:"load_duration,omitempty"`
	PromptEvalDuration time.Duration `json:"prompt_eval_duration,omitempty"`
	EvalDuration       time.Duration `json:"eval_duration,omitempty"`
	TotalDuration      time.Duration `json:"total_duration,omitempty"`
	PromptEvalCount    int           `json:"prompt_eval_count,omitempty"`
	EvalCount          int           `json:"eval_count,omitempty"`
	Usage
}

Stats has [Stats.String]

func (Stats) Summary added in v0.2.1

func (st Stats) Summary(w io.Writer) error

Summary in well-known format

func (Stats) SummaryString added in v0.2.1

func (st Stats) SummaryString() string

SummaryString collects [ChatResponse.Stats] into a string

type StreamHandler

type StreamHandler func(cr ChatResponse) error

func NewHandlerOut

func NewHandlerOut(w io.Writer, thinkpre string, thinkpost string) StreamHandler

NewHandlerOut plain 🍔

func (StreamHandler) HandleChat

func (c StreamHandler) HandleChat(cr ChatResponse) error

type StringCalls added in v0.3.2

type StringCalls []Call[string] // "arguments": "{"

func (StringCalls) Combined added in v0.3.2

func (c StringCalls) Combined() Calls[string]

Combined fragments of tool calls into final calls (one per call index, which usually 1) instead of bunch of fragments

Used in E.Read to finish a stream

Should remove Call from this TODO:

type Think

type Think struct {
	Value `json:"-"`
}

Think Value should be one of: nil,"low","medium","high",true,false

func (Think) MarshalJSON

func (t Think) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for sending request

type Tool added in v0.3.1

type Tool struct {
	Spec     // json.RawMessage     // Spec, contains name
	Exec any `json:"-"`
}

Tool has JSON spec and Exec func

Your toolrunner can parse args and pass to Exec how you want to.

func (Tool) GetName added in v0.3.2

func (t Tool) GetName() string

GetName extracts the name for finding the matching tool for a Call

Used by Tools.ByName

func (Tool) MarshalJSON added in v0.3.1

func (t Tool) MarshalJSON() ([]byte, error)

func (Tool) Run added in v0.4.0

func (t Tool) Run(ctx context.Context, args any) (output any, err error)

Run should be wrapped in a ReplyTool or ReplyToolOrError

type Tools added in v0.3.2

type Tools []Tool

func (Tools) ByName added in v0.3.2

func (t Tools) ByName(name string) Tool

ByName get a Tool

func (Tools) Names added in v0.4.10

func (t Tools) Names() []string

func (Tools) Run added in v0.3.2

func (t Tools) Run(ctx context.Context, name string, args any) (output any, err error)

Run returns the raw tool output, such as `42` or `"foo"` or `{"foo": 42}`

Tool Runner should wrap this in a ReplyTool or ReplyToolOrError

func (Tools) ToJSON added in v0.3.3

func (t Tools) ToJSON() []json.Marshaler

ToJSON ensures each tool is wrapped in a `"type": "function", "function":` wrapper.

see Tool.MarshalJSON

func (Tools) ToMarshalers added in v0.4.0

func (t Tools) ToMarshalers() []json.Marshaler

type Usage added in v0.3.1

type Usage struct {
	TotalTokens  int `json:"total_tokens,omitempty"`
	PromptTokens int `json:"prompt_tokens,omitempty"`
}

type Value added in v0.3.1

type Value = any

type W added in v0.3.2

type W interface{ New() StreamHandler }

type W1 added in v0.3.2

type W1 struct {
	// Writer if non-nil will be automatically added as a stream handler to [[E.Get]] and [[E.Stream]]
	Writer    io.Writer `json:"-"`
	ThinkPre  string    // optional, default used in [NewEndpoint]
	ThinkPost string    // optional, default used in [NewEndpoint]
}

func (W1) New added in v0.3.2

func (w W1) New() StreamHandler

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL