diff --git a/pkg/builtin/builtin.go b/pkg/builtin/builtin.go index 291384c3..3e05f05c 100644 --- a/pkg/builtin/builtin.go +++ b/pkg/builtin/builtin.go @@ -32,6 +32,7 @@ var SafeTools = map[string]struct{}{ "sys.echo": {}, "sys.prompt": {}, "sys.time.now": {}, + "sys.context": {}, } var tools = map[string]types.Tool{ @@ -228,16 +229,15 @@ var tools = map[string]types.Tool{ BuiltinFunc: SysChatHistory, }, }, -} - -func SysProgram() *types.Program { - result := &types.Program{ - ToolSet: types.ToolSet{}, - } - for _, tool := range ListTools() { - result.ToolSet[tool.ID] = tool - } - return result + "sys.context": { + ToolDef: types.ToolDef{ + Parameters: types.Parameters{ + Description: "Retrieves the current internal GPTScript tool call context information", + Arguments: types.ObjectSchema(), + }, + BuiltinFunc: SysContext, + }, + }, } func ListTools() (result []types.Tool) { @@ -626,6 +626,23 @@ func invalidArgument(input string, err error) string { return fmt.Sprintf("Failed to parse arguments %s: %v", input, err) } +func SysContext(ctx context.Context, _ []string, _ string, _ chan<- string) (string, error) { + engineContext, _ := engine.FromContext(ctx) + + callContext := *engineContext.GetCallContext() + callContext.ID = "" + callContext.ParentID = "" + data, err := json.Marshal(map[string]any{ + "program": engineContext.Program, + "call": callContext, + }) + if err != nil { + return invalidArgument("", err), nil + } + + return string(data), nil +} + func SysChatHistory(ctx context.Context, _ []string, _ string, _ chan<- string) (string, error) { engineContext, _ := engine.FromContext(ctx) diff --git a/pkg/embedded/embed.go b/pkg/embedded/embed.go index de12bec3..7ea7edb9 100644 --- a/pkg/embedded/embed.go +++ b/pkg/embedded/embed.go @@ -3,7 +3,6 @@ package embedded import ( "io/fs" "os" - "strings" "github.com/gptscript-ai/gptscript/internal" "github.com/gptscript-ai/gptscript/pkg/cli" @@ -22,10 +21,11 @@ func Run(opts ...Options) bool { } system.SetBinToSelf() - if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "sys.") { + if os.Getenv("GPTSCRIPT_EMBEDDED") == "true" { cli.Main() return true } + _ = os.Setenv("GPTSCRIPT_EMBEDDED", "true") return false } diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 9dd8c741..a76a3556 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -165,7 +165,7 @@ func WithToolCategory(ctx context.Context, toolCategory ToolCategory) context.Co return context.WithValue(ctx, toolCategoryKey{}, toolCategory) } -func NewContext(ctx context.Context, prg *types.Program, input string) Context { +func NewContext(ctx context.Context, prg *types.Program, input string) (Context, error) { category, _ := ctx.Value(toolCategoryKey{}).(ToolCategory) callCtx := Context{ @@ -178,7 +178,14 @@ func NewContext(ctx context.Context, prg *types.Program, input string) Context { Program: prg, Input: input, } - return callCtx + + agentGroup, err := callCtx.Tool.GetAgents(*prg) + if err != nil { + return callCtx, err + } + + callCtx.AgentGroup = agentGroup + return callCtx, nil } func (c *Context) SubCallContext(ctx context.Context, input, toolID, callID string, toolCategory ToolCategory) (Context, error) { @@ -191,7 +198,7 @@ func (c *Context) SubCallContext(ctx context.Context, input, toolID, callID stri callID = counter.Next() } - agentGroup, err := c.Tool.GetAgentGroup(c.AgentGroup, toolID) + agentGroup, err := c.Tool.GetNextAgentGroup(*c.Program, c.AgentGroup, toolID) if err != nil { return Context{}, err } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index ddb4b102..7df697ff 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -165,7 +165,11 @@ func (r *Runner) Chat(ctx context.Context, prevState ChatState, prg types.Progra monitor.Stop(resp.Content, err) }() - callCtx := engine.NewContext(ctx, &prg, input) + callCtx, err := engine.NewContext(ctx, &prg, input) + if err != nil { + return resp, err + } + if state == nil || state.StartContinuation { if state != nil { state = state.WithResumeInput(&input) diff --git a/pkg/tests/runner_test.go b/pkg/tests/runner_test.go index ffb30d8f..1421e849 100644 --- a/pkg/tests/runner_test.go +++ b/pkg/tests/runner_test.go @@ -7,6 +7,7 @@ import ( "runtime" "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/hexops/autogold/v2" @@ -847,3 +848,33 @@ func TestInput(t *testing.T) { autogold.Expect("TEST RESULT CALL: 2").Equal(t, resp.Content) autogold.ExpectFile(t, toJSONString(t, resp), autogold.Name(t.Name()+"/step2")) } + +func TestSysContext(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + r := tester.NewRunner(t) + + prg, err := r.Load("") + require.NoError(t, err) + + resp, err := r.Chat(context.Background(), nil, prg, nil, "input 1") + require.NoError(t, err) + r.AssertResponded(t) + assert.False(t, resp.Done) + autogold.Expect("TEST RESULT CALL: 1").Equal(t, resp.Content) + autogold.ExpectFile(t, toJSONString(t, resp), autogold.Name(t.Name()+"/step1")) + + data, err := os.ReadFile("testdata/TestSysContext/context.json") + require.NoError(t, err) + + context := struct { + Call engine.CallContext `json:"call"` + }{} + err = json.Unmarshal(data, &context) + require.NoError(t, err) + + require.Len(t, context.Call.AgentGroup, 1) + assert.Equal(t, context.Call.AgentGroup[0].Named, "iAmSuperman") +} diff --git a/pkg/tests/testdata/TestSysContext/call1-resp.golden b/pkg/tests/testdata/TestSysContext/call1-resp.golden new file mode 100644 index 00000000..2861a036 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/call1-resp.golden @@ -0,0 +1,9 @@ +`{ + "role": "assistant", + "content": [ + { + "text": "TEST RESULT CALL: 1" + } + ], + "usage": {} +}` diff --git a/pkg/tests/testdata/TestSysContext/call1.golden b/pkg/tests/testdata/TestSysContext/call1.golden new file mode 100644 index 00000000..c315d381 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/call1.golden @@ -0,0 +1,41 @@ +`{ + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestSysContext/file.gpt:I am Superman Agent", + "name": "iAmSuperman", + "parameters": { + "properties": { + "prompt": { + "description": "Prompt to send to the tool. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "{\"call\":{\"id\":\"\",\"tool\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"agentGroup\":[{\"named\":\"iAmSuperman\",\"reference\":\"./file.gpt\",\"toolID\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"}],\"inputContext\":null,\"toolCategory\":\"context\",\"toolName\":\"sys.context\"},\"program\":{\"name\":\"testdata/TestSysContext/test.gpt\",\"entryToolId\":\"testdata/TestSysContext/test.gpt:\",\"toolSet\":{\"sys.context\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"testdata/TestSysContext/file.gpt:I am Superman Agent\":{\"name\":\"I am Superman Agent\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"instructions\":\"I'm super\",\"id\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\",\"localTools\":{\"i am superman agent\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"},\"source\":{\"location\":\"testdata/TestSysContext/file.gpt\",\"lineNo\":1},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:\":{\"modelName\":\"gpt-4o\",\"chat\":true,\"internalPrompt\":null,\"context\":[\"agents\"],\"agents\":[\"./file.gpt\"],\"instructions\":\"Tool body\",\"id\":\"testdata/TestSysContext/test.gpt:\",\"toolMapping\":{\"./file.gpt\":[{\"reference\":\"./file.gpt\",\"toolID\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"}],\"agents\":[{\"reference\":\"agents\",\"toolID\":\"testdata/TestSysContext/test.gpt:agents\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":1},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:agents\":{\"name\":\"agents\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"context\":[\"sys.context\"],\"instructions\":\"#!/bin/bash\\n\\necho \\\"${GPTSCRIPT_CONTEXT}\\\"\\necho \\\"${GPTSCRIPT_CONTEXT}\\\" \\u003e ${GPTSCRIPT_TOOL_DIR}/context.json\",\"id\":\"testdata/TestSysContext/test.gpt:agents\",\"toolMapping\":{\"sys.context\":[{\"reference\":\"sys.context\",\"toolID\":\"sys.context\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":8},\"workingDir\":\"testdata/TestSysContext\"}}}}\n\nTool body" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "input 1" + } + ], + "usage": {} + } + ] +}` diff --git a/pkg/tests/testdata/TestSysContext/call1.golden.bkp b/pkg/tests/testdata/TestSysContext/call1.golden.bkp new file mode 100644 index 00000000..7bfb5403 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/call1.golden.bkp @@ -0,0 +1,41 @@ +`{ + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestSysContext/test.gpt:foo", + "name": "foo", + "parameters": { + "properties": { + "prompt": { + "description": "Prompt to send to the tool. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "{\"call\":{\"id\":\"\",\"tool\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"inputContext\":null,\"toolCategory\":\"context\",\"toolName\":\"sys.context\",\"parentID\":\"1718924874\",\"displayText\":\"Running sys.context\"},\"program\":{\"name\":\"testdata/TestSysContext/test.gpt\",\"entryToolId\":\"testdata/TestSysContext/test.gpt:\",\"toolSet\":{\"sys.context\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"testdata/TestSysContext/test.gpt:\":{\"modelName\":\"gpt-4o\",\"chat\":true,\"internalPrompt\":null,\"context\":[\"agents\"],\"agents\":[\"foo\"],\"instructions\":\"Tool body\",\"id\":\"testdata/TestSysContext/test.gpt:\",\"toolMapping\":{\"agents\":[{\"reference\":\"agents\",\"toolID\":\"testdata/TestSysContext/test.gpt:agents\"}],\"foo\":[{\"reference\":\"foo\",\"toolID\":\"testdata/TestSysContext/test.gpt:foo\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\",\"foo\":\"testdata/TestSysContext/test.gpt:foo\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":1},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:agents\":{\"name\":\"agents\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"context\":[\"sys.context\"],\"instructions\":\"#!/bin/bash\\n\\necho \\\"${GPTSCRIPT_CONTEXT}\\\"\\necho \\\"${GPTSCRIPT_CONTEXT}\\\" \\u003e ${GPTSCRIPT_TOOL_DIR}/context.json\",\"id\":\"testdata/TestSysContext/test.gpt:agents\",\"toolMapping\":{\"sys.context\":[{\"reference\":\"sys.context\",\"toolID\":\"sys.context\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\",\"foo\":\"testdata/TestSysContext/test.gpt:foo\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":13},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:foo\":{\"name\":\"foo\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"instructions\":\"I'm an agent\",\"id\":\"testdata/TestSysContext/test.gpt:foo\",\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\",\"foo\":\"testdata/TestSysContext/test.gpt:foo\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":8},\"workingDir\":\"testdata/TestSysContext\"}}}}\n\nTool body" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "input 1" + } + ], + "usage": {} + } + ] +}` diff --git a/pkg/tests/testdata/TestSysContext/context.json b/pkg/tests/testdata/TestSysContext/context.json new file mode 100644 index 00000000..c5608ec4 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/context.json @@ -0,0 +1 @@ +{"call":{"id":"","tool":{"name":"sys.context","description":"Retrieves the current internal GPTScript tool call context information","modelName":"gpt-4o","internalPrompt":null,"arguments":{"type":"object"},"instructions":"#!sys.context","id":"sys.context","source":{}},"agentGroup":[{"named":"iAmSuperman","reference":"./file.gpt","toolID":"testdata/TestSysContext/file.gpt:I am Superman Agent"}],"inputContext":null,"toolCategory":"context","toolName":"sys.context"},"program":{"name":"testdata/TestSysContext/test.gpt","entryToolId":"testdata/TestSysContext/test.gpt:","toolSet":{"sys.context":{"name":"sys.context","description":"Retrieves the current internal GPTScript tool call context information","modelName":"gpt-4o","internalPrompt":null,"arguments":{"type":"object"},"instructions":"#!sys.context","id":"sys.context","source":{}},"testdata/TestSysContext/file.gpt:I am Superman Agent":{"name":"I am Superman Agent","modelName":"gpt-4o","internalPrompt":null,"instructions":"I'm super","id":"testdata/TestSysContext/file.gpt:I am Superman Agent","localTools":{"i am superman agent":"testdata/TestSysContext/file.gpt:I am Superman Agent"},"source":{"location":"testdata/TestSysContext/file.gpt","lineNo":1},"workingDir":"testdata/TestSysContext"},"testdata/TestSysContext/test.gpt:":{"modelName":"gpt-4o","chat":true,"internalPrompt":null,"context":["agents"],"agents":["./file.gpt"],"instructions":"Tool body","id":"testdata/TestSysContext/test.gpt:","toolMapping":{"./file.gpt":[{"reference":"./file.gpt","toolID":"testdata/TestSysContext/file.gpt:I am Superman Agent"}],"agents":[{"reference":"agents","toolID":"testdata/TestSysContext/test.gpt:agents"}]},"localTools":{"":"testdata/TestSysContext/test.gpt:","agents":"testdata/TestSysContext/test.gpt:agents"},"source":{"location":"testdata/TestSysContext/test.gpt","lineNo":1},"workingDir":"testdata/TestSysContext"},"testdata/TestSysContext/test.gpt:agents":{"name":"agents","modelName":"gpt-4o","internalPrompt":null,"context":["sys.context"],"instructions":"#!/bin/bash\n\necho \"${GPTSCRIPT_CONTEXT}\"\necho \"${GPTSCRIPT_CONTEXT}\" \u003e ${GPTSCRIPT_TOOL_DIR}/context.json","id":"testdata/TestSysContext/test.gpt:agents","toolMapping":{"sys.context":[{"reference":"sys.context","toolID":"sys.context"}]},"localTools":{"":"testdata/TestSysContext/test.gpt:","agents":"testdata/TestSysContext/test.gpt:agents"},"source":{"location":"testdata/TestSysContext/test.gpt","lineNo":8},"workingDir":"testdata/TestSysContext"}}}} diff --git a/pkg/tests/testdata/TestSysContext/file.gpt b/pkg/tests/testdata/TestSysContext/file.gpt new file mode 100644 index 00000000..75f63087 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/file.gpt @@ -0,0 +1,3 @@ +name: I am Superman Agent + +I'm super \ No newline at end of file diff --git a/pkg/tests/testdata/TestSysContext/step1.golden b/pkg/tests/testdata/TestSysContext/step1.golden new file mode 100644 index 00000000..26b75508 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/step1.golden @@ -0,0 +1,64 @@ +`{ + "done": false, + "content": "TEST RESULT CALL: 1", + "toolID": "testdata/TestSysContext/test.gpt:", + "state": { + "continuation": { + "state": { + "input": "input 1", + "completion": { + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestSysContext/file.gpt:I am Superman Agent", + "name": "iAmSuperman", + "parameters": { + "properties": { + "prompt": { + "description": "Prompt to send to the tool. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "{\"call\":{\"id\":\"\",\"tool\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"agentGroup\":[{\"named\":\"iAmSuperman\",\"reference\":\"./file.gpt\",\"toolID\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"}],\"inputContext\":null,\"toolCategory\":\"context\",\"toolName\":\"sys.context\"},\"program\":{\"name\":\"testdata/TestSysContext/test.gpt\",\"entryToolId\":\"testdata/TestSysContext/test.gpt:\",\"toolSet\":{\"sys.context\":{\"name\":\"sys.context\",\"description\":\"Retrieves the current internal GPTScript tool call context information\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"arguments\":{\"type\":\"object\"},\"instructions\":\"#!sys.context\",\"id\":\"sys.context\",\"source\":{}},\"testdata/TestSysContext/file.gpt:I am Superman Agent\":{\"name\":\"I am Superman Agent\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"instructions\":\"I'm super\",\"id\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\",\"localTools\":{\"i am superman agent\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"},\"source\":{\"location\":\"testdata/TestSysContext/file.gpt\",\"lineNo\":1},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:\":{\"modelName\":\"gpt-4o\",\"chat\":true,\"internalPrompt\":null,\"context\":[\"agents\"],\"agents\":[\"./file.gpt\"],\"instructions\":\"Tool body\",\"id\":\"testdata/TestSysContext/test.gpt:\",\"toolMapping\":{\"./file.gpt\":[{\"reference\":\"./file.gpt\",\"toolID\":\"testdata/TestSysContext/file.gpt:I am Superman Agent\"}],\"agents\":[{\"reference\":\"agents\",\"toolID\":\"testdata/TestSysContext/test.gpt:agents\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":1},\"workingDir\":\"testdata/TestSysContext\"},\"testdata/TestSysContext/test.gpt:agents\":{\"name\":\"agents\",\"modelName\":\"gpt-4o\",\"internalPrompt\":null,\"context\":[\"sys.context\"],\"instructions\":\"#!/bin/bash\\n\\necho \\\"${GPTSCRIPT_CONTEXT}\\\"\\necho \\\"${GPTSCRIPT_CONTEXT}\\\" \\u003e ${GPTSCRIPT_TOOL_DIR}/context.json\",\"id\":\"testdata/TestSysContext/test.gpt:agents\",\"toolMapping\":{\"sys.context\":[{\"reference\":\"sys.context\",\"toolID\":\"sys.context\"}]},\"localTools\":{\"\":\"testdata/TestSysContext/test.gpt:\",\"agents\":\"testdata/TestSysContext/test.gpt:agents\"},\"source\":{\"location\":\"testdata/TestSysContext/test.gpt\",\"lineNo\":8},\"workingDir\":\"testdata/TestSysContext\"}}}}\n\nTool body" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "input 1" + } + ], + "usage": {} + }, + { + "role": "assistant", + "content": [ + { + "text": "TEST RESULT CALL: 1" + } + ], + "usage": {} + } + ] + } + }, + "result": "TEST RESULT CALL: 1" + }, + "continuationToolID": "testdata/TestSysContext/test.gpt:" + } +}` diff --git a/pkg/tests/testdata/TestSysContext/test.go b/pkg/tests/testdata/TestSysContext/test.go new file mode 100644 index 00000000..462ff284 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/test.go @@ -0,0 +1,22 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/gptscript-ai/gptscript/pkg/engine" +) + +func main() { + data := struct { + Call engine.CallContext `json:"call,omitempty"` + }{} + if err := json.Unmarshal([]byte(os.Getenv("GPTSCRIPT_CONTEXT")), &data); err != nil { + panic(err) + } + + for _, agent := range data.Call.AgentGroup { + fmt.Println(agent.Reference, agent.ToolID) + } +} diff --git a/pkg/tests/testdata/TestSysContext/test.gpt b/pkg/tests/testdata/TestSysContext/test.gpt new file mode 100644 index 00000000..63e93417 --- /dev/null +++ b/pkg/tests/testdata/TestSysContext/test.gpt @@ -0,0 +1,14 @@ +context: agents +agents: ./file.gpt +chat: true + +Tool body + +--- +name: agents +context: sys.context + +#!/bin/bash + +echo "${GPTSCRIPT_CONTEXT}" +echo "${GPTSCRIPT_CONTEXT}" > ${GPTSCRIPT_TOOL_DIR}/context.json \ No newline at end of file diff --git a/pkg/types/tool.go b/pkg/types/tool.go index cc84264d..dd89c471 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -335,6 +335,30 @@ func ParseCredentialArgs(toolName string, input string) (string, string, map[str return originalName, alias, args, nil } +func (t Tool) GetAgents(prg Program) (result []ToolReference, _ error) { + toolRefs, err := t.GetToolRefsFromNames(t.Agents) + if err != nil { + return nil, err + } + + // Agent Tool refs must be named + for i, toolRef := range toolRefs { + if toolRef.Named != "" { + continue + } + tool := prg.ToolSet[toolRef.ToolID] + name := tool.Name + if name == "" { + name = toolRef.Reference + } + normed := ToolNormalizer(name) + normed = strings.TrimSuffix(strings.TrimSuffix(normed, "Agent"), "Assistant") + toolRefs[i].Named = normed + } + + return toolRefs, nil +} + func (t Tool) GetToolRefsFromNames(names []string) (result []ToolReference, _ error) { for _, toolName := range names { toolRefs, ok := t.ToolMapping[toolName] @@ -522,9 +546,9 @@ func (t Tool) GetInputFilterTools(program Program) ([]ToolReference, error) { return result.List() } -func (t Tool) GetAgentGroup(agentGroup []ToolReference, toolID string) (result []ToolReference, _ error) { +func (t Tool) GetNextAgentGroup(prg Program, agentGroup []ToolReference, toolID string) (result []ToolReference, _ error) { newAgentGroup := toolRefSet{} - if err := t.addAgents(&newAgentGroup); err != nil { + if err := t.addAgents(prg, &newAgentGroup); err != nil { return nil, err } @@ -533,15 +557,7 @@ func (t Tool) GetAgentGroup(agentGroup []ToolReference, toolID string) (result [ return newAgentGroup.List() } - existingAgentGroup := toolRefSet{} - existingAgentGroup.AddAll(agentGroup, nil) - - if existingAgentGroup.HasTool(toolID) { - return existingAgentGroup.List() - } - - // No group - return nil, nil + return agentGroup, nil } func (t Tool) GetCompletionTools(prg Program, agentGroup ...ToolReference) (result []CompletionTool, err error) { @@ -552,8 +568,8 @@ func (t Tool) GetCompletionTools(prg Program, agentGroup ...ToolReference) (resu return toolRefsToCompletionTools(refs, prg), nil } -func (t Tool) addAgents(result *toolRefSet) error { - subToolRefs, err := t.GetToolRefsFromNames(t.Parameters.Agents) +func (t Tool) addAgents(prg Program, result *toolRefSet) error { + subToolRefs, err := t.GetAgents(prg) if err != nil { return err } @@ -617,7 +633,7 @@ func (t Tool) getCompletionToolRefs(prg Program, agentGroup []ToolReference) ([] return nil, err } - if err := t.addAgents(&result); err != nil { + if err := t.addAgents(prg, &result); err != nil { return nil, err } diff --git a/pkg/types/toolstring.go b/pkg/types/toolstring.go index 3bd6fd57..ede3401e 100644 --- a/pkg/types/toolstring.go +++ b/pkg/types/toolstring.go @@ -74,7 +74,7 @@ func ToSysDisplayString(id string, args map[string]string) (string, error) { return fmt.Sprintf("Removing `%s`", args["location"]), nil case "sys.write": return fmt.Sprintf("Writing `%s`", args["filename"]), nil - case "sys.stat", "sys.getenv", "sys.abort", "sys.chat.finish", "sys.chat.history", "sys.echo", "sys.prompt", "sys.time.now": + case "sys.context", "sys.stat", "sys.getenv", "sys.abort", "sys.chat.finish", "sys.chat.history", "sys.echo", "sys.prompt", "sys.time.now": return "", nil default: return "", fmt.Errorf("unknown tool for display string: %s", id)