From bc28accbb7968ea9736ad4ef9d5f05df80a08361 Mon Sep 17 00:00:00 2001 From: N3ko Date: Mon, 17 Nov 2025 10:53:56 +0800 Subject: [PATCH] feat: update commandline (#132) --- adk/multiagent/deep/operator.go | 18 ++++++++++++------ adk/multiagent/deep/tools/bash.go | 11 ++++++++++- adk/multiagent/deep/tools/python_runner.go | 11 ++++++----- adk/multiagent/deep/tools/read.go | 10 +++++++--- adk/multiagent/deep/tools/tree.go | 12 ++++++++++-- adk/multiagent/deep/utils/utils.go | 5 +++++ .../integration-excel-agent/operator.go | 18 ++++++++++++------ .../integration-excel-agent/tools/bash.go | 11 ++++++++++- .../tools/python_runner.go | 11 ++++++----- .../integration-excel-agent/tools/read.go | 10 +++++++--- .../integration-excel-agent/tools/tree.go | 12 ++++++++++-- .../integration-excel-agent/utils/utils.go | 5 +++++ go.mod | 2 +- go.sum | 4 ++-- 14 files changed, 103 insertions(+), 37 deletions(-) diff --git a/adk/multiagent/deep/operator.go b/adk/multiagent/deep/operator.go index 1dd2e39..94d582b 100644 --- a/adk/multiagent/deep/operator.go +++ b/adk/multiagent/deep/operator.go @@ -23,8 +23,10 @@ import ( "os" "os/exec" "runtime" + "strings" "github.com/cloudwego/eino-examples/adk/multiagent/deep/params" + "github.com/cloudwego/eino-ext/components/tool/commandline" ) type LocalOperator struct{} @@ -49,18 +51,18 @@ func (l *LocalOperator) Exists(ctx context.Context, path string) (bool, error) { return true, nil } -func (l *LocalOperator) RunCommand(ctx context.Context, command string) (string, error) { +func (l *LocalOperator) RunCommand(ctx context.Context, command []string) (*commandline.CommandOutput, error) { wd, ok := params.GetTypedContextParams[string](ctx, params.WorkDirSessionKey) if !ok { - return "", fmt.Errorf("work dir not found") + return nil, fmt.Errorf("work dir not found") } var shellCmd []string switch runtime.GOOS { case "windows": - shellCmd = []string{"cmd.exe", "/C", command} + shellCmd = append([]string{"cmd.exe", "/C"}, command...) default: - shellCmd = []string{"/bin/sh", "-c", command} + shellCmd = []string{"/bin/sh", "-c", strings.Join(command, " ")} } cmd := exec.CommandContext(ctx, shellCmd[0], shellCmd[1:]...) @@ -72,7 +74,11 @@ func (l *LocalOperator) RunCommand(ctx context.Context, command string) (string, cmd.Stderr = errBuf err := cmd.Run() if err != nil { - return fmt.Sprintf("internal error:\ncommand: %v\n\nexec error: %v", cmd.String(), errBuf.String()), nil + err = fmt.Errorf("internal error:\ncommand: %v\n\nerr: %v\n\nexec error: %v", cmd.String(), err, errBuf.String()) + return nil, err } - return outBuf.String(), nil + return &commandline.CommandOutput{ + Stdout: outBuf.String(), + Stderr: errBuf.String(), + }, nil } diff --git a/adk/multiagent/deep/tools/bash.go b/adk/multiagent/deep/tools/bash.go index d268005..467365b 100644 --- a/adk/multiagent/deep/tools/bash.go +++ b/adk/multiagent/deep/tools/bash.go @@ -19,7 +19,9 @@ package tools import ( "context" "encoding/json" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/deep/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -72,5 +74,12 @@ func (b *bashTool) InvokableRun(ctx context.Context, argumentsInJSON string, opt return "command cannot be empty", nil } o := tool.GetImplSpecificOptions(&options{b.op}, opts...) - return o.op.RunCommand(ctx, input.Command) + cmd, err := o.op.RunCommand(ctx, []string{input.Command}) + if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } + return "", err + } + return utils.FormatCommandOutput(cmd), nil } diff --git a/adk/multiagent/deep/tools/python_runner.go b/adk/multiagent/deep/tools/python_runner.go index 6797098..7322a58 100644 --- a/adk/multiagent/deep/tools/python_runner.go +++ b/adk/multiagent/deep/tools/python_runner.go @@ -24,6 +24,7 @@ import ( "regexp" "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/deep/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -84,14 +85,14 @@ func (p *pythonRunnerTool) InvokableRun(ctx context.Context, argumentsInJSON str if pyExecutablePath == "" { pyExecutablePath = "python" } - result, err := p.op.RunCommand(ctx, fmt.Sprintf("%s %s", pyExecutablePath, filePath)) + result, err := p.op.RunCommand(ctx, []string{pyExecutablePath, filePath}) if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } return "", fmt.Errorf("execute error: %w", err) } - if strings.HasPrefix(result, "internal error") { - result = fmt.Sprintf("%s\n\n code after parse:\n%v", result, code) - } - return result, nil + return utils.FormatCommandOutput(result), nil } func tryExtractCodeSnippet(res string) string { diff --git a/adk/multiagent/deep/tools/read.go b/adk/multiagent/deep/tools/read.go index d8ac79b..da3fb80 100644 --- a/adk/multiagent/deep/tools/read.go +++ b/adk/multiagent/deep/tools/read.go @@ -20,7 +20,9 @@ import ( "context" "encoding/json" "fmt" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/deep/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -85,10 +87,12 @@ func (r *readFile) InvokableRun(ctx context.Context, argumentsInJSON string, opt o := tool.GetImplSpecificOptions(&options{op: r.op}) cmd := fmt.Sprintf("python3 -c \"import sys; lines = (line for idx, line in enumerate(open(sys.argv[1], encoding='utf-8')) if %d <= idx < %d); print(''.join(lines))\" %s", input.StartRow, input.StartRow+input.NRows, input.Path) - content, err := o.op.RunCommand(ctx, cmd) + content, err := o.op.RunCommand(ctx, []string{cmd}) if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } return "", err } - - return content, nil + return utils.FormatCommandOutput(content), nil } diff --git a/adk/multiagent/deep/tools/tree.go b/adk/multiagent/deep/tools/tree.go index eac1404..718d8ed 100644 --- a/adk/multiagent/deep/tools/tree.go +++ b/adk/multiagent/deep/tools/tree.go @@ -19,8 +19,9 @@ package tools import ( "context" "encoding/json" - "fmt" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/deep/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -67,5 +68,12 @@ func (t *tree) InvokableRun(ctx context.Context, argumentsInJSON string, opts .. return "path can not be empty", nil } o := tool.GetImplSpecificOptions(&options{t.op}, opts...) - return o.op.RunCommand(ctx, fmt.Sprintf("find %s", input.Path)) + output, err := o.op.RunCommand(ctx, []string{"find", input.Path}) + if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } + return "", err + } + return utils.FormatCommandOutput(output), nil } diff --git a/adk/multiagent/deep/utils/utils.go b/adk/multiagent/deep/utils/utils.go index 346448b..984056e 100644 --- a/adk/multiagent/deep/utils/utils.go +++ b/adk/multiagent/deep/utils/utils.go @@ -23,6 +23,7 @@ import ( "time" "github.com/bytedance/sonic" + "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/adk" "github.com/cloudwego/eino/adk/prebuilt/planexecute" "github.com/kaptinlin/jsonrepair" @@ -114,3 +115,7 @@ func FormatExecutedSteps(in []planexecute.ExecutedStep) string { } return sb.String() } + +func FormatCommandOutput(output *commandline.CommandOutput) string { + return fmt.Sprintf("---\nstdout:%v\n---\nstderr:%v\n---", output.Stdout, output.Stderr) +} diff --git a/adk/multiagent/integration-excel-agent/operator.go b/adk/multiagent/integration-excel-agent/operator.go index 9abb2fc..801cf0e 100644 --- a/adk/multiagent/integration-excel-agent/operator.go +++ b/adk/multiagent/integration-excel-agent/operator.go @@ -23,8 +23,10 @@ import ( "os" "os/exec" "runtime" + "strings" "github.com/cloudwego/eino-examples/adk/multiagent/integration-excel-agent/params" + "github.com/cloudwego/eino-ext/components/tool/commandline" ) type LocalOperator struct{} @@ -49,18 +51,18 @@ func (l *LocalOperator) Exists(ctx context.Context, path string) (bool, error) { return true, nil } -func (l *LocalOperator) RunCommand(ctx context.Context, command string) (string, error) { +func (l *LocalOperator) RunCommand(ctx context.Context, command []string) (*commandline.CommandOutput, error) { wd, ok := params.GetTypedContextParams[string](ctx, params.WorkDirSessionKey) if !ok { - return "", fmt.Errorf("work dir not found") + return nil, fmt.Errorf("work dir not found") } var shellCmd []string switch runtime.GOOS { case "windows": - shellCmd = []string{"cmd.exe", "/C", command} + shellCmd = append([]string{"cmd.exe", "/C"}, command...) default: - shellCmd = []string{"/bin/sh", "-c", command} + shellCmd = []string{"/bin/sh", "-c", strings.Join(command, " ")} } cmd := exec.CommandContext(ctx, shellCmd[0], shellCmd[1:]...) @@ -72,7 +74,11 @@ func (l *LocalOperator) RunCommand(ctx context.Context, command string) (string, cmd.Stderr = errBuf err := cmd.Run() if err != nil { - return fmt.Sprintf("internal error:\ncommand: %v\n\nexec error: %v", cmd.String(), errBuf.String()), nil + err = fmt.Errorf("internal error:\ncommand: %v\n\nerr: %v\n\nexec error: %v", cmd.String(), err, errBuf.String()) + return nil, err } - return outBuf.String(), nil + return &commandline.CommandOutput{ + Stdout: outBuf.String(), + Stderr: errBuf.String(), + }, nil } diff --git a/adk/multiagent/integration-excel-agent/tools/bash.go b/adk/multiagent/integration-excel-agent/tools/bash.go index d268005..367e28f 100644 --- a/adk/multiagent/integration-excel-agent/tools/bash.go +++ b/adk/multiagent/integration-excel-agent/tools/bash.go @@ -19,7 +19,9 @@ package tools import ( "context" "encoding/json" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/integration-excel-agent/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -72,5 +74,12 @@ func (b *bashTool) InvokableRun(ctx context.Context, argumentsInJSON string, opt return "command cannot be empty", nil } o := tool.GetImplSpecificOptions(&options{b.op}, opts...) - return o.op.RunCommand(ctx, input.Command) + cmd, err := o.op.RunCommand(ctx, []string{input.Command}) + if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } + return "", err + } + return utils.FormatCommandOutput(cmd), nil } diff --git a/adk/multiagent/integration-excel-agent/tools/python_runner.go b/adk/multiagent/integration-excel-agent/tools/python_runner.go index 813e8ee..1984a11 100644 --- a/adk/multiagent/integration-excel-agent/tools/python_runner.go +++ b/adk/multiagent/integration-excel-agent/tools/python_runner.go @@ -24,6 +24,7 @@ import ( "regexp" "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/integration-excel-agent/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -84,14 +85,14 @@ func (p *pythonRunnerTool) InvokableRun(ctx context.Context, argumentsInJSON str if pyExecutablePath == "" { pyExecutablePath = "python" } - result, err := p.op.RunCommand(ctx, fmt.Sprintf("%s %s", pyExecutablePath, filePath)) + result, err := p.op.RunCommand(ctx, []string{pyExecutablePath, filePath}) if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } return "", fmt.Errorf("execute error: %w", err) } - if strings.HasPrefix(result, "internal error") { - result = fmt.Sprintf("%s\n\n code after parse:\n%v", result, code) - } - return result, nil + return utils.FormatCommandOutput(result), nil } func tryExtractCodeSnippet(res string) string { diff --git a/adk/multiagent/integration-excel-agent/tools/read.go b/adk/multiagent/integration-excel-agent/tools/read.go index d8ac79b..13f5aeb 100644 --- a/adk/multiagent/integration-excel-agent/tools/read.go +++ b/adk/multiagent/integration-excel-agent/tools/read.go @@ -20,7 +20,9 @@ import ( "context" "encoding/json" "fmt" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/integration-excel-agent/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -85,10 +87,12 @@ func (r *readFile) InvokableRun(ctx context.Context, argumentsInJSON string, opt o := tool.GetImplSpecificOptions(&options{op: r.op}) cmd := fmt.Sprintf("python3 -c \"import sys; lines = (line for idx, line in enumerate(open(sys.argv[1], encoding='utf-8')) if %d <= idx < %d); print(''.join(lines))\" %s", input.StartRow, input.StartRow+input.NRows, input.Path) - content, err := o.op.RunCommand(ctx, cmd) + content, err := o.op.RunCommand(ctx, []string{cmd}) if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } return "", err } - - return content, nil + return utils.FormatCommandOutput(content), nil } diff --git a/adk/multiagent/integration-excel-agent/tools/tree.go b/adk/multiagent/integration-excel-agent/tools/tree.go index eac1404..bff9f6b 100644 --- a/adk/multiagent/integration-excel-agent/tools/tree.go +++ b/adk/multiagent/integration-excel-agent/tools/tree.go @@ -19,8 +19,9 @@ package tools import ( "context" "encoding/json" - "fmt" + "strings" + "github.com/cloudwego/eino-examples/adk/multiagent/integration-excel-agent/utils" "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" @@ -67,5 +68,12 @@ func (t *tree) InvokableRun(ctx context.Context, argumentsInJSON string, opts .. return "path can not be empty", nil } o := tool.GetImplSpecificOptions(&options{t.op}, opts...) - return o.op.RunCommand(ctx, fmt.Sprintf("find %s", input.Path)) + output, err := o.op.RunCommand(ctx, []string{"find", input.Path}) + if err != nil { + if strings.HasPrefix(err.Error(), "internal error") { + return err.Error(), nil + } + return "", err + } + return utils.FormatCommandOutput(output), nil } diff --git a/adk/multiagent/integration-excel-agent/utils/utils.go b/adk/multiagent/integration-excel-agent/utils/utils.go index 346448b..984056e 100644 --- a/adk/multiagent/integration-excel-agent/utils/utils.go +++ b/adk/multiagent/integration-excel-agent/utils/utils.go @@ -23,6 +23,7 @@ import ( "time" "github.com/bytedance/sonic" + "github.com/cloudwego/eino-ext/components/tool/commandline" "github.com/cloudwego/eino/adk" "github.com/cloudwego/eino/adk/prebuilt/planexecute" "github.com/kaptinlin/jsonrepair" @@ -114,3 +115,7 @@ func FormatExecutedSteps(in []planexecute.ExecutedStep) string { } return sb.String() } + +func FormatCommandOutput(output *commandline.CommandOutput) string { + return fmt.Sprintf("---\nstdout:%v\n---\nstderr:%v\n---", output.Stdout, output.Stderr) +} diff --git a/go.mod b/go.mod index d4a2de2..91c1007 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/cloudwego/eino-ext/components/model/ollama v0.1.2 github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4a5029810 github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56 - github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251020080234-ca9942893983 + github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810 github.com/cloudwego/eino-ext/devops v0.1.7 github.com/coze-dev/cozeloop-go v0.1.11 diff --git a/go.sum b/go.sum index dad2c34..a8f51d0 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,8 @@ github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4 github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4a5029810/go.mod h1:QQhCuQxuBAVWvu/YAZBhs/RsR76mUigw59Tl0kh04C8= github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56 h1:yL7nTthGoz35dh7RK9lazxDedGmSmlss8HrtXmd0O3Q= github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56/go.mod h1:OPQYefu4EWAUcP0HhtzJK+UjLtQc8T9YzmxcAwFf29o= -github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251020080234-ca9942893983 h1:hBlj/kcsBY9hx4N7h2PinCTBLU8ssw8sO/svUUxE28Q= -github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251020080234-ca9942893983/go.mod h1:Ro6u8M4lPc6r6oRWaKnGz/sJnY60GpYKsxpUK/yr01k= +github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f h1:JkELXl5NquNnDgi81T3uiPfgpfcXzH81e3B/NDO4cwM= +github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f/go.mod h1:WfhOxJY7J2ZqY9muahNOMtypoe4ovcAG1E97y4bQPfU= github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810 h1:VtmhPdOY6wFR34Hdm4HNzWF9bwGz11x1TqBr8VpJDoc= github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810/go.mod h1:QB9TkAu6OVDvQm5hEoK+VFVIbfDHO+ZQyUR2cPSo6jk= github.com/cloudwego/eino-ext/devops v0.1.7 h1:w8q4SGDtrZk+8WUrLyVidX7GNsyWFsYPPz5HoJKgRcA=