feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
47
backend/crossdomain/contract/crossagent/single_agent.go
Normal file
47
backend/crossdomain/contract/crossagent/single_agent.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 crossagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/singleagent"
|
||||
)
|
||||
|
||||
// Requests and responses must not reference domain entities and can only use models under api/model/crossdomain.
|
||||
type SingleAgent interface {
|
||||
StreamExecute(ctx context.Context, historyMsg []*message.Message, query *message.Message,
|
||||
agentRuntime *singleagent.AgentRuntime) (*schema.StreamReader[*singleagent.AgentEvent], error)
|
||||
ObtainAgentByIdentity(ctx context.Context, identity *singleagent.AgentIdentity) (*singleagent.SingleAgent, error)
|
||||
}
|
||||
|
||||
type ResumeInfo = singleagent.InterruptInfo
|
||||
|
||||
type AgentEvent = singleagent.AgentEvent
|
||||
|
||||
var defaultSVC SingleAgent
|
||||
|
||||
func DefaultSVC() SingleAgent {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc SingleAgent) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 crossagentrun
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type AgentRun interface {
|
||||
Delete(ctx context.Context, runID []int64) error
|
||||
}
|
||||
|
||||
var defaultSVC AgentRun
|
||||
|
||||
func DefaultSVC() AgentRun {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc AgentRun) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 crossconnector
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/connector"
|
||||
)
|
||||
|
||||
type Connector interface {
|
||||
List(ctx context.Context) ([]*connector.Connector, error)
|
||||
GetByIDs(ctx context.Context, ids []int64) (map[int64]*connector.Connector, error)
|
||||
GetByID(ctx context.Context, id int64) (*connector.Connector, error)
|
||||
}
|
||||
|
||||
var defaultSVC Connector
|
||||
|
||||
func DefaultSVC() Connector {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c Connector) {
|
||||
defaultSVC = c
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 crossconversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/conversation"
|
||||
)
|
||||
|
||||
type Conversation interface {
|
||||
GetCurrentConversation(ctx context.Context, req *conversation.GetCurrent) (*conversation.Conversation, error)
|
||||
}
|
||||
|
||||
var defaultSVC Conversation
|
||||
|
||||
func DefaultSVC() Conversation {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c Conversation) {
|
||||
defaultSVC = c
|
||||
}
|
||||
43
backend/crossdomain/contract/crossdatabase/cross_database.go
Normal file
43
backend/crossdomain/contract/crossdatabase/cross_database.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 crossdatabase
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
)
|
||||
|
||||
type Database interface {
|
||||
ExecuteSQL(ctx context.Context, req *database.ExecuteSQLRequest) (*database.ExecuteSQLResponse, error)
|
||||
PublishDatabase(ctx context.Context, req *database.PublishDatabaseRequest) (resp *database.PublishDatabaseResponse, err error)
|
||||
DeleteDatabase(ctx context.Context, req *database.DeleteDatabaseRequest) error
|
||||
BindDatabase(ctx context.Context, req *database.BindDatabaseToAgentRequest) error
|
||||
UnBindDatabase(ctx context.Context, req *database.UnBindDatabaseToAgentRequest) error
|
||||
MGetDatabase(ctx context.Context, req *database.MGetDatabaseRequest) (*database.MGetDatabaseResponse, error)
|
||||
GetAllDatabaseByAppID(ctx context.Context, req *database.GetAllDatabaseByAppIDRequest) (*database.GetAllDatabaseByAppIDResponse, error)
|
||||
}
|
||||
|
||||
var defaultSVC Database
|
||||
|
||||
func DefaultSVC() Database {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c Database) {
|
||||
defaultSVC = c
|
||||
}
|
||||
41
backend/crossdomain/contract/crossdatacopy/cross_datacopy.go
Normal file
41
backend/crossdomain/contract/crossdatacopy/cross_datacopy.go
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 crossdatacopy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/datacopy"
|
||||
)
|
||||
|
||||
type DataCopy interface {
|
||||
CheckAndGenCopyTask(ctx context.Context, req *datacopy.CheckAndGenCopyTaskReq) (*datacopy.CheckAndGenCopyTaskResp, error)
|
||||
UpdateCopyTask(ctx context.Context, req *datacopy.UpdateCopyTaskReq) error
|
||||
UpdateCopyTaskWithTX(ctx context.Context, req *datacopy.UpdateCopyTaskReq, tx *gorm.DB) error
|
||||
}
|
||||
|
||||
var defaultSVC DataCopy
|
||||
|
||||
func DefaultSVC() DataCopy {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c DataCopy) {
|
||||
defaultSVC = c
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 crossknowledge
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
)
|
||||
|
||||
type Knowledge interface {
|
||||
ListKnowledge(ctx context.Context, request *knowledge.ListKnowledgeRequest) (response *knowledge.ListKnowledgeResponse, err error)
|
||||
GetKnowledgeByID(ctx context.Context, request *knowledge.GetKnowledgeByIDRequest) (response *knowledge.GetKnowledgeByIDResponse, err error)
|
||||
Retrieve(ctx context.Context, req *knowledge.RetrieveRequest) (*knowledge.RetrieveResponse, error)
|
||||
DeleteKnowledge(ctx context.Context, request *knowledge.DeleteKnowledgeRequest) error
|
||||
}
|
||||
|
||||
var defaultSVC Knowledge
|
||||
|
||||
func DefaultSVC() Knowledge {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c Knowledge) {
|
||||
defaultSVC = c
|
||||
}
|
||||
41
backend/crossdomain/contract/crossmessage/cross_message.go
Normal file
41
backend/crossdomain/contract/crossmessage/cross_message.go
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 crossmessage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
)
|
||||
|
||||
type Message interface {
|
||||
GetByRunIDs(ctx context.Context, conversationID int64, runIDs []int64) ([]*message.Message, error)
|
||||
Create(ctx context.Context, msg *message.Message) (*message.Message, error)
|
||||
Edit(ctx context.Context, msg *message.Message) (*message.Message, error)
|
||||
}
|
||||
|
||||
var defaultSVC Message
|
||||
|
||||
type MessageMeta = message.Message
|
||||
|
||||
func DefaultSVC() Message {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c Message) {
|
||||
defaultSVC = c
|
||||
}
|
||||
39
backend/crossdomain/contract/crossmodelmgr/cross_modelmgr.go
Normal file
39
backend/crossdomain/contract/crossmodelmgr/cross_modelmgr.go
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 crossmodelmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
)
|
||||
|
||||
type ModelMgr interface {
|
||||
MGetModelByID(ctx context.Context, req *modelmgr.MGetModelRequest) ([]*modelmgr.Model, error)
|
||||
}
|
||||
|
||||
type Model = modelmgr.Model
|
||||
|
||||
var defaultSVC ModelMgr
|
||||
|
||||
func DefaultSVC() ModelMgr {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(c ModelMgr) {
|
||||
defaultSVC = c
|
||||
}
|
||||
48
backend/crossdomain/contract/crossplugin/cross_plugin.go
Normal file
48
backend/crossdomain/contract/crossplugin/cross_plugin.go
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 crossplugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
)
|
||||
|
||||
type PluginService interface {
|
||||
MGetVersionPlugins(ctx context.Context, versionPlugins []model.VersionPlugin) (plugins []*model.PluginInfo, err error)
|
||||
MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (resp *model.MGetPluginLatestVersionResponse, err error)
|
||||
BindAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error)
|
||||
DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error)
|
||||
MGetAgentTools(ctx context.Context, req *model.MGetAgentToolsRequest) (tools []*model.ToolInfo, err error)
|
||||
ExecuteTool(ctx context.Context, req *model.ExecuteToolRequest, opts ...model.ExecuteToolOpt) (resp *model.ExecuteToolResponse, err error)
|
||||
PublishAgentTools(ctx context.Context, agentID int64, agentVersion string) (err error)
|
||||
DeleteDraftPlugin(ctx context.Context, PluginID int64) (err error)
|
||||
PublishPlugin(ctx context.Context, req *model.PublishPluginRequest) (err error)
|
||||
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)
|
||||
}
|
||||
|
||||
var defaultSVC PluginService
|
||||
|
||||
func DefaultSVC() PluginService {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc PluginService) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
37
backend/crossdomain/contract/crosssearch/cross_search.go
Normal file
37
backend/crossdomain/contract/crosssearch/cross_search.go
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 crosssearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/search"
|
||||
)
|
||||
|
||||
type Search interface {
|
||||
SearchResources(ctx context.Context, req *model.SearchResourcesRequest) (resp *model.SearchResourcesResponse, err error)
|
||||
}
|
||||
|
||||
var defaultSVC Search
|
||||
|
||||
func DefaultSVC() Search {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc Search) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
40
backend/crossdomain/contract/crossuser/crossuser.go
Normal file
40
backend/crossdomain/contract/crossuser/crossuser.go
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 crossuser
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/user/entity"
|
||||
)
|
||||
|
||||
type EntitySpace = entity.Space
|
||||
|
||||
//go:generate mockgen -destination ../../../internal/mock/crossdomain/crossuser/crossuser.go --package mockCrossUser -source crossuser.go
|
||||
type User interface {
|
||||
GetUserSpaceList(ctx context.Context, userID int64) (spaces []*EntitySpace, err error)
|
||||
}
|
||||
|
||||
var defaultSVC User
|
||||
|
||||
func DefaultSVC() User {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(u User) {
|
||||
defaultSVC = u
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 crossvariables
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/variables"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/kvmemory"
|
||||
)
|
||||
|
||||
type Variables interface {
|
||||
GetVariableInstance(ctx context.Context, e *variables.UserVariableMeta, keywords []string) ([]*kvmemory.KVItem, error)
|
||||
SetVariableInstance(ctx context.Context, e *variables.UserVariableMeta, items []*kvmemory.KVItem) ([]string, error)
|
||||
DecryptSysUUIDKey(ctx context.Context, encryptSysUUIDKey string) *variables.UserVariableMeta
|
||||
}
|
||||
|
||||
var defaultSVC Variables
|
||||
|
||||
func DefaultSVC() Variables {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc Variables) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
77
backend/crossdomain/contract/crossworkflow/crossworkflow.go
Normal file
77
backend/crossdomain/contract/crossworkflow/crossworkflow.go
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 crossworkflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
workflowEntity "github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
)
|
||||
|
||||
// TODO(@fanlv): 参数引用需要修改。
|
||||
type Workflow interface {
|
||||
WorkflowAsModelTool(ctx context.Context, policies []*vo.GetPolicy) ([]workflow.ToolFromWorkflow, error)
|
||||
DeleteWorkflow(ctx context.Context, id int64) error
|
||||
PublishWorkflow(ctx context.Context, info *vo.PublishPolicy) (err error)
|
||||
WithResumeToolWorkflow(resumingEvent *workflowEntity.ToolInterruptEvent, resumeData string,
|
||||
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
|
||||
}
|
||||
|
||||
type ExecuteConfig = vo.ExecuteConfig
|
||||
type ExecuteMode = vo.ExecuteMode
|
||||
|
||||
const (
|
||||
ExecuteModeDebug ExecuteMode = "debug"
|
||||
ExecuteModeRelease ExecuteMode = "release"
|
||||
ExecuteModeNodeDebug ExecuteMode = "node_debug"
|
||||
)
|
||||
|
||||
type TaskType = vo.TaskType
|
||||
|
||||
const (
|
||||
TaskTypeForeground TaskType = "foreground"
|
||||
TaskTypeBackground TaskType = "background"
|
||||
)
|
||||
|
||||
type BizType = vo.BizType
|
||||
|
||||
const (
|
||||
BizTypeAgent BizType = "agent"
|
||||
BizTypeWorkflow BizType = "workflow"
|
||||
)
|
||||
|
||||
type ReleaseWorkflowConfig = vo.ReleaseWorkflowConfig
|
||||
|
||||
type ToolInterruptEvent = workflowEntity.ToolInterruptEvent
|
||||
|
||||
var defaultSVC Workflow
|
||||
|
||||
func DefaultSVC() Workflow {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func SetDefaultSVC(svc Workflow) {
|
||||
defaultSVC = svc
|
||||
}
|
||||
46
backend/crossdomain/impl/agentrun/agent_run.go
Normal file
46
backend/crossdomain/impl/agentrun/agent_run.go
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 agentrun
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossagentrun"
|
||||
agentrun "github.com/coze-dev/coze-studio/backend/domain/conversation/agentrun/service"
|
||||
)
|
||||
|
||||
type AgentRun interface {
|
||||
Delete(ctx context.Context, runID []int64) error
|
||||
}
|
||||
|
||||
var defaultSVC crossagentrun.AgentRun
|
||||
|
||||
type impl struct {
|
||||
DomainSVC agentrun.Run
|
||||
}
|
||||
|
||||
func InitDomainService(c agentrun.Run) crossagentrun.AgentRun {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (c *impl) Delete(ctx context.Context, runID []int64) error {
|
||||
return c.DomainSVC.Delete(ctx, runID)
|
||||
}
|
||||
80
backend/crossdomain/impl/connector/connector.go
Normal file
80
backend/crossdomain/impl/connector/connector.go
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/connector"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossconnector"
|
||||
connector "github.com/coze-dev/coze-studio/backend/domain/connector/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossconnector.Connector
|
||||
|
||||
func InitDomainService(c connector.Connector) crossconnector.Connector {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func DefaultSVC() crossconnector.Connector {
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
type impl struct {
|
||||
DomainSVC connector.Connector
|
||||
}
|
||||
|
||||
func (c *impl) GetByIDs(ctx context.Context, ids []int64) (map[int64]*model.Connector, error) {
|
||||
res, err := c.DomainSVC.GetByIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make(map[int64]*model.Connector, len(res))
|
||||
for _, v := range res {
|
||||
ret[v.ID] = v.Connector
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *impl) List(ctx context.Context) ([]*model.Connector, error) {
|
||||
res, err := c.DomainSVC.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]*model.Connector, 0, len(res))
|
||||
for _, v := range res {
|
||||
ret = append(ret, v.Connector)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *impl) GetByID(ctx context.Context, id int64) (*model.Connector, error) {
|
||||
info, err := c.DomainSVC.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info.Connector, nil
|
||||
}
|
||||
42
backend/crossdomain/impl/conversation/conversation.go
Normal file
42
backend/crossdomain/impl/conversation/conversation.go
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 conversation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/conversation"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossconversation"
|
||||
conversation "github.com/coze-dev/coze-studio/backend/domain/conversation/conversation/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossconversation.Conversation
|
||||
|
||||
type impl struct {
|
||||
DomainSVC conversation.Conversation
|
||||
}
|
||||
|
||||
func InitDomainService(c conversation.Conversation) crossconversation.Conversation {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (s *impl) GetCurrentConversation(ctx context.Context, req *model.GetCurrent) (*model.Conversation, error) {
|
||||
return s.DomainSVC.GetCurrentConversation(ctx, req)
|
||||
}
|
||||
42
backend/crossdomain/impl/crossuser/crossuser.go
Normal file
42
backend/crossdomain/impl/crossuser/crossuser.go
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 crossuser
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossuser"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/user/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/user/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossuser.User
|
||||
|
||||
type impl struct {
|
||||
DomainSVC service.User
|
||||
}
|
||||
|
||||
func InitDomainService(u service.User) crossuser.User {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: u,
|
||||
}
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (u *impl) GetUserSpaceList(ctx context.Context, userID int64) (spaces []*entity.Space, err error) {
|
||||
return u.DomainSVC.GetUserSpaceList(ctx, userID)
|
||||
}
|
||||
67
backend/crossdomain/impl/database/database.go
Normal file
67
backend/crossdomain/impl/database/database.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossdatabase"
|
||||
database "github.com/coze-dev/coze-studio/backend/domain/memory/database/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossdatabase.Database
|
||||
|
||||
type databaseImpl struct {
|
||||
DomainSVC database.Database
|
||||
}
|
||||
|
||||
func InitDomainService(c database.Database) crossdatabase.Database {
|
||||
defaultSVC = &databaseImpl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (c *databaseImpl) ExecuteSQL(ctx context.Context, req *model.ExecuteSQLRequest) (*model.ExecuteSQLResponse, error) {
|
||||
return c.DomainSVC.ExecuteSQL(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) PublishDatabase(ctx context.Context, req *model.PublishDatabaseRequest) (resp *model.PublishDatabaseResponse, err error) {
|
||||
return c.DomainSVC.PublishDatabase(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) DeleteDatabase(ctx context.Context, req *model.DeleteDatabaseRequest) error {
|
||||
return c.DomainSVC.DeleteDatabase(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) BindDatabase(ctx context.Context, req *model.BindDatabaseToAgentRequest) error {
|
||||
return c.DomainSVC.BindDatabase(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) UnBindDatabase(ctx context.Context, req *model.UnBindDatabaseToAgentRequest) error {
|
||||
return c.DomainSVC.UnBindDatabase(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) MGetDatabase(ctx context.Context, req *model.MGetDatabaseRequest) (*model.MGetDatabaseResponse, error) {
|
||||
return c.DomainSVC.MGetDatabase(ctx, req)
|
||||
}
|
||||
|
||||
func (c *databaseImpl) GetAllDatabaseByAppID(ctx context.Context, req *model.GetAllDatabaseByAppIDRequest) (*model.GetAllDatabaseByAppIDResponse, error) {
|
||||
return c.DomainSVC.GetAllDatabaseByAppID(ctx, req)
|
||||
}
|
||||
53
backend/crossdomain/impl/datacopy/datacopy.go
Normal file
53
backend/crossdomain/impl/datacopy/datacopy.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 datacopy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/appinfra"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossdatacopy"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/datacopy"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/datacopy/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossdatacopy.DataCopy
|
||||
|
||||
type impl struct {
|
||||
DomainSVC datacopy.DataCopy
|
||||
}
|
||||
|
||||
func InitDomainService(a *appinfra.AppDependencies) crossdatacopy.DataCopy {
|
||||
svc := service.NewDataCopySVC(&service.DataCopySVCConfig{
|
||||
DB: a.DB,
|
||||
IDGen: a.IDGenSVC,
|
||||
})
|
||||
return svc
|
||||
}
|
||||
|
||||
func (i *impl) CheckAndGenCopyTask(ctx context.Context, req *datacopy.CheckAndGenCopyTaskReq) (*datacopy.CheckAndGenCopyTaskResp, error) {
|
||||
return i.DomainSVC.CheckAndGenCopyTask(ctx, req)
|
||||
}
|
||||
|
||||
func (i *impl) UpdateCopyTask(ctx context.Context, req *datacopy.UpdateCopyTaskReq) error {
|
||||
return i.DomainSVC.UpdateCopyTask(ctx, req)
|
||||
}
|
||||
func (i *impl) UpdateCopyTaskWithTX(ctx context.Context, req *datacopy.UpdateCopyTaskReq, tx *gorm.DB) error {
|
||||
return i.DomainSVC.UpdateCopyTaskWithTX(ctx, req, tx)
|
||||
}
|
||||
59
backend/crossdomain/impl/knowledge/knowledge.go
Normal file
59
backend/crossdomain/impl/knowledge/knowledge.go
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 knowledge
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossknowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/knowledge/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossknowledge.Knowledge
|
||||
|
||||
type impl struct {
|
||||
DomainSVC service.Knowledge
|
||||
}
|
||||
|
||||
func InitDomainService(c service.Knowledge) crossknowledge.Knowledge {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (i *impl) ListKnowledge(ctx context.Context, request *model.ListKnowledgeRequest) (response *model.ListKnowledgeResponse, err error) {
|
||||
return i.DomainSVC.ListKnowledge(ctx, request)
|
||||
}
|
||||
|
||||
func (i *impl) Retrieve(ctx context.Context, req *model.RetrieveRequest) (*model.RetrieveResponse, error) {
|
||||
return i.DomainSVC.Retrieve(ctx, req)
|
||||
}
|
||||
|
||||
func (i *impl) DeleteKnowledge(ctx context.Context, req *model.DeleteKnowledgeRequest) error {
|
||||
return i.DomainSVC.DeleteKnowledge(ctx, req)
|
||||
}
|
||||
|
||||
func (i *impl) GetKnowledgeByID(ctx context.Context, request *model.GetKnowledgeByIDRequest) (response *model.GetKnowledgeByIDResponse, err error) {
|
||||
return i.DomainSVC.GetKnowledgeByID(ctx, request)
|
||||
}
|
||||
|
||||
func (i *impl) MGetKnowledgeByID(ctx context.Context, request *model.MGetKnowledgeByIDRequest) (response *model.MGetKnowledgeByIDResponse, err error) {
|
||||
return i.DomainSVC.MGetKnowledgeByID(ctx, request)
|
||||
}
|
||||
51
backend/crossdomain/impl/message/message.go
Normal file
51
backend/crossdomain/impl/message/message.go
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 message
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmessage"
|
||||
message "github.com/coze-dev/coze-studio/backend/domain/conversation/message/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossmessage.Message
|
||||
|
||||
type impl struct {
|
||||
DomainSVC message.Message
|
||||
}
|
||||
|
||||
func InitDomainService(c message.Message) crossmessage.Message {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (c *impl) GetByRunIDs(ctx context.Context, conversationID int64, runIDs []int64) ([]*model.Message, error) {
|
||||
return c.DomainSVC.GetByRunIDs(ctx, conversationID, runIDs)
|
||||
}
|
||||
|
||||
func (c *impl) Create(ctx context.Context, msg *model.Message) (*model.Message, error) {
|
||||
return c.DomainSVC.Create(ctx, msg)
|
||||
}
|
||||
|
||||
func (c *impl) Edit(ctx context.Context, msg *model.Message) (*model.Message, error) {
|
||||
return c.DomainSVC.Edit(ctx, msg)
|
||||
}
|
||||
52
backend/crossdomain/impl/modelmgr/modelmgr.go
Normal file
52
backend/crossdomain/impl/modelmgr/modelmgr.go
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 modelmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmodelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/modelmgr"
|
||||
)
|
||||
|
||||
var defaultSVC crossmodelmgr.ModelMgr
|
||||
|
||||
type impl struct {
|
||||
DomainSVC modelmgr.Manager
|
||||
}
|
||||
|
||||
func InitDomainService(c modelmgr.Manager) crossmodelmgr.ModelMgr {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (s *impl) MGetModelByID(ctx context.Context, req *modelmgr.MGetModelRequest) ([]*model.Model, error) {
|
||||
res, err := s.DomainSVC.MGetModelByID(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]*model.Model, 0, len(res))
|
||||
for _, v := range res {
|
||||
ret = append(ret, v.Model)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
107
backend/crossdomain/impl/plugin/plugin.go
Normal file
107
backend/crossdomain/impl/plugin/plugin.go
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossplugin"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
plugin "github.com/coze-dev/coze-studio/backend/domain/plugin/service"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
)
|
||||
|
||||
var defaultSVC crossplugin.PluginService
|
||||
|
||||
type impl struct {
|
||||
DomainSVC plugin.PluginService
|
||||
}
|
||||
|
||||
func InitDomainService(c plugin.PluginService) crossplugin.PluginService {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (s *impl) MGetVersionPlugins(ctx context.Context, versionPlugins []model.VersionPlugin) (mPlugins []*model.PluginInfo, err error) {
|
||||
plugins, err := s.DomainSVC.MGetVersionPlugins(ctx, versionPlugins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mPlugins = slices.Transform(plugins, func(e *entity.PluginInfo) *model.PluginInfo {
|
||||
return e.PluginInfo
|
||||
})
|
||||
|
||||
return mPlugins, nil
|
||||
}
|
||||
|
||||
func (s *impl) BindAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error) {
|
||||
return s.DomainSVC.BindAgentTools(ctx, agentID, toolIDs)
|
||||
}
|
||||
|
||||
func (s *impl) DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error) {
|
||||
return s.DomainSVC.DuplicateDraftAgentTools(ctx, fromAgentID, toAgentID)
|
||||
}
|
||||
|
||||
func (s *impl) MGetAgentTools(ctx context.Context, req *model.MGetAgentToolsRequest) (tools []*model.ToolInfo, err error) {
|
||||
return s.DomainSVC.MGetAgentTools(ctx, req)
|
||||
}
|
||||
|
||||
func (s *impl) ExecuteTool(ctx context.Context, req *model.ExecuteToolRequest, opts ...model.ExecuteToolOpt) (resp *model.ExecuteToolResponse, err error) {
|
||||
return s.DomainSVC.ExecuteTool(ctx, req, opts...)
|
||||
}
|
||||
|
||||
func (s *impl) PublishAgentTools(ctx context.Context, agentID int64, agentVersion string) (err error) {
|
||||
return s.DomainSVC.PublishAgentTools(ctx, agentID, agentVersion)
|
||||
}
|
||||
|
||||
func (s *impl) DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error) {
|
||||
return s.DomainSVC.DeleteDraftPlugin(ctx, pluginID)
|
||||
}
|
||||
|
||||
func (s *impl) PublishPlugin(ctx context.Context, req *model.PublishPluginRequest) (err error) {
|
||||
return s.DomainSVC.PublishPlugin(ctx, req)
|
||||
}
|
||||
|
||||
func (s *impl) PublishAPPPlugins(ctx context.Context, req *model.PublishAPPPluginsRequest) (resp *model.PublishAPPPluginsResponse, err error) {
|
||||
return s.DomainSVC.PublishAPPPlugins(ctx, req)
|
||||
}
|
||||
|
||||
func (s *impl) MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (resp *model.MGetPluginLatestVersionResponse, err error) {
|
||||
return s.DomainSVC.MGetPluginLatestVersion(ctx, pluginIDs)
|
||||
}
|
||||
|
||||
func (s *impl) MGetVersionTools(ctx context.Context, versionTools []model.VersionTool) (tools []*model.ToolInfo, err error) {
|
||||
return s.DomainSVC.MGetVersionTools(ctx, versionTools)
|
||||
}
|
||||
|
||||
func (s *impl) GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*model.PluginInfo, err error) {
|
||||
_plugins, err := s.DomainSVC.GetAPPAllPlugins(ctx, appID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plugins = slices.Transform(_plugins, func(e *entity.PluginInfo) *model.PluginInfo {
|
||||
return e.PluginInfo
|
||||
})
|
||||
|
||||
return plugins, nil
|
||||
}
|
||||
43
backend/crossdomain/impl/search/search.go
Normal file
43
backend/crossdomain/impl/search/search.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 search
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/search"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crosssearch"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/search/service"
|
||||
)
|
||||
|
||||
var defaultSVC crosssearch.Search
|
||||
|
||||
type impl struct {
|
||||
DomainSVC crosssearch.Search
|
||||
}
|
||||
|
||||
func (i impl) SearchResources(ctx context.Context, req *model.SearchResourcesRequest) (resp *model.SearchResourcesResponse, err error) {
|
||||
return i.DomainSVC.SearchResources(ctx, req)
|
||||
}
|
||||
|
||||
func InitDomainService(c service.Search) crosssearch.Search {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
191
backend/crossdomain/impl/singleagent/single_agent.go
Normal file
191
backend/crossdomain/impl/singleagent/single_agent.go
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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 agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/agentrun"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/message"
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/singleagent"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossagent"
|
||||
singleagent "github.com/coze-dev/coze-studio/backend/domain/agent/singleagent/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/conversation/message/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
)
|
||||
|
||||
var defaultSVC crossagent.SingleAgent
|
||||
|
||||
type impl struct {
|
||||
DomainSVC singleagent.SingleAgent
|
||||
}
|
||||
|
||||
func InitDomainService(c singleagent.SingleAgent) crossagent.SingleAgent {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (c *impl) StreamExecute(ctx context.Context, historyMsg []*message.Message,
|
||||
query *message.Message, agentRuntime *model.AgentRuntime,
|
||||
) (*schema.StreamReader[*model.AgentEvent], error) {
|
||||
|
||||
historyMsg = c.historyPairs(historyMsg)
|
||||
|
||||
singleAgentStreamExecReq := c.buildSingleAgentStreamExecuteReq(ctx, historyMsg, query, agentRuntime)
|
||||
|
||||
streamEvent, err := c.DomainSVC.StreamExecute(ctx, singleAgentStreamExecReq)
|
||||
logs.CtxInfof(ctx, "agent StreamExecute req:%v, streamEvent:%v, err:%v", conv.DebugJsonToStr(singleAgentStreamExecReq), streamEvent, err)
|
||||
return streamEvent, err
|
||||
}
|
||||
|
||||
func (c *impl) buildSingleAgentStreamExecuteReq(ctx context.Context, historyMsg []*message.Message,
|
||||
input *message.Message, agentRuntime *model.AgentRuntime,
|
||||
) *model.ExecuteRequest {
|
||||
identity := c.buildIdentity(input, agentRuntime)
|
||||
inputBuild := c.buildSchemaMessage([]*message.Message{input})
|
||||
history := c.buildSchemaMessage(historyMsg)
|
||||
|
||||
resumeInfo := c.checkResumeInfo(ctx, historyMsg)
|
||||
|
||||
return &model.ExecuteRequest{
|
||||
Identity: identity,
|
||||
Input: inputBuild[0],
|
||||
History: history,
|
||||
UserID: input.UserID,
|
||||
PreCallTools: slices.Transform(agentRuntime.PreRetrieveTools, func(tool *agentrun.Tool) *agentrun.ToolsRetriever {
|
||||
return &agentrun.ToolsRetriever{
|
||||
PluginID: tool.PluginID,
|
||||
ToolName: tool.ToolName,
|
||||
ToolID: tool.ToolID,
|
||||
Arguments: tool.Arguments,
|
||||
Type: func(toolType agentrun.ToolType) agentrun.ToolType {
|
||||
switch toolType {
|
||||
case agentrun.ToolTypeWorkflow:
|
||||
return agentrun.ToolTypeWorkflow
|
||||
case agentrun.ToolTypePlugin:
|
||||
return agentrun.ToolTypePlugin
|
||||
}
|
||||
return agentrun.ToolTypePlugin
|
||||
}(tool.Type),
|
||||
}
|
||||
}),
|
||||
|
||||
ResumeInfo: resumeInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *impl) historyPairs(historyMsg []*message.Message) []*message.Message {
|
||||
|
||||
fcMsgPairs := make(map[int64][]*message.Message)
|
||||
for _, one := range historyMsg {
|
||||
if one.MessageType != message.MessageTypeFunctionCall && one.MessageType != message.MessageTypeToolResponse {
|
||||
continue
|
||||
}
|
||||
if _, ok := fcMsgPairs[one.RunID]; !ok {
|
||||
fcMsgPairs[one.RunID] = []*message.Message{one}
|
||||
} else {
|
||||
fcMsgPairs[one.RunID] = append(fcMsgPairs[one.RunID], one)
|
||||
}
|
||||
}
|
||||
|
||||
var historyAfterPairs []*message.Message
|
||||
for _, value := range historyMsg {
|
||||
if value.MessageType == message.MessageTypeFunctionCall {
|
||||
if len(fcMsgPairs[value.RunID])%2 == 0 {
|
||||
historyAfterPairs = append(historyAfterPairs, value)
|
||||
}
|
||||
} else {
|
||||
historyAfterPairs = append(historyAfterPairs, value)
|
||||
}
|
||||
}
|
||||
return historyAfterPairs
|
||||
|
||||
}
|
||||
func (c *impl) checkResumeInfo(_ context.Context, historyMsg []*message.Message) *crossagent.ResumeInfo {
|
||||
|
||||
var resumeInfo *crossagent.ResumeInfo
|
||||
for i := len(historyMsg) - 1; i >= 0; i-- {
|
||||
if historyMsg[i].MessageType == message.MessageTypeQuestion {
|
||||
break
|
||||
}
|
||||
if historyMsg[i].MessageType == message.MessageTypeVerbose {
|
||||
if historyMsg[i].Ext[string(entity.ExtKeyResumeInfo)] != "" {
|
||||
err := json.Unmarshal([]byte(historyMsg[i].Ext[string(entity.ExtKeyResumeInfo)]), &resumeInfo)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resumeInfo
|
||||
}
|
||||
|
||||
func (c *impl) buildSchemaMessage(msgs []*message.Message) []*schema.Message {
|
||||
schemaMessage := make([]*schema.Message, 0, len(msgs))
|
||||
|
||||
for _, msgOne := range msgs {
|
||||
if msgOne.ModelContent == "" {
|
||||
continue
|
||||
}
|
||||
if msgOne.MessageType == message.MessageTypeVerbose || msgOne.MessageType == message.MessageTypeFlowUp {
|
||||
continue
|
||||
}
|
||||
var sm *schema.Message
|
||||
err := json.Unmarshal([]byte(msgOne.ModelContent), &sm)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
schemaMessage = append(schemaMessage, sm)
|
||||
}
|
||||
|
||||
return schemaMessage
|
||||
}
|
||||
|
||||
func (c *impl) buildIdentity(input *message.Message, agentRuntime *model.AgentRuntime) *model.AgentIdentity {
|
||||
return &model.AgentIdentity{
|
||||
AgentID: input.AgentID,
|
||||
Version: agentRuntime.AgentVersion,
|
||||
IsDraft: agentRuntime.IsDraft,
|
||||
ConnectorID: agentRuntime.ConnectorID,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *impl) GetSingleAgent(ctx context.Context, agentID int64, version string) (agent *model.SingleAgent, err error) {
|
||||
agentInfo, err := c.DomainSVC.GetSingleAgent(ctx, agentID, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return agentInfo.SingleAgent, nil
|
||||
}
|
||||
|
||||
func (c *impl) ObtainAgentByIdentity(ctx context.Context, identity *model.AgentIdentity) (*model.SingleAgent, error) {
|
||||
agentInfo, err := c.DomainSVC.ObtainAgentByIdentity(ctx, identity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agentInfo.SingleAgent, nil
|
||||
}
|
||||
66
backend/crossdomain/impl/variables/variables.go
Normal file
66
backend/crossdomain/impl/variables/variables.go
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 variables
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/variables"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/kvmemory"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossvariables"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/memory/variables/entity"
|
||||
variables "github.com/coze-dev/coze-studio/backend/domain/memory/variables/service"
|
||||
)
|
||||
|
||||
var defaultSVC crossvariables.Variables
|
||||
|
||||
type impl struct {
|
||||
DomainSVC variables.Variables
|
||||
}
|
||||
|
||||
func InitDomainService(c variables.Variables) crossvariables.Variables {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (s *impl) GetVariableInstance(ctx context.Context, e *model.UserVariableMeta, keywords []string) ([]*kvmemory.KVItem, error) {
|
||||
m := entity.NewUserVariableMeta(e)
|
||||
return s.DomainSVC.GetVariableInstance(ctx, m, keywords)
|
||||
}
|
||||
|
||||
func (s *impl) SetVariableInstance(ctx context.Context, e *model.UserVariableMeta, items []*kvmemory.KVItem) ([]string, error) {
|
||||
m := entity.NewUserVariableMeta(e)
|
||||
return s.DomainSVC.SetVariableInstance(ctx, m, items)
|
||||
}
|
||||
|
||||
func (s *impl) DecryptSysUUIDKey(ctx context.Context, encryptSysUUIDKey string) *model.UserVariableMeta {
|
||||
m := s.DomainSVC.DecryptSysUUIDKey(ctx, encryptSysUUIDKey)
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &model.UserVariableMeta{
|
||||
BizType: m.BizType,
|
||||
BizID: m.BizID,
|
||||
Version: m.Version,
|
||||
ConnectorUID: m.ConnectorUID,
|
||||
ConnectorID: m.ConnectorID,
|
||||
}
|
||||
}
|
||||
88
backend/crossdomain/impl/workflow/workflow.go
Normal file
88
backend/crossdomain/impl/workflow/workflow.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 workflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossworkflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow"
|
||||
workflowEntity "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/pkg/lang/ptr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
)
|
||||
|
||||
var defaultSVC crossworkflow.Workflow
|
||||
|
||||
type impl struct {
|
||||
DomainSVC workflow.Service
|
||||
}
|
||||
|
||||
func InitDomainService(c workflow.Service) crossworkflow.Workflow {
|
||||
defaultSVC = &impl{
|
||||
DomainSVC: c,
|
||||
}
|
||||
|
||||
return defaultSVC
|
||||
}
|
||||
|
||||
func (i *impl) WorkflowAsModelTool(ctx context.Context, policies []*vo.GetPolicy) ([]workflow.ToolFromWorkflow, error) {
|
||||
return i.DomainSVC.WorkflowAsModelTool(ctx, policies)
|
||||
}
|
||||
|
||||
func (i *impl) PublishWorkflow(ctx context.Context, info *vo.PublishPolicy) (err error) {
|
||||
return i.DomainSVC.Publish(ctx, info)
|
||||
}
|
||||
|
||||
func (i *impl) DeleteWorkflow(ctx context.Context, id int64) error {
|
||||
return i.DomainSVC.Delete(ctx, &vo.DeletePolicy{
|
||||
ID: ptr.Of(id),
|
||||
})
|
||||
}
|
||||
|
||||
func (i *impl) ReleaseApplicationWorkflows(ctx context.Context, appID int64, config *vo.ReleaseWorkflowConfig) ([]*vo.ValidateIssue, error) {
|
||||
return i.DomainSVC.ReleaseApplicationWorkflows(ctx, appID, config)
|
||||
}
|
||||
|
||||
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) {
|
||||
return i.DomainSVC.SyncExecute(ctx, config, input)
|
||||
}
|
||||
|
||||
func (i *impl) WithExecuteConfig(cfg vo.ExecuteConfig) einoCompose.Option {
|
||||
return i.DomainSVC.WithExecuteConfig(cfg)
|
||||
}
|
||||
|
||||
func (i *impl) GetWorkflowIDsByAppID(ctx context.Context, appID int64) ([]int64, error) {
|
||||
metas, _, err := i.DomainSVC.MGet(ctx, &vo.MGetPolicy{
|
||||
MetaQuery: vo.MetaQuery{
|
||||
AppID: ptr.Of(appID),
|
||||
},
|
||||
MetaOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return slices.Transform(metas, func(a *workflowEntity.Workflow) int64 {
|
||||
return a.ID
|
||||
}), err
|
||||
}
|
||||
442
backend/crossdomain/workflow/database/database.go
Normal file
442
backend/crossdomain/workflow/database/database.go
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* 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 database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/table"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/memory/database/service"
|
||||
nodedatabase "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/database"
|
||||
"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/ternary"
|
||||
)
|
||||
|
||||
type DatabaseRepository struct {
|
||||
client service.Database
|
||||
}
|
||||
|
||||
func NewDatabaseRepository(client service.Database) *DatabaseRepository {
|
||||
return &DatabaseRepository{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) Execute(ctx context.Context, request *nodedatabase.CustomSQLRequest) (*nodedatabase.Response, error) {
|
||||
var (
|
||||
err error
|
||||
databaseInfoID = request.DatabaseInfoID
|
||||
tableType = ternary.IFElse[table.TableType](request.IsDebugRun, table.TableType_DraftTable, table.TableType_OnlineTable)
|
||||
)
|
||||
|
||||
if request.IsDebugRun {
|
||||
databaseInfoID, err = d.getDraftTableID(ctx, databaseInfoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req := &service.ExecuteSQLRequest{
|
||||
DatabaseID: databaseInfoID,
|
||||
OperateType: database.OperateType_Custom,
|
||||
SQL: &request.SQL,
|
||||
TableType: tableType,
|
||||
UserID: strconv.FormatInt(request.UserID, 10),
|
||||
}
|
||||
|
||||
req.SQLParams = make([]*database.SQLParamVal, 0, len(request.Params))
|
||||
for i := range request.Params {
|
||||
param := request.Params[i]
|
||||
req.SQLParams = append(req.SQLParams, &database.SQLParamVal{
|
||||
ValueType: table.FieldItemType_Text,
|
||||
Value: ¶m.Value,
|
||||
ISNull: param.IsNull,
|
||||
})
|
||||
}
|
||||
response, err := d.client.ExecuteSQL(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if rows affected is nil use 0 instead
|
||||
if response.RowsAffected == nil {
|
||||
response.RowsAffected = ptr.Of(int64(0))
|
||||
}
|
||||
return toNodeDateBaseResponse(response), nil
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) Delete(ctx context.Context, request *nodedatabase.DeleteRequest) (*nodedatabase.Response, error) {
|
||||
var (
|
||||
err error
|
||||
databaseInfoID = request.DatabaseInfoID
|
||||
tableType = ternary.IFElse[table.TableType](request.IsDebugRun, table.TableType_DraftTable, table.TableType_OnlineTable)
|
||||
)
|
||||
|
||||
if request.IsDebugRun {
|
||||
databaseInfoID, err = d.getDraftTableID(ctx, databaseInfoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req := &service.ExecuteSQLRequest{
|
||||
DatabaseID: databaseInfoID,
|
||||
OperateType: database.OperateType_Delete,
|
||||
TableType: tableType,
|
||||
UserID: strconv.FormatInt(request.UserID, 10),
|
||||
}
|
||||
|
||||
if request.ConditionGroup != nil {
|
||||
req.Condition, req.SQLParams, err = buildComplexCondition(request.ConditionGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
response, err := d.client.ExecuteSQL(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toNodeDateBaseResponse(response), nil
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) Query(ctx context.Context, request *nodedatabase.QueryRequest) (*nodedatabase.Response, error) {
|
||||
var (
|
||||
err error
|
||||
databaseInfoID = request.DatabaseInfoID
|
||||
tableType = ternary.IFElse[table.TableType](request.IsDebugRun, table.TableType_DraftTable, table.TableType_OnlineTable)
|
||||
)
|
||||
|
||||
if request.IsDebugRun {
|
||||
databaseInfoID, err = d.getDraftTableID(ctx, databaseInfoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req := &service.ExecuteSQLRequest{
|
||||
DatabaseID: databaseInfoID,
|
||||
OperateType: database.OperateType_Select,
|
||||
TableType: tableType,
|
||||
UserID: strconv.FormatInt(request.UserID, 10),
|
||||
}
|
||||
|
||||
req.SelectFieldList = &database.SelectFieldList{FieldID: make([]string, 0, len(request.SelectFields))}
|
||||
for i := range request.SelectFields {
|
||||
req.SelectFieldList.FieldID = append(req.SelectFieldList.FieldID, request.SelectFields[i])
|
||||
}
|
||||
|
||||
req.OrderByList = make([]database.OrderBy, 0)
|
||||
for i := range request.OrderClauses {
|
||||
clause := request.OrderClauses[i]
|
||||
req.OrderByList = append(req.OrderByList, database.OrderBy{
|
||||
Field: clause.FieldID,
|
||||
Direction: toOrderDirection(clause.IsAsc),
|
||||
})
|
||||
}
|
||||
|
||||
if request.ConditionGroup != nil {
|
||||
req.Condition, req.SQLParams, err = buildComplexCondition(request.ConditionGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
limit := request.Limit
|
||||
req.Limit = &limit
|
||||
|
||||
response, err := d.client.ExecuteSQL(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toNodeDateBaseResponse(response), nil
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) Update(ctx context.Context, request *nodedatabase.UpdateRequest) (*nodedatabase.Response, error) {
|
||||
|
||||
var (
|
||||
err error
|
||||
condition *database.ComplexCondition
|
||||
params []*database.SQLParamVal
|
||||
databaseInfoID = request.DatabaseInfoID
|
||||
tableType = ternary.IFElse[table.TableType](request.IsDebugRun, table.TableType_DraftTable, table.TableType_OnlineTable)
|
||||
)
|
||||
|
||||
if request.IsDebugRun {
|
||||
databaseInfoID, err = d.getDraftTableID(ctx, databaseInfoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req := &service.ExecuteSQLRequest{
|
||||
DatabaseID: databaseInfoID,
|
||||
OperateType: database.OperateType_Update,
|
||||
SQLParams: make([]*database.SQLParamVal, 0),
|
||||
TableType: tableType,
|
||||
}
|
||||
|
||||
uid := ctxutil.GetUIDFromCtx(ctx)
|
||||
if uid != nil {
|
||||
req.UserID = conv.Int64ToStr(*uid)
|
||||
}
|
||||
req.UpsertRows, req.SQLParams, err = resolveUpsertRow(request.Fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if request.ConditionGroup != nil {
|
||||
condition, params, err = buildComplexCondition(request.ConditionGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Condition = condition
|
||||
req.SQLParams = append(req.SQLParams, params...)
|
||||
}
|
||||
|
||||
response, err := d.client.ExecuteSQL(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toNodeDateBaseResponse(response), nil
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) Insert(ctx context.Context, request *nodedatabase.InsertRequest) (*nodedatabase.Response, error) {
|
||||
var (
|
||||
err error
|
||||
databaseInfoID = request.DatabaseInfoID
|
||||
tableType = ternary.IFElse[table.TableType](request.IsDebugRun, table.TableType_DraftTable, table.TableType_OnlineTable)
|
||||
)
|
||||
|
||||
if request.IsDebugRun {
|
||||
databaseInfoID, err = d.getDraftTableID(ctx, databaseInfoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req := &service.ExecuteSQLRequest{
|
||||
DatabaseID: databaseInfoID,
|
||||
OperateType: database.OperateType_Insert,
|
||||
TableType: tableType,
|
||||
UserID: strconv.FormatInt(request.UserID, 10),
|
||||
}
|
||||
|
||||
req.UpsertRows, req.SQLParams, err = resolveUpsertRow(request.Fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := d.client.ExecuteSQL(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toNodeDateBaseResponse(response), nil
|
||||
}
|
||||
|
||||
func (d *DatabaseRepository) getDraftTableID(ctx context.Context, onlineID int64) (int64, error) {
|
||||
resp, err := d.client.GetDraftDatabaseByOnlineID(ctx, &service.GetDraftDatabaseByOnlineIDRequest{OnlineID: onlineID})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return resp.Database.ID, nil
|
||||
|
||||
}
|
||||
|
||||
func buildComplexCondition(conditionGroup *nodedatabase.ConditionGroup) (*database.ComplexCondition, []*database.SQLParamVal, error) {
|
||||
condition := &database.ComplexCondition{}
|
||||
logic, err := toLogic(conditionGroup.Relation)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
condition.Logic = logic
|
||||
|
||||
params := make([]*database.SQLParamVal, 0)
|
||||
for i := range conditionGroup.Conditions {
|
||||
var (
|
||||
nCond = conditionGroup.Conditions[i]
|
||||
vals []*database.SQLParamVal
|
||||
dCond = &database.Condition{
|
||||
Left: nCond.Left,
|
||||
}
|
||||
)
|
||||
opt, err := toOperation(nCond.Operator)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dCond.Operation = opt
|
||||
|
||||
if isNullOrNotNull(opt) {
|
||||
condition.Conditions = append(condition.Conditions, dCond)
|
||||
continue
|
||||
}
|
||||
dCond.Right, vals, err = resolveRightValue(opt, nCond.Right)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
condition.Conditions = append(condition.Conditions, dCond)
|
||||
|
||||
params = append(params, vals...)
|
||||
|
||||
}
|
||||
return condition, params, nil
|
||||
}
|
||||
|
||||
func toMapStringAny(m map[string]string) map[string]any {
|
||||
ret := make(map[string]any, len(m))
|
||||
for k, v := range m {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func toOperation(operator nodedatabase.Operator) (database.Operation, error) {
|
||||
switch operator {
|
||||
case nodedatabase.OperatorEqual:
|
||||
return database.Operation_EQUAL, nil
|
||||
case nodedatabase.OperatorNotEqual:
|
||||
return database.Operation_NOT_EQUAL, nil
|
||||
case nodedatabase.OperatorGreater:
|
||||
return database.Operation_GREATER_THAN, nil
|
||||
case nodedatabase.OperatorGreaterOrEqual:
|
||||
return database.Operation_GREATER_EQUAL, nil
|
||||
case nodedatabase.OperatorLesser:
|
||||
return database.Operation_LESS_THAN, nil
|
||||
case nodedatabase.OperatorLesserOrEqual:
|
||||
return database.Operation_LESS_EQUAL, nil
|
||||
case nodedatabase.OperatorIn:
|
||||
return database.Operation_IN, nil
|
||||
case nodedatabase.OperatorNotIn:
|
||||
return database.Operation_NOT_IN, nil
|
||||
case nodedatabase.OperatorIsNotNull:
|
||||
return database.Operation_IS_NOT_NULL, nil
|
||||
case nodedatabase.OperatorIsNull:
|
||||
return database.Operation_IS_NULL, nil
|
||||
case nodedatabase.OperatorLike:
|
||||
return database.Operation_LIKE, nil
|
||||
case nodedatabase.OperatorNotLike:
|
||||
return database.Operation_NOT_LIKE, nil
|
||||
default:
|
||||
return database.Operation(0), fmt.Errorf("invalid operator %v", operator)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveRightValue(operator database.Operation, right any) (string, []*database.SQLParamVal, error) {
|
||||
|
||||
if isInOrNotIn(operator) {
|
||||
var (
|
||||
vals = make([]*database.SQLParamVal, 0)
|
||||
anyVals = make([]any, 0)
|
||||
commas = make([]string, 0, len(anyVals))
|
||||
)
|
||||
|
||||
anyVals = right.([]any)
|
||||
for i := range anyVals {
|
||||
v := cast.ToString(anyVals[i])
|
||||
vals = append(vals, &database.SQLParamVal{ValueType: table.FieldItemType_Text, Value: &v})
|
||||
commas = append(commas, "?")
|
||||
}
|
||||
value := "(" + strings.Join(commas, ",") + ")"
|
||||
return value, vals, nil
|
||||
}
|
||||
|
||||
rightValue, err := cast.ToStringE(right)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if isLikeOrNotLike(operator) {
|
||||
var (
|
||||
value = "?"
|
||||
v = "%s" + rightValue + "%s"
|
||||
)
|
||||
return value, []*database.SQLParamVal{{ValueType: table.FieldItemType_Text, Value: &v}}, nil
|
||||
}
|
||||
|
||||
return "?", []*database.SQLParamVal{{ValueType: table.FieldItemType_Text, Value: &rightValue}}, nil
|
||||
}
|
||||
|
||||
func resolveUpsertRow(fields map[string]any) ([]*database.UpsertRow, []*database.SQLParamVal, error) {
|
||||
upsertRow := &database.UpsertRow{Records: make([]*database.Record, 0, len(fields))}
|
||||
params := make([]*database.SQLParamVal, 0)
|
||||
for key, value := range fields {
|
||||
val, err := cast.ToStringE(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
record := &database.Record{
|
||||
FieldId: key,
|
||||
FieldValue: "?",
|
||||
}
|
||||
upsertRow.Records = append(upsertRow.Records, record)
|
||||
params = append(params, &database.SQLParamVal{
|
||||
ValueType: table.FieldItemType_Text,
|
||||
Value: &val,
|
||||
})
|
||||
}
|
||||
return []*database.UpsertRow{upsertRow}, params, nil
|
||||
}
|
||||
|
||||
func isNullOrNotNull(opt database.Operation) bool {
|
||||
return opt == database.Operation_IS_NOT_NULL || opt == database.Operation_IS_NULL
|
||||
}
|
||||
|
||||
func isLikeOrNotLike(opt database.Operation) bool {
|
||||
return opt == database.Operation_LIKE || opt == database.Operation_NOT_LIKE
|
||||
}
|
||||
|
||||
func isInOrNotIn(opt database.Operation) bool {
|
||||
return opt == database.Operation_IN || opt == database.Operation_NOT_IN
|
||||
}
|
||||
|
||||
func toOrderDirection(isAsc bool) table.SortDirection {
|
||||
if isAsc {
|
||||
return table.SortDirection_ASC
|
||||
}
|
||||
return table.SortDirection_Desc
|
||||
}
|
||||
|
||||
func toLogic(relation nodedatabase.ClauseRelation) (database.Logic, error) {
|
||||
switch relation {
|
||||
case nodedatabase.ClauseRelationOR:
|
||||
return database.Logic_Or, nil
|
||||
case nodedatabase.ClauseRelationAND:
|
||||
return database.Logic_And, nil
|
||||
default:
|
||||
return database.Logic(0), fmt.Errorf("invalid relation %v", relation)
|
||||
}
|
||||
}
|
||||
|
||||
func toNodeDateBaseResponse(response *service.ExecuteSQLResponse) *nodedatabase.Response {
|
||||
objects := make([]nodedatabase.Object, 0, len(response.Records))
|
||||
for i := range response.Records {
|
||||
objects = append(objects, response.Records[i])
|
||||
}
|
||||
return &nodedatabase.Response{
|
||||
Objects: objects,
|
||||
RowNumber: response.RowsAffected,
|
||||
}
|
||||
}
|
||||
224
backend/crossdomain/workflow/database/database_test.go
Normal file
224
backend/crossdomain/workflow/database/database_test.go
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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 database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/database"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/memory/database/service"
|
||||
nodedatabase "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/database"
|
||||
mockDatabase "github.com/coze-dev/coze-studio/backend/internal/mock/domain/memory/database"
|
||||
)
|
||||
|
||||
func mockExecuteSQL(t *testing.T) func(ctx context.Context, request *service.ExecuteSQLRequest) (*service.ExecuteSQLResponse, error) {
|
||||
return func(ctx context.Context, request *service.ExecuteSQLRequest) (*service.ExecuteSQLResponse, error) {
|
||||
if request.OperateType == database.OperateType_Custom {
|
||||
assert.Equal(t, *request.SQL, "select * from table where v1=? and v2=?")
|
||||
rs := make([]string, 0)
|
||||
for idx := range request.SQLParams {
|
||||
rs = append(rs, *request.SQLParams[idx].Value)
|
||||
}
|
||||
assert.Equal(t, rs, []string{"1", "2"})
|
||||
return &service.ExecuteSQLResponse{
|
||||
Records: []map[string]any{
|
||||
{"v1": "1", "v2": "2"},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
if request.OperateType == database.OperateType_Select {
|
||||
sFields := []string{"v1", "v2", "v3", "v4"}
|
||||
assert.Equal(t, request.SelectFieldList.FieldID, sFields)
|
||||
cond := request.Condition.Conditions[1] // in
|
||||
assert.Equal(t, "(?,?)", cond.Right)
|
||||
assert.Equal(t, database.Operation_IN, cond.Operation)
|
||||
assert.Equal(t, "v2_1", *request.SQLParams[1].Value)
|
||||
assert.Equal(t, "v2_2", *request.SQLParams[2].Value)
|
||||
assert.Equal(t, "%sv4%s", *request.SQLParams[3].Value)
|
||||
rowsAffected := int64(10)
|
||||
return &service.ExecuteSQLResponse{
|
||||
Records: []map[string]any{
|
||||
{"v1": "1", "v2": "2", "v3": "3", "v4": "4"},
|
||||
},
|
||||
RowsAffected: &rowsAffected,
|
||||
}, nil
|
||||
|
||||
}
|
||||
if request.OperateType == database.OperateType_Delete {
|
||||
cond := request.Condition.Conditions[1] // in
|
||||
assert.Equal(t, "(?,?)", cond.Right)
|
||||
assert.Equal(t, database.Operation_NOT_IN, cond.Operation)
|
||||
assert.Equal(t, "v2_1", *request.SQLParams[1].Value)
|
||||
assert.Equal(t, "v2_2", *request.SQLParams[2].Value)
|
||||
assert.Equal(t, "%sv4%s", *request.SQLParams[3].Value)
|
||||
rowsAffected := int64(10)
|
||||
return &service.ExecuteSQLResponse{
|
||||
Records: []map[string]any{
|
||||
{"v1": "1", "v2": "2", "v3": "3", "v4": "4"},
|
||||
},
|
||||
RowsAffected: &rowsAffected,
|
||||
}, nil
|
||||
}
|
||||
if request.OperateType == database.OperateType_Insert {
|
||||
records := request.UpsertRows[0].Records
|
||||
ret := map[string]interface{}{
|
||||
"v1": "1",
|
||||
"v2": 2,
|
||||
"v3": 33,
|
||||
"v4": "44aacc",
|
||||
}
|
||||
for idx := range records {
|
||||
assert.Equal(t, *request.SQLParams[idx].Value, cast.ToString(ret[records[idx].FieldId]))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if request.OperateType == database.OperateType_Update {
|
||||
|
||||
records := request.UpsertRows[0].Records
|
||||
ret := map[string]interface{}{
|
||||
"v1": "1",
|
||||
"v2": 2,
|
||||
"v3": 33,
|
||||
"v4": "aabbcc",
|
||||
}
|
||||
for idx := range records {
|
||||
assert.Equal(t, *request.SQLParams[idx].Value, cast.ToString(ret[records[idx].FieldId]))
|
||||
}
|
||||
|
||||
request.SQLParams = request.SQLParams[len(records):]
|
||||
cond := request.Condition.Conditions[1] // in
|
||||
assert.Equal(t, "(?,?)", cond.Right)
|
||||
assert.Equal(t, database.Operation_IN, cond.Operation)
|
||||
assert.Equal(t, "v2_1", *request.SQLParams[1].Value)
|
||||
assert.Equal(t, "v2_2", *request.SQLParams[2].Value)
|
||||
assert.Equal(t, "%sv4%s", *request.SQLParams[3].Value)
|
||||
|
||||
}
|
||||
return &service.ExecuteSQLResponse{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabase_Database(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
mockClient := mockDatabase.NewMockDatabase(ctrl)
|
||||
defer ctrl.Finish()
|
||||
ds := DatabaseRepository{
|
||||
client: mockClient,
|
||||
}
|
||||
mockClient.EXPECT().ExecuteSQL(gomock.Any(), gomock.Any()).DoAndReturn(mockExecuteSQL(t)).AnyTimes()
|
||||
|
||||
t.Run("execute", func(t *testing.T) {
|
||||
response, err := ds.Execute(context.Background(), &nodedatabase.CustomSQLRequest{
|
||||
DatabaseInfoID: 1,
|
||||
SQL: "select * from table where v1=? and v2=?",
|
||||
Params: []nodedatabase.SQLParam{
|
||||
nodedatabase.SQLParam{Value: "1"},
|
||||
nodedatabase.SQLParam{Value: "2"},
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, response.Objects, []nodedatabase.Object{
|
||||
{"v1": "1", "v2": "2"},
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("select", func(t *testing.T) {
|
||||
req := &nodedatabase.QueryRequest{
|
||||
DatabaseInfoID: 1,
|
||||
SelectFields: []string{"v1", "v2", "v3", "v4"},
|
||||
Limit: 10,
|
||||
OrderClauses: []*nodedatabase.OrderClause{
|
||||
{FieldID: "v1", IsAsc: true},
|
||||
{FieldID: "v2", IsAsc: false},
|
||||
},
|
||||
ConditionGroup: &nodedatabase.ConditionGroup{
|
||||
Conditions: []*nodedatabase.Condition{
|
||||
{Left: "v1", Operator: nodedatabase.OperatorEqual, Right: "1"},
|
||||
{Left: "v2", Operator: nodedatabase.OperatorIn, Right: []any{"v2_1", "v2_2"}},
|
||||
{Left: "v3", Operator: nodedatabase.OperatorIsNull},
|
||||
{Left: "v4", Operator: nodedatabase.OperatorLike, Right: "v4"},
|
||||
},
|
||||
Relation: nodedatabase.ClauseRelationOR,
|
||||
},
|
||||
}
|
||||
|
||||
response, err := ds.Query(context.Background(), req)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *response.RowNumber, int64(10))
|
||||
})
|
||||
|
||||
t.Run("delete", func(t *testing.T) {
|
||||
req := &nodedatabase.DeleteRequest{
|
||||
DatabaseInfoID: 1,
|
||||
ConditionGroup: &nodedatabase.ConditionGroup{
|
||||
Conditions: []*nodedatabase.Condition{
|
||||
{Left: "v1", Operator: nodedatabase.OperatorEqual, Right: "1"},
|
||||
{Left: "v2", Operator: nodedatabase.OperatorNotIn, Right: []any{"v2_1", "v2_2"}},
|
||||
{Left: "v3", Operator: nodedatabase.OperatorIsNotNull},
|
||||
{Left: "v4", Operator: nodedatabase.OperatorNotLike, Right: "v4"},
|
||||
},
|
||||
Relation: nodedatabase.ClauseRelationOR,
|
||||
},
|
||||
}
|
||||
response, err := ds.Delete(context.Background(), req)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *response.RowNumber, int64(10))
|
||||
})
|
||||
|
||||
t.Run("insert", func(t *testing.T) {
|
||||
req := &nodedatabase.InsertRequest{
|
||||
DatabaseInfoID: 1,
|
||||
Fields: map[string]interface{}{
|
||||
"v1": "1",
|
||||
"v2": 2,
|
||||
"v3": 33,
|
||||
"v4": "44aacc",
|
||||
},
|
||||
}
|
||||
_, err := ds.Insert(context.Background(), req)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("update", func(t *testing.T) {
|
||||
req := &nodedatabase.UpdateRequest{
|
||||
DatabaseInfoID: 1,
|
||||
ConditionGroup: &nodedatabase.ConditionGroup{
|
||||
Conditions: []*nodedatabase.Condition{
|
||||
{Left: "v1", Operator: nodedatabase.OperatorEqual, Right: "1"},
|
||||
{Left: "v2", Operator: nodedatabase.OperatorIn, Right: []any{"v2_1", "v2_2"}},
|
||||
{Left: "v3", Operator: nodedatabase.OperatorIsNull},
|
||||
{Left: "v4", Operator: nodedatabase.OperatorLike, Right: "v4"},
|
||||
},
|
||||
Relation: nodedatabase.ClauseRelationOR,
|
||||
},
|
||||
Fields: map[string]interface{}{
|
||||
"v1": "1",
|
||||
"v2": 2,
|
||||
"v3": 33,
|
||||
"v4": "aabbcc",
|
||||
},
|
||||
}
|
||||
_, err := ds.Update(context.Background(), req)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
217
backend/crossdomain/workflow/knowledge/knowledge.go
Normal file
217
backend/crossdomain/workflow/knowledge/knowledge.go
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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 knowledge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/application/base/ctxutil"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/knowledge/entity"
|
||||
domainknowledge "github.com/coze-dev/coze-studio/backend/domain/knowledge/service"
|
||||
crossknowledge "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/knowledge"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/parser"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
)
|
||||
|
||||
type Knowledge struct {
|
||||
client domainknowledge.Knowledge
|
||||
idGen idgen.IDGenerator
|
||||
}
|
||||
|
||||
func NewKnowledgeRepository(client domainknowledge.Knowledge, idGen idgen.IDGenerator) *Knowledge {
|
||||
return &Knowledge{
|
||||
client: client,
|
||||
idGen: idGen,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Knowledge) Store(ctx context.Context, document *crossknowledge.CreateDocumentRequest) (*crossknowledge.CreateDocumentResponse, error) {
|
||||
var (
|
||||
ps *entity.ParsingStrategy
|
||||
cs = &entity.ChunkingStrategy{}
|
||||
)
|
||||
|
||||
if document.ParsingStrategy == nil {
|
||||
return nil, errors.New("document parsing strategy is required")
|
||||
}
|
||||
|
||||
if document.ChunkingStrategy == nil {
|
||||
return nil, errors.New("document chunking strategy is required")
|
||||
}
|
||||
|
||||
if document.ParsingStrategy.ParseMode == crossknowledge.AccurateParseMode {
|
||||
ps = &entity.ParsingStrategy{}
|
||||
ps.ExtractImage = document.ParsingStrategy.ExtractImage
|
||||
ps.ExtractTable = document.ParsingStrategy.ExtractTable
|
||||
ps.ImageOCR = document.ParsingStrategy.ImageOCR
|
||||
}
|
||||
|
||||
chunkType, err := toChunkType(document.ChunkingStrategy.ChunkType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.ChunkType = chunkType
|
||||
cs.Separator = document.ChunkingStrategy.Separator
|
||||
cs.ChunkSize = document.ChunkingStrategy.ChunkSize
|
||||
cs.Overlap = document.ChunkingStrategy.Overlap
|
||||
|
||||
req := &entity.Document{
|
||||
Info: knowledge.Info{
|
||||
Name: document.FileName,
|
||||
},
|
||||
KnowledgeID: document.KnowledgeID,
|
||||
Type: knowledge.DocumentTypeText,
|
||||
URL: document.FileURL,
|
||||
Source: entity.DocumentSourceLocal,
|
||||
ParsingStrategy: ps,
|
||||
ChunkingStrategy: cs,
|
||||
FileExtension: document.FileExtension,
|
||||
}
|
||||
|
||||
uid := ctxutil.GetUIDFromCtx(ctx)
|
||||
if uid != nil {
|
||||
req.Info.CreatorID = *uid
|
||||
}
|
||||
|
||||
response, err := k.client.CreateDocument(ctx, &domainknowledge.CreateDocumentRequest{
|
||||
Documents: []*entity.Document{req},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kCResponse := &crossknowledge.CreateDocumentResponse{
|
||||
FileURL: document.FileURL,
|
||||
DocumentID: response.Documents[0].Info.ID,
|
||||
FileName: response.Documents[0].Info.Name,
|
||||
}
|
||||
|
||||
return kCResponse, nil
|
||||
}
|
||||
|
||||
func (k *Knowledge) Retrieve(ctx context.Context, r *crossknowledge.RetrieveRequest) (*crossknowledge.RetrieveResponse, error) {
|
||||
rs := &entity.RetrievalStrategy{}
|
||||
if r.RetrievalStrategy != nil {
|
||||
rs.TopK = r.RetrievalStrategy.TopK
|
||||
rs.MinScore = r.RetrievalStrategy.MinScore
|
||||
searchType, err := toSearchType(r.RetrievalStrategy.SearchType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.SearchType = searchType
|
||||
rs.EnableQueryRewrite = r.RetrievalStrategy.EnableQueryRewrite
|
||||
rs.EnableRerank = r.RetrievalStrategy.EnableRerank
|
||||
rs.EnableNL2SQL = r.RetrievalStrategy.EnableNL2SQL
|
||||
}
|
||||
|
||||
req := &domainknowledge.RetrieveRequest{
|
||||
Query: r.Query,
|
||||
KnowledgeIDs: r.KnowledgeIDs,
|
||||
Strategy: rs,
|
||||
}
|
||||
|
||||
response, err := k.client.Retrieve(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss := make([]*crossknowledge.Slice, 0, len(response.RetrieveSlices))
|
||||
for _, s := range response.RetrieveSlices {
|
||||
if s.Slice == nil {
|
||||
continue
|
||||
}
|
||||
ss = append(ss, &crossknowledge.Slice{
|
||||
DocumentID: strconv.FormatInt(s.Slice.DocumentID, 10),
|
||||
Output: s.Slice.GetSliceContent(),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return &crossknowledge.RetrieveResponse{
|
||||
Slices: ss,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k *Knowledge) Delete(ctx context.Context, r *crossknowledge.DeleteDocumentRequest) (*crossknowledge.DeleteDocumentResponse, error) {
|
||||
docID, err := strconv.ParseInt(r.DocumentID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid document id: %s", r.DocumentID)
|
||||
}
|
||||
|
||||
err = k.client.DeleteDocument(ctx, &domainknowledge.DeleteDocumentRequest{
|
||||
DocumentID: docID,
|
||||
})
|
||||
if err != nil {
|
||||
return &crossknowledge.DeleteDocumentResponse{IsSuccess: false}, err
|
||||
}
|
||||
|
||||
return &crossknowledge.DeleteDocumentResponse{IsSuccess: true}, nil
|
||||
}
|
||||
|
||||
func (k *Knowledge) ListKnowledgeDetail(ctx context.Context, req *crossknowledge.ListKnowledgeDetailRequest) (*crossknowledge.ListKnowledgeDetailResponse, error) {
|
||||
response, err := k.client.MGetKnowledgeByID(ctx, &domainknowledge.MGetKnowledgeByIDRequest{
|
||||
KnowledgeIDs: req.KnowledgeIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &crossknowledge.ListKnowledgeDetailResponse{
|
||||
KnowledgeDetails: slices.Transform(response.Knowledge, func(a *knowledge.Knowledge) *crossknowledge.KnowledgeDetail {
|
||||
return &crossknowledge.KnowledgeDetail{
|
||||
ID: a.ID,
|
||||
Name: a.Name,
|
||||
Description: a.Description,
|
||||
IconURL: a.IconURL,
|
||||
FormatType: int64(a.Type),
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func toSearchType(typ crossknowledge.SearchType) (knowledge.SearchType, error) {
|
||||
switch typ {
|
||||
case crossknowledge.SearchTypeSemantic:
|
||||
return knowledge.SearchTypeSemantic, nil
|
||||
case crossknowledge.SearchTypeFullText:
|
||||
return knowledge.SearchTypeFullText, nil
|
||||
case crossknowledge.SearchTypeHybrid:
|
||||
return knowledge.SearchTypeHybrid, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown search type: %v", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func toChunkType(typ crossknowledge.ChunkType) (parser.ChunkType, error) {
|
||||
switch typ {
|
||||
case crossknowledge.ChunkTypeDefault:
|
||||
return parser.ChunkTypeDefault, nil
|
||||
case crossknowledge.ChunkTypeCustom:
|
||||
return parser.ChunkTypeCustom, nil
|
||||
case crossknowledge.ChunkTypeLeveled:
|
||||
return parser.ChunkTypeLeveled, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown chunk type: %v", typ)
|
||||
}
|
||||
}
|
||||
101
backend/crossdomain/workflow/model/model.go
Normal file
101
backend/crossdomain/workflow/model/model.go
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
model2 "github.com/cloudwego/eino/components/model"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossmodelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/modelmgr"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/model"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
chatmodel2 "github.com/coze-dev/coze-studio/backend/infra/impl/chatmodel"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
)
|
||||
|
||||
type ModelManager struct {
|
||||
modelMgr modelmgr.Manager
|
||||
factory chatmodel.Factory
|
||||
}
|
||||
|
||||
func NewModelManager(m modelmgr.Manager, f chatmodel.Factory) *ModelManager {
|
||||
if f == nil {
|
||||
f = chatmodel2.NewDefaultFactory()
|
||||
}
|
||||
return &ModelManager{
|
||||
modelMgr: m,
|
||||
factory: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ModelManager) GetModel(ctx context.Context, params *model.LLMParams) (model2.BaseChatModel, *crossmodelmgr.Model, error) {
|
||||
modelID := params.ModelType
|
||||
models, err := crossmodelmgr.DefaultSVC().MGetModelByID(ctx, &modelmgr.MGetModelRequest{
|
||||
IDs: []int64{modelID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var config *chatmodel.Config
|
||||
var protocol chatmodel.Protocol
|
||||
var mdl *crossmodelmgr.Model
|
||||
for i := range models {
|
||||
md := models[i]
|
||||
if md.ID == modelID {
|
||||
protocol = md.Meta.Protocol
|
||||
config = md.Meta.ConnConfig
|
||||
mdl = md
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
return nil, nil, fmt.Errorf("model type %v ,not found config ", modelID)
|
||||
}
|
||||
|
||||
if len(protocol) == 0 {
|
||||
return nil, nil, fmt.Errorf("model type %v ,not found protocol ", modelID)
|
||||
}
|
||||
|
||||
if params.TopP != nil {
|
||||
config.TopP = ptr.Of(float32(ptr.From(params.TopP)))
|
||||
}
|
||||
|
||||
if params.TopK != nil {
|
||||
config.TopK = params.TopK
|
||||
}
|
||||
|
||||
if params.Temperature != nil {
|
||||
config.Temperature = ptr.Of(float32(ptr.From(params.Temperature)))
|
||||
}
|
||||
|
||||
config.MaxTokens = ptr.Of(params.MaxTokens)
|
||||
|
||||
// Whether you need to use a pointer
|
||||
config.FrequencyPenalty = ptr.Of(float32(params.FrequencyPenalty))
|
||||
config.PresencePenalty = ptr.Of(float32(params.PresencePenalty))
|
||||
|
||||
cm, err := m.factory.CreateChatModel(ctx, protocol, config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return cm, mdl, nil
|
||||
}
|
||||
510
backend/crossdomain/workflow/plugin/plugin.go
Normal file
510
backend/crossdomain/workflow/plugin/plugin.go
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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"
|
||||
workflow3 "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
"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.RequestExample
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
req := &service.ExecuteToolRequest{
|
||||
UserID: conv.Int64ToStr(cfg.Operator),
|
||||
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.RawResp, &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))
|
||||
}
|
||||
|
||||
if len(parameter.SubParameters) > 0 {
|
||||
p.SubParameters = make([]*workflow3.APIParameter, 0, len(parameter.SubParameters))
|
||||
for _, subParam := range parameter.SubParameters {
|
||||
p.SubParameters = append(p.SubParameters, toWorkflowAPIParameter(subParam))
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
74
backend/crossdomain/workflow/search/search.go
Normal file
74
backend/crossdomain/workflow/search/search.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 search
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/resource/common"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/search/entity"
|
||||
search "github.com/coze-dev/coze-studio/backend/domain/search/service"
|
||||
crosssearch "github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/search"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
)
|
||||
|
||||
type Notifier interface {
|
||||
PublishWorkflowResource(ctx context.Context, OpType crosssearch.OpType, event *crosssearch.Resource) error
|
||||
}
|
||||
|
||||
type Notify struct {
|
||||
client search.ResourceEventBus
|
||||
}
|
||||
|
||||
func NewNotify(client search.ResourceEventBus) *Notify {
|
||||
return &Notify{client: client}
|
||||
}
|
||||
|
||||
func (n *Notify) PublishWorkflowResource(ctx context.Context, op crosssearch.OpType, r *crosssearch.Resource) error {
|
||||
entityResource := &entity.ResourceDocument{
|
||||
ResType: common.ResType_Workflow,
|
||||
ResID: r.WorkflowID,
|
||||
ResSubType: r.Mode,
|
||||
Name: r.Name,
|
||||
SpaceID: r.SpaceID,
|
||||
OwnerID: r.OwnerID,
|
||||
APPID: r.APPID,
|
||||
}
|
||||
if r.PublishStatus != nil {
|
||||
publishStatus := *r.PublishStatus
|
||||
entityResource.PublishStatus = ptr.Of(common.PublishStatus(publishStatus))
|
||||
entityResource.PublishTimeMS = r.PublishedAt
|
||||
}
|
||||
|
||||
resource := &entity.ResourceDomainEvent{
|
||||
OpType: entity.OpType(op),
|
||||
Resource: entityResource,
|
||||
}
|
||||
if op == crosssearch.Created {
|
||||
resource.Resource.CreateTimeMS = r.CreatedAt
|
||||
resource.Resource.UpdateTimeMS = r.UpdatedAt
|
||||
} else if op == crosssearch.Updated {
|
||||
resource.Resource.UpdateTimeMS = r.UpdatedAt
|
||||
}
|
||||
|
||||
err := n.client.PublishResources(ctx, resource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
399
backend/crossdomain/workflow/variable/variable.go
Normal file
399
backend/crossdomain/workflow/variable/variable.go
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* 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 variable
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
variablesModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/variables"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/kvmemory"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/project_memory"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/memory/variables/entity"
|
||||
variables "github.com/coze-dev/coze-studio/backend/domain/memory/variables/service"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/variable"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ternary"
|
||||
)
|
||||
|
||||
type varStore struct {
|
||||
variableChannel project_memory.VariableChannel
|
||||
vs variables.Variables
|
||||
}
|
||||
|
||||
func NewVariableHandler(vs variables.Variables) *variable.Handler {
|
||||
return &variable.Handler{
|
||||
UserVarStore: newUserVarStore(vs),
|
||||
AppVarStore: newAppVarStore(vs),
|
||||
SystemVarStore: newSystemVarStore(vs),
|
||||
}
|
||||
}
|
||||
|
||||
func newUserVarStore(vs variables.Variables) variable.Store {
|
||||
return &varStore{
|
||||
variableChannel: project_memory.VariableChannel_Custom,
|
||||
vs: vs,
|
||||
}
|
||||
}
|
||||
|
||||
func newAppVarStore(vs variables.Variables) variable.Store {
|
||||
return &varStore{
|
||||
variableChannel: project_memory.VariableChannel_APP,
|
||||
vs: vs,
|
||||
}
|
||||
}
|
||||
|
||||
func newSystemVarStore(vs variables.Variables) variable.Store {
|
||||
return &varStore{
|
||||
variableChannel: project_memory.VariableChannel_System,
|
||||
vs: vs,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *varStore) Init(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (v *varStore) Get(ctx context.Context, path compose.FieldPath, opts ...variable.OptionFn) (any, error) {
|
||||
opt := &variable.StoreConfig{}
|
||||
for _, o := range opts {
|
||||
o(opt)
|
||||
}
|
||||
|
||||
var (
|
||||
bizID string
|
||||
bizType project_memory.VariableConnector
|
||||
)
|
||||
|
||||
if opt.StoreInfo.AppID != nil {
|
||||
bizID = strconv.FormatInt(*opt.StoreInfo.AppID, 10)
|
||||
bizType = project_memory.VariableConnector_Project
|
||||
} else if opt.StoreInfo.AgentID != nil {
|
||||
bizID = strconv.FormatInt(*opt.StoreInfo.AgentID, 10)
|
||||
bizType = project_memory.VariableConnector_Bot
|
||||
} else {
|
||||
return nil, fmt.Errorf("there must be one of the App ID or Agent ID")
|
||||
}
|
||||
|
||||
meta := entity.NewUserVariableMeta(&variablesModel.UserVariableMeta{
|
||||
BizType: bizType,
|
||||
BizID: bizID,
|
||||
ConnectorID: opt.StoreInfo.ConnectorID,
|
||||
ConnectorUID: opt.StoreInfo.ConnectorUID,
|
||||
})
|
||||
if len(path) == 0 {
|
||||
return nil, errors.New("field path is required")
|
||||
}
|
||||
key := path[0]
|
||||
kvItems, err := v.vs.GetVariableChannelInstance(ctx, meta, []string{key}, project_memory.VariableChannelPtr(v.variableChannel))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(kvItems) == 0 {
|
||||
return nil, fmt.Errorf("variable %s not exists", key)
|
||||
}
|
||||
|
||||
value := kvItems[0].GetValue()
|
||||
|
||||
schema := kvItems[0].GetSchema()
|
||||
|
||||
varSchema, err := entity.NewVariableMetaSchema([]byte(schema))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if varSchema.IsArrayType() {
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
result := make([]interface{}, 0)
|
||||
err = sonic.Unmarshal([]byte(value), &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if varSchema.IsObjectType() {
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
result := make(map[string]any)
|
||||
err = sonic.Unmarshal([]byte(value), &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(path) > 1 {
|
||||
if val, ok := takeMapValue(result, path[1:]); ok {
|
||||
return val, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if varSchema.IsStringType() {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
if varSchema.IsBooleanType() {
|
||||
if value == "" {
|
||||
return false, nil
|
||||
}
|
||||
result, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if varSchema.IsNumberType() {
|
||||
if value == "" {
|
||||
return 0, nil
|
||||
}
|
||||
result, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if varSchema.IsIntegerType() {
|
||||
if value == "" {
|
||||
return 0, nil
|
||||
}
|
||||
result, err := strconv.ParseInt(value, 64, 10)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (v *varStore) Set(ctx context.Context, path compose.FieldPath, value any, opts ...variable.OptionFn) (err error) {
|
||||
opt := &variable.StoreConfig{}
|
||||
for _, o := range opts {
|
||||
o(opt)
|
||||
}
|
||||
|
||||
var (
|
||||
bizID string
|
||||
bizType project_memory.VariableConnector
|
||||
)
|
||||
|
||||
if opt.StoreInfo.AppID != nil {
|
||||
bizID = strconv.FormatInt(*opt.StoreInfo.AppID, 10)
|
||||
bizType = project_memory.VariableConnector_Project
|
||||
} else if opt.StoreInfo.AgentID != nil {
|
||||
bizID = strconv.FormatInt(*opt.StoreInfo.AgentID, 10)
|
||||
bizType = project_memory.VariableConnector_Bot
|
||||
} else {
|
||||
return fmt.Errorf("there must be one of the App ID or Agent ID")
|
||||
}
|
||||
|
||||
meta := entity.NewUserVariableMeta(&variablesModel.UserVariableMeta{
|
||||
BizType: bizType,
|
||||
BizID: bizID,
|
||||
ConnectorID: opt.StoreInfo.ConnectorID,
|
||||
ConnectorUID: opt.StoreInfo.ConnectorUID,
|
||||
})
|
||||
|
||||
if len(path) == 0 {
|
||||
return errors.New("field path is required")
|
||||
}
|
||||
|
||||
key := path[0]
|
||||
kvItems := make([]*kvmemory.KVItem, 0, 1)
|
||||
|
||||
valueString := ""
|
||||
if _, ok := value.(string); ok {
|
||||
valueString = value.(string)
|
||||
} else {
|
||||
valueString, err = sonic.MarshalString(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
isSystem := ternary.IFElse[bool](v.variableChannel == project_memory.VariableChannel_System, true, false)
|
||||
kvItems = append(kvItems, &kvmemory.KVItem{
|
||||
Keyword: key,
|
||||
Value: valueString,
|
||||
IsSystem: isSystem,
|
||||
})
|
||||
|
||||
_, err = v.vs.SetVariableInstance(ctx, meta, kvItems)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type variablesMetaGetter struct {
|
||||
vs variables.Variables
|
||||
}
|
||||
|
||||
func NewVariablesMetaGetter(vs variables.Variables) variable.VariablesMetaGetter {
|
||||
return &variablesMetaGetter{
|
||||
vs: vs,
|
||||
}
|
||||
}
|
||||
|
||||
func (v variablesMetaGetter) GetAppVariablesMeta(ctx context.Context, id, version string) (m map[string]*vo.TypeInfo, err error) {
|
||||
var varMetas *entity.VariablesMeta
|
||||
varMetas, err = v.vs.GetProjectVariablesMeta(ctx, id, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = make(map[string]*vo.TypeInfo, len(varMetas.Variables))
|
||||
for _, v := range varMetas.Variables {
|
||||
varSchema, err := v.GetSchema(ctx)
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrVariablesAPIFail, err)
|
||||
}
|
||||
|
||||
t, err := varMeta2TypeInfo(varSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m[v.Keyword] = t
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (v variablesMetaGetter) GetAgentVariablesMeta(ctx context.Context, id int64, version string) (m map[string]*vo.TypeInfo, err error) {
|
||||
var varMetas *entity.VariablesMeta
|
||||
varMetas, err = v.vs.GetAgentVariableMeta(ctx, id, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = make(map[string]*vo.TypeInfo, len(varMetas.Variables))
|
||||
for _, v := range varMetas.Variables {
|
||||
varSchema, err := v.GetSchema(ctx)
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrVariablesAPIFail, err)
|
||||
}
|
||||
|
||||
t, err := varMeta2TypeInfo(varSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m[v.Keyword] = t
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func varMeta2TypeInfo(v *entity.VariableMetaSchema) (*vo.TypeInfo, error) {
|
||||
if v.IsBooleanType() {
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeBoolean,
|
||||
}, nil
|
||||
}
|
||||
if v.IsStringType() {
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeString,
|
||||
}, nil
|
||||
}
|
||||
if v.IsNumberType() {
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeNumber,
|
||||
}, nil
|
||||
}
|
||||
if v.IsIntegerType() {
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeInteger,
|
||||
}, nil
|
||||
}
|
||||
if v.IsArrayType() {
|
||||
if len(v.Schema) == 0 {
|
||||
return nil, vo.WrapError(errno.ErrVariablesAPIFail, fmt.Errorf("array type should contain element type info"))
|
||||
}
|
||||
|
||||
elemType, err := entity.NewVariableMetaSchema(v.Schema)
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrVariablesAPIFail, err)
|
||||
}
|
||||
|
||||
et, err := varMeta2TypeInfo(elemType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeArray,
|
||||
ElemTypeInfo: et,
|
||||
}, nil
|
||||
}
|
||||
if v.IsObjectType() {
|
||||
ps, err := v.GetObjectProperties(v.Schema)
|
||||
if err != nil {
|
||||
return nil, vo.WrapIfNeeded(errno.ErrVariablesAPIFail, err)
|
||||
}
|
||||
|
||||
properties := make(map[string]*vo.TypeInfo, len(ps))
|
||||
for k, p := range ps {
|
||||
pt, err := varMeta2TypeInfo(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
properties[k] = pt
|
||||
}
|
||||
|
||||
return &vo.TypeInfo{
|
||||
Type: vo.DataTypeObject,
|
||||
Properties: properties,
|
||||
}, nil
|
||||
}
|
||||
return nil, vo.WrapError(errno.ErrVariablesAPIFail, fmt.Errorf("invalid variable type"))
|
||||
}
|
||||
|
||||
func takeMapValue(m map[string]any, path []string) (any, bool) {
|
||||
if m == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
container := m
|
||||
for _, p := range path[:len(path)-1] {
|
||||
if _, ok := container[p]; !ok {
|
||||
return nil, false
|
||||
}
|
||||
container = container[p].(map[string]any)
|
||||
}
|
||||
|
||||
if v, ok := container[path[len(path)-1]]; ok {
|
||||
return v, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
Reference in New Issue
Block a user