feat: py sandbox for workflow
* chore: update Dockerfile and sandbox.py * feat: py sandbox for workflow * feat: py sandbox for workflow See merge request: !885
This commit is contained in:
@@ -16,35 +16,16 @@
|
||||
|
||||
package code
|
||||
|
||||
import "context"
|
||||
|
||||
type Language string
|
||||
|
||||
const (
|
||||
Python Language = "Python"
|
||||
JavaScript Language = "JavaScript"
|
||||
import (
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
)
|
||||
|
||||
type RunRequest struct {
|
||||
Code string
|
||||
Params map[string]any
|
||||
Language Language
|
||||
}
|
||||
type RunResponse struct {
|
||||
Result map[string]any
|
||||
}
|
||||
|
||||
func GetCodeRunner() Runner {
|
||||
func GetCodeRunner() coderunner.Runner {
|
||||
return runnerImpl
|
||||
}
|
||||
|
||||
func SetCodeRunner(runner Runner) {
|
||||
func SetCodeRunner(runner coderunner.Runner) {
|
||||
runnerImpl = runner
|
||||
}
|
||||
|
||||
var runnerImpl Runner
|
||||
|
||||
//go:generate mockgen -destination ../../../../internal/mock/domain/workflow/crossdomain/code/code_mock.go --package code -source code.go
|
||||
type Runner interface {
|
||||
Run(ctx context.Context, request *RunRequest) (*RunResponse, error)
|
||||
}
|
||||
var runnerImpl coderunner.Runner
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/bytedance/mockey"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
@@ -746,7 +747,7 @@ func TestCodeAndPluginNodes(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
mockCodeRunner := mockcode.NewMockRunner(ctrl)
|
||||
mockey.Mock(code.GetCodeRunner).Return(mockCodeRunner).Build()
|
||||
mockCodeRunner.EXPECT().Run(gomock.Any(), gomock.Any()).Return(&code.RunResponse{
|
||||
mockCodeRunner.EXPECT().Run(gomock.Any(), gomock.Any()).Return(&coderunner.RunResponse{
|
||||
Result: map[string]any{
|
||||
"key0": "value0",
|
||||
"key1": []string{"value1", "value2"},
|
||||
|
||||
@@ -23,8 +23,6 @@ import (
|
||||
"strings"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/code"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/model"
|
||||
@@ -34,6 +32,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/loop"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/qa"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/selector"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/crypto"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
@@ -1075,12 +1074,12 @@ func ConvertRetrievalSearchType(s int64) (knowledge.SearchType, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertCodeLanguage(l int64) (code.Language, error) {
|
||||
func ConvertCodeLanguage(l int64) (coderunner.Language, error) {
|
||||
switch l {
|
||||
case 5:
|
||||
return code.JavaScript, nil
|
||||
return coderunner.JavaScript, nil
|
||||
case 3:
|
||||
return code.Python, nil
|
||||
return coderunner.Python, nil
|
||||
default:
|
||||
return "", fmt.Errorf("invalid language: %d", l)
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/textprocessor"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/variableaggregator"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/variableassigner"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/safego"
|
||||
@@ -577,7 +578,7 @@ func (s *NodeSchema) ToPluginConfig() (*plugin.Config, error) {
|
||||
func (s *NodeSchema) ToCodeRunnerConfig() (*code.Config, error) {
|
||||
return &code.Config{
|
||||
Code: mustGetKey[string]("Code", s.Configs),
|
||||
Language: mustGetKey[crosscode.Language]("Language", s.Configs),
|
||||
Language: mustGetKey[coderunner.Language]("Language", s.Configs),
|
||||
OutputConfig: s.OutputTypes,
|
||||
Runner: crosscode.GetCodeRunner(),
|
||||
}, nil
|
||||
|
||||
@@ -23,9 +23,9 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/code"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
@@ -113,9 +113,9 @@ var pythonThirdPartyWhitelist = map[string]struct{}{
|
||||
|
||||
type Config struct {
|
||||
Code string
|
||||
Language code.Language
|
||||
Language coderunner.Language
|
||||
OutputConfig map[string]*vo.TypeInfo
|
||||
Runner code.Runner
|
||||
Runner coderunner.Runner
|
||||
}
|
||||
|
||||
type CodeRunner struct {
|
||||
@@ -136,7 +136,7 @@ func NewCodeRunner(ctx context.Context, cfg *Config) (*CodeRunner, error) {
|
||||
return nil, errors.New("code is required")
|
||||
}
|
||||
|
||||
if cfg.Language != code.Python {
|
||||
if cfg.Language != coderunner.Python {
|
||||
return nil, errors.New("only support python language")
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func (c *CodeRunner) RunCode(ctx context.Context, input map[string]any) (ret map
|
||||
if c.importError != nil {
|
||||
return nil, vo.WrapError(errno.ErrCodeExecuteFail, c.importError, errorx.KV("detail", c.importError.Error()))
|
||||
}
|
||||
response, err := c.config.Runner.Run(ctx, &code.RunRequest{Code: c.config.Code, Language: c.config.Language, Params: input})
|
||||
response, err := c.config.Runner.Run(ctx, &coderunner.RunRequest{Code: c.config.Code, Language: c.config.Language, Params: input})
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrCodeExecuteFail, err, errorx.KV("detail", err.Error()))
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/coderunner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/code"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
mockcode "github.com/coze-dev/coze-studio/backend/internal/mock/domain/workflow/crossdomain/code"
|
||||
@@ -68,7 +68,7 @@ async def main(args:Args)->Output:
|
||||
},
|
||||
}
|
||||
|
||||
response := &code.RunResponse{
|
||||
response := &coderunner.RunResponse{
|
||||
Result: ret,
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ async def main(args:Args)->Output:
|
||||
ctx := t.Context()
|
||||
c := &CodeRunner{
|
||||
config: &Config{
|
||||
Language: code.Python,
|
||||
Language: coderunner.Python,
|
||||
Code: codeTpl,
|
||||
OutputConfig: map[string]*vo.TypeInfo{
|
||||
"key0": {Type: vo.DataTypeInteger},
|
||||
@@ -138,7 +138,7 @@ async def main(args:Args)->Output:
|
||||
"key3": map[string]interface{}{"key31": "hi", "key32": "hello", "key34": map[string]interface{}{"key341": "123"}},
|
||||
}
|
||||
|
||||
response := &code.RunResponse{
|
||||
response := &coderunner.RunResponse{
|
||||
Result: ret,
|
||||
}
|
||||
mockRunner.EXPECT().Run(gomock.Any(), gomock.Any()).Return(response, nil)
|
||||
@@ -147,7 +147,7 @@ async def main(args:Args)->Output:
|
||||
c := &CodeRunner{
|
||||
config: &Config{
|
||||
Code: codeTpl,
|
||||
Language: code.Python,
|
||||
Language: coderunner.Python,
|
||||
OutputConfig: map[string]*vo.TypeInfo{
|
||||
"key0": {Type: vo.DataTypeInteger},
|
||||
"key1": {Type: vo.DataTypeArray, ElemTypeInfo: &vo.TypeInfo{Type: vo.DataTypeString}},
|
||||
@@ -213,7 +213,7 @@ async def main(args:Args)->Output:
|
||||
"key2": []interface{}{int64(123), "345"},
|
||||
"key3": map[string]interface{}{"key31": "hi", "key32": "hello", "key34": map[string]interface{}{"key341": "123", "key343": []any{"hello", "world"}}},
|
||||
}
|
||||
response := &code.RunResponse{
|
||||
response := &coderunner.RunResponse{
|
||||
Result: ret,
|
||||
}
|
||||
mockRunner.EXPECT().Run(gomock.Any(), gomock.Any()).Return(response, nil)
|
||||
@@ -221,7 +221,7 @@ async def main(args:Args)->Output:
|
||||
c := &CodeRunner{
|
||||
config: &Config{
|
||||
Code: codeTpl,
|
||||
Language: code.Python,
|
||||
Language: coderunner.Python,
|
||||
OutputConfig: map[string]*vo.TypeInfo{
|
||||
"key0": {Type: vo.DataTypeInteger},
|
||||
"key1": {Type: vo.DataTypeArray, ElemTypeInfo: &vo.TypeInfo{Type: vo.DataTypeNumber}},
|
||||
|
||||
Reference in New Issue
Block a user