diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index b9ec8cb1..c8fc0e2c 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -45,21 +45,23 @@ type Return struct { } type Call struct { - ToolName string `json:"toolName,omitempty"` - Input string `json:"input,omitempty"` + ToolID string `json:"toolID,omitempty"` + Input string `json:"input,omitempty"` } type CallResult struct { - ID string `json:"id,omitempty"` + ToolID string `json:"toolID,omitempty"` + CallID string `json:"callID,omitempty"` Result string `json:"result,omitempty"` } type Context struct { - ID string - Ctx context.Context - Parent *Context - Program *types.Program - Tool types.Tool + ID string + Ctx context.Context + Parent *Context + Program *types.Program + Tool types.Tool + toolNames map[string]struct{} } func (c *Context) ParentID() string { @@ -97,10 +99,10 @@ func NewContext(ctx context.Context, prg *types.Program) Context { return callCtx } -func (c *Context) SubCall(ctx context.Context, toolName, callID string) (Context, error) { - tool, err := c.getTool(toolName) - if err != nil { - return Context{}, err +func (c *Context) SubCall(ctx context.Context, toolID, callID string) (Context, error) { + tool, ok := c.Program.ToolSet[toolID] + if !ok { + return Context{}, fmt.Errorf("failed to file tool for id [%s]", toolID) } return Context{ ID: callID, @@ -111,8 +113,8 @@ func (c *Context) SubCall(ctx context.Context, toolName, callID string) (Context }, nil } -func (c *Context) getTool(name string) (types.Tool, error) { - toolID, ok := c.Tool.ToolMapping[name] +func (c *Context) getTool(parent types.Tool, name string) (types.Tool, error) { + toolID, ok := parent.ToolMapping[name] if !ok { return types.Tool{}, &ErrToolNotFound{ ToolName: name, @@ -127,6 +129,45 @@ func (c *Context) getTool(name string) (types.Tool, error) { return tool, nil } +func (c *Context) appendTool(completion *types.CompletionRequest, parentTool types.Tool, subToolName string) error { + subTool, err := c.getTool(parentTool, subToolName) + if err != nil { + return err + } + + args := subTool.Parameters.Arguments + if args == nil && !subTool.IsCommand() { + args = &system.DefaultToolSchema + } + + for _, existingTool := range completion.Tools { + if existingTool.Function.ToolID == subTool.ID { + return nil + } + } + + if c.toolNames == nil { + c.toolNames = map[string]struct{}{} + } + + completion.Tools = append(completion.Tools, types.CompletionTool{ + Function: types.CompletionFunctionDefinition{ + ToolID: subTool.ID, + Name: PickToolName(subToolName, c.toolNames), + Description: subTool.Parameters.Description, + Parameters: args, + }, + }) + + for _, export := range subTool.Export { + if err := c.appendTool(completion, subTool, export); err != nil { + return err + } + } + + return nil +} + func (e *Engine) Start(ctx Context, input string) (*Return, error) { tool := ctx.Tool @@ -155,21 +196,9 @@ func (e *Engine) Start(ctx Context, input string) (*Return, error) { } for _, subToolName := range tool.Parameters.Tools { - subTool, err := ctx.getTool(subToolName) - if err != nil { + if err := ctx.appendTool(&completion, ctx.Tool, subToolName); err != nil { return nil, err } - args := subTool.Parameters.Arguments - if args == nil && !subTool.IsCommand() { - args = &system.DefaultToolSchema - } - completion.Tools = append(completion.Tools, types.CompletionTool{ - Function: types.CompletionFunctionDefinition{ - Name: subToolName, - Description: subTool.Parameters.Description, - Parameters: args, - }, - }) } if tool.Instructions != "" { @@ -225,10 +254,19 @@ func (e *Engine) complete(ctx context.Context, state *State) (*Return, error) { state.Pending = map[string]types.CompletionToolCall{} for _, content := range resp.Content { if content.ToolCall != nil { + var toolID string + for _, tool := range state.Completion.Tools { + if tool.Function.Name == content.ToolCall.Function.Name { + toolID = tool.Function.ToolID + } + } + if toolID == "" { + return nil, fmt.Errorf("failed to find tool id for tool %s in tool_call result", content.ToolCall.Function.Name) + } state.Pending[content.ToolCall.ID] = *content.ToolCall ret.Calls[content.ToolCall.ID] = Call{ - ToolName: content.ToolCall.Function.Name, - Input: content.ToolCall.Function.Arguments, + ToolID: toolID, + Input: content.ToolCall.Function.Arguments, } } else { cp := content.Text @@ -247,7 +285,7 @@ func (e *Engine) Continue(ctx context.Context, state *State, results ...CallResu } for _, result := range results { - state.Results[result.ID] = result + state.Results[result.CallID] = result } ret := Return{ @@ -262,8 +300,8 @@ func (e *Engine) Continue(ctx context.Context, state *State, results ...CallResu for id, pending := range state.Pending { if _, ok := state.Results[id]; !ok { ret.Calls[id] = Call{ - ToolName: pending.Function.Name, - Input: pending.Function.Arguments, + ToolID: state.Completion.Tools[*pending.Index].Function.ToolID, + Input: pending.Function.Arguments, } } } diff --git a/pkg/engine/toolname.go b/pkg/engine/toolname.go new file mode 100644 index 00000000..0887aad4 --- /dev/null +++ b/pkg/engine/toolname.go @@ -0,0 +1,53 @@ +package engine + +import ( + "crypto/md5" + "encoding/hex" + "path/filepath" + "regexp" + "strings" + + "github.com/gptscript-ai/gptscript/pkg/system" +) + +var ( + validToolName = regexp.MustCompile("^[a-zA-Z0-9_-]{1,64}$") + invalidChars = regexp.MustCompile("[^a-zA-Z0-9_-]+") +) + +func ToolNormalizer(tool string) string { + parts := strings.Split(tool, "/") + tool = parts[len(parts)-1] + if strings.HasSuffix(tool, system.Suffix) { + tool = strings.TrimSuffix(tool, filepath.Ext(tool)) + } + + if validToolName.MatchString(tool) { + return tool + } + + name := invalidChars.ReplaceAllString(tool, "-") + if len(name) > 55 { + name = name[:55] + } + + hash := md5.Sum([]byte(tool)) + hexed := hex.EncodeToString(hash[:]) + + return name + "-" + hexed[:8] +} + +func PickToolName(toolName string, existing map[string]struct{}) string { + if toolName == "" { + toolName = "external" + } + + for { + testName := ToolNormalizer(toolName) + if _, ok := existing[testName]; !ok { + existing[testName] = struct{}{} + return testName + } + toolName += "0" + } +} diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index 141b901b..20edaca3 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -3,7 +3,6 @@ package loader import ( "bytes" "context" - "crypto/md5" "crypto/sha256" "encoding/hex" "encoding/json" @@ -13,14 +12,12 @@ import ( "io/fs" "os" "path/filepath" - "regexp" "strings" "github.com/gptscript-ai/gptscript/pkg/assemble" "github.com/gptscript-ai/gptscript/pkg/builtin" "github.com/gptscript-ai/gptscript/pkg/engine" "github.com/gptscript-ai/gptscript/pkg/parser" - "github.com/gptscript-ai/gptscript/pkg/system" "github.com/gptscript-ai/gptscript/pkg/types" ) @@ -182,48 +179,6 @@ func readTool(ctx context.Context, prg *types.Program, base *source, targetToolN return link(ctx, prg, base, mainTool, localTools) } -var ( - validToolName = regexp.MustCompile("^[a-zA-Z0-9_-]{1,64}$") - invalidChars = regexp.MustCompile("[^a-zA-Z0-9_-]+") -) - -func ToolNormalizer(tool string) string { - parts := strings.Split(tool, "/") - tool = parts[len(parts)-1] - if strings.HasSuffix(tool, system.Suffix) { - tool = strings.TrimSuffix(tool, filepath.Ext(tool)) - } - - if validToolName.MatchString(tool) { - return tool - } - - name := invalidChars.ReplaceAllString(tool, "-") - if len(name) > 55 { - name = name[:55] - } - - hash := md5.Sum([]byte(tool)) - hexed := hex.EncodeToString(hash[:]) - - return name + "-" + hexed[:8] -} - -func pickToolName(toolName string, existing map[string]struct{}) string { - if toolName == "" { - toolName = "external" - } - - for { - testName := ToolNormalizer(toolName) - if _, ok := existing[testName]; !ok { - existing[testName] = struct{}{} - return testName - } - toolName += "0" - } -} - func link(ctx context.Context, prg *types.Program, base *source, tool types.Tool, localTools types.ToolSet) (types.Tool, error) { if existing, ok := prg.ToolSet[tool.ID]; ok { return existing, nil @@ -240,50 +195,39 @@ func link(ctx context.Context, prg *types.Program, base *source, tool types.Tool // The below is done in two loops so that local names stay as the tool names // and don't get mangled by external references - for _, targetToolName := range tool.Parameters.Tools { + for _, targetToolName := range append(tool.Parameters.Tools, tool.Parameters.Export...) { localTool, ok := localTools[targetToolName] - if !ok { - continue - } + if ok { + var linkedTool types.Tool + if existing, ok := prg.ToolSet[localTool.ID]; ok { + linkedTool = existing + } else { + var err error + linkedTool, err = link(ctx, prg, base, localTool, localTools) + if err != nil { + return types.Tool{}, fmt.Errorf("failed linking %s at %s: %w", targetToolName, base, err) + } + } - var linkedTool types.Tool - if existing, ok := prg.ToolSet[localTool.ID]; ok { - linkedTool = existing + tool.ToolMapping[targetToolName] = linkedTool.ID + toolNames[targetToolName] = struct{}{} } else { - var err error - linkedTool, err = link(ctx, prg, base, localTool, localTools) - if err != nil { - return types.Tool{}, fmt.Errorf("failed linking %s at %s: %w", targetToolName, base, err) + subTool, toolName, ok := strings.Cut(targetToolName, " from ") + if ok { + toolName = strings.TrimSpace(toolName) + subTool = strings.TrimSpace(subTool) + } else { + toolName = targetToolName + subTool = "" } - } - - tool.ToolMapping[targetToolName] = linkedTool.ID - toolNames[targetToolName] = struct{}{} - } - - for i, targetToolName := range tool.Parameters.Tools { - _, ok := localTools[targetToolName] - if ok { - continue - } - subTool, toolName, ok := strings.Cut(targetToolName, " from ") - if ok { - toolName = strings.TrimSpace(toolName) - subTool = strings.TrimSpace(subTool) - } else { - toolName = targetToolName - subTool = "" - } + resolvedTool, err := resolve(ctx, prg, base, toolName, subTool) + if err != nil { + return types.Tool{}, fmt.Errorf("failed resolving %s at %s: %w", targetToolName, base, err) + } - resolvedTool, err := resolve(ctx, prg, base, toolName, subTool) - if err != nil { - return types.Tool{}, fmt.Errorf("failed resolving %s at %s: %w", targetToolName, base, err) + tool.ToolMapping[targetToolName] = resolvedTool.ID } - - newToolName := pickToolName(toolName, toolNames) - tool.ToolMapping[newToolName] = resolvedTool.ID - tool.Parameters.Tools[i] = newToolName } for _, localTool := range localTools { diff --git a/pkg/openai/client.go b/pkg/openai/client.go index 1590f29c..e6c246c3 100644 --- a/pkg/openai/client.go +++ b/pkg/openai/client.go @@ -9,6 +9,7 @@ import ( "io" "log/slog" "os" + "slices" "sort" "strings" "sync/atomic" @@ -188,14 +189,38 @@ func toToolCall(call types.CompletionToolCall) openai.ToolCall { } func toMessages(request types.CompletionRequest) (result []openai.ChatCompletionMessage, err error) { + var ( + systemPrompts []string + msgs []types.CompletionMessage + ) + if request.InternalSystemPrompt == nil || *request.InternalSystemPrompt { - result = append(result, openai.ChatCompletionMessage{ - Role: openai.ChatMessageRoleSystem, - Content: system.InternalSystemPrompt, + systemPrompts = append(systemPrompts, system.InternalSystemPrompt) + } + + for i, message := range request.Messages { + if message.Role == types.CompletionMessageRoleTypeSystem { + // Append if the next message is system or user, otherwise set as user message + if i == len(request.Messages)-1 || + (request.Messages[i].Role != types.CompletionMessageRoleTypeSystem && + request.Messages[i].Role != types.CompletionMessageRoleTypeUser) { + message.Role = types.CompletionMessageRoleTypeUser + } else { + systemPrompts = append(systemPrompts, message.Content[0].Text) + continue + } + } + msgs = append(msgs, message) + } + + if len(systemPrompts) > 0 { + msgs = slices.Insert(msgs, 0, types.CompletionMessage{ + Role: types.CompletionMessageRoleTypeSystem, + Content: types.Text(strings.Join(systemPrompts, "\n")), }) } - for _, message := range request.Messages { + for _, message := range msgs { chatMessage := openai.ChatCompletionMessage{ Role: string(message.Role), } @@ -230,6 +255,7 @@ func toMessages(request types.CompletionRequest) (result []openai.ChatCompletion result = append(result, chatMessage) } + return } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index a8274204..6466bece 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -90,6 +90,8 @@ func isParam(line string, tool *types.Tool) (_ bool, err error) { return false, err } tool.Parameters.InternalPrompt = &v + case "export": + tool.Parameters.Export = append(tool.Parameters.Export, csv(strings.ToLower(value))...) case "tools": tool.Parameters.Tools = append(tool.Parameters.Tools, csv(strings.ToLower(value))...) case "args": @@ -161,7 +163,7 @@ type context struct { func (c *context) finish(tools *[]types.Tool) { c.tool.Instructions = strings.TrimSpace(strings.Join(c.instructions, "")) - if c.tool.Instructions != "" || c.tool.Parameters.Name != "" { + if c.tool.Instructions != "" || c.tool.Parameters.Name != "" || len(c.tool.Export) > 0 || len(c.tool.Tools) > 0 { *tools = append(*tools, c.tool) } *c = context{} diff --git a/pkg/runner/log.go b/pkg/runner/log.go new file mode 100644 index 00000000..72772a6c --- /dev/null +++ b/pkg/runner/log.go @@ -0,0 +1,5 @@ +package runner + +import "github.com/gptscript-ai/gptscript/pkg/mvl" + +var log = mvl.Package() diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 10d536ef..2be8de02 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -11,7 +11,6 @@ import ( "github.com/gptscript-ai/gptscript/pkg/engine" "github.com/gptscript-ai/gptscript/pkg/types" - "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) @@ -121,8 +120,8 @@ func (r *Runner) call(callCtx engine.Context, monitor Monitor, env []string, inp Content: *result.Result, }) if err := recordStateMessage(result.State); err != nil { - // Log a warning message if failed to record state message so that it doesn't affect the main process if state can't be recorded - logrus.Warningf("Failed to record state message: %v", err) + // Log a message if failed to record state message so that it doesn't affect the main process if state can't be recorded + log.Infof("Failed to record state message: %v", err) } return *result.Result, nil } @@ -200,7 +199,7 @@ func (r *Runner) subCalls(callCtx engine.Context, monitor Monitor, env []string, eg, subCtx := errgroup.WithContext(callCtx.Ctx) for id, call := range lastReturn.Calls { eg.Go(func() error { - callCtx, err := callCtx.SubCall(subCtx, call.ToolName, id) + callCtx, err := callCtx.SubCall(subCtx, call.ToolID, id) if err != nil { return err } @@ -213,7 +212,8 @@ func (r *Runner) subCalls(callCtx engine.Context, monitor Monitor, env []string, resultLock.Lock() defer resultLock.Unlock() callResults = append(callResults, engine.CallResult{ - ID: id, + ToolID: call.ToolID, + CallID: id, Result: result, }) diff --git a/pkg/tests/runner_test.go b/pkg/tests/runner_test.go index 6c82eae3..6e911977 100644 --- a/pkg/tests/runner_test.go +++ b/pkg/tests/runner_test.go @@ -3,9 +3,11 @@ package tests import ( "testing" + "github.com/gptscript-ai/gptscript/pkg/engine" "github.com/gptscript-ai/gptscript/pkg/tests/tester" "github.com/gptscript-ai/gptscript/pkg/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCwd(t *testing.T) { @@ -13,7 +15,7 @@ func TestCwd(t *testing.T) { runner.RespondWith(tester.Result{ Func: types.CompletionFunctionCall{ - Name: "subtool/test", + Name: engine.ToolNormalizer("./subtool/test.gpt"), }, }) runner.RespondWith(tester.Result{ @@ -24,3 +26,16 @@ func TestCwd(t *testing.T) { x := runner.RunDefault() assert.Equal(t, "TEST RESULT CALL: 3", x) } + +func TestExport(t *testing.T) { + runner := tester.NewRunner(t) + + runner.RespondWith(tester.Result{ + Func: types.CompletionFunctionCall{ + Name: "transient", + }, + }) + x, err := runner.Run("parent.gpt", "") + require.NoError(t, err) + assert.Equal(t, "TEST RESULT CALL: 3", x) +} diff --git a/pkg/tests/testdata/TestCwd/call1.golden b/pkg/tests/testdata/TestCwd/call1.golden index 68e2851e..d7fc990c 100644 --- a/pkg/tests/testdata/TestCwd/call1.golden +++ b/pkg/tests/testdata/TestCwd/call1.golden @@ -4,12 +4,14 @@ "Tools": [ { "function": { + "toolID": "testdata/TestCwd/subtool/test.gpt:1", "name": "test", "parameters": null } }, { "function": { + "toolID": "testdata/TestCwd/test.gpt:6", "name": "local", "parameters": null } diff --git a/pkg/tests/testdata/TestCwd/call2.golden b/pkg/tests/testdata/TestCwd/call2.golden index 6ab85bd2..b5832591 100644 --- a/pkg/tests/testdata/TestCwd/call2.golden +++ b/pkg/tests/testdata/TestCwd/call2.golden @@ -4,12 +4,14 @@ "Tools": [ { "function": { + "toolID": "testdata/TestCwd/subtool/test.gpt:1", "name": "test", "parameters": null } }, { "function": { + "toolID": "testdata/TestCwd/test.gpt:6", "name": "local", "parameters": null } diff --git a/pkg/tests/testdata/TestCwd/call3.golden b/pkg/tests/testdata/TestCwd/call3.golden index 8116fbc0..8d91f14b 100644 --- a/pkg/tests/testdata/TestCwd/call3.golden +++ b/pkg/tests/testdata/TestCwd/call3.golden @@ -4,12 +4,14 @@ "Tools": [ { "function": { + "toolID": "testdata/TestCwd/subtool/test.gpt:1", "name": "test", "parameters": null } }, { "function": { + "toolID": "testdata/TestCwd/test.gpt:6", "name": "local", "parameters": null } diff --git a/pkg/tests/testdata/TestExport/call1.golden b/pkg/tests/testdata/TestExport/call1.golden new file mode 100644 index 00000000..b1d0c9f0 --- /dev/null +++ b/pkg/tests/testdata/TestExport/call1.golden @@ -0,0 +1,84 @@ +`{ + "Model": "gpt-4-turbo-preview", + "InternalSystemPrompt": null, + "Tools": [ + { + "function": { + "toolID": "testdata/TestExport/parent.gpt:4", + "name": "frommain", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/parent.gpt:8", + "name": "parent-local", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/sub/child.gpt:4", + "name": "child", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/sub/child.gpt:8", + "name": "transient", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + } + ], + "Messages": null, + "MaxTokens": 0, + "Temperature": null, + "JSONResponse": false, + "Grammar": "", + "Cache": null +}` diff --git a/pkg/tests/testdata/TestExport/call2.golden b/pkg/tests/testdata/TestExport/call2.golden new file mode 100644 index 00000000..babfc6da --- /dev/null +++ b/pkg/tests/testdata/TestExport/call2.golden @@ -0,0 +1,11 @@ +`{ + "Model": "gpt-4-turbo-preview", + "InternalSystemPrompt": null, + "Tools": null, + "Messages": null, + "MaxTokens": 0, + "Temperature": null, + "JSONResponse": false, + "Grammar": "", + "Cache": null +}` diff --git a/pkg/tests/testdata/TestExport/call3.golden b/pkg/tests/testdata/TestExport/call3.golden new file mode 100644 index 00000000..2ca34642 --- /dev/null +++ b/pkg/tests/testdata/TestExport/call3.golden @@ -0,0 +1,114 @@ +`{ + "Model": "gpt-4-turbo-preview", + "InternalSystemPrompt": null, + "Tools": [ + { + "function": { + "toolID": "testdata/TestExport/parent.gpt:4", + "name": "frommain", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/parent.gpt:8", + "name": "parent-local", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/sub/child.gpt:4", + "name": "child", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + }, + { + "function": { + "toolID": "testdata/TestExport/sub/child.gpt:8", + "name": "transient", + "parameters": { + "type": "object", + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the tool or assistant. This may be instructions or question.", + "type": "string" + } + }, + "required": [ + "defaultPromptParameter" + ] + } + } + } + ], + "Messages": [ + { + "role": "assistant", + "content": [ + { + "toolCall": { + "index": 3, + "id": "call_1", + "function": { + "name": "transient" + } + } + } + ] + }, + { + "role": "tool", + "content": [ + { + "text": "TEST RESULT CALL: 2" + } + ], + "toolCall": { + "index": 3, + "id": "call_1", + "function": { + "name": "transient" + } + } + } + ], + "MaxTokens": 0, + "Temperature": null, + "JSONResponse": false, + "Grammar": "", + "Cache": null +}` diff --git a/pkg/tests/testdata/TestExport/parent.gpt b/pkg/tests/testdata/TestExport/parent.gpt new file mode 100644 index 00000000..212b8cf2 --- /dev/null +++ b/pkg/tests/testdata/TestExport/parent.gpt @@ -0,0 +1,8 @@ +tools: frommain, sub/child.gpt + +--- +name: frommain +export: parent-local, fromchild from sub/child.gpt + +--- +name: parent-local diff --git a/pkg/tests/testdata/TestExport/sub/child.gpt b/pkg/tests/testdata/TestExport/sub/child.gpt new file mode 100644 index 00000000..2f591ace --- /dev/null +++ b/pkg/tests/testdata/TestExport/sub/child.gpt @@ -0,0 +1,11 @@ + + +--- +name: fromchild +export: transient + +--- +name: transient + +--- +name: miss diff --git a/pkg/tests/tester/runner.go b/pkg/tests/tester/runner.go index 0d997543..06f170d8 100644 --- a/pkg/tests/tester/runner.go +++ b/pkg/tests/tester/runner.go @@ -54,8 +54,7 @@ func (c *Client) Call(_ context.Context, messageRequest types.CompletionRequest, } for i, tool := range messageRequest.Tools { - name := loader.ToolNormalizer(result.Func.Name) - if tool.Function.Name == name { + if tool.Function.Name == result.Func.Name { return &types.CompletionMessage{ Role: types.CompletionMessageRoleTypeAssistant, Content: []types.ContentPart{ @@ -75,7 +74,7 @@ func (c *Client) Call(_ context.Context, messageRequest types.CompletionRequest, } if result.Func.Name != "" { - c.t.Fatalf("failed to find tool %s, normalized as %s", result.Func.Name, loader.ToolNormalizer(result.Func.Name)) + c.t.Fatalf("failed to find tool %s", result.Func.Name) } return &types.CompletionMessage{ diff --git a/pkg/types/completion.go b/pkg/types/completion.go index 7d7d927e..b78a1aa4 100644 --- a/pkg/types/completion.go +++ b/pkg/types/completion.go @@ -22,6 +22,7 @@ type CompletionTool struct { } type CompletionFunctionDefinition struct { + ToolID string `json:"toolID,omitempty"` Name string `json:"name"` Description string `json:"description,omitempty"` Domain string `json:"domain,omitempty"` diff --git a/pkg/types/tool.go b/pkg/types/tool.go index 3c4e6623..a0f1143a 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -34,6 +34,7 @@ type Parameters struct { InternalPrompt *bool `json:"internalPrompt"` Arguments *JSONSchema `json:"arguments,omitempty"` Tools []string `json:"tools,omitempty"` + Export []string `json:"export,omitempty"` } type Tool struct { @@ -59,6 +60,9 @@ func (t Tool) String() string { if len(t.Parameters.Tools) != 0 { _, _ = fmt.Fprintf(buf, "Tools: %s\n", strings.Join(t.Parameters.Tools, ", ")) } + if len(t.Parameters.Export) != 0 { + _, _ = fmt.Fprintf(buf, "Export: %s\n", strings.Join(t.Parameters.Export, ", ")) + } if t.Parameters.MaxTokens != 0 { _, _ = fmt.Fprintf(buf, "Max Tokens: %d\n", t.Parameters.MaxTokens) }