Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions adk/backend/agentkit/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ type Config struct {
ExecutionTimeout int
}

type sandboxToolBackend struct {
type SandboxToolBackend struct {
secretAccessKey string
accessKeyID string
baseURL string
Expand All @@ -117,14 +117,14 @@ type sandboxToolBackend struct {
executionTimeout int
}

// NewSandboxToolBackend creates a new sandboxToolBackend instance.
// sandboxToolBackend refers to the sandbox running instance created by the sandbox tool in Volcengine.
// NewSandboxToolBackend creates a new SandboxToolBackend instance.
// SandboxToolBackend refers to the sandbox running instance created by the sandbox tool in Volcengine.
// For creating a sandbox tool environment, please refer to: https://www.volcengine.com/docs/86681/1847934?lang=zh;
// For creating a sandbox tool running instance, please refer to: https://www.volcengine.com/docs/86681/1860266?lang=zh.
// Note: The execution paths within the sandbox environment may be subject to permission restrictions (read, write, execute, etc.).
// Improper path selection can result in operation failures or permission errors.
// It is recommended to perform operations within paths where the sandbox environment has explicit permissions to mitigate permission-related risks.
func NewSandboxToolBackend(config *Config) (filesystem.Backend, error) {
func NewSandboxToolBackend(config *Config) (*SandboxToolBackend, error) {
if config.AccessKeyID == "" {
return nil, fmt.Errorf("AccessKeyID is required")
}
Expand Down Expand Up @@ -159,7 +159,7 @@ func NewSandboxToolBackend(config *Config) (filesystem.Backend, error) {
return nil, fmt.Errorf("invalid region: %s", region)
}

return &sandboxToolBackend{
return &SandboxToolBackend{
accessKeyID: config.AccessKeyID,
secretAccessKey: config.SecretAccessKey,
httpClient: httpClient,
Expand All @@ -174,7 +174,7 @@ func NewSandboxToolBackend(config *Config) (filesystem.Backend, error) {
}

// LsInfo lists file information under the given path.
func (s *sandboxToolBackend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error) {
func (s *SandboxToolBackend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error) {
path, err := formatPath(req.Path, "/", true)
if err != nil {
return nil, err
Expand Down Expand Up @@ -216,7 +216,7 @@ func (s *sandboxToolBackend) LsInfo(ctx context.Context, req *filesystem.LsInfoR
}

// Read reads file content with support for line-based offset and limit.
func (s *sandboxToolBackend) Read(ctx context.Context, req *filesystem.ReadRequest) (string, error) {
func (s *SandboxToolBackend) Read(ctx context.Context, req *filesystem.ReadRequest) (string, error) {
path, err := formatPath(req.FilePath, "", true)
if err != nil {
return "", err
Expand Down Expand Up @@ -251,7 +251,7 @@ func (s *sandboxToolBackend) Read(ctx context.Context, req *filesystem.ReadReque
}

// GrepRaw searches for content matching the specified pattern in files.
func (s *sandboxToolBackend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
func (s *SandboxToolBackend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
path, _ := formatPath(req.Path, "", false)
params := map[string]any{
"pattern": req.Pattern,
Expand Down Expand Up @@ -292,7 +292,7 @@ func (s *sandboxToolBackend) GrepRaw(ctx context.Context, req *filesystem.GrepRe
}

// GlobInfo returns file information matching the glob pattern.
func (s *sandboxToolBackend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error) {
func (s *SandboxToolBackend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error) {
path, _ := formatPath(req.Path, "/", false)
params := map[string]any{
"path_b64": base64.StdEncoding.EncodeToString([]byte(path)),
Expand Down Expand Up @@ -330,7 +330,7 @@ func (s *sandboxToolBackend) GlobInfo(ctx context.Context, req *filesystem.GlobI
}

// Write creates file content.
func (s *sandboxToolBackend) Write(ctx context.Context, req *filesystem.WriteRequest) error {
func (s *SandboxToolBackend) Write(ctx context.Context, req *filesystem.WriteRequest) error {
path, err := formatPath(req.FilePath, "", true)
if err != nil {
return err
Expand Down Expand Up @@ -358,7 +358,7 @@ func (s *sandboxToolBackend) Write(ctx context.Context, req *filesystem.WriteReq
}

// Edit replaces string occurrences in a file.
func (s *sandboxToolBackend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
func (s *SandboxToolBackend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
path, err := formatPath(req.FilePath, "", true)
if err != nil {
return err
Expand Down Expand Up @@ -401,7 +401,7 @@ func (s *sandboxToolBackend) Edit(ctx context.Context, req *filesystem.EditReque
}

// execute executes a command in the sandbox.
func (s *sandboxToolBackend) execute(ctx context.Context, command string) (text string, exitCode *int, err error) {
func (s *SandboxToolBackend) execute(ctx context.Context, command string) (text string, exitCode *int, err error) {
var operationPayload string
if s.executionTimeout <= 0 {
operationPayload, err = sonic.MarshalString(map[string]any{
Expand Down Expand Up @@ -473,7 +473,7 @@ func (s *sandboxToolBackend) execute(ctx context.Context, command string) (text
return text, exitCode, nil
}

func (s *sandboxToolBackend) invokeTool(ctx context.Context, method string, body []byte) ([]byte, error) {
func (s *SandboxToolBackend) invokeTool(ctx context.Context, method string, body []byte) ([]byte, error) {
queries := make(url.Values)
queries.Set("Action", "InvokeTool")
queries.Set("Version", "2025-10-30")
Expand Down Expand Up @@ -506,7 +506,7 @@ func (s *sandboxToolBackend) invokeTool(ctx context.Context, method string, body
return responseBody, nil
}

func (s *sandboxToolBackend) signRequest(request *http.Request, queries url.Values, body []byte) {
func (s *SandboxToolBackend) signRequest(request *http.Request, queries url.Values, body []byte) {
now := time.Now()
date := now.UTC().Format("20060102T150405Z")
authDate := date[:8]
Expand Down Expand Up @@ -558,7 +558,7 @@ func (s *sandboxToolBackend) signRequest(request *http.Request, queries url.Valu
request.Header.Set("Authorization", authorization)
}

func (s *sandboxToolBackend) Execute(ctx context.Context, input *filesystem.ExecuteRequest) (result *filesystem.ExecuteResponse, err error) {
func (s *SandboxToolBackend) Execute(ctx context.Context, input *filesystem.ExecuteRequest) (result *filesystem.ExecuteResponse, err error) {
if input.Command == "" {
return nil, fmt.Errorf("command is required")
}
Expand Down
13 changes: 6 additions & 7 deletions adk/backend/agentkit/sandbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func TestNewArkSandbox(t *testing.T) {
SessionTTL: 3600,
ExecutionTimeout: 60,
}
ss, err := NewSandboxToolBackend(config)
s := ss.(*sandboxToolBackend)
s, err := NewSandboxToolBackend(config)

require.NoError(t, err)
require.NotNil(t, s)
assert.Equal(t, "test-ak", s.accessKeyID)
Expand All @@ -61,8 +61,8 @@ func TestNewArkSandbox(t *testing.T) {
ToolID: "test-tool",
UserSessionID: "test-session",
}
ss, err := NewSandboxToolBackend(config)
s := ss.(*sandboxToolBackend)
s, err := NewSandboxToolBackend(config)

require.NoError(t, err)
require.NotNil(t, s)
assert.Equal(t, RegionOfBeijing, s.region)
Expand Down Expand Up @@ -115,7 +115,7 @@ func TestNewArkSandbox(t *testing.T) {
var mockAPIHandler http.HandlerFunc

// setupTest creates a mock server and an ArkSandbox client configured to use it.
func setupTest(t *testing.T) (*sandboxToolBackend, *httptest.Server) {
func setupTest(t *testing.T) (*SandboxToolBackend, *httptest.Server) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if mockAPIHandler != nil {
mockAPIHandler(w, r)
Expand All @@ -131,8 +131,7 @@ func setupTest(t *testing.T) (*sandboxToolBackend, *httptest.Server) {
UserSessionID: "test-session",
HTTPClient: server.Client(),
}
ss, err := NewSandboxToolBackend(config)
sandbox := ss.(*sandboxToolBackend)
sandbox, err := NewSandboxToolBackend(config)
require.NoError(t, err)
sandbox.baseURL = server.URL // Override to point to the mock server

Expand Down
4 changes: 0 additions & 4 deletions adk/backend/local/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFos
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cloudwego/eino v0.7.19 h1:KoA3KHoZ3adQI0nvC0EBR7tpeu/Ks69n+baRMOQGLqA=
github.com/cloudwego/eino v0.7.19/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
github.com/cloudwego/eino v0.7.26 h1:FD8xnhd8WyV495eJs0Rka8aHnknqj/ljq3ZbwGH/SiQ=
github.com/cloudwego/eino v0.7.26/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
github.com/cloudwego/eino v0.7.27 h1:pHxpvpQjAqez+yPgxxX0V298YmJd5cDQqCBAn8XnJYo=
github.com/cloudwego/eino v0.7.27/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
22 changes: 11 additions & 11 deletions adk/backend/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,22 @@ type Config struct {
ValidateCommand func(string) error
}

type backend struct {
type Backend struct {
validateCommand func(string) error
}

var defaultValidateCommand = func(string) error {
return nil
}

// NewBackend creates a new local filesystem backend instance.
// NewBackend creates a new local filesystem Backend instance.
//
// IMPORTANT - System Compatibility:
// - Supported: Unix/MacOS only
// - NOT Supported: Windows (requires custom implementation of Backend)
// - Command Execution: Uses /bin/sh by default for Execute method
// - If /bin/sh does not meet your requirements, please implement your own Backend
func NewBackend(_ context.Context, cfg *Config) (filesystem.Backend, error) {
func NewBackend(_ context.Context, cfg *Config) (*Backend, error) {
if cfg == nil {
return nil, errors.New("config is required")
}
Expand All @@ -65,12 +65,12 @@ func NewBackend(_ context.Context, cfg *Config) (filesystem.Backend, error) {
validateCommand = cfg.ValidateCommand
}

return &backend{
return &Backend{
validateCommand: validateCommand,
}, nil
}

func (s *backend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error) {
func (s *Backend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error) {
if req.Path == "" {
req.Path = defaultRootPath
}
Expand Down Expand Up @@ -105,7 +105,7 @@ func (s *backend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]
return files, nil
}

func (s *backend) Read(ctx context.Context, req *filesystem.ReadRequest) (string, error) {
func (s *Backend) Read(ctx context.Context, req *filesystem.ReadRequest) (string, error) {
path := filepath.Clean(req.FilePath)
if !filepath.IsAbs(path) {
return "", fmt.Errorf("path must be an absolute path: %s", path)
Expand Down Expand Up @@ -160,7 +160,7 @@ func (s *backend) Read(ctx context.Context, req *filesystem.ReadRequest) (string
return result.String(), nil
}

func (s *backend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
func (s *Backend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
path := filepath.Clean(req.Path)

var matches []filesystem.GrepMatch
Expand Down Expand Up @@ -232,7 +232,7 @@ func (s *backend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]f
return matches, nil
}

func (s *backend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error) {
func (s *Backend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error) {
if req.Path == "" {
req.Path = defaultRootPath
}
Expand Down Expand Up @@ -337,7 +337,7 @@ func globToRegex(pattern string) (*regexp.Regexp, error) {
return regexp.Compile(pattern)
}

func (s *backend) Write(ctx context.Context, req *filesystem.WriteRequest) error {
func (s *Backend) Write(ctx context.Context, req *filesystem.WriteRequest) error {
if !filepath.IsAbs(req.FilePath) {
return fmt.Errorf("path must be an absolute path: %s", req.FilePath)
}
Expand All @@ -364,7 +364,7 @@ func (s *backend) Write(ctx context.Context, req *filesystem.WriteRequest) error
return nil
}

func (s *backend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
func (s *Backend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
path := filepath.Clean(req.FilePath)
if !filepath.IsAbs(path) {
return fmt.Errorf("path must be an absolute path: %s", path)
Expand Down Expand Up @@ -403,7 +403,7 @@ func (s *backend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
return os.WriteFile(path, []byte(newText), 0644)
}

func (s *backend) ExecuteStreaming(ctx context.Context, input *filesystem.ExecuteRequest) (result *schema.StreamReader[*filesystem.ExecuteResponse], err error) {
func (s *Backend) ExecuteStreaming(ctx context.Context, input *filesystem.ExecuteRequest) (result *schema.StreamReader[*filesystem.ExecuteResponse], err error) {
if input.Command == "" {
return nil, fmt.Errorf("command is required")
}
Expand Down
30 changes: 11 additions & 19 deletions adk/backend/local/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
Expand Down Expand Up @@ -465,7 +464,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with echo", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "echo line1 && echo line2 && echo line3"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var outputs []string
Expand All @@ -487,7 +486,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with ping", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "ping -c 3 127.0.0.1"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var lineCount int
Expand All @@ -506,7 +505,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with seq command", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "seq 1 5"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var numbers []string
Expand All @@ -530,7 +529,7 @@ func TestExecuteStreaming(t *testing.T) {
defer cancel()

req := &filesystem.ExecuteRequest{Command: "seq 1 1000000"}
sr, err := s.(*backend).ExecuteStreaming(cancelCtx, req)
sr, err := s.ExecuteStreaming(cancelCtx, req)
assert.NoError(t, err)

var lineCount int
Expand All @@ -552,7 +551,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with command failure", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "echo output && exit 1"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var hasOutput bool
Expand All @@ -575,7 +574,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with stderr output", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "echo stdout && echo stderr >&2 && exit 1"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var outputs []string
Expand All @@ -600,14 +599,14 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with empty command", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: ""}
_, err := s.(*backend).ExecuteStreaming(ctx, req)
_, err := s.ExecuteStreaming(ctx, req)
assert.Error(t, err)
assert.Contains(t, err.Error(), "command is required")
})

t.Run("ExecuteStreaming with large output", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "seq 1 100"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var lineCount int
Expand All @@ -626,7 +625,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with normal completion", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "echo test"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var receivedOutput bool
Expand All @@ -645,7 +644,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with invalid command", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "/nonexistent/command"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var lastErr error
Expand All @@ -665,7 +664,7 @@ func TestExecuteStreaming(t *testing.T) {

t.Run("ExecuteStreaming with no stdout output", func(t *testing.T) {
req := &filesystem.ExecuteRequest{Command: "true"}
sr, err := s.(*backend).ExecuteStreaming(ctx, req)
sr, err := s.ExecuteStreaming(ctx, req)
assert.NoError(t, err)

var receivedResponse bool
Expand All @@ -688,10 +687,3 @@ func TestExecuteStreaming(t *testing.T) {
assert.Equal(t, 0, *exitCode, "exit code should be 0 for successful command")
})
}

func TestExecute1(t *testing.T) {
fs := strings.Fields("ls -al")
bs, err := exec.Command(fs[0], fs[1:]...).Output()
assert.NoError(t, err)
fmt.Println(string(bs))
}
2 changes: 1 addition & 1 deletion components/model/ark/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/cloudwego/eino-ext/components/model/ark
go 1.18

require (
github.com/bytedance/mockey v1.2.14
github.com/bytedance/mockey v1.4.4
github.com/bytedance/sonic v1.14.1
github.com/cloudwego/eino v0.7.13
github.com/eino-contrib/jsonschema v1.0.3
Expand Down
Loading
Loading