refactor: how to add a node type in workflow (#558)
This commit is contained in:
118
backend/domain/workflow/internal/compose/node_builder.go
Normal file
118
backend/domain/workflow/internal/compose/node_builder.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"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/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes/subworkflow"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/safego"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Lambda *compose.Lambda
|
||||
}
|
||||
|
||||
// New instantiates the actual node type from NodeSchema.
|
||||
func New(ctx context.Context, s *schema.NodeSchema,
|
||||
inner compose.Runnable[map[string]any, map[string]any], // inner workflow for composite node
|
||||
sc *schema.WorkflowSchema, // the workflow this NodeSchema is in
|
||||
deps *dependencyInfo, // the dependency for this node pre-calculated by workflow engine
|
||||
) (_ *Node, err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = safego.NewPanicErr(panicErr, debug.Stack())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = vo.WrapIfNeeded(errno.ErrCreateNodeFail, err, errorx.KV("node_name", s.Name), errorx.KV("cause", err.Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
var fullSources map[string]*schema.SourceInfo
|
||||
if m := entity.NodeMetaByNodeType(s.Type); m != nil && m.InputSourceAware {
|
||||
if fullSources, err = GetFullSources(s, sc, deps); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.FullSources = fullSources
|
||||
}
|
||||
|
||||
// if NodeSchema's Configs implements NodeBuilder, will use it to build the node
|
||||
nb, ok := s.Configs.(schema.NodeBuilder)
|
||||
if ok {
|
||||
opts := []schema.BuildOption{
|
||||
schema.WithWorkflowSchema(sc),
|
||||
schema.WithInnerWorkflow(inner),
|
||||
}
|
||||
|
||||
// build the actual InvokableNode, etc.
|
||||
n, err := nb.Build(ctx, s, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// wrap InvokableNode, etc. within NodeRunner, converting to eino's Lambda
|
||||
return toNode(s, n), nil
|
||||
}
|
||||
|
||||
switch s.Type {
|
||||
case entity.NodeTypeLambda:
|
||||
if s.Lambda == nil {
|
||||
return nil, fmt.Errorf("lambda is not defined for NodeTypeLambda")
|
||||
}
|
||||
|
||||
return &Node{Lambda: s.Lambda}, nil
|
||||
case entity.NodeTypeSubWorkflow:
|
||||
subWorkflow, err := buildSubWorkflow(ctx, s, sc.RequireCheckpoint())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toNode(s, subWorkflow), nil
|
||||
default:
|
||||
panic(fmt.Sprintf("node schema's Configs does not implement NodeBuilder. type: %v", s.Type))
|
||||
}
|
||||
}
|
||||
|
||||
func buildSubWorkflow(ctx context.Context, s *schema.NodeSchema, requireCheckpoint bool) (*subworkflow.SubWorkflow, error) {
|
||||
var opts []WorkflowOption
|
||||
opts = append(opts, WithIDAsName(s.Configs.(*subworkflow.Config).WorkflowID))
|
||||
if requireCheckpoint {
|
||||
opts = append(opts, WithParentRequireCheckpoint())
|
||||
}
|
||||
if s := execute.GetStaticConfig(); s != nil && s.MaxNodeCountPerWorkflow > 0 {
|
||||
opts = append(opts, WithMaxNodeCount(s.MaxNodeCountPerWorkflow))
|
||||
}
|
||||
wf, err := NewWorkflow(ctx, s.SubWorkflowSchema, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &subworkflow.SubWorkflow{
|
||||
Runner: wf.Runner,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user