597 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			597 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
 * 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 vo
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/cloudwego/eino/compose"
 | 
						|
	"github.com/cloudwego/eino/schema"
 | 
						|
 | 
						|
	"github.com/coze-dev/coze-studio/backend/pkg/errorx"
 | 
						|
	"github.com/coze-dev/coze-studio/backend/pkg/sonic"
 | 
						|
	"github.com/coze-dev/coze-studio/backend/types/errno"
 | 
						|
)
 | 
						|
 | 
						|
type NodeKey string
 | 
						|
 | 
						|
type FieldInfo struct {
 | 
						|
	Path   compose.FieldPath `json:"path"`
 | 
						|
	Source FieldSource       `json:"source"`
 | 
						|
}
 | 
						|
 | 
						|
type Reference struct {
 | 
						|
	FromNodeKey NodeKey           `json:"from_node_key,omitempty"`
 | 
						|
	FromPath    compose.FieldPath `json:"from_path"`
 | 
						|
 | 
						|
	VariableType *GlobalVarType `json:"variable_type,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type FieldSource struct {
 | 
						|
	Ref *Reference `json:"ref,omitempty"`
 | 
						|
	Val any        `json:"val,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type TypeInfo struct {
 | 
						|
	Type         DataType             `json:"type"`
 | 
						|
	ElemTypeInfo *TypeInfo            `json:"elem_type_info,omitempty"`
 | 
						|
	FileType     *FileSubType         `json:"file_type,omitempty"`
 | 
						|
	Required     bool                 `json:"required,omitempty"`
 | 
						|
	Desc         string               `json:"desc,omitempty"`
 | 
						|
	Properties   map[string]*TypeInfo `json:"properties,omitempty"`
 | 
						|
}
 | 
						|
