Skip to content

Commit 3e0557d

Browse files
author
rainu
committed
don't force the LLM to split command into name and arguments (it works better, if the LLM can just enter shell-like commands)
1 parent 37dffa7 commit 3e0557d

File tree

8 files changed

+39
-54
lines changed

8 files changed

+39
-54
lines changed

frontend/src/components/toolcall/BuiltinToolCallCommandExecution.vue

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,7 @@ export default defineComponent({
4747
return null
4848
},
4949
title(){
50-
let line = this.parsedArguments.name
51-
if(this.parsedArguments.arguments) {
52-
if (Array.isArray(this.parsedArguments.arguments)) {
53-
line += " " + this.parsedArguments.arguments.join(' ')
54-
} else {
55-
line += " " + this.parsedArguments.arguments
56-
}
57-
}
50+
let line = this.parsedArguments.command
5851
return line
5952
},
6053
resultAsMarkdown(): string {
@@ -71,14 +64,7 @@ export default defineComponent({
7164
})
7265
}
7366
74-
line += this.parsedArguments.name
75-
if(this.parsedArguments.arguments) {
76-
if (Array.isArray(this.parsedArguments.arguments)) {
77-
line += " " + this.parsedArguments.arguments.join(' ')
78-
} else {
79-
line += " " + this.parsedArguments.arguments
80-
}
81-
}
67+
line += this.parsedArguments.command
8268
8369
if(this.parsedResult) {
8470
line += '\n' + this.parsedResult.trim() + '\n```'

frontend/wailsjs/go/models.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -678,8 +678,7 @@ export namespace builtin {
678678
export namespace command {
679679

680680
export class CommandExecutionArguments {
681-
name: string;
682-
arguments: string[];
681+
command: string;
683682
working_directory: string;
684683
environment: Record<string, string>;
685684
out: boolean;
@@ -693,8 +692,7 @@ export namespace command {
693692

694693
constructor(source: any = {}) {
695694
if ('string' === typeof source) source = JSON.parse(source);
696-
this.name = source["name"];
697-
this.arguments = source["arguments"];
695+
this.command = source["command"];
698696
this.working_directory = source["working_directory"];
699697
this.environment = source["environment"];
700698
this.out = source["out"];
@@ -1704,7 +1702,7 @@ export namespace http {
17041702
export class CallResult {
17051703
status_code: number;
17061704
status: string;
1707-
header: Record<string, string[]>;
1705+
header: Record<string, Array<string>>;
17081706
body: string;
17091707

17101708
static createFrom(source: any = {}) {

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ require (
1616
github.com/kteru/reversereader v0.0.0-20190328040929-bd5e29d6c056
1717
github.com/mark3labs/mcp-go v0.27.1
1818
github.com/olekukonko/tablewriter v0.0.5
19-
github.com/rainu/go-command-chain v0.4.0
19+
github.com/rainu/go-command-chain v0.5.1
2020
github.com/rainu/go-yacl v0.3.0
2121
github.com/shirou/gopsutil/v4 v4.25.2
2222
github.com/stretchr/testify v1.10.0
2323
github.com/tmc/langchaingo v0.1.13
2424
github.com/wailsapp/wails/v2 v2.10.1
25-
mvdan.cc/sh/v3 v3.7.0
25+
mvdan.cc/sh/v3 v3.12.0
2626
)
2727

2828
require (
@@ -91,7 +91,7 @@ require (
9191
golang.org/x/net v0.38.0 // indirect
9292
golang.org/x/oauth2 v0.25.0 // indirect
9393
golang.org/x/sync v0.12.0 // indirect
94-
golang.org/x/sys v0.31.0 // indirect
94+
golang.org/x/sys v0.33.0 // indirect
9595
golang.org/x/text v0.23.0 // indirect
9696
golang.org/x/time v0.9.0 // indirect
9797
google.golang.org/api v0.218.0 // indirect

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
2121
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
2222
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
2323
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
24-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2524
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2625
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2726
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
@@ -50,6 +49,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
5049
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
5150
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
5251
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
52+
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
53+
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
5354
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
5455
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
5556
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
@@ -132,25 +133,23 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
132133
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
133134
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
134135
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
135-
github.com/rainu/go-command-chain v0.4.0 h1:qgrNbNsqkTfJHdwGzVuGPPK+p+XSnGAhAT/8x1A8SLE=
136-
github.com/rainu/go-command-chain v0.4.0/go.mod h1:RvLsDKnTGD9XoUY7nmBz73ayffI0bFCDH/EVJPRgfks=
136+
github.com/rainu/go-command-chain v0.5.1 h1:WRkD6yXSh2/hbV45aT9pd/buIzZuiR6ODNVeKivt4L8=
137+
github.com/rainu/go-command-chain v0.5.1/go.mod h1:a6Da8cW7zE/cppCVh92WVW+ROaVTpcRu1H/iW46YHKo=
137138
github.com/rainu/go-yacl v0.3.0 h1:bXMS2wE2ZPGrmrlAyBGuU5ojRoqtkmpoOYwYvTpVHi4=
138139
github.com/rainu/go-yacl v0.3.0/go.mod h1:cZwUkCDYE1w6xlTUi6vCqdV1O3iLvM/govQdUn6I9NU=
139140
github.com/rainu/langchaingo v0.0.0-20250604143547-beb77b25378e h1:YBpd7ThvG8zlQHvHyQ5otTM8Xgb5zeupdO3Z88f/GAg=
140141
github.com/rainu/langchaingo v0.0.0-20250604143547-beb77b25378e/go.mod h1:5TXP7bKcWjN05g9e2+MpqUXprf5jwI62Q2xGtAKLno8=
141142
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
142143
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
143144
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
144-
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
145-
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
145+
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
146+
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
146147
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
147148
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
148149
github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk=
149150
github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA=
150151
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
151152
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
152-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
153-
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
154153
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
155154
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
156155
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
@@ -189,6 +188,8 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiy
189188
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
190189
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
191190
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
191+
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
192+
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
192193
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
193194
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
194195
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -208,8 +209,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
208209
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
209210
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
210211
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
211-
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
212-
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
212+
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
213+
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
213214
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
214215
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
215216
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
@@ -235,10 +236,9 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
235236
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
236237
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
237238
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
238-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
239239
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
240240
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
241-
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
242-
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
241+
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=
242+
mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
243243
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
244244
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

internal/config/help.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func printHelpExpression(output io.Writer) {
215215
je := json.NewEncoder(&js)
216216
je.SetIndent(" ", " ")
217217
je.Encode(mcpCommand.CommandDescriptor{
218-
Command: "/path/to/command",
218+
Name: "/path/to/command",
219219
Arguments: []string{"arg1", "...argN"},
220220
Environment: map[string]string{
221221
"ENV_VAR": "value",

internal/config/model/llm/tools/command/command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func (c Command) CommandFn(fd FunctionDefinition) CommandFn {
2525
cmdDesc := command.CommandDescriptor{}
2626
var err error
2727

28-
cmdDesc.Command, cmdDesc.Arguments, err = fd.GetCommandWithArgs(argsAsJson)
28+
cmdDesc.Name, cmdDesc.Arguments, err = fd.GetCommandWithArgs(argsAsJson)
2929
if err != nil {
3030
return nil, fmt.Errorf("error creating command for tool '%s': %w", fd.Name, err)
3131
}

internal/mcp/server/builtin/tools/command/command.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111
)
1212

1313
type CommandDescriptor struct {
14-
Command string `json:"command"`
15-
Arguments []string `json:"arguments"`
14+
CommandLine string `json:"command,omitempty"`
15+
Name string `json:"name,omitempty"`
16+
Arguments []string `json:"arguments,omitempty"`
1617
Environment map[string]string `json:"env"`
1718
AdditionalEnvironment map[string]string `json:"additionalEnv"`
1819
WorkingDirectory string `json:"workingDir"`
@@ -27,7 +28,13 @@ type OutputSettings struct {
2728
}
2829

2930
func (c CommandDescriptor) Run(ctx context.Context) ([]byte, error) {
30-
cmdBuild := cmdchain.Builder().JoinWithContext(ctx, c.Command, c.Arguments...)
31+
var cmdBuild cmdchain.CommandBuilder
32+
33+
if c.CommandLine != "" {
34+
cmdBuild = cmdchain.Builder().JoinShellCmdWithContext(ctx, c.CommandLine)
35+
} else {
36+
cmdBuild = cmdchain.Builder().JoinWithContext(ctx, c.Name, c.Arguments...)
37+
}
3138

3239
if len(c.Environment) > 0 {
3340
cmdBuild = cmdBuild.WithEnvironmentMap(toAnyMap(c.Environment))

internal/mcp/server/builtin/tools/command/exec.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import (
99
)
1010

1111
type CommandExecutionArguments struct {
12-
Name string `json:"name"`
13-
Arguments []string `json:"arguments"`
12+
Command string `json:"command"`
1413
WorkingDirectory string `json:"working_directory"`
1514
Environment map[string]string `json:"environment"`
1615

@@ -26,14 +25,10 @@ var defaultCommandExecutionArguments = CommandExecutionArguments{
2625
}
2726

2827
var CommandExecutionTool = mcp.NewTool("executeCommand",
29-
mcp.WithDescription("Execute a command on the user's system."),
30-
mcp.WithString("name",
28+
mcp.WithDescription(`Execute a command on the user's system. Concatenations with binary operators like "&&" or "||" are not supported.`),
29+
mcp.WithString("command",
3130
mcp.Required(),
32-
mcp.Description("The name / path to the command to execute."),
33-
),
34-
mcp.WithArray("arguments",
35-
mcp.Description("The arguments for the command. Must be a list of strings."),
36-
mcp.Items(map[string]any{"type": "string"}),
31+
mcp.Description("The shell-like command to execute."),
3732
),
3833
mcp.WithString("working_directory",
3934
mcp.Description("The working directory for the command."),
@@ -75,13 +70,12 @@ var CommandExecutionToolHandler = func(ctx context.Context, request mcp.CallTool
7570
return nil, fmt.Errorf("error parsing arguments: %w", err)
7671
}
7772

78-
if pArgs.Name == "" {
79-
return nil, fmt.Errorf("missing parameter: 'name'")
73+
if pArgs.Command == "" {
74+
return nil, fmt.Errorf("missing parameter: 'command'")
8075
}
8176

8277
cmdDesc := CommandDescriptor{
83-
Command: pArgs.Name,
84-
Arguments: pArgs.Arguments,
78+
CommandLine: pArgs.Command,
8579
AdditionalEnvironment: pArgs.Environment,
8680
WorkingDirectory: pArgs.WorkingDirectory,
8781
Output: &OutputSettings{

0 commit comments

Comments
 (0)