feat: add DeepSeek, Moonshot, xAI, Groq, Ollama; drop v1; migrate TUI to v2
Five OpenAI-compatible providers join the library as first-class constructors (llm.DeepSeek, llm.Moonshot, llm.XAI, llm.Groq, llm.Ollama). Their wire-level implementation is shared via a new v2/openaicompat package which is the extracted guts of the old v2/openai provider; each provider supplies its own Rules value to declare per-model constraints (e.g., DeepSeek Reasoner rejects tools and temperature, Moonshot/xAI accept images only on *-vision* models, Groq rejects audio input). v2/openai itself becomes a thin wrapper that sets RestrictTemperature for o-series and gpt-5 models. A new provider registry (v2/registry.go) exposes llm.Providers() and drives the TUI's provider picker so adding a provider in future is a single-file change. The TUI at cmd/llm was migrated from v1 to v2 and moved to v2/cmd/llm. With nothing else depending on v1, the v1 code at the repo root (all .go files, schema/, internal/, provider/, root go.mod/go.sum) is deleted. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
llm "gitea.stevedudenhoeffer.com/steve/go-llm/v2"
|
||||
)
|
||||
|
||||
// TimeParams is the parameter struct for the GetTime function.
|
||||
type TimeParams struct{}
|
||||
|
||||
// GetTime returns the current time.
|
||||
func GetTime(_ context.Context, _ TimeParams) (string, error) {
|
||||
return time.Now().Format("Monday, January 2, 2006 3:04:05 PM MST"), nil
|
||||
}
|
||||
|
||||
// CalcParams is the parameter struct for the Calculate function.
|
||||
type CalcParams struct {
|
||||
A float64 `json:"a" description:"First number"`
|
||||
B float64 `json:"b" description:"Second number"`
|
||||
Op string `json:"op" description:"Operation: add, subtract, multiply, divide, power, sqrt, mod"`
|
||||
}
|
||||
|
||||
// Calculate performs basic math operations.
|
||||
func Calculate(_ context.Context, params CalcParams) (string, error) {
|
||||
var result float64
|
||||
switch strings.ToLower(params.Op) {
|
||||
case "add", "+":
|
||||
result = params.A + params.B
|
||||
case "subtract", "sub", "-":
|
||||
result = params.A - params.B
|
||||
case "multiply", "mul", "*":
|
||||
result = params.A * params.B
|
||||
case "divide", "div", "/":
|
||||
if params.B == 0 {
|
||||
return "", fmt.Errorf("division by zero")
|
||||
}
|
||||
result = params.A / params.B
|
||||
case "power", "pow", "^":
|
||||
result = math.Pow(params.A, params.B)
|
||||
case "sqrt":
|
||||
if params.A < 0 {
|
||||
return "", fmt.Errorf("cannot take square root of negative number")
|
||||
}
|
||||
result = math.Sqrt(params.A)
|
||||
case "mod", "%":
|
||||
result = math.Mod(params.A, params.B)
|
||||
default:
|
||||
return "", fmt.Errorf("unknown operation: %s", params.Op)
|
||||
}
|
||||
return strconv.FormatFloat(result, 'f', -1, 64), nil
|
||||
}
|
||||
|
||||
// WeatherParams is the parameter struct for the GetWeather function.
|
||||
type WeatherParams struct {
|
||||
Location string `json:"location" description:"City name or location"`
|
||||
}
|
||||
|
||||
// GetWeather returns mock weather data (for demo purposes).
|
||||
func GetWeather(_ context.Context, params WeatherParams) (string, error) {
|
||||
weathers := []string{"sunny", "cloudy", "rainy", "partly cloudy", "windy"}
|
||||
temps := []int{65, 72, 58, 80, 45}
|
||||
idx := len(params.Location) % len(weathers)
|
||||
|
||||
out := map[string]any{
|
||||
"location": params.Location,
|
||||
"temperature": strconv.Itoa(temps[idx]) + "F",
|
||||
"condition": weathers[idx],
|
||||
"humidity": "45%",
|
||||
"note": "This is mock data for demonstration purposes",
|
||||
}
|
||||
b, err := json.Marshal(out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// RandomNumberParams is the parameter struct for the RandomNumber function.
|
||||
type RandomNumberParams struct {
|
||||
Min int `json:"min" description:"Minimum value (inclusive)"`
|
||||
Max int `json:"max" description:"Maximum value (inclusive)"`
|
||||
}
|
||||
|
||||
// RandomNumber generates a pseudo-random number (using current time nanoseconds).
|
||||
func RandomNumber(_ context.Context, params RandomNumberParams) (string, error) {
|
||||
if params.Min > params.Max {
|
||||
return "", fmt.Errorf("min cannot be greater than max")
|
||||
}
|
||||
n := time.Now().UnixNano()
|
||||
rangeSize := params.Max - params.Min + 1
|
||||
result := params.Min + int(n%int64(rangeSize))
|
||||
return strconv.Itoa(result), nil
|
||||
}
|
||||
|
||||
// createDemoToolbox creates a toolbox with demo tools for testing.
|
||||
func createDemoToolbox() *llm.ToolBox {
|
||||
return llm.NewToolBox(
|
||||
llm.Define[TimeParams]("get_time", "Get the current date and time", GetTime),
|
||||
llm.Define[CalcParams]("calculate",
|
||||
"Perform basic math operations (add, subtract, multiply, divide, power, sqrt, mod)",
|
||||
Calculate),
|
||||
llm.Define[WeatherParams]("get_weather",
|
||||
"Get weather information for a location (demo data)", GetWeather),
|
||||
llm.Define[RandomNumberParams]("random_number",
|
||||
"Generate a random number between min and max", RandomNumber),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user