refactor(workflow): Move the plugin component in the Workflow package into the common crossdomain package (#717)
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
|
||||
eino "github.com/cloudwego/eino/components/model"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/modelmgr"
|
||||
)
|
||||
|
||||
@@ -19,6 +19,8 @@ package plugin
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
)
|
||||
|
||||
@@ -35,6 +37,14 @@ type PluginService interface {
|
||||
PublishAPPPlugins(ctx context.Context, req *model.PublishAPPPluginsRequest) (resp *model.PublishAPPPluginsResponse, err error)
|
||||
GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*model.PluginInfo, err error)
|
||||
MGetVersionTools(ctx context.Context, versionTools []model.VersionTool) (tools []*model.ToolInfo, err error)
|
||||
GetPluginToolsInfo(ctx context.Context, req *model.ToolsInfoRequest) (*model.ToolsInfoResponse, error)
|
||||
GetPluginInvokableTools(ctx context.Context, req *model.ToolsInvokableRequest) (map[int64]InvokableTool, error)
|
||||
ExecutePlugin(ctx context.Context, input map[string]any, pe *model.PluginEntity, toolID int64, cfg model.ExecuteConfig) (map[string]any, error)
|
||||
}
|
||||
|
||||
type InvokableTool interface {
|
||||
Info(ctx context.Context) (*schema.ToolInfo, error)
|
||||
PluginInvoke(ctx context.Context, argumentsInJSON string, cfg model.ExecuteConfig) (string, error)
|
||||
}
|
||||
|
||||
var defaultSVC PluginService
|
||||
|
||||
323
backend/crossdomain/contract/plugin/pluginmock/plugin_mock.go
Normal file
323
backend/crossdomain/contract/plugin/pluginmock/plugin_mock.go
Normal file
@@ -0,0 +1,323 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: plugin.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -destination pluginmock/plugin_mock.go --package pluginmock -source plugin.go
|
||||
//
|
||||
|
||||
// Package pluginmock is a generated GoMock package.
|
||||
package pluginmock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
schema "github.com/cloudwego/eino/schema"
|
||||
plugin "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
plugin0 "github.com/coze-dev/coze-studio/backend/crossdomain/contract/plugin"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockPluginService is a mock of PluginService interface.
|
||||
type MockPluginService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPluginServiceMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockPluginServiceMockRecorder is the mock recorder for MockPluginService.
|
||||
type MockPluginServiceMockRecorder struct {
|
||||
mock *MockPluginService
|
||||
}
|
||||
|
||||
// NewMockPluginService creates a new mock instance.
|
||||
func NewMockPluginService(ctrl *gomock.Controller) *MockPluginService {
|
||||
mock := &MockPluginService{ctrl: ctrl}
|
||||
mock.recorder = &MockPluginServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPluginService) EXPECT() *MockPluginServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BindAgentTools mocks base method.
|
||||
func (m *MockPluginService) BindAgentTools(ctx context.Context, agentID int64, toolIDs []int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BindAgentTools", ctx, agentID, toolIDs)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BindAgentTools indicates an expected call of BindAgentTools.
|
||||
func (mr *MockPluginServiceMockRecorder) BindAgentTools(ctx, agentID, toolIDs any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BindAgentTools", reflect.TypeOf((*MockPluginService)(nil).BindAgentTools), ctx, agentID, toolIDs)
|
||||
}
|
||||
|
||||
// DeleteDraftPlugin mocks base method.
|
||||
func (m *MockPluginService) DeleteDraftPlugin(ctx context.Context, PluginID int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteDraftPlugin", ctx, PluginID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteDraftPlugin indicates an expected call of DeleteDraftPlugin.
|
||||
func (mr *MockPluginServiceMockRecorder) DeleteDraftPlugin(ctx, PluginID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDraftPlugin", reflect.TypeOf((*MockPluginService)(nil).DeleteDraftPlugin), ctx, PluginID)
|
||||
}
|
||||
|
||||
// DuplicateDraftAgentTools mocks base method.
|
||||
func (m *MockPluginService) DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DuplicateDraftAgentTools", ctx, fromAgentID, toAgentID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DuplicateDraftAgentTools indicates an expected call of DuplicateDraftAgentTools.
|
||||
func (mr *MockPluginServiceMockRecorder) DuplicateDraftAgentTools(ctx, fromAgentID, toAgentID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicateDraftAgentTools", reflect.TypeOf((*MockPluginService)(nil).DuplicateDraftAgentTools), ctx, fromAgentID, toAgentID)
|
||||
}
|
||||
|
||||
// ExecutePlugin mocks base method.
|
||||
func (m *MockPluginService) ExecutePlugin(ctx context.Context, input map[string]any, pe *plugin.PluginEntity, toolID int64, cfg plugin.ExecuteConfig) (map[string]any, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ExecutePlugin", ctx, input, pe, toolID, cfg)
|
||||
ret0, _ := ret[0].(map[string]any)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ExecutePlugin indicates an expected call of ExecutePlugin.
|
||||
func (mr *MockPluginServiceMockRecorder) ExecutePlugin(ctx, input, pe, toolID, cfg any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecutePlugin", reflect.TypeOf((*MockPluginService)(nil).ExecutePlugin), ctx, input, pe, toolID, cfg)
|
||||
}
|
||||
|
||||
// ExecuteTool mocks base method.
|
||||
func (m *MockPluginService) ExecuteTool(ctx context.Context, req *plugin.ExecuteToolRequest, opts ...plugin.ExecuteToolOpt) (*plugin.ExecuteToolResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{ctx, req}
|
||||
for _, a := range opts {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "ExecuteTool", varargs...)
|
||||
ret0, _ := ret[0].(*plugin.ExecuteToolResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ExecuteTool indicates an expected call of ExecuteTool.
|
||||
func (mr *MockPluginServiceMockRecorder) ExecuteTool(ctx, req any, opts ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{ctx, req}, opts...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteTool", reflect.TypeOf((*MockPluginService)(nil).ExecuteTool), varargs...)
|
||||
}
|
||||
|
||||
// GetAPPAllPlugins mocks base method.
|
||||
func (m *MockPluginService) GetAPPAllPlugins(ctx context.Context, appID int64) ([]*plugin.PluginInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAPPAllPlugins", ctx, appID)
|
||||
ret0, _ := ret[0].([]*plugin.PluginInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetAPPAllPlugins indicates an expected call of GetAPPAllPlugins.
|
||||
func (mr *MockPluginServiceMockRecorder) GetAPPAllPlugins(ctx, appID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPPAllPlugins", reflect.TypeOf((*MockPluginService)(nil).GetAPPAllPlugins), ctx, appID)
|
||||
}
|
||||
|
||||
// GetPluginInvokableTools mocks base method.
|
||||
func (m *MockPluginService) GetPluginInvokableTools(ctx context.Context, req *plugin.ToolsInvokableRequest) (map[int64]plugin0.InvokableTool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPluginInvokableTools", ctx, req)
|
||||
ret0, _ := ret[0].(map[int64]plugin0.InvokableTool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPluginInvokableTools indicates an expected call of GetPluginInvokableTools.
|
||||
func (mr *MockPluginServiceMockRecorder) GetPluginInvokableTools(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginInvokableTools", reflect.TypeOf((*MockPluginService)(nil).GetPluginInvokableTools), ctx, req)
|
||||
}
|
||||
|
||||
// GetPluginToolsInfo mocks base method.
|
||||
func (m *MockPluginService) GetPluginToolsInfo(ctx context.Context, req *plugin.ToolsInfoRequest) (*plugin.ToolsInfoResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPluginToolsInfo", ctx, req)
|
||||
ret0, _ := ret[0].(*plugin.ToolsInfoResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPluginToolsInfo indicates an expected call of GetPluginToolsInfo.
|
||||
func (mr *MockPluginServiceMockRecorder) GetPluginToolsInfo(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginToolsInfo", reflect.TypeOf((*MockPluginService)(nil).GetPluginToolsInfo), ctx, req)
|
||||
}
|
||||
|
||||
// MGetAgentTools mocks base method.
|
||||
func (m *MockPluginService) MGetAgentTools(ctx context.Context, req *plugin.MGetAgentToolsRequest) ([]*plugin.ToolInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MGetAgentTools", ctx, req)
|
||||
ret0, _ := ret[0].([]*plugin.ToolInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MGetAgentTools indicates an expected call of MGetAgentTools.
|
||||
func (mr *MockPluginServiceMockRecorder) MGetAgentTools(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MGetAgentTools", reflect.TypeOf((*MockPluginService)(nil).MGetAgentTools), ctx, req)
|
||||
}
|
||||
|
||||
// MGetPluginLatestVersion mocks base method.
|
||||
func (m *MockPluginService) MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (*plugin.MGetPluginLatestVersionResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MGetPluginLatestVersion", ctx, pluginIDs)
|
||||
ret0, _ := ret[0].(*plugin.MGetPluginLatestVersionResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MGetPluginLatestVersion indicates an expected call of MGetPluginLatestVersion.
|
||||
func (mr *MockPluginServiceMockRecorder) MGetPluginLatestVersion(ctx, pluginIDs any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MGetPluginLatestVersion", reflect.TypeOf((*MockPluginService)(nil).MGetPluginLatestVersion), ctx, pluginIDs)
|
||||
}
|
||||
|
||||
// MGetVersionPlugins mocks base method.
|
||||
func (m *MockPluginService) MGetVersionPlugins(ctx context.Context, versionPlugins []plugin.VersionPlugin) ([]*plugin.PluginInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MGetVersionPlugins", ctx, versionPlugins)
|
||||
ret0, _ := ret[0].([]*plugin.PluginInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MGetVersionPlugins indicates an expected call of MGetVersionPlugins.
|
||||
func (mr *MockPluginServiceMockRecorder) MGetVersionPlugins(ctx, versionPlugins any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MGetVersionPlugins", reflect.TypeOf((*MockPluginService)(nil).MGetVersionPlugins), ctx, versionPlugins)
|
||||
}
|
||||
|
||||
// MGetVersionTools mocks base method.
|
||||
func (m *MockPluginService) MGetVersionTools(ctx context.Context, versionTools []plugin.VersionTool) ([]*plugin.ToolInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MGetVersionTools", ctx, versionTools)
|
||||
ret0, _ := ret[0].([]*plugin.ToolInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MGetVersionTools indicates an expected call of MGetVersionTools.
|
||||
func (mr *MockPluginServiceMockRecorder) MGetVersionTools(ctx, versionTools any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MGetVersionTools", reflect.TypeOf((*MockPluginService)(nil).MGetVersionTools), ctx, versionTools)
|
||||
}
|
||||
|
||||
// PublishAPPPlugins mocks base method.
|
||||
func (m *MockPluginService) PublishAPPPlugins(ctx context.Context, req *plugin.PublishAPPPluginsRequest) (*plugin.PublishAPPPluginsResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PublishAPPPlugins", ctx, req)
|
||||
ret0, _ := ret[0].(*plugin.PublishAPPPluginsResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PublishAPPPlugins indicates an expected call of PublishAPPPlugins.
|
||||
func (mr *MockPluginServiceMockRecorder) PublishAPPPlugins(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishAPPPlugins", reflect.TypeOf((*MockPluginService)(nil).PublishAPPPlugins), ctx, req)
|
||||
}
|
||||
|
||||
// PublishAgentTools mocks base method.
|
||||
func (m *MockPluginService) PublishAgentTools(ctx context.Context, agentID int64, agentVersion string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PublishAgentTools", ctx, agentID, agentVersion)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PublishAgentTools indicates an expected call of PublishAgentTools.
|
||||
func (mr *MockPluginServiceMockRecorder) PublishAgentTools(ctx, agentID, agentVersion any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishAgentTools", reflect.TypeOf((*MockPluginService)(nil).PublishAgentTools), ctx, agentID, agentVersion)
|
||||
}
|
||||
|
||||
// PublishPlugin mocks base method.
|
||||
func (m *MockPluginService) PublishPlugin(ctx context.Context, req *plugin.PublishPluginRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PublishPlugin", ctx, req)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PublishPlugin indicates an expected call of PublishPlugin.
|
||||
func (mr *MockPluginServiceMockRecorder) PublishPlugin(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishPlugin", reflect.TypeOf((*MockPluginService)(nil).PublishPlugin), ctx, req)
|
||||
}
|
||||
|
||||
// MockInvokableTool is a mock of InvokableTool interface.
|
||||
type MockInvokableTool struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockInvokableToolMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockInvokableToolMockRecorder is the mock recorder for MockInvokableTool.
|
||||
type MockInvokableToolMockRecorder struct {
|
||||
mock *MockInvokableTool
|
||||
}
|
||||
|
||||
// NewMockInvokableTool creates a new mock instance.
|
||||
func NewMockInvokableTool(ctrl *gomock.Controller) *MockInvokableTool {
|
||||
mock := &MockInvokableTool{ctrl: ctrl}
|
||||
mock.recorder = &MockInvokableToolMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockInvokableTool) EXPECT() *MockInvokableToolMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Info mocks base method.
|
||||
func (m *MockInvokableTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Info", ctx)
|
||||
ret0, _ := ret[0].(*schema.ToolInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Info indicates an expected call of Info.
|
||||
func (mr *MockInvokableToolMockRecorder) Info(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockInvokableTool)(nil).Info), ctx)
|
||||
}
|
||||
|
||||
// PluginInvoke mocks base method.
|
||||
func (m *MockInvokableTool) PluginInvoke(ctx context.Context, argumentsInJSON string, cfg plugin.ExecuteConfig) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PluginInvoke", ctx, argumentsInJSON, cfg)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PluginInvoke indicates an expected call of PluginInvoke.
|
||||
func (mr *MockInvokableToolMockRecorder) PluginInvoke(ctx, argumentsInJSON, cfg any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PluginInvoke", reflect.TypeOf((*MockInvokableTool)(nil).PluginInvoke), ctx, argumentsInJSON, cfg)
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
workflowEntity "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
@@ -38,13 +39,13 @@ type Workflow interface {
|
||||
allInterruptEvents map[string]*workflowEntity.ToolInterruptEvent) einoCompose.Option
|
||||
ReleaseApplicationWorkflows(ctx context.Context, appID int64, config *ReleaseWorkflowConfig) ([]*vo.ValidateIssue, error)
|
||||
GetWorkflowIDsByAppID(ctx context.Context, appID int64) ([]int64, error)
|
||||
SyncExecuteWorkflow(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*workflowEntity.WorkflowExecution, vo.TerminatePlan, error)
|
||||
WithExecuteConfig(cfg vo.ExecuteConfig) einoCompose.Option
|
||||
SyncExecuteWorkflow(ctx context.Context, config model.ExecuteConfig, input map[string]any) (*workflowEntity.WorkflowExecution, vo.TerminatePlan, error)
|
||||
WithExecuteConfig(cfg model.ExecuteConfig) einoCompose.Option
|
||||
WithMessagePipe() (compose.Option, *schema.StreamReader[*entity.Message])
|
||||
}
|
||||
|
||||
type ExecuteConfig = vo.ExecuteConfig
|
||||
type ExecuteMode = vo.ExecuteMode
|
||||
type ExecuteConfig = model.ExecuteConfig
|
||||
type ExecuteMode = model.ExecuteMode
|
||||
type NodeType = entity.NodeType
|
||||
|
||||
type WorkflowMessage = entity.Message
|
||||
@@ -59,14 +60,14 @@ const (
|
||||
ExecuteModeNodeDebug ExecuteMode = "node_debug"
|
||||
)
|
||||
|
||||
type TaskType = vo.TaskType
|
||||
type TaskType = model.TaskType
|
||||
|
||||
const (
|
||||
TaskTypeForeground TaskType = "foreground"
|
||||
TaskTypeBackground TaskType = "background"
|
||||
)
|
||||
|
||||
type BizType = vo.BizType
|
||||
type BizType = model.BizType
|
||||
|
||||
const (
|
||||
BizTypeAgent BizType = "agent"
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
eino "github.com/cloudwego/eino/components/model"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
crossmodelmgr "github.com/coze-dev/coze-studio/backend/crossdomain/contract/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
|
||||
@@ -18,23 +18,45 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop/common"
|
||||
workflow3 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/pluginutil"
|
||||
crossplugin "github.com/coze-dev/coze-studio/backend/crossdomain/contract/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
plugin "github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
entity2 "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
var defaultSVC crossplugin.PluginService
|
||||
|
||||
type impl struct {
|
||||
DomainSVC plugin.PluginService
|
||||
tos storage.Storage
|
||||
}
|
||||
|
||||
func InitDomainService(c plugin.PluginService) crossplugin.PluginService {
|
||||
func InitDomainService(c plugin.PluginService, tos storage.Storage) crossplugin.PluginService {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
tos: tos,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
@@ -105,3 +127,479 @@ func (s *impl) GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*mo
|
||||
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
type pluginInfo struct {
|
||||
*entity.PluginInfo
|
||||
LatestVersion *string
|
||||
}
|
||||
|
||||
func (s *impl) getPluginsWithTools(ctx context.Context, pluginEntity *model.PluginEntity, toolIDs []int64, isDraft bool) (
|
||||
_ *pluginInfo, toolsInfo []*entity.ToolInfo, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var pluginsInfo []*entity.PluginInfo
|
||||
var latestPluginInfo *entity.PluginInfo
|
||||
pluginID := pluginEntity.PluginID
|
||||
if isDraft {
|
||||
plugins, err := s.DomainSVC.MGetDraftPlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
} else if pluginEntity.PluginVersion == nil || (pluginEntity.PluginVersion != nil && *pluginEntity.PluginVersion == "") {
|
||||
plugins, err := s.DomainSVC.MGetOnlinePlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
|
||||
} else {
|
||||
plugins, err := s.DomainSVC.MGetVersionPlugins(ctx, []entity.VersionPlugin{
|
||||
{PluginID: pluginID, Version: *pluginEntity.PluginVersion},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
|
||||
onlinePlugins, err := s.DomainSVC.MGetOnlinePlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, pi := range onlinePlugins {
|
||||
if pi.ID == pluginID {
|
||||
latestPluginInfo = pi
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pInfo *entity.PluginInfo
|
||||
for _, p := range pluginsInfo {
|
||||
if p.ID == pluginID {
|
||||
pInfo = p
|
||||
break
|
||||
}
|
||||
}
|
||||
if pInfo == nil {
|
||||
return nil, nil, vo.NewError(errno.ErrPluginIDNotFound, errorx.KV("id", strconv.FormatInt(pluginID, 10)))
|
||||
}
|
||||
|
||||
if isDraft {
|
||||
tools, err := s.DomainSVC.MGetDraftTools(ctx, toolIDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
} else if pluginEntity.PluginVersion == nil || (pluginEntity.PluginVersion != nil && *pluginEntity.PluginVersion == "") {
|
||||
tools, err := s.DomainSVC.MGetOnlineTools(ctx, toolIDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
} else {
|
||||
eVersionTools := slices.Transform(toolIDs, func(tid int64) entity.VersionTool {
|
||||
return entity.VersionTool{
|
||||
ToolID: tid,
|
||||
Version: *pluginEntity.PluginVersion,
|
||||
}
|
||||
})
|
||||
tools, err := s.DomainSVC.MGetVersionTools(ctx, eVersionTools)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
}
|
||||
|
||||
if latestPluginInfo != nil {
|
||||
return &pluginInfo{PluginInfo: pInfo, LatestVersion: latestPluginInfo.Version}, toolsInfo, nil
|
||||
}
|
||||
|
||||
return &pluginInfo{PluginInfo: pInfo}, toolsInfo, nil
|
||||
}
|
||||
|
||||
func (s *impl) GetPluginToolsInfo(ctx context.Context, req *model.ToolsInfoRequest) (
|
||||
_ *model.ToolsInfoResponse, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var toolsInfo []*entity.ToolInfo
|
||||
isDraft := req.IsDraft || (req.PluginEntity.PluginVersion != nil && *req.PluginEntity.PluginVersion == "0")
|
||||
pInfo, toolsInfo, err := s.getPluginsWithTools(ctx, &model.PluginEntity{PluginID: req.PluginEntity.PluginID, PluginVersion: req.PluginEntity.PluginVersion}, req.ToolIDs, isDraft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url, err := s.tos.GetObjectUrl(ctx, pInfo.GetIconURI())
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrTOSError, err)
|
||||
}
|
||||
|
||||
response := &model.ToolsInfoResponse{
|
||||
PluginID: pInfo.ID,
|
||||
SpaceID: pInfo.SpaceID,
|
||||
Version: pInfo.GetVersion(),
|
||||
PluginName: pInfo.GetName(),
|
||||
Description: pInfo.GetDesc(),
|
||||
IconURL: url,
|
||||
PluginType: int64(pInfo.PluginType),
|
||||
ToolInfoList: make(map[int64]model.ToolInfoW),
|
||||
LatestVersion: pInfo.LatestVersion,
|
||||
IsOfficial: pInfo.IsOfficial(),
|
||||
AppID: pInfo.GetAPPID(),
|
||||
}
|
||||
|
||||
for _, tf := range toolsInfo {
|
||||
inputs, err := tf.ToReqAPIParameter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputs, err := tf.ToRespAPIParameter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toolExample := pInfo.GetToolExample(ctx, tf.GetName())
|
||||
|
||||
var (
|
||||
requestExample string
|
||||
responseExample string
|
||||
)
|
||||
if toolExample != nil {
|
||||
requestExample = toolExample.RequestExample
|
||||
responseExample = toolExample.ResponseExample
|
||||
}
|
||||
|
||||
response.ToolInfoList[tf.ID] = model.ToolInfoW{
|
||||
ToolID: tf.ID,
|
||||
ToolName: tf.GetName(),
|
||||
Inputs: slices.Transform(inputs, toWorkflowAPIParameter),
|
||||
Outputs: slices.Transform(outputs, toWorkflowAPIParameter),
|
||||
Description: tf.GetDesc(),
|
||||
DebugExample: &model.DebugExample{
|
||||
ReqExample: requestExample,
|
||||
RespExample: responseExample,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *impl) GetPluginInvokableTools(ctx context.Context, req *model.ToolsInvokableRequest) (
|
||||
_ map[int64]crossplugin.InvokableTool, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var toolsInfo []*entity.ToolInfo
|
||||
isDraft := req.IsDraft || (req.PluginEntity.PluginVersion != nil && *req.PluginEntity.PluginVersion == "0")
|
||||
pInfo, toolsInfo, err := s.getPluginsWithTools(ctx, &model.PluginEntity{
|
||||
PluginID: req.PluginEntity.PluginID,
|
||||
PluginVersion: req.PluginEntity.PluginVersion,
|
||||
}, maps.Keys(req.ToolsInvokableInfo), isDraft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := map[int64]crossplugin.InvokableTool{}
|
||||
for _, tf := range toolsInfo {
|
||||
tl := &pluginInvokeTool{
|
||||
pluginEntity: model.PluginEntity{
|
||||
PluginID: pInfo.ID,
|
||||
PluginVersion: pInfo.Version,
|
||||
},
|
||||
client: s.DomainSVC,
|
||||
toolInfo: tf,
|
||||
IsDraft: isDraft,
|
||||
}
|
||||
|
||||
if r, ok := req.ToolsInvokableInfo[tf.ID]; ok && (r.RequestAPIParametersConfig != nil && r.ResponseAPIParametersConfig != nil) {
|
||||
reqPluginCommonAPIParameters := slices.Transform(r.RequestAPIParametersConfig, toPluginCommonAPIParameter)
|
||||
respPluginCommonAPIParameters := slices.Transform(r.ResponseAPIParametersConfig, toPluginCommonAPIParameter)
|
||||
|
||||
tl.toolOperation, err = pluginutil.APIParamsToOpenapiOperation(reqPluginCommonAPIParameters, respPluginCommonAPIParameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tl.toolOperation.OperationID = tf.Operation.OperationID
|
||||
tl.toolOperation.Summary = tf.Operation.Summary
|
||||
}
|
||||
|
||||
result[tf.ID] = tl
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *impl) ExecutePlugin(ctx context.Context, input map[string]any, pe *model.PluginEntity,
|
||||
toolID int64, cfg model.ExecuteConfig) (map[string]any, error) {
|
||||
args, err := sonic.MarshalString(input)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
|
||||
var uID string
|
||||
if cfg.AgentID != nil {
|
||||
uID = cfg.ConnectorUID
|
||||
} else {
|
||||
uID = conv.Int64ToStr(cfg.Operator)
|
||||
}
|
||||
|
||||
req := &service.ExecuteToolRequest{
|
||||
UserID: uID,
|
||||
PluginID: pe.PluginID,
|
||||
ToolID: toolID,
|
||||
ExecScene: model.ExecSceneOfWorkflow,
|
||||
ArgumentsInJson: args,
|
||||
ExecDraftTool: pe.PluginVersion == nil || *pe.PluginVersion == "0",
|
||||
}
|
||||
execOpts := []entity.ExecuteToolOpt{
|
||||
model.WithInvalidRespProcessStrategy(model.InvalidResponseProcessStrategyOfReturnDefault),
|
||||
}
|
||||
|
||||
if pe.PluginVersion != nil {
|
||||
execOpts = append(execOpts, model.WithToolVersion(*pe.PluginVersion))
|
||||
}
|
||||
|
||||
r, err := s.DomainSVC.ExecuteTool(ctx, req, execOpts...)
|
||||
if err != nil {
|
||||
if extra, ok := compose.IsInterruptRerunError(err); ok {
|
||||
pluginTIE, ok := extra.(*model.ToolInterruptEvent)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrPluginAPIErr, fmt.Errorf("expects ToolInterruptEvent, got %T", extra))
|
||||
}
|
||||
|
||||
var eventType workflow3.EventType
|
||||
switch pluginTIE.Event {
|
||||
case model.InterruptEventTypeOfToolNeedOAuth:
|
||||
eventType = workflow3.EventType_WorkflowOauthPlugin
|
||||
default:
|
||||
return nil, vo.WrapError(errno.ErrPluginAPIErr,
|
||||
fmt.Errorf("unsupported interrupt event type: %s", pluginTIE.Event))
|
||||
}
|
||||
|
||||
id, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrIDGenError, err)
|
||||
}
|
||||
|
||||
ie := &entity2.InterruptEvent{
|
||||
ID: id,
|
||||
InterruptData: pluginTIE.ToolNeedOAuth.Message,
|
||||
EventType: eventType,
|
||||
}
|
||||
|
||||
// temporarily replace interrupt with real error, until frontend can handle plugin oauth interrupt
|
||||
interruptData := ie.InterruptData
|
||||
return nil, vo.NewError(errno.ErrAuthorizationRequired, errorx.KV("extra", interruptData))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var output map[string]any
|
||||
err = sonic.UnmarshalString(r.TrimmedResp, &output)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
type pluginInvokeTool struct {
|
||||
pluginEntity model.PluginEntity
|
||||
client service.PluginService
|
||||
toolInfo *entity.ToolInfo
|
||||
toolOperation *openapi3.Operation
|
||||
IsDraft bool
|
||||
}
|
||||
|
||||
func (p *pluginInvokeTool) Info(ctx context.Context) (_ *schema.ToolInfo, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var parameterInfo map[string]*schema.ParameterInfo
|
||||
if p.toolOperation != nil {
|
||||
parameterInfo, err = model.NewOpenapi3Operation(p.toolOperation).ToEinoSchemaParameterInfo(ctx)
|
||||
} else {
|
||||
parameterInfo, err = p.toolInfo.Operation.ToEinoSchemaParameterInfo(ctx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &schema.ToolInfo{
|
||||
Name: p.toolInfo.GetName(),
|
||||
Desc: p.toolInfo.GetDesc(),
|
||||
ParamsOneOf: schema.NewParamsOneOfByParams(parameterInfo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *pluginInvokeTool) PluginInvoke(ctx context.Context, argumentsInJSON string, cfg model.ExecuteConfig) (string, error) {
|
||||
req := &service.ExecuteToolRequest{
|
||||
UserID: conv.Int64ToStr(cfg.Operator),
|
||||
PluginID: p.pluginEntity.PluginID,
|
||||
ToolID: p.toolInfo.ID,
|
||||
ExecScene: model.ExecSceneOfWorkflow,
|
||||
ArgumentsInJson: argumentsInJSON,
|
||||
ExecDraftTool: p.IsDraft,
|
||||
}
|
||||
execOpts := []entity.ExecuteToolOpt{
|
||||
model.WithInvalidRespProcessStrategy(model.InvalidResponseProcessStrategyOfReturnDefault),
|
||||
}
|
||||
|
||||
if p.pluginEntity.PluginVersion != nil {
|
||||
execOpts = append(execOpts, model.WithToolVersion(*p.pluginEntity.PluginVersion))
|
||||
}
|
||||
|
||||
if p.toolOperation != nil {
|
||||
execOpts = append(execOpts, model.WithOpenapiOperation(model.NewOpenapi3Operation(p.toolOperation)))
|
||||
}
|
||||
|
||||
r, err := p.client.ExecuteTool(ctx, req, execOpts...)
|
||||
if err != nil {
|
||||
if extra, ok := compose.IsInterruptRerunError(err); ok {
|
||||
pluginTIE, ok := extra.(*model.ToolInterruptEvent)
|
||||
if !ok {
|
||||
return "", vo.WrapError(errno.ErrPluginAPIErr, fmt.Errorf("expects ToolInterruptEvent, got %T", extra))
|
||||
}
|
||||
|
||||
var eventType workflow3.EventType
|
||||
switch pluginTIE.Event {
|
||||
case model.InterruptEventTypeOfToolNeedOAuth:
|
||||
eventType = workflow3.EventType_WorkflowOauthPlugin
|
||||
default:
|
||||
return "", vo.WrapError(errno.ErrPluginAPIErr,
|
||||
fmt.Errorf("unsupported interrupt event type: %s", pluginTIE.Event))
|
||||
}
|
||||
|
||||
id, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return "", vo.WrapError(errno.ErrIDGenError, err)
|
||||
}
|
||||
|
||||
ie := &entity2.InterruptEvent{
|
||||
ID: id,
|
||||
InterruptData: pluginTIE.ToolNeedOAuth.Message,
|
||||
EventType: eventType,
|
||||
}
|
||||
|
||||
tie := &entity2.ToolInterruptEvent{
|
||||
ToolCallID: compose.GetToolCallID(ctx),
|
||||
ToolName: p.toolInfo.GetName(),
|
||||
InterruptEvent: ie,
|
||||
}
|
||||
|
||||
// temporarily replace interrupt with real error, until frontend can handle plugin oauth interrupt
|
||||
_ = tie
|
||||
interruptData := ie.InterruptData
|
||||
return "", vo.NewError(errno.ErrAuthorizationRequired, errorx.KV("extra", interruptData))
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return r.TrimmedResp, nil
|
||||
}
|
||||
|
||||
func toPluginCommonAPIParameter(parameter *workflow3.APIParameter) *common.APIParameter {
|
||||
if parameter == nil {
|
||||
return nil
|
||||
}
|
||||
p := &common.APIParameter{
|
||||
ID: parameter.ID,
|
||||
Name: parameter.Name,
|
||||
Desc: parameter.Desc,
|
||||
Type: common.ParameterType(parameter.Type),
|
||||
Location: common.ParameterLocation(parameter.Location),
|
||||
IsRequired: parameter.IsRequired,
|
||||
GlobalDefault: parameter.GlobalDefault,
|
||||
GlobalDisable: parameter.GlobalDisable,
|
||||
LocalDefault: parameter.LocalDefault,
|
||||
LocalDisable: parameter.LocalDisable,
|
||||
VariableRef: parameter.VariableRef,
|
||||
}
|
||||
if parameter.SubType != nil {
|
||||
p.SubType = ptr.Of(common.ParameterType(*parameter.SubType))
|
||||
}
|
||||
|
||||
if parameter.DefaultParamSource != nil {
|
||||
p.DefaultParamSource = ptr.Of(common.DefaultParamSource(*parameter.DefaultParamSource))
|
||||
}
|
||||
if parameter.AssistType != nil {
|
||||
p.AssistType = ptr.Of(common.AssistParameterType(*parameter.AssistType))
|
||||
}
|
||||
|
||||
if len(parameter.SubParameters) > 0 {
|
||||
p.SubParameters = make([]*common.APIParameter, 0, len(parameter.SubParameters))
|
||||
for _, subParam := range parameter.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toPluginCommonAPIParameter(subParam))
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func toWorkflowAPIParameter(parameter *common.APIParameter) *workflow3.APIParameter {
|
||||
if parameter == nil {
|
||||
return nil
|
||||
}
|
||||
p := &workflow3.APIParameter{
|
||||
ID: parameter.ID,
|
||||
Name: parameter.Name,
|
||||
Desc: parameter.Desc,
|
||||
Type: workflow3.ParameterType(parameter.Type),
|
||||
Location: workflow3.ParameterLocation(parameter.Location),
|
||||
IsRequired: parameter.IsRequired,
|
||||
GlobalDefault: parameter.GlobalDefault,
|
||||
GlobalDisable: parameter.GlobalDisable,
|
||||
LocalDefault: parameter.LocalDefault,
|
||||
LocalDisable: parameter.LocalDisable,
|
||||
VariableRef: parameter.VariableRef,
|
||||
}
|
||||
if parameter.SubType != nil {
|
||||
p.SubType = ptr.Of(workflow3.ParameterType(*parameter.SubType))
|
||||
}
|
||||
|
||||
if parameter.DefaultParamSource != nil {
|
||||
p.DefaultParamSource = ptr.Of(workflow3.DefaultParamSource(*parameter.DefaultParamSource))
|
||||
}
|
||||
if parameter.AssistType != nil {
|
||||
p.AssistType = ptr.Of(workflow3.AssistParameterType(*parameter.AssistType))
|
||||
}
|
||||
|
||||
// Check if it's an array that needs unwrapping.
|
||||
if parameter.Type == common.ParameterType_Array && len(parameter.SubParameters) == 1 && parameter.SubParameters[0].Name == "[Array Item]" {
|
||||
arrayItem := parameter.SubParameters[0]
|
||||
p.SubType = ptr.Of(workflow3.ParameterType(arrayItem.Type))
|
||||
// If the "[Array Item]" is an object, its sub-parameters become the array's sub-parameters.
|
||||
if arrayItem.Type == common.ParameterType_Object {
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, len(arrayItem.SubParameters))
|
||||
for _, subParam := range arrayItem.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(subParam))
|
||||
}
|
||||
} else {
|
||||
// The array's SubType is the Type of the "[Array Item]".
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, 1)
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(arrayItem))
|
||||
p.SubParameters[0].Name = "" // Remove the "[Array Item]" name.
|
||||
}
|
||||
} else if len(parameter.SubParameters) > 0 { // A simple object or a non-wrapped array.
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, len(parameter.SubParameters))
|
||||
for _, subParam := range parameter.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(subParam))
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
crossworkflow "github.com/coze-dev/coze-studio/backend/crossdomain/contract/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
@@ -67,11 +68,11 @@ func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, con
|
||||
func (i *impl) WithResumeToolWorkflow(resumingEvent *workflowEntity.ToolInterruptEvent, resumeData string, allInterruptEvents map[string]*workflowEntity.ToolInterruptEvent) einoCompose.Option {
|
||||
return i.DomainSVC.WithResumeToolWorkflow(resumingEvent, resumeData, allInterruptEvents)
|
||||
}
|
||||
func (i *impl) SyncExecuteWorkflow(ctx context.Context, config vo.ExecuteConfig, input map[string]any) (*workflowEntity.WorkflowExecution, vo.TerminatePlan, error) {
|
||||
func (i *impl) SyncExecuteWorkflow(ctx context.Context, config model.ExecuteConfig, input map[string]any) (*workflowEntity.WorkflowExecution, vo.TerminatePlan, error) {
|
||||
return i.DomainSVC.SyncExecute(ctx, config, input)
|
||||
}
|
||||
|
||||
func (i *impl) WithExecuteConfig(cfg vo.ExecuteConfig) einoCompose.Option {
|
||||
func (i *impl) WithExecuteConfig(cfg model.ExecuteConfig) einoCompose.Option {
|
||||
return i.DomainSVC.WithExecuteConfig(cfg)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,533 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop/common"
|
||||
workflow3 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/pluginutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
crossplugin "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/plugin"
|
||||
entity2 "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type pluginService struct {
|
||||
client service.PluginService
|
||||
tos storage.Storage
|
||||
}
|
||||
|
||||
func NewPluginService(client service.PluginService, tos storage.Storage) crossplugin.Service {
|
||||
return &pluginService{client: client, tos: tos}
|
||||
}
|
||||
|
||||
type pluginInfo struct {
|
||||
*entity.PluginInfo
|
||||
LatestVersion *string
|
||||
}
|
||||
|
||||
func (t *pluginService) getPluginsWithTools(ctx context.Context, pluginEntity *crossplugin.Entity, toolIDs []int64, isDraft bool) (
|
||||
_ *pluginInfo, toolsInfo []*entity.ToolInfo, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var pluginsInfo []*entity.PluginInfo
|
||||
var latestPluginInfo *entity.PluginInfo
|
||||
pluginID := pluginEntity.PluginID
|
||||
if isDraft {
|
||||
plugins, err := t.client.MGetDraftPlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
} else if pluginEntity.PluginVersion == nil || (pluginEntity.PluginVersion != nil && *pluginEntity.PluginVersion == "") {
|
||||
plugins, err := t.client.MGetOnlinePlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
|
||||
} else {
|
||||
plugins, err := t.client.MGetVersionPlugins(ctx, []entity.VersionPlugin{
|
||||
{PluginID: pluginID, Version: *pluginEntity.PluginVersion},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pluginsInfo = plugins
|
||||
|
||||
onlinePlugins, err := t.client.MGetOnlinePlugins(ctx, []int64{pluginID})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, pi := range onlinePlugins {
|
||||
if pi.ID == pluginID {
|
||||
latestPluginInfo = pi
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pInfo *entity.PluginInfo
|
||||
for _, p := range pluginsInfo {
|
||||
if p.ID == pluginID {
|
||||
pInfo = p
|
||||
break
|
||||
}
|
||||
}
|
||||
if pInfo == nil {
|
||||
return nil, nil, vo.NewError(errno.ErrPluginIDNotFound, errorx.KV("id", strconv.FormatInt(pluginID, 10)))
|
||||
}
|
||||
|
||||
if isDraft {
|
||||
tools, err := t.client.MGetDraftTools(ctx, toolIDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
} else if pluginEntity.PluginVersion == nil || (pluginEntity.PluginVersion != nil && *pluginEntity.PluginVersion == "") {
|
||||
tools, err := t.client.MGetOnlineTools(ctx, toolIDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
} else {
|
||||
eVersionTools := slices.Transform(toolIDs, func(tid int64) entity.VersionTool {
|
||||
return entity.VersionTool{
|
||||
ToolID: tid,
|
||||
Version: *pluginEntity.PluginVersion,
|
||||
}
|
||||
})
|
||||
tools, err := t.client.MGetVersionTools(ctx, eVersionTools)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toolsInfo = tools
|
||||
}
|
||||
|
||||
if latestPluginInfo != nil {
|
||||
return &pluginInfo{PluginInfo: pInfo, LatestVersion: latestPluginInfo.Version}, toolsInfo, nil
|
||||
}
|
||||
|
||||
return &pluginInfo{PluginInfo: pInfo}, toolsInfo, nil
|
||||
}
|
||||
|
||||
func (t *pluginService) GetPluginToolsInfo(ctx context.Context, req *crossplugin.ToolsInfoRequest) (
|
||||
_ *crossplugin.ToolsInfoResponse, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var toolsInfo []*entity.ToolInfo
|
||||
isDraft := req.IsDraft || (req.PluginEntity.PluginVersion != nil && *req.PluginEntity.PluginVersion == "0")
|
||||
pInfo, toolsInfo, err := t.getPluginsWithTools(ctx, &crossplugin.Entity{PluginID: req.PluginEntity.PluginID, PluginVersion: req.PluginEntity.PluginVersion}, req.ToolIDs, isDraft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url, err := t.tos.GetObjectUrl(ctx, pInfo.GetIconURI())
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrTOSError, err)
|
||||
}
|
||||
|
||||
response := &crossplugin.ToolsInfoResponse{
|
||||
PluginID: pInfo.ID,
|
||||
SpaceID: pInfo.SpaceID,
|
||||
Version: pInfo.GetVersion(),
|
||||
PluginName: pInfo.GetName(),
|
||||
Description: pInfo.GetDesc(),
|
||||
IconURL: url,
|
||||
PluginType: int64(pInfo.PluginType),
|
||||
ToolInfoList: make(map[int64]crossplugin.ToolInfo),
|
||||
LatestVersion: pInfo.LatestVersion,
|
||||
IsOfficial: pInfo.IsOfficial(),
|
||||
AppID: pInfo.GetAPPID(),
|
||||
}
|
||||
|
||||
for _, tf := range toolsInfo {
|
||||
inputs, err := tf.ToReqAPIParameter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputs, err := tf.ToRespAPIParameter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toolExample := pInfo.GetToolExample(ctx, tf.GetName())
|
||||
|
||||
var (
|
||||
requestExample string
|
||||
responseExample string
|
||||
)
|
||||
if toolExample != nil {
|
||||
requestExample = toolExample.RequestExample
|
||||
responseExample = toolExample.ResponseExample
|
||||
}
|
||||
|
||||
response.ToolInfoList[tf.ID] = crossplugin.ToolInfo{
|
||||
ToolID: tf.ID,
|
||||
ToolName: tf.GetName(),
|
||||
Inputs: slices.Transform(inputs, toWorkflowAPIParameter),
|
||||
Outputs: slices.Transform(outputs, toWorkflowAPIParameter),
|
||||
Description: tf.GetDesc(),
|
||||
DebugExample: &crossplugin.DebugExample{
|
||||
ReqExample: requestExample,
|
||||
RespExample: responseExample,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (t *pluginService) GetPluginInvokableTools(ctx context.Context, req *crossplugin.ToolsInvokableRequest) (
|
||||
_ map[int64]crossplugin.InvokableTool, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var toolsInfo []*entity.ToolInfo
|
||||
isDraft := req.IsDraft || (req.PluginEntity.PluginVersion != nil && *req.PluginEntity.PluginVersion == "0")
|
||||
pInfo, toolsInfo, err := t.getPluginsWithTools(ctx, &crossplugin.Entity{
|
||||
PluginID: req.PluginEntity.PluginID,
|
||||
PluginVersion: req.PluginEntity.PluginVersion,
|
||||
}, maps.Keys(req.ToolsInvokableInfo), isDraft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := map[int64]crossplugin.InvokableTool{}
|
||||
for _, tf := range toolsInfo {
|
||||
tl := &pluginInvokeTool{
|
||||
pluginEntity: crossplugin.Entity{
|
||||
PluginID: pInfo.ID,
|
||||
PluginVersion: pInfo.Version,
|
||||
},
|
||||
client: t.client,
|
||||
toolInfo: tf,
|
||||
IsDraft: isDraft,
|
||||
}
|
||||
|
||||
if r, ok := req.ToolsInvokableInfo[tf.ID]; ok && (r.RequestAPIParametersConfig != nil && r.ResponseAPIParametersConfig != nil) {
|
||||
reqPluginCommonAPIParameters := slices.Transform(r.RequestAPIParametersConfig, toPluginCommonAPIParameter)
|
||||
respPluginCommonAPIParameters := slices.Transform(r.ResponseAPIParametersConfig, toPluginCommonAPIParameter)
|
||||
|
||||
tl.toolOperation, err = pluginutil.APIParamsToOpenapiOperation(reqPluginCommonAPIParameters, respPluginCommonAPIParameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tl.toolOperation.OperationID = tf.Operation.OperationID
|
||||
tl.toolOperation.Summary = tf.Operation.Summary
|
||||
}
|
||||
|
||||
result[tf.ID] = tl
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (t *pluginService) ExecutePlugin(ctx context.Context, input map[string]any, pe *crossplugin.Entity,
|
||||
toolID int64, cfg crossplugin.ExecConfig) (map[string]any, error) {
|
||||
args, err := sonic.MarshalString(input)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
|
||||
var uID string
|
||||
if cfg.AgentID != nil {
|
||||
uID = cfg.ConnectorUID
|
||||
} else {
|
||||
uID = conv.Int64ToStr(cfg.Operator)
|
||||
}
|
||||
|
||||
req := &service.ExecuteToolRequest{
|
||||
UserID: uID,
|
||||
PluginID: pe.PluginID,
|
||||
ToolID: toolID,
|
||||
ExecScene: plugin.ExecSceneOfWorkflow,
|
||||
ArgumentsInJson: args,
|
||||
ExecDraftTool: pe.PluginVersion == nil || *pe.PluginVersion == "0",
|
||||
}
|
||||
execOpts := []entity.ExecuteToolOpt{
|
||||
plugin.WithInvalidRespProcessStrategy(plugin.InvalidResponseProcessStrategyOfReturnDefault),
|
||||
}
|
||||
|
||||
if pe.PluginVersion != nil {
|
||||
execOpts = append(execOpts, plugin.WithToolVersion(*pe.PluginVersion))
|
||||
}
|
||||
|
||||
r, err := t.client.ExecuteTool(ctx, req, execOpts...)
|
||||
if err != nil {
|
||||
if extra, ok := compose.IsInterruptRerunError(err); ok {
|
||||
pluginTIE, ok := extra.(*plugin.ToolInterruptEvent)
|
||||
if !ok {
|
||||
return nil, vo.WrapError(errno.ErrPluginAPIErr, fmt.Errorf("expects ToolInterruptEvent, got %T", extra))
|
||||
}
|
||||
|
||||
var eventType workflow3.EventType
|
||||
switch pluginTIE.Event {
|
||||
case plugin.InterruptEventTypeOfToolNeedOAuth:
|
||||
eventType = workflow3.EventType_WorkflowOauthPlugin
|
||||
default:
|
||||
return nil, vo.WrapError(errno.ErrPluginAPIErr,
|
||||
fmt.Errorf("unsupported interrupt event type: %s", pluginTIE.Event))
|
||||
}
|
||||
|
||||
id, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrIDGenError, err)
|
||||
}
|
||||
|
||||
ie := &entity2.InterruptEvent{
|
||||
ID: id,
|
||||
InterruptData: pluginTIE.ToolNeedOAuth.Message,
|
||||
EventType: eventType,
|
||||
}
|
||||
|
||||
// temporarily replace interrupt with real error, until frontend can handle plugin oauth interrupt
|
||||
interruptData := ie.InterruptData
|
||||
return nil, vo.NewError(errno.ErrAuthorizationRequired, errorx.KV("extra", interruptData))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var output map[string]any
|
||||
err = sonic.UnmarshalString(r.TrimmedResp, &output)
|
||||
if err != nil {
|
||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
type pluginInvokeTool struct {
|
||||
pluginEntity crossplugin.Entity
|
||||
client service.PluginService
|
||||
toolInfo *entity.ToolInfo
|
||||
toolOperation *openapi3.Operation
|
||||
IsDraft bool
|
||||
}
|
||||
|
||||
func (p *pluginInvokeTool) Info(ctx context.Context) (_ *schema.ToolInfo, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrPluginAPIErr, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var parameterInfo map[string]*schema.ParameterInfo
|
||||
if p.toolOperation != nil {
|
||||
parameterInfo, err = plugin.NewOpenapi3Operation(p.toolOperation).ToEinoSchemaParameterInfo(ctx)
|
||||
} else {
|
||||
parameterInfo, err = p.toolInfo.Operation.ToEinoSchemaParameterInfo(ctx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &schema.ToolInfo{
|
||||
Name: p.toolInfo.GetName(),
|
||||
Desc: p.toolInfo.GetDesc(),
|
||||
ParamsOneOf: schema.NewParamsOneOfByParams(parameterInfo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *pluginInvokeTool) PluginInvoke(ctx context.Context, argumentsInJSON string, cfg crossplugin.ExecConfig) (string, error) {
|
||||
req := &service.ExecuteToolRequest{
|
||||
UserID: conv.Int64ToStr(cfg.Operator),
|
||||
PluginID: p.pluginEntity.PluginID,
|
||||
ToolID: p.toolInfo.ID,
|
||||
ExecScene: plugin.ExecSceneOfWorkflow,
|
||||
ArgumentsInJson: argumentsInJSON,
|
||||
ExecDraftTool: p.IsDraft,
|
||||
}
|
||||
execOpts := []entity.ExecuteToolOpt{
|
||||
plugin.WithInvalidRespProcessStrategy(plugin.InvalidResponseProcessStrategyOfReturnDefault),
|
||||
}
|
||||
|
||||
if p.pluginEntity.PluginVersion != nil {
|
||||
execOpts = append(execOpts, plugin.WithToolVersion(*p.pluginEntity.PluginVersion))
|
||||
}
|
||||
|
||||
if p.toolOperation != nil {
|
||||
execOpts = append(execOpts, plugin.WithOpenapiOperation(plugin.NewOpenapi3Operation(p.toolOperation)))
|
||||
}
|
||||
|
||||
r, err := p.client.ExecuteTool(ctx, req, execOpts...)
|
||||
if err != nil {
|
||||
if extra, ok := compose.IsInterruptRerunError(err); ok {
|
||||
pluginTIE, ok := extra.(*plugin.ToolInterruptEvent)
|
||||
if !ok {
|
||||
return "", vo.WrapError(errno.ErrPluginAPIErr, fmt.Errorf("expects ToolInterruptEvent, got %T", extra))
|
||||
}
|
||||
|
||||
var eventType workflow3.EventType
|
||||
switch pluginTIE.Event {
|
||||
case plugin.InterruptEventTypeOfToolNeedOAuth:
|
||||
eventType = workflow3.EventType_WorkflowOauthPlugin
|
||||
default:
|
||||
return "", vo.WrapError(errno.ErrPluginAPIErr,
|
||||
fmt.Errorf("unsupported interrupt event type: %s", pluginTIE.Event))
|
||||
}
|
||||
|
||||
id, err := workflow.GetRepository().GenID(ctx)
|
||||
if err != nil {
|
||||
return "", vo.WrapError(errno.ErrIDGenError, err)
|
||||
}
|
||||
|
||||
ie := &entity2.InterruptEvent{
|
||||
ID: id,
|
||||
InterruptData: pluginTIE.ToolNeedOAuth.Message,
|
||||
EventType: eventType,
|
||||
}
|
||||
|
||||
tie := &entity2.ToolInterruptEvent{
|
||||
ToolCallID: compose.GetToolCallID(ctx),
|
||||
ToolName: p.toolInfo.GetName(),
|
||||
InterruptEvent: ie,
|
||||
}
|
||||
|
||||
// temporarily replace interrupt with real error, until frontend can handle plugin oauth interrupt
|
||||
_ = tie
|
||||
interruptData := ie.InterruptData
|
||||
return "", vo.NewError(errno.ErrAuthorizationRequired, errorx.KV("extra", interruptData))
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return r.TrimmedResp, nil
|
||||
}
|
||||
|
||||
func toPluginCommonAPIParameter(parameter *workflow3.APIParameter) *common.APIParameter {
|
||||
if parameter == nil {
|
||||
return nil
|
||||
}
|
||||
p := &common.APIParameter{
|
||||
ID: parameter.ID,
|
||||
Name: parameter.Name,
|
||||
Desc: parameter.Desc,
|
||||
Type: common.ParameterType(parameter.Type),
|
||||
Location: common.ParameterLocation(parameter.Location),
|
||||
IsRequired: parameter.IsRequired,
|
||||
GlobalDefault: parameter.GlobalDefault,
|
||||
GlobalDisable: parameter.GlobalDisable,
|
||||
LocalDefault: parameter.LocalDefault,
|
||||
LocalDisable: parameter.LocalDisable,
|
||||
VariableRef: parameter.VariableRef,
|
||||
}
|
||||
if parameter.SubType != nil {
|
||||
p.SubType = ptr.Of(common.ParameterType(*parameter.SubType))
|
||||
}
|
||||
|
||||
if parameter.DefaultParamSource != nil {
|
||||
p.DefaultParamSource = ptr.Of(common.DefaultParamSource(*parameter.DefaultParamSource))
|
||||
}
|
||||
if parameter.AssistType != nil {
|
||||
p.AssistType = ptr.Of(common.AssistParameterType(*parameter.AssistType))
|
||||
}
|
||||
|
||||
if len(parameter.SubParameters) > 0 {
|
||||
p.SubParameters = make([]*common.APIParameter, 0, len(parameter.SubParameters))
|
||||
for _, subParam := range parameter.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toPluginCommonAPIParameter(subParam))
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func toWorkflowAPIParameter(parameter *common.APIParameter) *workflow3.APIParameter {
|
||||
if parameter == nil {
|
||||
return nil
|
||||
}
|
||||
p := &workflow3.APIParameter{
|
||||
ID: parameter.ID,
|
||||
Name: parameter.Name,
|
||||
Desc: parameter.Desc,
|
||||
Type: workflow3.ParameterType(parameter.Type),
|
||||
Location: workflow3.ParameterLocation(parameter.Location),
|
||||
IsRequired: parameter.IsRequired,
|
||||
GlobalDefault: parameter.GlobalDefault,
|
||||
GlobalDisable: parameter.GlobalDisable,
|
||||
LocalDefault: parameter.LocalDefault,
|
||||
LocalDisable: parameter.LocalDisable,
|
||||
VariableRef: parameter.VariableRef,
|
||||
}
|
||||
if parameter.SubType != nil {
|
||||
p.SubType = ptr.Of(workflow3.ParameterType(*parameter.SubType))
|
||||
}
|
||||
|
||||
if parameter.DefaultParamSource != nil {
|
||||
p.DefaultParamSource = ptr.Of(workflow3.DefaultParamSource(*parameter.DefaultParamSource))
|
||||
}
|
||||
if parameter.AssistType != nil {
|
||||
p.AssistType = ptr.Of(workflow3.AssistParameterType(*parameter.AssistType))
|
||||
}
|
||||
|
||||
// Check if it's an array that needs unwrapping.
|
||||
if parameter.Type == common.ParameterType_Array && len(parameter.SubParameters) == 1 && parameter.SubParameters[0].Name == "[Array Item]" {
|
||||
arrayItem := parameter.SubParameters[0]
|
||||
p.SubType = ptr.Of(workflow3.ParameterType(arrayItem.Type))
|
||||
// If the "[Array Item]" is an object, its sub-parameters become the array's sub-parameters.
|
||||
if arrayItem.Type == common.ParameterType_Object {
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, len(arrayItem.SubParameters))
|
||||
for _, subParam := range arrayItem.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(subParam))
|
||||
}
|
||||
} else {
|
||||
// The array's SubType is the Type of the "[Array Item]".
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, 1)
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(arrayItem))
|
||||
p.SubParameters[0].Name = "" // Remove the "[Array Item]" name.
|
||||
}
|
||||
} else if len(parameter.SubParameters) > 0 { // A simple object or a non-wrapped array.
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, len(parameter.SubParameters))
|
||||
for _, subParam := range parameter.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(subParam))
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop/common"
|
||||
workflow3 "github.com/coze-dev/coze-studio/backend/api/model/workflow"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
)
|
||||
|
||||
func TestToWorkflowAPIParameter(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
param *common.APIParameter
|
||||
expected *workflow3.APIParameter
|
||||
}{
|
||||
{
|
||||
name: "nil parameter",
|
||||
param: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "simple string parameter",
|
||||
param: &common.APIParameter{
|
||||
Name: "prompt",
|
||||
Type: common.ParameterType_String,
|
||||
Desc: "User's prompt",
|
||||
},
|
||||
expected: &workflow3.APIParameter{
|
||||
Name: "prompt",
|
||||
Type: workflow3.ParameterType_String,
|
||||
Desc: "User's prompt",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple object parameter",
|
||||
param: &common.APIParameter{
|
||||
Name: "user_info",
|
||||
Type: common.ParameterType_Object,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "name",
|
||||
Type: common.ParameterType_String,
|
||||
},
|
||||
{
|
||||
Name: "age",
|
||||
Type: common.ParameterType_Number,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &workflow3.APIParameter{
|
||||
Name: "user_info",
|
||||
Type: workflow3.ParameterType_Object,
|
||||
SubParameters: []*workflow3.APIParameter{
|
||||
{
|
||||
Name: "name",
|
||||
Type: workflow3.ParameterType_String,
|
||||
},
|
||||
{
|
||||
Name: "age",
|
||||
Type: workflow3.ParameterType_Number,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "array of strings",
|
||||
param: &common.APIParameter{
|
||||
Name: "tags",
|
||||
Type: common.ParameterType_Array,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "[Array Item]",
|
||||
Type: common.ParameterType_String,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &workflow3.APIParameter{
|
||||
Name: "tags",
|
||||
Type: workflow3.ParameterType_Array,
|
||||
SubType: ptr.Of(workflow3.ParameterType_String),
|
||||
SubParameters: []*workflow3.APIParameter{
|
||||
{
|
||||
Type: workflow3.ParameterType_String,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "array of objects",
|
||||
param: &common.APIParameter{
|
||||
Name: "users",
|
||||
Type: common.ParameterType_Array,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "[Array Item]",
|
||||
Type: common.ParameterType_Object,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "name",
|
||||
Type: common.ParameterType_String,
|
||||
},
|
||||
{
|
||||
Name: "id",
|
||||
Type: common.ParameterType_Number,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &workflow3.APIParameter{
|
||||
Name: "users",
|
||||
Type: workflow3.ParameterType_Array,
|
||||
SubType: ptr.Of(workflow3.ParameterType_Object),
|
||||
SubParameters: []*workflow3.APIParameter{
|
||||
{
|
||||
Name: "name",
|
||||
Type: workflow3.ParameterType_String,
|
||||
},
|
||||
{
|
||||
Name: "id",
|
||||
Type: workflow3.ParameterType_Number,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "array of array of strings",
|
||||
param: &common.APIParameter{
|
||||
Name: "matrix",
|
||||
Type: common.ParameterType_Array,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "[Array Item]",
|
||||
Type: common.ParameterType_Array,
|
||||
SubParameters: []*common.APIParameter{
|
||||
{
|
||||
Name: "[Array Item]",
|
||||
Type: common.ParameterType_String,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &workflow3.APIParameter{
|
||||
Name: "matrix",
|
||||
Type: workflow3.ParameterType_Array,
|
||||
SubType: ptr.Of(workflow3.ParameterType_Array),
|
||||
SubParameters: []*workflow3.APIParameter{
|
||||
{
|
||||
Name: "", // Name is cleared
|
||||
Type: workflow3.ParameterType_Array,
|
||||
SubType: ptr.Of(workflow3.ParameterType_String),
|
||||
SubParameters: []*workflow3.APIParameter{
|
||||
{
|
||||
Type: workflow3.ParameterType_String,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual := toWorkflowAPIParameter(tc.param)
|
||||
assert.Equal(t, tc.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user