fix: delete redundant fields in plugin output data (#469)
This commit is contained in:
parent
a44b4e8f7e
commit
c7bf6bbdec
|
|
@ -2520,6 +2520,12 @@ func (w *ApplicationService) GetApiDetail(ctx context.Context, req *workflow.Get
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, v := range outputVars {
|
||||||
|
if err := crossplugin.GetPluginService().UnwrapArrayItemFieldsInVariable(v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toolDetailInfo := &vo.ToolDetailInfo{
|
toolDetailInfo := &vo.ToolDetailInfo{
|
||||||
ApiDetailData: &workflow.ApiDetailData{
|
ApiDetailData: &workflow.ApiDetailData{
|
||||||
PluginID: req.GetPluginID(),
|
PluginID: req.GetPluginID(),
|
||||||
|
|
@ -3701,7 +3707,7 @@ func toVariable(p *workflow.APIParameter) (*vo.Variable, error) {
|
||||||
case workflow.ParameterType_Array:
|
case workflow.ParameterType_Array:
|
||||||
v.Type = vo.VariableTypeList
|
v.Type = vo.VariableTypeList
|
||||||
if len(p.SubParameters) > 0 {
|
if len(p.SubParameters) > 0 {
|
||||||
subVs := make([]any, 0)
|
subVs := make([]*vo.Variable, 0)
|
||||||
for _, ap := range p.SubParameters {
|
for _, ap := range p.SubParameters {
|
||||||
av, err := toVariable(ap)
|
av, err := toVariable(ap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ func (t *pluginService) GetPluginToolsInfo(ctx context.Context, req *crossplugin
|
||||||
)
|
)
|
||||||
if toolExample != nil {
|
if toolExample != nil {
|
||||||
requestExample = toolExample.RequestExample
|
requestExample = toolExample.RequestExample
|
||||||
responseExample = toolExample.RequestExample
|
responseExample = toolExample.ResponseExample
|
||||||
}
|
}
|
||||||
|
|
||||||
response.ToolInfoList[tf.ID] = crossplugin.ToolInfo{
|
response.ToolInfoList[tf.ID] = crossplugin.ToolInfo{
|
||||||
|
|
@ -220,6 +220,63 @@ func (t *pluginService) GetPluginToolsInfo(ctx context.Context, req *crossplugin
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *pluginService) UnwrapArrayItemFieldsInVariable(v *vo.Variable) error {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Type == vo.VariableTypeObject {
|
||||||
|
subVars, ok := v.Schema.([]*vo.Variable)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newSubVars := make([]*vo.Variable, 0, len(subVars))
|
||||||
|
for _, subVar := range subVars {
|
||||||
|
if subVar.Name == "[Array Item]" {
|
||||||
|
if err := t.UnwrapArrayItemFieldsInVariable(subVar); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// If the array item is an object, append its children
|
||||||
|
if subVar.Type == vo.VariableTypeObject {
|
||||||
|
if innerSubVars, ok := subVar.Schema.([]*vo.Variable); ok {
|
||||||
|
newSubVars = append(newSubVars, innerSubVars...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the array item is a primitive type, clear its name and append it
|
||||||
|
subVar.Name = ""
|
||||||
|
newSubVars = append(newSubVars, subVar)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other sub-variables, recursively unwrap and append
|
||||||
|
if err := t.UnwrapArrayItemFieldsInVariable(subVar); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newSubVars = append(newSubVars, subVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.Schema = newSubVars
|
||||||
|
|
||||||
|
} else if v.Type == vo.VariableTypeList {
|
||||||
|
if v.Schema != nil {
|
||||||
|
subVar, ok := v.Schema.(*vo.Variable)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.UnwrapArrayItemFieldsInVariable(subVar); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// If the array item definition itself has "[Array Item]" name, clear it
|
||||||
|
if subVar.Name == "[Array Item]" {
|
||||||
|
subVar.Name = ""
|
||||||
|
}
|
||||||
|
v.Schema = subVar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *pluginService) GetPluginInvokableTools(ctx context.Context, req *crossplugin.ToolsInvokableRequest) (
|
func (t *pluginService) GetPluginInvokableTools(ctx context.Context, req *crossplugin.ToolsInvokableRequest) (
|
||||||
_ map[int64]crossplugin.InvokableTool, err error) {
|
_ map[int64]crossplugin.InvokableTool, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -327,7 +384,7 @@ func (t *pluginService) ExecutePlugin(ctx context.Context, input map[string]any,
|
||||||
}
|
}
|
||||||
|
|
||||||
var output map[string]any
|
var output map[string]any
|
||||||
err = sonic.UnmarshalString(r.RawResp, &output)
|
err = sonic.UnmarshalString(r.TrimmedResp, &output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
return nil, vo.WrapError(errno.ErrSerializationDeserializationFail, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPluginService_UnwrapArrayItemFieldsInVariable(t *testing.T) {
|
||||||
|
s := &pluginService{}
|
||||||
|
t.Run("unwraps a simple array item", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{Name: "field2", Type: vo.VariableTypeInteger},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{Name: "field2", Type: vo.VariableTypeInteger},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles nested array items", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "nestedField", Type: vo.VariableTypeBoolean},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{Name: "nestedField", Type: vo.VariableTypeBoolean},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles array item within a list", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "rootList",
|
||||||
|
Type: vo.VariableTypeList,
|
||||||
|
Schema: &vo.Variable{
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "itemField", Type: vo.VariableTypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "rootList",
|
||||||
|
Type: vo.VariableTypeList,
|
||||||
|
Schema: &vo.Variable{
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "itemField", Type: vo.VariableTypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("does nothing if no array item is present", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{Name: "field2", Type: vo.VariableTypeInteger},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a copy for comparison as the input will be modified in place.
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{Name: "field1", Type: vo.VariableTypeString},
|
||||||
|
{Name: "field2", Type: vo.VariableTypeInteger},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles primitive type array item in object", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeString,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "anotherField",
|
||||||
|
Type: vo.VariableTypeInteger,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "root",
|
||||||
|
Type: vo.VariableTypeObject,
|
||||||
|
Schema: []*vo.Variable{
|
||||||
|
{
|
||||||
|
Name: "",
|
||||||
|
Type: vo.VariableTypeString,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "anotherField",
|
||||||
|
Type: vo.VariableTypeInteger,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles list of primitives", func(t *testing.T) {
|
||||||
|
input := &vo.Variable{
|
||||||
|
Name: "listOfStrings",
|
||||||
|
Type: vo.VariableTypeList,
|
||||||
|
Schema: &vo.Variable{
|
||||||
|
Name: "[Array Item]",
|
||||||
|
Type: vo.VariableTypeString,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &vo.Variable{
|
||||||
|
Name: "listOfStrings",
|
||||||
|
Type: vo.VariableTypeList,
|
||||||
|
Schema: &vo.Variable{
|
||||||
|
Name: "",
|
||||||
|
Type: vo.VariableTypeString,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, input)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles nil input", func(t *testing.T) {
|
||||||
|
err := s.UnwrapArrayItemFieldsInVariable(nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
//go:generate mockgen -destination pluginmock/plugin_mock.go --package pluginmock -source plugin.go
|
//go:generate mockgen -destination pluginmock/plugin_mock.go --package pluginmock -source plugin.go
|
||||||
type Service interface {
|
type Service interface {
|
||||||
GetPluginToolsInfo(ctx context.Context, req *ToolsInfoRequest) (*ToolsInfoResponse, error)
|
GetPluginToolsInfo(ctx context.Context, req *ToolsInfoRequest) (*ToolsInfoResponse, error)
|
||||||
|
UnwrapArrayItemFieldsInVariable(v *vo.Variable) error
|
||||||
GetPluginInvokableTools(ctx context.Context, req *ToolsInvokableRequest) (map[int64]InvokableTool, error)
|
GetPluginInvokableTools(ctx context.Context, req *ToolsInvokableRequest) (map[int64]InvokableTool, error)
|
||||||
ExecutePlugin(ctx context.Context, input map[string]any, pe *Entity,
|
ExecutePlugin(ctx context.Context, input map[string]any, pe *Entity,
|
||||||
toolID int64, cfg ExecConfig) (map[string]any, error)
|
toolID int64, cfg ExecConfig) (map[string]any, error)
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ type FunctionInfo struct {
|
||||||
|
|
||||||
type FunctionCallInfo struct {
|
type FunctionCallInfo struct {
|
||||||
FunctionInfo
|
FunctionInfo
|
||||||
CallID string `json:"-"`
|
CallID string `json:"-"`
|
||||||
Arguments string `json:"arguments"`
|
Arguments map[string]any `json:"arguments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolResponseInfo struct {
|
type ToolResponseInfo struct {
|
||||||
|
|
|
||||||
|
|
@ -2061,7 +2061,7 @@ func buildClauseFromParams(params []*vo.Param) (*database.Clause, error) {
|
||||||
|
|
||||||
func parseBatchMode(n *vo.Node) (
|
func parseBatchMode(n *vo.Node) (
|
||||||
batchN *vo.Node, // the new batch node
|
batchN *vo.Node, // the new batch node
|
||||||
enabled bool, // whether the node has enabled batch mode
|
enabled bool, // whether the node has enabled batch mode
|
||||||
err error) {
|
err error) {
|
||||||
if n.Data == nil || n.Data.Inputs == nil {
|
if n.Data == nil || n.Data.Inputs == nil {
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||||
|
|
||||||
"github.com/cloudwego/eino/callbacks"
|
"github.com/cloudwego/eino/callbacks"
|
||||||
"github.com/cloudwego/eino/components/tool"
|
"github.com/cloudwego/eino/components/tool"
|
||||||
"github.com/cloudwego/eino/compose"
|
"github.com/cloudwego/eino/compose"
|
||||||
|
|
@ -1271,13 +1273,21 @@ func (t *ToolHandler) OnStart(ctx context.Context, info *callbacks.RunInfo,
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var args map[string]any
|
||||||
|
if input.ArgumentsInJSON != "" {
|
||||||
|
if err := sonic.UnmarshalString(input.ArgumentsInJSON, &args); err != nil {
|
||||||
|
logs.Errorf("failed to unmarshal arguments: %v", err)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t.ch <- &Event{
|
t.ch <- &Event{
|
||||||
Type: FunctionCall,
|
Type: FunctionCall,
|
||||||
Context: GetExeCtx(ctx),
|
Context: GetExeCtx(ctx),
|
||||||
functionCall: &entity.FunctionCallInfo{
|
functionCall: &entity.FunctionCallInfo{
|
||||||
FunctionInfo: t.info,
|
FunctionInfo: t.info,
|
||||||
CallID: compose.GetToolCallID(ctx),
|
CallID: compose.GetToolCallID(ctx),
|
||||||
Arguments: input.ArgumentsInJSON,
|
Arguments: args,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -887,7 +887,12 @@ func getFCInfos(ctx context.Context, nodeKey vo.NodeKey) map[string]*fcInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fcInfo) inputString() string {
|
func (f *fcInfo) inputString() string {
|
||||||
|
if f.input == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
m, err := sonic.MarshalString(f.input)
|
m, err := sonic.MarshalString(f.input)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -899,12 +904,5 @@ func (f *fcInfo) outputString() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
m := map[string]any{
|
return f.output.Response
|
||||||
"data": f.output.Response, // TODO: traceID, code, message?
|
|
||||||
}
|
|
||||||
b, err := sonic.MarshalString(m)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue