From f773577c977feb3da163dbac7f1921df25211aa6 Mon Sep 17 00:00:00 2001 From: Taylor Price Date: Thu, 11 Jul 2024 10:37:26 -0700 Subject: [PATCH 1/4] chore: maintain homebrew tap as well as homebrew core formulas Signed-off-by: Taylor Price --- .github/workflows/release.yaml | 10 ++ .goreleaser.yml | 7 +- docs/docs/01-overview.md | 11 ++ examples/gptreview.gpt | 28 +++ pkg/engine/engine.go | 5 + pkg/input/input.go | 6 +- pkg/parser/parser.go | 1 + pkg/tests/runner_test.go | 20 +++ .../testdata/TestAgentOnly/call1-resp.golden | 16 ++ pkg/tests/testdata/TestAgentOnly/call1.golden | 42 +++++ .../testdata/TestAgentOnly/call2-resp.golden | 9 + pkg/tests/testdata/TestAgentOnly/call2.golden | 57 ++++++ pkg/tests/testdata/TestAgentOnly/step1.golden | 168 ++++++++++++++++++ pkg/tests/testdata/TestAgentOnly/test.gpt | 20 +++ pkg/types/tool.go | 4 + 15 files changed, 399 insertions(+), 5 deletions(-) create mode 100644 examples/gptreview.gpt create mode 100644 pkg/tests/testdata/TestAgentOnly/call1-resp.golden create mode 100644 pkg/tests/testdata/TestAgentOnly/call1.golden create mode 100644 pkg/tests/testdata/TestAgentOnly/call2-resp.golden create mode 100644 pkg/tests/testdata/TestAgentOnly/call2.golden create mode 100644 pkg/tests/testdata/TestAgentOnly/step1.golden create mode 100644 pkg/tests/testdata/TestAgentOnly/test.gpt diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 883a479d..d09608e7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,6 +40,16 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }} GORELEASER_CURRENT_TAG: ${{ github.ref_name }} + homebrew-release: + needs: release-tag + if: "! contains(github.ref_name, '-rc')" + runs-on: ubuntu-latest + steps: + - name: Update Homebrew formula + uses: dawidd6/action-homebrew-bump-formula@v3 + with: + token: ${{secrets.BREW_GH_TOKEN}} + formula: gptscript winget-release: needs: release-tag if: "! contains(github.ref_name, '-rc')" diff --git a/.goreleaser.yml b/.goreleaser.yml index b04bb8ea..3f767be0 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -52,13 +52,14 @@ release: prerelease: auto brews: - - description: "GPTScript CLI" + - name: gptscript + description: "GPTScript CLI" install: | bin.install "gptscript" - generate_completions_from_executable(bin/"gptscript", "completion", shells: [:bash, :zsh, :fish]) + generate_completions_from_executable(bin/"gptscript", "completion") homepage: "https://github.com/gptscript-ai/gptscript" skip_upload: false - folder: "Formula" + directory: "Formula" repository: owner: gptscript-ai name: homebrew-tap diff --git a/docs/docs/01-overview.md b/docs/docs/01-overview.md index a3e71857..b3d5b9fc 100644 --- a/docs/docs/01-overview.md +++ b/docs/docs/01-overview.md @@ -21,10 +21,21 @@ Here are some sample use cases of GPTScript: + ## Homebrew Tap +___ ```shell brew install gptscript-ai/tap/gptscript gptscript github.com/gptscript-ai/llm-basics-demo ``` + ## Homebrew +___ +:::warning +The [formula in homebrew-core](https://github.com/Homebrew/homebrew-core/blob/master/Formula/g/gptscript.rb) might be slightly outdated. Use our homebrew tap to always get the latest updates. +::: + ``` + brew install gptscript + gptscript github.com/gptscript-ai/llm-basics-demo + ``` ```shell diff --git a/examples/gptreview.gpt b/examples/gptreview.gpt new file mode 100644 index 00000000..2176c89a --- /dev/null +++ b/examples/gptreview.gpt @@ -0,0 +1,28 @@ + Name: Code Reviewer + Description: A tool to help you perform code review of open PRs + Context: learn-gh + Tools: sys.exec, sys.http.html2text?, sys.find, sys.read, sys.write + Args: PR_URL: The GitHub PR_URL + chat:true + + You have the gh cli available to you. Use it to perform code review for a pr. + + Perform the following steps in order: + 1. Ask the user for the ($PR_URL) and save it. + 2. Identify the files changed in the pull request ($PR_URL) using the pr number and perform a diff. + 1. Analyze the complete code of each identified file and perform a detailed line by line code review. + 2. Repeat the process for each changed file in the pr. + 3. Share your review comments separately for each file. + 4. In a new line write "Code: Approved" or "Code: Require Changes" based on the review. + --- + Name: learn-gh + Description: A tool to help you learn gh cli + + #!/usr/bin/env bash + + echo "The following is the help text for the gh cli and some of its sub-commands. Use these when figuring out how to construct new commands. Note that the --search flag is used for filtering and sorting as well; there is no dedicated --sort flag." + gh --help + gh repo --help + gh pr --help + gh pr checkout --help + gh pr diff --help \ No newline at end of file diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index b0a6e4eb..43c1da99 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -207,6 +207,11 @@ func NewContext(ctx context.Context, prg *types.Program, input string) (Context, } callCtx.AgentGroup = agentGroup + + if callCtx.Tool.IsAgentsOnly() && len(callCtx.AgentGroup) > 0 { + callCtx.Tool = callCtx.Program.ToolSet[callCtx.AgentGroup[0].ToolID] + } + return callCtx, nil } diff --git a/pkg/input/input.go b/pkg/input/input.go index 0037fa5e..3d480431 100644 --- a/pkg/input/input.go +++ b/pkg/input/input.go @@ -3,10 +3,12 @@ package input import ( "fmt" "io" + "io/fs" "os" "path/filepath" "strings" + "github.com/gptscript-ai/gptscript/internal" "github.com/gptscript-ai/gptscript/pkg/loader" "github.com/gptscript-ai/gptscript/pkg/types" ) @@ -33,7 +35,7 @@ func FromFile(file string) (string, error) { } return string(data), nil } else if file != "" { - if s, err := os.Stat(file); err == nil && s.IsDir() { + if s, err := fs.Stat(internal.FS, file); err == nil && s.IsDir() { for _, ext := range types.DefaultFiles { if _, err := os.Stat(filepath.Join(file, ext)); err == nil { file = filepath.Join(file, ext) @@ -42,7 +44,7 @@ func FromFile(file string) (string, error) { } } log.Debugf("reading file %s", file) - data, err := os.ReadFile(file) + data, err := fs.ReadFile(internal.FS, file) if err != nil { return "", fmt.Errorf("reading %s: %w", file, err) } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index b998320b..22cd5e9e 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -199,6 +199,7 @@ func (c *context) finish(tools *[]Node) { len(c.tool.GlobalTools) > 0 || len(c.tool.ExportInputFilters) > 0 || len(c.tool.ExportOutputFilters) > 0 || + len(c.tool.Agents) > 0 || c.tool.Chat { *tools = append(*tools, Node{ ToolNode: &ToolNode{ diff --git a/pkg/tests/runner_test.go b/pkg/tests/runner_test.go index 6efe4a11..0b75c8a2 100644 --- a/pkg/tests/runner_test.go +++ b/pkg/tests/runner_test.go @@ -800,6 +800,26 @@ func TestExport(t *testing.T) { assert.Equal(t, "TEST RESULT CALL: 3", x) } +func TestAgentOnly(t *testing.T) { + r := tester.NewRunner(t) + + prg, err := r.Load("") + require.NoError(t, err) + + r.RespondWith(tester.Result{ + Func: types.CompletionFunctionCall{ + Name: "agent2", + Arguments: "Agent 2 input", + }, + }) + + 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: 2").Equal(t, resp.Content) + autogold.ExpectFile(t, toJSONString(t, resp), autogold.Name(t.Name()+"/step1")) +} func TestAgents(t *testing.T) { r := tester.NewRunner(t) diff --git a/pkg/tests/testdata/TestAgentOnly/call1-resp.golden b/pkg/tests/testdata/TestAgentOnly/call1-resp.golden new file mode 100644 index 00000000..ea865122 --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/call1-resp.golden @@ -0,0 +1,16 @@ +`{ + "role": "assistant", + "content": [ + { + "toolCall": { + "index": 0, + "id": "call_1", + "function": { + "name": "agent2", + "arguments": "Agent 2 input" + } + } + } + ], + "usage": {} +}` diff --git a/pkg/tests/testdata/TestAgentOnly/call1.golden b/pkg/tests/testdata/TestAgentOnly/call1.golden new file mode 100644 index 00000000..b63c6fd3 --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/call1.golden @@ -0,0 +1,42 @@ +`{ + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent2", + "name": "agent2", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "I am agent1" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "Input 1" + } + ], + "usage": {} + } + ], + "chat": true +}` diff --git a/pkg/tests/testdata/TestAgentOnly/call2-resp.golden b/pkg/tests/testdata/TestAgentOnly/call2-resp.golden new file mode 100644 index 00000000..997ca1b9 --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/call2-resp.golden @@ -0,0 +1,9 @@ +`{ + "role": "assistant", + "content": [ + { + "text": "TEST RESULT CALL: 2" + } + ], + "usage": {} +}` diff --git a/pkg/tests/testdata/TestAgentOnly/call2.golden b/pkg/tests/testdata/TestAgentOnly/call2.golden new file mode 100644 index 00000000..82f95523 --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/call2.golden @@ -0,0 +1,57 @@ +`{ + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent1", + "name": "agent1", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + }, + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent3", + "name": "agent3", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "I am agent2" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "Agent 2 input" + } + ], + "usage": {} + } + ], + "chat": true +}` diff --git a/pkg/tests/testdata/TestAgentOnly/step1.golden b/pkg/tests/testdata/TestAgentOnly/step1.golden new file mode 100644 index 00000000..662dbf04 --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/step1.golden @@ -0,0 +1,168 @@ +`{ + "done": false, + "content": "TEST RESULT CALL: 2", + "toolID": "testdata/TestAgentOnly/test.gpt:agent2", + "state": { + "continuation": { + "state": { + "input": "Input 1", + "completion": { + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent2", + "name": "agent2", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "I am agent1" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "Input 1" + } + ], + "usage": {} + }, + { + "role": "assistant", + "content": [ + { + "toolCall": { + "index": 0, + "id": "call_1", + "function": { + "name": "agent2", + "arguments": "Agent 2 input" + } + } + } + ], + "usage": {} + } + ], + "chat": true + }, + "pending": { + "call_1": { + "index": 0, + "id": "call_1", + "function": { + "name": "agent2", + "arguments": "Agent 2 input" + } + } + } + }, + "calls": { + "call_1": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent2", + "input": "Agent 2 input" + } + } + }, + "subCalls": [ + { + "toolId": "testdata/TestAgentOnly/test.gpt:agent2", + "callId": "call_1", + "state": { + "continuation": { + "state": { + "input": "Agent 2 input", + "completion": { + "model": "gpt-4o", + "internalSystemPrompt": false, + "tools": [ + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent1", + "name": "agent1", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + }, + { + "function": { + "toolID": "testdata/TestAgentOnly/test.gpt:agent3", + "name": "agent3", + "parameters": { + "properties": { + "defaultPromptParameter": { + "description": "Prompt to send to the assistant. This may be an instruction or question.", + "type": "string" + } + }, + "type": "object" + } + } + } + ], + "messages": [ + { + "role": "system", + "content": [ + { + "text": "I am agent2" + } + ], + "usage": {} + }, + { + "role": "user", + "content": [ + { + "text": "Agent 2 input" + } + ], + "usage": {} + }, + { + "role": "assistant", + "content": [ + { + "text": "TEST RESULT CALL: 2" + } + ], + "usage": {} + } + ], + "chat": true + } + }, + "result": "TEST RESULT CALL: 2" + }, + "continuationToolID": "testdata/TestAgentOnly/test.gpt:agent2" + } + } + ], + "subCallID": "call_1" + } +}` diff --git a/pkg/tests/testdata/TestAgentOnly/test.gpt b/pkg/tests/testdata/TestAgentOnly/test.gpt new file mode 100644 index 00000000..f2ae9f9e --- /dev/null +++ b/pkg/tests/testdata/TestAgentOnly/test.gpt @@ -0,0 +1,20 @@ +agents: agent1, agent2 + +---- +name: agent1 +chat: true + +I am agent1 + +---- +name: agent2 +chat: true +agents: agent3 + +I am agent2 + +--- +name: agent3 +chat: true + +I am agent3 \ No newline at end of file diff --git a/pkg/types/tool.go b/pkg/types/tool.go index b0af5183..e4b3424a 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -763,6 +763,10 @@ func (t Tool) IsOpenAPI() bool { return strings.HasPrefix(t.Instructions, OpenAPIPrefix) } +func (t Tool) IsAgentsOnly() bool { + return t.IsNoop() && len(t.Context) == 0 +} + func (t Tool) IsEcho() bool { return strings.HasPrefix(t.Instructions, EchoPrefix) } From 1f2d7c7c56cdd88c20b5275932120b106747e28a Mon Sep 17 00:00:00 2001 From: Taylor Price Date: Thu, 11 Jul 2024 11:01:46 -0700 Subject: [PATCH 2/4] chore: update goreleaser Signed-off-by: Taylor Price --- .github/workflows/release.yaml | 2 +- .goreleaser.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d09608e7..10b852cc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,7 @@ jobs: uses: goreleaser/goreleaser-action@v4 with: distribution: goreleaser - version: v1.23.0 + version: v2.0.1 args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 3f767be0..6695c68a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,4 @@ +version: 2 dist: releases snapshot: name_template: '{{ trimprefix .Summary "v" }}' From 5d7cde648dde0da1ca9d0b6a20c77fa9bcf4dcb0 Mon Sep 17 00:00:00 2001 From: Taylor Price Date: Thu, 11 Jul 2024 11:03:21 -0700 Subject: [PATCH 3/4] chore: update goreleaser action Signed-off-by: Taylor Price --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 10b852cc..edc8b2ac 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -31,7 +31,7 @@ jobs: # After the issue is resolved, this can be set to 1.22 go-version: "1.22.4" - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser version: v2.0.1 From d3cf668b59b536ccd8eb19449416ecddf1c9aa2b Mon Sep 17 00:00:00 2001 From: Taylor Price Date: Thu, 11 Jul 2024 11:31:56 -0700 Subject: [PATCH 4/4] fix: replace user PAT with bot PAT Signed-off-by: Taylor Price --- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- .goreleaser.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 6ea47e8f..f916fdab 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -37,7 +37,7 @@ jobs: args: release --clean --snapshot env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }} + TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} - name: Upload to S3 uses: jakejarvis/s3-sync-action@v0.5.1 env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index edc8b2ac..bf38499d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -38,7 +38,7 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }} + TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} GORELEASER_CURRENT_TAG: ${{ github.ref_name }} homebrew-release: needs: release-tag diff --git a/.goreleaser.yml b/.goreleaser.yml index 6695c68a..522e3b22 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -64,4 +64,4 @@ brews: repository: owner: gptscript-ai name: homebrew-tap - token: "{{ .Env.GH_PROJECT_TOKEN }}" + token: "{{ .Env.TAP_GITHUB_TOKEN }}"