type NamedTypeInfo struct {
 | 
						|
	Name         string           `json:"name"`
 | 
						|
	Type         DataType         `json:"type"`
 | 
						|
	ElemTypeInfo *NamedTypeInfo   `json:"elem_type_info,omitempty"`
 | 
						|
	FileType     *FileSubType     `json:"file_type,omitempty"`
 | 
						|
	Required     bool             `json:"required,omitempty"`
 | 
						|
	Desc         string           `json:"desc,omitempty"`
 | 
						|
	Properties   []*NamedTypeInfo `json:"properties,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type ErrorLevel string
 | 
						|
 | 
						|
const (
 | 
						|
	LevelWarn   ErrorLevel = "Warn"
 | 
						|
	LevelError  ErrorLevel = "Error"
 | 
						|
	LevelCancel ErrorLevel = "pending" // forget about why it's called 'pending', somebody named it and it's now part of the protocol
 | 
						|
)
 | 
						|
 | 
						|
type WorkflowError interface {
 | 
						|
	errorx.StatusError
 | 
						|
	DebugURL() string
 | 
						|
	Level() ErrorLevel
 | 
						|
	OpenAPICode() int
 | 
						|
	AppendDebug(exeID, spaceID, workflowID int64) WorkflowError
 | 
						|
	ChangeErrLevel(newLevel ErrorLevel) WorkflowError
 | 
						|
}
 | 
						|
 | 
						|
type wfErr struct {
 | 
						|
	errorx.StatusError
 | 
						|
	exeID      int64
 | 
						|
	spaceID    int64
 | 
						|
	workflowID int64
 | 
						|
	cause      error
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) DebugURL() string {
 | 
						|
	if w.StatusError.Extra() == nil {
 | 
						|
		return fmt.Sprintf(DebugURLTpl, w.exeID, w.spaceID, w.workflowID)
 | 
						|
	}
 | 
						|
 | 
						|
	debugURL, ok := w.StatusError.Extra()["debug_url"]
 | 
						|
	if ok {
 | 
						|
		return debugURL
 | 
						|
	}
 | 
						|
 | 
						|
	return fmt.Sprintf(DebugURLTpl, w.exeID, w.spaceID, w.workflowID)
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) Level() ErrorLevel {
 | 
						|
	if w.StatusError.Extra() == nil {
 | 
						|
		return LevelError
 | 
						|
	}
 | 
						|
 | 
						|
	level, ok := w.StatusError.Extra()["level"]
 | 
						|
	if ok {
 | 
						|
		return ErrorLevel(level)
 | 
						|
	}
 | 
						|
 | 
						|
	return LevelError
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) Error() string {
 | 
						|
	if w.cause == nil {
 | 
						|
		return w.StatusError.Error()
 | 
						|
	}
 | 
						|
 | 
						|
	return fmt.Sprintf("%s, cause: %s", w.StatusError.Error(), w.cause.Error())
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) OpenAPICode() int {
 | 
						|
	return errno.CodeForOpenAPI(w)
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) AppendDebug(exeID, spaceID, workflowID int64) WorkflowError {
 | 
						|
	w.exeID = exeID
 | 
						|
	w.spaceID = spaceID
 | 
						|
	w.workflowID = workflowID
 | 
						|
	return w
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) Unwrap() error {
 | 
						|
	return w.cause
 | 
						|
}
 | 
						|
 | 
						|
func (w *wfErr) ChangeErrLevel(newLevel ErrorLevel) WorkflowError {
 | 
						|
	w.StatusError.Extra()["level"] = string(newLevel)
 | 
						|
	return w
 | 
						|
}
 | 
						|
 | 
						|
func NewError(code int, opts ...errorx.Option) WorkflowError {
 | 
						|
	opts = append(opts, errorx.Extra("level", string(LevelError)))
 | 
						|
	e := errorx.New(int32(code), opts...)
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
	}
 | 
						|
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
func WrapError(code int, err error, opts ...errorx.Option) WorkflowError {
 | 
						|
	opts = append(opts, errorx.Extra("level", string(LevelError)))
 | 
						|
	e := errorx.WrapByCode(err, int32(code), opts...)
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
		cause:       err,
 | 
						|
	}
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
func WrapWithDebug(code int, err error, exeID, spaceID, workflowID int64, opts ...errorx.Option) WorkflowError {
 | 
						|
	debugURL := fmt.Sprintf(DebugURLTpl, exeID, spaceID, workflowID)
 | 
						|
	opts = append(opts, errorx.Extra("debug_url", debugURL))
 | 
						|
	return WrapError(code, err, opts...)
 | 
						|
}
 | 
						|
 | 
						|
func NewWarn(code int, opts ...errorx.Option) WorkflowError {
 | 
						|
	opts = append(opts, errorx.Extra("level", string(LevelWarn)))
 | 
						|
	e := errorx.New(int32(code), opts...)
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
	}
 | 
						|
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
func WrapWarn(code int, err error, opts ...errorx.Option) WorkflowError {
 | 
						|
	opts = append(opts, errorx.Extra("level", string(LevelWarn)))
 | 
						|
	e := errorx.WrapByCode(err, int32(code), opts...)
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
		cause:       err,
 | 
						|
	}
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
func WrapIfNeeded(code int, err error, opts ...errorx.Option) WorkflowError {
 | 
						|
	var wfe WorkflowError
 | 
						|
	if errors.As(err, &wfe) {
 | 
						|
		return wfe
 | 
						|
	}
 | 
						|
	return WrapError(code, err, opts...)
 | 
						|
}
 | 
						|
 | 
						|
var CancelErr = newCancel()
 | 
						|
 | 
						|
func newCancel() WorkflowError {
 | 
						|
	e := errorx.New(errno.ErrWorkflowCanceledByUser, errorx.Extra("level", string(LevelCancel)))
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
	}
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
var NodeTimeoutErr = newNodeTimeout()
 | 
						|
 | 
						|
func newNodeTimeout() WorkflowError {
 | 
						|
	e := errorx.New(errno.ErrNodeTimeout, errorx.Extra("level", string(LevelError)))
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
	}
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
var WorkflowTimeoutErr = newWorkflowTimeout()
 | 
						|
 | 
						|
func newWorkflowTimeout() WorkflowError {
 | 
						|
	e := errorx.New(errno.ErrWorkflowTimeout, errorx.Extra("level", string(LevelError)))
 | 
						|
	var sErr errorx.StatusError
 | 
						|
	_ = errors.As(e, &sErr)
 | 
						|
	wfe := &wfErr{
 | 
						|
		StatusError: sErr,
 | 
						|
	}
 | 
						|
	return wfe
 | 
						|
}
 | 
						|
 | 
						|
func UnwrapRootErr(err error) error {
 | 
						|
	var (
 | 
						|
		rootE    = err
 | 
						|
		currentE error
 | 
						|
	)
 | 
						|
	for {
 | 
						|
		currentE = errors.Unwrap(rootE)
 | 
						|
		if currentE == nil {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		rootE = currentE
 | 
						|
	}
 | 
						|
 | 
						|
	return rootE
 | 
						|
}
 | 
						|
 | 
						|
type DataType string
 | 
						|
 | 
						|
const (
 | 
						|
	DataTypeString  DataType = "string"  // string
 | 
						|
	DataTypeInteger DataType = "integer" // int64
 | 
						|
	DataTypeNumber  DataType = "number"  // float64
 | 
						|
	DataTypeBoolean DataType = "boolean" // bool
 | 
						|
	DataTypeTime    DataType = "time"    // time.Time
 | 
						|
	DataTypeObject  DataType = "object"  // map[string]any
 | 
						|
	DataTypeArray   DataType = "list"    // []any
 | 
						|
	DataTypeFile    DataType = "file"    // string (url)
 | 
						|
)
 | 
						|
 | 
						|
// Zero creates a zero value
 | 
						|
func (t *TypeInfo) Zero() any {
 | 
						|
	switch t.Type {
 | 
						|
	case DataTypeString:
 | 
						|
		return ""
 | 
						|
	case DataTypeInteger:
 | 
						|
		return int64(0)
 | 
						|
	case DataTypeNumber:
 | 
						|
		return float64(0)
 | 
						|
	case DataTypeBoolean:
 | 
						|
		return false
 | 
						|
	case DataTypeTime:
 | 
						|
		return ""
 | 
						|
	case DataTypeObject:
 | 
						|
		var m map[string]any
 | 
						|
		return m
 | 
						|
	case DataTypeArray:
 | 
						|
		var a []any
 | 
						|
		return a
 | 
						|
	case DataTypeFile:
 | 
						|
		return ""
 | 
						|
	default:
 | 
						|
		panic("impossible")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *NamedTypeInfo) ToParameterInfo() (*schema.ParameterInfo, error) {
 | 
						|
	param := &schema.ParameterInfo{
 | 
						|
		Type:     convertDataType(n.Type),
 | 
						|
		Desc:     n.Desc,
 | 
						|
		Required: n.Required,
 | 
						|
	}
 | 
						|
 | 
						|
	if n.Type == DataTypeObject {
 | 
						|
		param.SubParams = make(map[string]*schema.ParameterInfo, len(n.Properties))
 | 
						|
		for _, subT := range n.Properties {
 | 
						|
			subParam, err := subT.ToParameterInfo()
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			param.SubParams[subT.Name] = subParam
 | 
						|
		}
 | 
						|
	} else if n.Type == DataTypeArray {
 | 
						|
		elemParam, err := n.ElemTypeInfo.ToParameterInfo()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		param.ElemInfo = elemParam
 | 
						|
	}
 | 
						|
 | 
						|
	return param, nil
 | 
						|
}
 | 
						|
 | 
						|
func (n *NamedTypeInfo) ToVariable() (*Variable, error) {
 | 
						|
 | 
						|
	variableType, err := convertVariableType(n.Type)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	v := &Variable{
 | 
						|
		Name:     n.Name,
 | 
						|
		Type:     variableType,
 | 
						|
		Required: n.Required,
 | 
						|
	}
 | 
						|
 | 
						|
	if n.Type == DataTypeFile && n.FileType != nil {
 | 
						|
		v.AssistType = toAssistType(*n.FileType)
 | 
						|
	}
 | 
						|
 | 
						|
	if n.Type == DataTypeArray && n.ElemTypeInfo != nil {
 | 
						|
		ele, err := n.ElemTypeInfo.ToVariable()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		v.Schema = ele
 | 
						|
	}
 | 
						|
 | 
						|
	if n.Type == DataTypeObject && len(n.Properties) > 0 {
 | 
						|
		varList := make([]*Variable, 0, len(n.Properties))
 | 
						|
		for _, p := range n.Properties {
 | 
						|
			v, err := p.ToVariable()
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			varList = append(varList, v)
 | 
						|
		}
 | 
						|
		v.Schema = varList
 | 
						|
	}
 | 
						|
 | 
						|
	return v, nil
 | 
						|
}
 | 
						|
 | 
						|
func toAssistType(f FileSubType) AssistType {
 | 
						|
	switch f {
 | 
						|
	case FileTypeDefault:
 | 
						|
		return AssistTypeDefault
 | 
						|
	case FileTypeImage:
 | 
						|
		return AssistTypeImage
 | 
						|
	case FileTypeSVG:
 | 
						|
		return AssistTypeSvg
 | 
						|
	case FileTypeAudio:
 | 
						|
		return AssistTypeAudio
 | 
						|
	case FileTypeVideo:
 | 
						|
		return AssistTypeVideo
 | 
						|
	case FileTypeDocument:
 | 
						|
		return AssistTypeDoc
 | 
						|
	case FileTypePPT:
 | 
						|
		return AssistTypePPT
 | 
						|
	case FileTypeExcel:
 | 
						|
		return AssistTypeExcel
 | 
						|
	case FileTypeTxt:
 | 
						|
		return AssistTypeTXT
 | 
						|
	case FileTypeCode:
 | 
						|
		return AssistTypeCode
 | 
						|
	case FileTypeZip:
 | 
						|
		return AssistTypeZip
 | 
						|
	default:
 | 
						|
		return AssistTypeNotSet
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func convertVariableType(d DataType) (VariableType, error) {
 | 
						|
	switch d {
 | 
						|
	case DataTypeString, DataTypeTime, DataTypeFile:
 | 
						|
		return VariableTypeString, nil
 | 
						|
	case DataTypeNumber:
 | 
						|
		return VariableTypeFloat, nil
 | 
						|
	case DataTypeInteger:
 | 
						|
		return VariableTypeInteger, nil
 | 
						|
	case DataTypeBoolean:
 | 
						|
		return VariableTypeBoolean, nil
 | 
						|
	case DataTypeObject:
 | 
						|
		return VariableTypeObject, nil
 | 
						|
	case DataTypeArray:
 | 
						|
		return VariableTypeList, nil
 | 
						|
	default:
 | 
						|
		return "", fmt.Errorf("unknown variable type: %v", d)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func convertDataType(d DataType) schema.DataType {
 | 
						|
	switch d {
 | 
						|
	case DataTypeString, DataTypeTime, DataTypeFile:
 | 
						|
		return schema.String
 | 
						|
	case DataTypeNumber:
 | 
						|
		return schema.Number
 | 
						|
	case DataTypeInteger:
 | 
						|
		return schema.Integer
 | 
						|
	case DataTypeBoolean:
 | 
						|
		return schema.Boolean
 | 
						|
	case DataTypeObject:
 | 
						|
		return schema.Object
 | 
						|
	case DataTypeArray:
 | 
						|
		return schema.Array
 | 
						|
	default:
 | 
						|
		panic("unknown data type")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TypeInfoToJSONSchema(tis map[string]*TypeInfo, structName *string) (string, error) {
 | 
						|
	schema_ := map[string]any{
 | 
						|
		"type":       "object",
 | 
						|
		"properties": make(map[string]any),
 | 
						|
		"required":   []string{},
 | 
						|
	}
 | 
						|
 | 
						|
	if structName != nil {
 | 
						|
		schema_["title"] = *structName
 | 
						|
	}
 | 
						|
 | 
						|
	properties := schema_["properties"].(map[string]any)
 | 
						|
	for key, typeInfo := range tis {
 | 
						|
		if typeInfo == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		sc, err := typeInfoToJSONSchema(typeInfo)
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
		properties[key] = sc
 | 
						|
		if typeInfo.Required {
 | 
						|
			schema_["required"] = append(schema_["required"].([]string), key)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	jsonBytes, err := sonic.Marshal(schema_)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	return string(jsonBytes), nil
 | 
						|
}
 | 
						|
 | 
						|
func typeInfoToJSONSchema(info *TypeInfo) (map[string]interface{}, error) {
 | 
						|
 | 
						|
	sc := make(map[string]interface{})
 | 
						|
 | 
						|
	switch info.Type {
 | 
						|
	case DataTypeString:
 | 
						|
		sc["type"] = "string"
 | 
						|
	case DataTypeInteger:
 | 
						|
		sc["type"] = "integer"
 | 
						|
	case DataTypeNumber:
 | 
						|
		sc["type"] = "number"
 | 
						|
	case DataTypeBoolean:
 | 
						|
		sc["type"] = "boolean"
 | 
						|
	case DataTypeTime:
 | 
						|
		sc["type"] = "string"
 | 
						|
		sc["format"] = "date-time"
 | 
						|
	case DataTypeObject:
 | 
						|
		sc["type"] = "object"
 | 
						|
	case DataTypeArray:
 | 
						|
		sc["type"] = "array"
 | 
						|
	case DataTypeFile:
 | 
						|
		sc["type"] = "string"
 | 
						|
		if info.FileType != nil {
 | 
						|
			sc["contentMediaType"] = string(*info.FileType)
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("impossible")
 | 
						|
	}
 | 
						|
 | 
						|
	if info.Desc != "" {
 | 
						|
		sc["description"] = info.Desc
 | 
						|
	}
 | 
						|
 | 
						|
	if info.Type == DataTypeArray && info.ElemTypeInfo != nil {
 | 
						|
		itemsSchema, err := typeInfoToJSONSchema(info.ElemTypeInfo)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("failed to convert array element type: %v", err)
 | 
						|
		}
 | 
						|
		sc["items"] = itemsSchema
 | 
						|
	}
 | 
						|
	if info.Type == DataTypeObject && info.Properties != nil {
 | 
						|
		properties := make(map[string]interface{})
 | 
						|
		required := make([]string, 0)
 | 
						|
 | 
						|
		for name, propInfo := range info.Properties {
 | 
						|
			propSchema, err := typeInfoToJSONSchema(propInfo)
 | 
						|
			if err != nil {
 | 
						|
				return nil, fmt.Errorf("failed to convert property %s: %v", name, err)
 | 
						|
			}
 | 
						|
 | 
						|
			properties[name] = propSchema
 | 
						|
 | 
						|
			if propInfo.Required {
 | 
						|
				required = append(required, name)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		sc["properties"] = properties
 | 
						|
 | 
						|
		if len(required) > 0 {
 | 
						|
			sc["required"] = required
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return sc, nil
 | 
						|
}
 | 
						|
 | 
						|
type FileSubType string
 | 
						|
 | 
						|
const (
 | 
						|
	FileTypeDefault  FileSubType = "default"
 | 
						|
	FileTypeImage    FileSubType = "image"
 | 
						|
	FileTypeSVG      FileSubType = "svg"
 | 
						|
	FileTypeAudio    FileSubType = "audio"
 | 
						|
	FileTypeVideo    FileSubType = "video"
 | 
						|
	FileTypeVoice    FileSubType = "voice"
 | 
						|
	FileTypeDocument FileSubType = "doc"
 | 
						|
	FileTypePPT      FileSubType = "ppt"
 | 
						|
	FileTypeExcel    FileSubType = "excel"
 | 
						|
	FileTypeTxt      FileSubType = "txt"
 | 
						|
	FileTypeCode     FileSubType = "code"
 | 
						|
	FileTypeZip      FileSubType = "zip"
 | 
						|
)
 | 
						|
 | 
						|
type NodeProperty struct {
 | 
						|
	Type                string
 | 
						|
	IsEnableChatHistory bool
 | 
						|
	IsEnableUserQuery   bool
 | 
						|
	IsRefGlobalVariable bool
 | 
						|
	SubWorkflow         map[string]*NodeProperty
 | 
						|
}
 | 
						|
 | 
						|
func (f *FieldInfo) IsRefGlobalVariable() bool {
 | 
						|
	if f.Source.Ref != nil && f.Source.Ref.VariableType != nil {
 | 
						|
		return *f.Source.Ref.VariableType == GlobalUser || *f.Source.Ref.VariableType == GlobalSystem || *f.Source.Ref.VariableType == GlobalAPP
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func ParseVariable(v any) (*Variable, error) {
 | 
						|
	if va, ok := v.(*Variable); ok {
 | 
						|
		return va, nil
 | 
						|
	}
 | 
						|
 | 
						|
	m, ok := v.(map[string]any)
 | 
						|
	if !ok {
 | 
						|
		return nil, fmt.Errorf("invalid content type: %T when parse Variable", v)
 | 
						|
	}
 | 
						|
 | 
						|
	marshaled, err := sonic.Marshal(m)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	p := &Variable{}
 | 
						|
	if err := sonic.Unmarshal(marshaled, p); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return p, nil
 | 
						|
}
 | 
						|
 | 
						|
type GlobalVarType string
 | 
						|
 | 
						|
const (
 | 
						|
	ParentIntermediate GlobalVarType = "parent_intermediate"
 | 
						|
	GlobalUser         GlobalVarType = "global_user"
 | 
						|
	GlobalSystem       GlobalVarType = "global_system"
 | 
						|
	GlobalAPP          GlobalVarType = "global_app"
 | 
						|
)
 |