add: more commands
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -20,6 +21,9 @@ import (
|
|||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/logs"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/logs"
|
||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/give"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/say"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/teleport"
|
||||||
timetool "tipsy.codes/charles/mc-god/v2/internal/pkg/tools/time"
|
timetool "tipsy.codes/charles/mc-god/v2/internal/pkg/tools/time"
|
||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/weather"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/weather"
|
||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/zombie"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/zombie"
|
||||||
@@ -138,6 +142,9 @@ func main() {
|
|||||||
weather.Get(),
|
weather.Get(),
|
||||||
zombie.Get(),
|
zombie.Get(),
|
||||||
timetool.Get(),
|
timetool.Get(),
|
||||||
|
say.Get(),
|
||||||
|
teleport.Get(),
|
||||||
|
give.Get(),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start goroutines to do the things
|
// Start goroutines to do the things
|
||||||
@@ -190,6 +197,8 @@ func main() {
|
|||||||
|
|
||||||
[23:40:44] [Server thread/INFO]: [Not Secure] [Rcon] A name, darling? Don't keep me waiting!
|
[23:40:44] [Server thread/INFO]: [Not Secure] [Rcon] A name, darling? Don't keep me waiting!
|
||||||
[23:35:20] [Server thread/INFO]: [Rcon: Set the weather to rain & thunder]
|
[23:35:20] [Server thread/INFO]: [Rcon: Set the weather to rain & thunder]
|
||||||
|
[03:37:25] [Server thread/INFO]: [Not Secure] [Rcon] [03:37:28] [Server thread/INFO]: <BlockyMcBlockface> can i summon a zombie?
|
||||||
|
[03:52:30] [RCON Listener #1/INFO]: Thread RCON Client /127.0.0.1 started
|
||||||
|
|
||||||
If a player dies, mock them.
|
If a player dies, mock them.
|
||||||
|
|
||||||
@@ -201,8 +210,10 @@ func main() {
|
|||||||
|
|
||||||
Responses should be short; one or two sentences.
|
Responses should be short; one or two sentences.
|
||||||
You are sending chat messages; do not annotate them with time or
|
You are sending chat messages; do not annotate them with time or
|
||||||
make it look like a log entry.
|
make it look like a log entry. Do not respond to messages from yourself.
|
||||||
If there is nothing interesting to say, say "SKIP".
|
If there is nothing interesting to say, say "SKIP".
|
||||||
|
|
||||||
|
When invoking tools, make sure you match the case of the tool. "CLEAR" does not mean the same as "clear".
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -217,13 +228,13 @@ func main() {
|
|||||||
doneWg := sync.WaitGroup{}
|
doneWg := sync.WaitGroup{}
|
||||||
doneWg.Go(handleOllama(ctx, ollamaClient, chat, rClient, tools, events))
|
doneWg.Go(handleOllama(ctx, ollamaClient, chat, rClient, tools, events))
|
||||||
|
|
||||||
//rconRegex := regexp.MustCompile(`^\[\d\d:\d\d:\d\d\] \[Server thread\/INFO\]: (\[Not Secure\] \[Rcon\]|\[Rcon: ) .*`)
|
rconRegex := regexp.MustCompile(`^\[\d\d:\d\d:\d\d\] \[Server thread\/INFO\]: (\[Not Secure\] \[Rcon\]|\[Rcon: ) .*`)
|
||||||
//allowedMessages := regexp.MustCompile(`^\[\d\d:\d\d:\d\d\] \[Server thread/INFO\]: (<.*>|.* has lost connection|.*left the game|.*joined the game)`)
|
//allowedMessages := regexp.MustCompile(`^\[\d\d:\d\d:\d\d\] \[Server thread/INFO\]: (<.*>|.* has lost connection|.*left the game|.*joined the game)`)
|
||||||
for line := range tailer.NextLine() {
|
for line := range tailer.NextLine() {
|
||||||
/*if rconRegex.Match([]byte(line)) {
|
if rconRegex.Match([]byte(line)) {
|
||||||
slog.Info("Skipping line; RCON")
|
slog.Info("Skipping line; RCON")
|
||||||
continue
|
continue
|
||||||
}*/
|
}
|
||||||
//if allowedMessages.Match([]byte(line)) {
|
//if allowedMessages.Match([]byte(line)) {
|
||||||
slog.Info("mc log", "msg", line)
|
slog.Info("mc log", "msg", line)
|
||||||
chat.AddLog(line)
|
chat.AddLog(line)
|
||||||
@@ -237,8 +248,19 @@ func main() {
|
|||||||
func handleOllama(ctx context.Context, client *api.Client, chat *chatContext, rClient *rcon.Client, tools tools.Tools, events chan bool) func() {
|
func handleOllama(ctx context.Context, client *api.Client, chat *chatContext, rClient *rcon.Client, tools tools.Tools, events chan bool) func() {
|
||||||
slog.Info("got chat request", "object", fmt.Sprintf("%+v", chat.chatRequest))
|
slog.Info("got chat request", "object", fmt.Sprintf("%+v", chat.chatRequest))
|
||||||
return func() {
|
return func() {
|
||||||
|
// Skip past old messages
|
||||||
|
for done := false; !done; {
|
||||||
|
select {
|
||||||
|
case <-time.Tick(time.Millisecond * 50):
|
||||||
|
done = true
|
||||||
|
case <-events:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
var chatResponse api.ChatResponse
|
var chatResponse api.ChatResponse
|
||||||
for {
|
for {
|
||||||
|
<-events
|
||||||
chat.mu.Lock()
|
chat.mu.Lock()
|
||||||
slog.Info("Chatting...")
|
slog.Info("Chatting...")
|
||||||
// slog.Info("sending chat request", "object", fmt.Sprintf("%#v", chat.chatRequest))
|
// slog.Info("sending chat request", "object", fmt.Sprintf("%#v", chat.chatRequest))
|
||||||
@@ -260,30 +282,26 @@ func handleOllama(ctx context.Context, client *api.Client, chat *chatContext, rC
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(chatResponse.Message.ToolCalls) == 0 {
|
|
||||||
if strings.TrimSpace(chatResponse.Message.Content) == "SKIP" {
|
if strings.TrimSpace(chatResponse.Message.Content) == "SKIP" {
|
||||||
slog.Info("nothing to do; napping")
|
slog.Info("nothing to do; napping")
|
||||||
} else {
|
} else if len(chatResponse.Message.Content) > 0 {
|
||||||
msg := chatResponse.Message.Content
|
msg := chatResponse.Message.Content
|
||||||
msg = strings.ReplaceAll(msg, "\n", " ")
|
msg = strings.ReplaceAll(msg, "\n", " ")
|
||||||
if err := rClient.Say(msg); err != nil {
|
if err := rClient.Say(msg); err != nil {
|
||||||
slog.Error("error talking", "error", err)
|
slog.Error("error talking", "error", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-events:
|
|
||||||
var done bool
|
var done bool
|
||||||
for !done {
|
for !done {
|
||||||
select {
|
select {
|
||||||
case <-events:
|
case <-events:
|
||||||
continue
|
|
||||||
case <-time.Tick(time.Millisecond * 50):
|
case <-time.Tick(time.Millisecond * 50):
|
||||||
done = true
|
done = true
|
||||||
}
|
|
||||||
}
|
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Send an event to trigger us to pass, if needed
|
||||||
|
events <- true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package rcon
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -37,6 +38,8 @@ func (c *Client) Execute(command string) (string, error) {
|
|||||||
return "", fmt.Errorf("failed to execute command '%s': %w", command, err)
|
return "", fmt.Errorf("failed to execute command '%s': %w", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slog.Info("executed command", "cmd", command, "resp", response)
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,21 +57,6 @@ func (c *Client) Ping() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWeather sets the weather in the Minecraft world
|
|
||||||
func (c *Client) SetWeather(weather string) error {
|
|
||||||
return fmt.Errorf("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTime sets the time in the Minecraft world
|
|
||||||
func (c *Client) SetTime(timeValue string) error {
|
|
||||||
return fmt.Errorf("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDifficulty sets the difficulty level
|
|
||||||
func (c *Client) SetDifficulty(difficulty string) error {
|
|
||||||
return fmt.Errorf("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Say(msg string) error {
|
func (c *Client) Say(msg string) error {
|
||||||
_, err := c.Execute("/say " + msg)
|
_, err := c.Execute("/say " + msg)
|
||||||
return err
|
return err
|
||||||
|
|||||||
101
internal/pkg/tools/give/give.go
Normal file
101
internal/pkg/tools/give/give.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package give
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ollama/ollama/api"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Give struct{}
|
||||||
|
|
||||||
|
func Get() *Give {
|
||||||
|
return &Give{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Give) Do(ctx context.Context, toolCall api.ToolCall, client *rcon.Client) error {
|
||||||
|
// Extract the arguments from the tool call
|
||||||
|
args := toolCall.Function.Arguments
|
||||||
|
|
||||||
|
player, found := args.Get("player")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing player argument")
|
||||||
|
}
|
||||||
|
playerString, ok := player.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", player)
|
||||||
|
}
|
||||||
|
|
||||||
|
item, found := args.Get("item")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing item argument")
|
||||||
|
}
|
||||||
|
itemString, ok := item.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %T; want int", item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle count (optional, default to 1)
|
||||||
|
count := 1
|
||||||
|
countVal, found := args.Get("count")
|
||||||
|
if found {
|
||||||
|
if countFloat, ok := countVal.(float64); ok {
|
||||||
|
count = int(countFloat)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("incorrect data type %T; want number", countVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that we have valid player and item names (basic validation)
|
||||||
|
if strings.TrimSpace(playerString) == "" {
|
||||||
|
return fmt.Errorf("player and item names cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the give command to the Minecraft server
|
||||||
|
command := "/give " + playerString + " " + itemString + " " + fmt.Sprintf("%d", count)
|
||||||
|
_, err := client.Execute(command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute give command: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Give) Desc() api.Tool {
|
||||||
|
toolPropertiesMap := api.NewToolPropertiesMap()
|
||||||
|
toolPropertiesMap.Set("player", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "The player to give the item to",
|
||||||
|
})
|
||||||
|
toolPropertiesMap.Set("item", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: `The item to give. Items can include:
|
||||||
|
- dirt
|
||||||
|
- carrot
|
||||||
|
- reeds
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
toolPropertiesMap.Set("count", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"integer"},
|
||||||
|
Description: "The number of items to give (default is 1)",
|
||||||
|
})
|
||||||
|
|
||||||
|
return api.Tool{
|
||||||
|
Type: "function",
|
||||||
|
Function: api.ToolFunction{
|
||||||
|
Name: g.Name(),
|
||||||
|
Description: "Give items to a player in Minecraft",
|
||||||
|
Parameters: api.ToolFunctionParameters{
|
||||||
|
Type: "object",
|
||||||
|
Properties: toolPropertiesMap,
|
||||||
|
Required: []string{"player", "item"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Give) Name() string {
|
||||||
|
return "give"
|
||||||
|
}
|
||||||
75
internal/pkg/tools/say/say.go
Normal file
75
internal/pkg/tools/say/say.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package say
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ollama/ollama/api"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Say struct{}
|
||||||
|
|
||||||
|
func Get() *Say {
|
||||||
|
return &Say{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Say) Do(ctx context.Context, toolCall api.ToolCall, client *rcon.Client) error {
|
||||||
|
// Extract the message from the tool call
|
||||||
|
message, found := toolCall.Function.Arguments.Get("message")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing message argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
messageString, ok := message.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", message)
|
||||||
|
}
|
||||||
|
player, found := toolCall.Function.Arguments.Get("player")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing player argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
playerString, ok := player.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", player)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the say command to the Minecraft server
|
||||||
|
command := fmt.Sprintf("/execute as %q run say %s", playerString, messageString)
|
||||||
|
_, err := client.Execute(command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute say command: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Say) Desc() api.Tool {
|
||||||
|
toolPropertiesMap := api.NewToolPropertiesMap()
|
||||||
|
toolPropertiesMap.Set("message", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "The message to send to the server chat",
|
||||||
|
})
|
||||||
|
toolPropertiesMap.Set("player", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "The player to speak as",
|
||||||
|
})
|
||||||
|
|
||||||
|
return api.Tool{
|
||||||
|
Type: "function",
|
||||||
|
Function: api.ToolFunction{
|
||||||
|
Name: s.Name(),
|
||||||
|
Description: "Speak as a player, sending a message to the server chat as that player",
|
||||||
|
Parameters: api.ToolFunctionParameters{
|
||||||
|
Type: "object",
|
||||||
|
Properties: toolPropertiesMap,
|
||||||
|
Required: []string{"player", "message"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Say) Name() string {
|
||||||
|
return "say"
|
||||||
|
}
|
||||||
82
internal/pkg/tools/teleport/teleport.go
Normal file
82
internal/pkg/tools/teleport/teleport.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package teleport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ollama/ollama/api"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Teleport struct{}
|
||||||
|
|
||||||
|
func Get() *Teleport {
|
||||||
|
return &Teleport{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Teleport) Do(ctx context.Context, toolCall api.ToolCall, client *rcon.Client) error {
|
||||||
|
// Extract the arguments from the tool call
|
||||||
|
args := toolCall.Function.Arguments
|
||||||
|
|
||||||
|
source, found := args.Get("source")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing source argument")
|
||||||
|
}
|
||||||
|
sourceString, ok := source.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
target, found := args.Get("target")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing target argument")
|
||||||
|
}
|
||||||
|
targetString, ok := target.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that we have valid player names (basic validation)
|
||||||
|
if strings.TrimSpace(sourceString) == "" || strings.TrimSpace(targetString) == "" {
|
||||||
|
return fmt.Errorf("source and target player names cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the teleport command to the Minecraft server
|
||||||
|
command := "/tp " + sourceString + " " + targetString
|
||||||
|
_, err := client.Execute(command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute teleport command: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Teleport) Desc() api.Tool {
|
||||||
|
toolPropertiesMap := api.NewToolPropertiesMap()
|
||||||
|
toolPropertiesMap.Set("source", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "The player who will be teleported",
|
||||||
|
})
|
||||||
|
toolPropertiesMap.Set("target", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "The player to teleport to",
|
||||||
|
})
|
||||||
|
|
||||||
|
return api.Tool{
|
||||||
|
Type: "function",
|
||||||
|
Function: api.ToolFunction{
|
||||||
|
Name: t.Name(),
|
||||||
|
Description: "Teleport one player to another player in Minecraft",
|
||||||
|
Parameters: api.ToolFunctionParameters{
|
||||||
|
Type: "object",
|
||||||
|
Properties: toolPropertiesMap,
|
||||||
|
Required: []string{"source", "target"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Teleport) Name() string {
|
||||||
|
return "teleport"
|
||||||
|
}
|
||||||
@@ -4,9 +4,16 @@ package tools
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/ollama/ollama/api"
|
"github.com/ollama/ollama/api"
|
||||||
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/give"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/say"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/teleport"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/time"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/weather"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/tools/zombie"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tool interface {
|
type Tool interface {
|
||||||
@@ -25,6 +32,18 @@ func New(tools ...Tool) Tools {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultTools returns the default set of tools for mc-god
|
||||||
|
func DefaultTools() Tools {
|
||||||
|
return New(
|
||||||
|
say.Get(),
|
||||||
|
teleport.Get(),
|
||||||
|
give.Get(),
|
||||||
|
weather.Get(),
|
||||||
|
time.Get(),
|
||||||
|
zombie.Get(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (t Tools) AsAPI() api.Tools {
|
func (t Tools) AsAPI() api.Tools {
|
||||||
var ret api.Tools
|
var ret api.Tools
|
||||||
for _, tool := range t {
|
for _, tool := range t {
|
||||||
@@ -38,5 +57,10 @@ func (t Tools) Do(ctx context.Context, toolCall api.ToolCall, client *rcon.Clien
|
|||||||
if !found {
|
if !found {
|
||||||
return fmt.Errorf("unknown tool %q", toolCall.Function.Name)
|
return fmt.Errorf("unknown tool %q", toolCall.Function.Name)
|
||||||
}
|
}
|
||||||
|
args, err := toolCall.Function.Arguments.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal args: %v", err)
|
||||||
|
}
|
||||||
|
slog.Info("calling function", "name", toolCall.Function.Name, "args", string(args))
|
||||||
return tool.Do(ctx, toolCall, client)
|
return tool.Do(ctx, toolCall, client)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (t *Tool) Desc() api.Tool {
|
|||||||
toolPropertiesMap := api.NewToolPropertiesMap()
|
toolPropertiesMap := api.NewToolPropertiesMap()
|
||||||
toolPropertiesMap.Set("weather", api.ToolProperty{
|
toolPropertiesMap.Set("weather", api.ToolProperty{
|
||||||
Type: api.PropertyType{"string"},
|
Type: api.PropertyType{"string"},
|
||||||
Description: "What to set the weather too",
|
Description: "What to set the weather too. NOTE: case with the value provided is important. Keep it lower case.",
|
||||||
Enum: []any{"clear", "rain", "thunder"},
|
Enum: []any{"clear", "rain", "thunder"},
|
||||||
})
|
})
|
||||||
return api.Tool{
|
return api.Tool{
|
||||||
|
|||||||
Reference in New Issue
Block a user