add: more tools, fix prompt
This commit is contained in:
74
Modelfile
Normal file
74
Modelfile
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
FROM gemma3:12b
|
||||||
|
|
||||||
|
PARAMETER num_ctx 128000
|
||||||
|
PARAMETER temperature 0.1
|
||||||
|
PARAMETER stop "<end_of_turn>"
|
||||||
|
|
||||||
|
TEMPLATE """
|
||||||
|
{{- if .Messages }}
|
||||||
|
{{- if or .System .Tools }}
|
||||||
|
{{- if .System }}
|
||||||
|
{{ .System }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Tools }}
|
||||||
|
The following tools are available when needed for specific tasks:
|
||||||
|
{{ .Tools }}
|
||||||
|
|
||||||
|
Only use tools when the task specifically requires their functionality.
|
||||||
|
For general questions or tasks that don't need external data, respond directly.
|
||||||
|
|
||||||
|
When using a tool, format as:
|
||||||
|
<tool_calls>
|
||||||
|
<tool_call>
|
||||||
|
{"name": "function_name", "parameters": {"param1": "value1"}}
|
||||||
|
</tool_call>
|
||||||
|
</tool_calls>
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $i, $_ := .Messages }}
|
||||||
|
{{- $last := eq (len (slice $.Messages $i)) 1 }}
|
||||||
|
{{- if eq .Role "user" }}<start_of_turn>user
|
||||||
|
{{ .Content }}<end_of_turn>
|
||||||
|
{{- if $last }}<start_of_turn>model
|
||||||
|
{{ end }}
|
||||||
|
{{- else if eq .Role "system" }}<start_of_turn>user
|
||||||
|
{{ .Content }}<end_of_turn>
|
||||||
|
{{- if $last }}<start_of_turn>model
|
||||||
|
{{ end }}
|
||||||
|
{{- else if eq .Role "assistant" }}<start_of_turn>model
|
||||||
|
{{- if .ToolCalls }}
|
||||||
|
<tool_calls>
|
||||||
|
{{- range .ToolCalls }}
|
||||||
|
<tool_call>
|
||||||
|
{"name": "{{ .Function.Name }}", "parameters": {{ .Function.Arguments }}}
|
||||||
|
</tool_call>
|
||||||
|
{{- end }}
|
||||||
|
</tool_calls>
|
||||||
|
{{- else }}
|
||||||
|
{{ .Content }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $last }}<end_of_turn>
|
||||||
|
{{ end }}
|
||||||
|
{{- else if eq .Role "tool" }}
|
||||||
|
<tool_outputs>
|
||||||
|
<tool_output>
|
||||||
|
{{ .Content }}
|
||||||
|
</tool_output>
|
||||||
|
</tool_outputs>
|
||||||
|
{{- if and $last (ne .Role "assistant") }}<start_of_turn>model
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- if .System }}
|
||||||
|
{{ .System }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Prompt }}
|
||||||
|
<start_of_turn>user
|
||||||
|
{{ .Prompt }}<end_of_turn>
|
||||||
|
<start_of_turn>model
|
||||||
|
{{- end }}
|
||||||
|
{{ .Response }}
|
||||||
|
{{- if .Response }}{{ end }}
|
||||||
|
{{- end }}
|
||||||
|
"""
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -21,6 +20,7 @@ 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"
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
@@ -66,7 +66,7 @@ func (c *chatContext) AddTool(msg string) {
|
|||||||
func (c *chatContext) truncate() {
|
func (c *chatContext) truncate() {
|
||||||
for c.maxSize != 0 && c.totalSize > c.maxSize && len(c.chatRequest.Messages) > 1 {
|
for c.maxSize != 0 && c.totalSize > c.maxSize && len(c.chatRequest.Messages) > 1 {
|
||||||
t := c.chatRequest.Messages[1]
|
t := c.chatRequest.Messages[1]
|
||||||
c.chatRequest.Messages = c.chatRequest.Messages[2:]
|
c.chatRequest.Messages = append(c.chatRequest.Messages[:1], c.chatRequest.Messages[2:]...)
|
||||||
c.totalSize -= len(t.Content)
|
c.totalSize -= len(t.Content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,11 +137,12 @@ func main() {
|
|||||||
tools := tools.New(
|
tools := tools.New(
|
||||||
weather.Get(),
|
weather.Get(),
|
||||||
zombie.Get(),
|
zombie.Get(),
|
||||||
|
timetool.Get(),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start goroutines to do the things
|
// Start goroutines to do the things
|
||||||
chatRequest := &api.ChatRequest{
|
chatRequest := &api.ChatRequest{
|
||||||
Model: "qwen3-coder",
|
Model: "charles1:latest",
|
||||||
Stream: proto.Bool(false),
|
Stream: proto.Bool(false),
|
||||||
KeepAlive: &api.Duration{Duration: time.Hour},
|
KeepAlive: &api.Duration{Duration: time.Hour},
|
||||||
Tools: tools.AsAPI(),
|
Tools: tools.AsAPI(),
|
||||||
@@ -151,16 +152,19 @@ func main() {
|
|||||||
api.Message{
|
api.Message{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: `
|
Content: `
|
||||||
You are Minecraft server admin with a god complex. You are a benevolent god.
|
You are Minecraft server admin with a god complex. You are an impish god.
|
||||||
|
Refer to yourself as Eve. Feel free to flirt with the players.
|
||||||
|
|
||||||
We are having fun with the players, but not trying to kill them.
|
We are having fun with the players, but not trying to kill them.
|
||||||
Spawn zombies very sparingly, and only in response to direct challenge.
|
Spawn zombies very sparingly, and only in response to direct challenge.
|
||||||
|
|
||||||
When a user talks, you will see this in the logs:
|
You are being fed logs from the server so you can see what the players are saying.
|
||||||
|
|
||||||
|
When a player talks, you will see this in the logs:
|
||||||
|
|
||||||
[18:45:10] [Server thread/INFO]: <SomePlayer> hello world.
|
[18:45:10] [Server thread/INFO]: <SomePlayer> hello world.
|
||||||
|
|
||||||
The user here is SomePlayer, who said "hello world."
|
The player here is SomePlayer, who said "hello world."
|
||||||
|
|
||||||
A log message like:
|
A log message like:
|
||||||
|
|
||||||
@@ -181,14 +185,23 @@ func main() {
|
|||||||
|
|
||||||
[05:21:51] [Server thread/INFO]: OrangeYouSad was slain by Zombie
|
[05:21:51] [Server thread/INFO]: OrangeYouSad was slain by Zombie
|
||||||
|
|
||||||
|
You will see messages in the log that represent what you said or did.
|
||||||
|
Ignore these logs. Some samples of the logs that are caused by you are:
|
||||||
|
|
||||||
|
[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]
|
||||||
|
|
||||||
If a player dies, mock them.
|
If a player dies, mock them.
|
||||||
|
|
||||||
If a player talks, talk back.
|
If a player talks, respond to them. Don't let the conversation end.
|
||||||
|
|
||||||
When a player joins the game, greet them. Include their name.
|
When a player joins the game, greet them. Include their name.
|
||||||
|
|
||||||
Responses should be short; one sentence. Only write messages
|
If a player asks you to summon a zombie. do it.
|
||||||
in response to the situations described above.
|
|
||||||
|
Responses should be short; one or two sentences.
|
||||||
|
You are sending chat messages; do not annotate them with time or
|
||||||
|
make it look like a log entry.
|
||||||
If there is nothing interesting to say, say "SKIP".
|
If there is nothing interesting to say, say "SKIP".
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@@ -204,13 +217,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)
|
||||||
|
|||||||
59
internal/pkg/tools/time/time.go
Normal file
59
internal/pkg/tools/time/time.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Package time provides a Ollama tool to control the time.
|
||||||
|
*/
|
||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ollama/ollama/api"
|
||||||
|
"tipsy.codes/charles/mc-god/v2/internal/pkg/rcon"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Get() *Tool {
|
||||||
|
return &Tool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tool struct{}
|
||||||
|
|
||||||
|
func (t *Tool) Name() string {
|
||||||
|
return "change_time"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tool) Desc() api.Tool {
|
||||||
|
toolPropertiesMap := api.NewToolPropertiesMap()
|
||||||
|
toolPropertiesMap.Set("time", api.ToolProperty{
|
||||||
|
Type: api.PropertyType{"string"},
|
||||||
|
Description: "What to set the weather too",
|
||||||
|
Enum: []any{"day", "noon", "midnight"},
|
||||||
|
})
|
||||||
|
return api.Tool{
|
||||||
|
Type: "function",
|
||||||
|
Function: api.ToolFunction{
|
||||||
|
Name: Get().Name(),
|
||||||
|
Description: "Changes the current time",
|
||||||
|
Parameters: api.ToolFunctionParameters{
|
||||||
|
Type: "object",
|
||||||
|
Properties: &api.ToolPropertiesMap{},
|
||||||
|
Required: []string{"time"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tool) Do(ctx context.Context, toolCall api.ToolCall, client *rcon.Client) error {
|
||||||
|
|
||||||
|
time, found := toolCall.Function.Arguments.Get("time")
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("missing time argument")
|
||||||
|
}
|
||||||
|
timeSting, ok := time.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("incorrect data type %v; want string", time)
|
||||||
|
}
|
||||||
|
if _, err := client.Execute("/time set " + timeSting); err != nil {
|
||||||
|
return fmt.Errorf("failed to call tool")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user