Documentation
¶
Overview ¶
Package mllm is simple llm client, part of aerth/mostly project
Index ¶
- Variables
- func Flags()
- func L2normalize[T float32 | float64](v []T) []T
- func Noop(cr ChatResponse) error
- func StderrHandler(cr ChatResponse) error
- func StdoutHandler(cr ChatResponse) error
- func Summary(w io.Writer, st Stats) (err error)
- func ToMarshalers(v ...json.Marshaler) []json.Marshaler
- func WrapToolSpec(js json.RawMessage) ([]byte, error)
- type Call
- func (c *Call[T]) FromPlain(from Call[json.RawMessage]) error
- func (c *Call[T]) FromRaw(js json.RawMessage) error
- func (c Call[T]) ReplyTool(val any) Message
- func (c Call[T]) ReplyToolOrError(val any, err error) Message
- func (c *Call[T]) ToJSON() json.RawMessage
- func (c Call[T]) ToRaw() Call[json.RawMessage]
- func (c *Call[T]) UnmarshalJSON(b []byte) error
- type CallFuncV1
- type CallFuncV1B
- type Calls
- type ChatHandlerT
- type ChatMessage
- type ChatMessageFormatter
- type ChatMessageWithID
- type ChatMessages
- func (cm ChatMessages) ID(id uuid.UUID) *ChatMessage
- func (cm ChatMessages) IndexOf(id uuid.UUID) int
- func (cm ChatMessages) ToMessages() Messages
- func (cm ChatMessages) ToMessagesFormat(fn ChatMessageFormatter) []Message
- func (cm ChatMessages) Top() ChatMessage
- func (cm ChatMessages) TopN(n int) ChatMessages
- func (cm ChatMessages) TopP() *ChatMessage
- func (cm ChatMessages) TopRole(role string) ChatMessage
- type ChatRequest
- type ChatResponse
- type Choice
- type Client
- type E
- func (e E) AddHandlers(h ...StreamHandler) E
- func (e E) Do(ctx context.Context, creq ChatRequest, handlers []StreamHandler) error
- func (e E) Embed(ctx context.Context, req EmbedRequest) (*EmbedResponse, error)
- func (e E) Generate(ctx context.Context, sys string, usr string, think any) (Message, error)
- func (e E) Get(ctx context.Context, messages []Message, think any) (ChatResponse, error)
- func (e E) GetMessage(ctx context.Context, messages []Message, think any) (Message, error)
- func (e E) MultiChat(ctx context.Context, messages ChatMessages, think any) (ChatMessage, error)
- func (e E) MultiChat2(ctx context.Context, messages Messages, think any) (ChatMessage, error)
- func (e E) NewRequest(messages []Message, think any) *ChatRequest
- func (e E) Read(ctx context.Context, reader *bufio.Reader, handlers ...StreamHandler) error
- func (e E) Stream(ctx context.Context, messages []Message, think any, handlers ...StreamHandler) error
- func (e E) StreamBG(ctx context.Context, messages []Message, think any, handlers ...StreamHandler) chan error
- func (e *E) ValidateConfig(think any) error
- func (e E) WithHandlers(h ...StreamHandler) E
- func (e E) WithOptions(options *Options) E
- func (e E) WithTools(tools ...json.Marshaler) E
- func (e E) WithoutTools() E
- type EmbedRequest
- type EmbedResponse
- type ErrorWithResponse
- type Function
- type LChoices
- type LDelta
- type LMessage
- type LTimings
- type Message
- type Messages
- type Name
- type Options
- type Spec
- type Stats
- type StreamHandler
- type StringCalls
- type Think
- type Tool
- type Tools
- type Usage
- type Value
- type W
- type W1
Constants ¶
This section is empty.
Variables ¶
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 )
var ( DefaultOptions = Options{ Temperature: new(1.0), Seed: -1, } DefaultModel string DefaultHost string ForcePath = false )
var ( Errorf = stackerr.Errorf Slog = slog.Default )
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.
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.
var DefaultEmbedOptions map[string]any // nil
DefaultEmbedOptions is added to the embed requests
Untested
var DefaultFrom string
var DefaultThread = uuid.Nil()
DefaultThread for all Message.ToChatMessage calls.
Applications may use this for chat rooms, conversations, etc
var DefaultWriter io.Writer = os.Stderr
DefaultWriter added to all new endpoints
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.
var NewE = NewEndpoint
NewE custom NewEndpoint
var ToolWriter = toolWriter
Functions ¶
func L2normalize ¶ added in v0.3.4
L2normalize for llama.cpp to truncate dimensions
func Noop ¶ added in v0.3.2
func Noop(cr ChatResponse) error
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.
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]) ReplyToolOrError ¶ added in v0.3.2
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
type CallFuncV1 ¶ added in v0.3.2
CallFuncV1 is completly optional. Any function signature may be used by a custom toolrunner.
type CallFuncV1B ¶ added in v0.3.2
CallFuncV1 is completly optional. Any function signature may be used by a custom toolrunner.
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 (m ChatMessage) Add(m2 ChatMessage) ChatMessage
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) 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 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 NewEndpoint ¶
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
Generate helper, uses E.GetMessage with a new conversation.
Like all E methods, uses stream mode with /v1/chat/completions endpoint.
func (E) Get ¶
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
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
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
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) WithHandlers ¶
func (e E) WithHandlers(h ...StreamHandler) E
func (E) WithOptions ¶
func (E) WithoutTools ¶ added in v0.2.1
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 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
func (Function[T]) ArgsToJSON ¶ added in v0.3.2
func (f Function[T]) ArgsToJSON() json.RawMessage
func (Function[T]) ToJSON ¶ added in v0.3.2
func (f Function[T]) ToJSON() json.RawMessage
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 ReplyToolOrError ¶ added in v0.3.2
func (Message) Add ¶
Add fields of c2 to c for gathering streamed chunks
Used in ChatResponse.Handler
func (Message) IsBlank ¶ added in v0.4.0
IsBlank DOES NOT check m.Aux or m.Role -- see also: Message.IsEmpty
func (Message) IsEmpty ¶
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 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
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) SummaryString ¶ added in v0.2.1
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 Think ¶
type Think struct {
Value `json:"-"`
}
Think Value should be one of: nil,"low","medium","high",true,false
func (Think) MarshalJSON ¶
MarshalJSON implements json.Marshaler for sending request
type Tool ¶ added in v0.3.1
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
GetName extracts the name for finding the matching tool for a Call
Used by Tools.ByName
func (Tool) MarshalJSON ¶ added in v0.3.1
type Tools ¶ added in v0.3.2
type Tools []Tool
func (Tools) Run ¶ added in v0.3.2
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
ToJSON ensures each tool is wrapped in a `"type": "function", "function":` wrapper.
func (Tools) ToMarshalers ¶ added in v0.4.0
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