diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 36806189..e29f6b9d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -53,4 +53,26 @@ jobs: token: ${{ secrets.DISPATCH_PAT }} repository: gptscript-ai/node-gptscript event-type: release - client-payload: '{"tag": "${{ github.ref_name }}"}' \ No newline at end of file + client-payload: '{"tag": "${{ github.ref_name }}"}' + python-release: + needs: release-tag + runs-on: ubuntu-latest + steps: + - name: trigger dispatch + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.DISPATCH_PAT }} + repository: gptscript-ai/py-gptscript + event-type: release + client-payload: '{"tag": "${{ github.ref_name }}"}' + go-release: + needs: release-tag + runs-on: ubuntu-latest + steps: + - name: trigger dispatch + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.DISPATCH_PAT }} + repository: gptscript-ai/go-gptscript + event-type: release + client-payload: '{"tag": "${{ github.ref_name }}"}' diff --git a/docs/docs/03-tools/02-authoring.md b/docs/docs/03-tools/02-authoring.md index 9a06c947..3e81613a 100644 --- a/docs/docs/03-tools/02-authoring.md +++ b/docs/docs/03-tools/02-authoring.md @@ -31,13 +31,13 @@ Create a file called `tool.gpt` with the following contents: ``` Description: Returns the contents of a webpage. -Args: url: The URL of the webpage. +Param: url: The URL of the webpage. #!/usr/bin/env python3 ${GPTSCRIPT_TOOL_DIR}/tool.py ``` :::tip -Every arg becomes an environment variable when the tool is invoked. So instead of accepting args using flags like `--size="${size}"`, your program can just read the `size` environment variable. +Every param becomes an environment variable when the tool is invoked. So instead of accepting params using flags like `--size="${size}"`, your program can just read the `size` environment variable. ::: The `GPTSCRIPT_TOOL_DIR` environment variable is automatically populated by GPTScript so that the tool @@ -57,9 +57,15 @@ Tools: github.com// Get the contents of https://github.com ``` +You can also run the tool directly and set the parameter from the command line using a JSON string: + +```bash +gptscript github.com// '{"url": "https://github.com"}' +``` + ## Sharing Tools -GPTScript is designed to easily export and import tools. Doing this is currently based entirely around the use of GitHub repositories. You can export a tool by creating a GitHub repository and ensureing you have the `tool.gpt` file in the root of the repository. You can then import the tool into a GPTScript by specifying the URL of the repository in the `tools` section of the script. For example, we can leverage the `image-generation` tool by adding the following line to a GPTScript: +GPTScript is designed to easily export and import tools. Doing this is currently based entirely around the use of GitHub repositories. You can export a tool by creating a GitHub repository and ensuring you have the `tool.gpt` file in the root of the repository. You can then import the tool into a GPTScript by specifying the URL of the repository in the `tools` section of the script. For example, we can leverage the `image-generation` tool by adding the following line to a GPTScript: ```yaml tools: github.com/gptscript-ai/dalle-image-generation @@ -71,11 +77,11 @@ Generate an image of a city skyline at night. GPTScript can execute any binary that you ask it to. However, it can also manage the installation of a language runtime and dependencies for you. Currently this is only supported for a few languages. Here are the supported languages and examples of tools written in those languages: -| Language | Example | -|----------|----------------------------------------------------------------------------------------------------------------| -| `Python` | [Image Generation](https://github.com/gptscript-ai/dalle-image-generation) - Generate images based on a prompt | -| `Node.js` | [Vision](https://github.com/gptscript-ai/gpt4-v-vision) - Analyze and interpret images | -| `Golang` | [Search](https://github.com/gptscript-ai/search) - Use various providers to search the internet | +| Language | Example | +|-----------|----------------------------------------------------------------------------------------------------------------| +| `Python` | [Image Generation](https://github.com/gptscript-ai/dalle-image-generation) - Generate images based on a prompt | +| `Node.js` | [Vision](https://github.com/gptscript-ai/gpt4-v-vision) - Analyze and interpret images | +| `Golang` | [Search](https://github.com/gptscript-ai/search) - Use various providers to search the internet | ### Automatic Documentation diff --git a/go.mod b/go.mod index 4ab2b395..c5eba627 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,6 @@ go 1.22.3 require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 - github.com/acorn-io/broadcaster v0.0.0-20240105011354-bfadd4a7b45d - github.com/acorn-io/cmd v0.0.0-20240404013709-34f690bde37b github.com/adrg/xdg v0.4.0 github.com/chzyer/readline v1.5.1 github.com/docker/cli v26.0.0+incompatible @@ -15,8 +13,10 @@ require ( github.com/getkin/kin-openapi v0.124.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.6.0 + github.com/gptscript-ai/broadcaster v0.0.0-20240625175512-c43682019b86 github.com/gptscript-ai/chat-completion-client v0.0.0-20240531200700-af8e7ecf0379 - github.com/gptscript-ai/tui v0.0.0-20240618230843-2b5961f3341b + github.com/gptscript-ai/cmd v0.0.0-20240625175447-4250b42feb7d + github.com/gptscript-ai/tui v0.0.0-20240625175717-1e6eca7a66c1 github.com/hexops/autogold/v2 v2.2.1 github.com/hexops/valast v1.4.4 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 @@ -62,7 +62,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gorilla/css v1.0.0 // indirect - github.com/gptscript-ai/go-gptscript v0.0.0-20240613214812-8111c2b02d71 // indirect + github.com/gptscript-ai/go-gptscript v0.0.0-20240625134437-4b83849794cc // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hexops/autogold v1.3.1 // indirect diff --git a/go.sum b/go.sum index 1ab5607d..c61794f1 100644 --- a/go.sum +++ b/go.sum @@ -40,10 +40,6 @@ github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= -github.com/acorn-io/broadcaster v0.0.0-20240105011354-bfadd4a7b45d h1:hfpNQkJ4I2b8+DbMr8m97gG67ku0uPsMzUfskVu3cHU= -github.com/acorn-io/broadcaster v0.0.0-20240105011354-bfadd4a7b45d/go.mod h1:WF6FYrEqW0+ZtY5OKb21JhSL0aeL5VJoVrm+u0d4gOE= -github.com/acorn-io/cmd v0.0.0-20240404013709-34f690bde37b h1:VzGEGrJn54UcsEvTqcpJj9USv7vc6TIxQGZVS0Ff304= -github.com/acorn-io/cmd v0.0.0-20240404013709-34f690bde37b/go.mod h1:9jrYuzTJCv6QgGKl5gbhKqhG3kke31PmUE2KruBHzpg= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= @@ -169,12 +165,16 @@ github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gptscript-ai/broadcaster v0.0.0-20240625175512-c43682019b86 h1:m9yLtIEd0z1ia8qFjq3u0Ozb6QKwidyL856JLJp6nbA= +github.com/gptscript-ai/broadcaster v0.0.0-20240625175512-c43682019b86/go.mod h1:lK3K5EZx4dyT24UG3yCt0wmspkYqrj4D/8kxdN3relk= github.com/gptscript-ai/chat-completion-client v0.0.0-20240531200700-af8e7ecf0379 h1:vYnXoIyCXzaCEw0sYifQ4bDpsv3/fO/dZ2suEsTwCIo= github.com/gptscript-ai/chat-completion-client v0.0.0-20240531200700-af8e7ecf0379/go.mod h1:7P/o6/IWa1KqsntVf68hSnLKuu3+xuqm6lYhch1w4jo= -github.com/gptscript-ai/go-gptscript v0.0.0-20240613214812-8111c2b02d71 h1:WehkkausLuXI91ePpIVrzZ6eBmfFIU/HfNsSA1CHiwo= -github.com/gptscript-ai/go-gptscript v0.0.0-20240613214812-8111c2b02d71/go.mod h1:Dh6vYRAiVcyC3ElZIGzTvNF1FxtYwA07BHfSiFKQY7s= -github.com/gptscript-ai/tui v0.0.0-20240618230843-2b5961f3341b h1:OJfmpDQ/6ffz5P4UdJJEd5xeqo2dfWnsg1YZLDqJWYo= -github.com/gptscript-ai/tui v0.0.0-20240618230843-2b5961f3341b/go.mod h1:ZlyM+BRiD6mV04w+Xw2mXP1VKGEUbn8BvwrosWlplUo= +github.com/gptscript-ai/cmd v0.0.0-20240625175447-4250b42feb7d h1:sKf7T7twhGXs6AVbvD9pKDVewykkwSAPwEpmIEQIR/4= +github.com/gptscript-ai/cmd v0.0.0-20240625175447-4250b42feb7d/go.mod h1:DJAo1xTht1LDkNYFNydVjTHd576TC7MlpsVRl3oloVw= +github.com/gptscript-ai/go-gptscript v0.0.0-20240625134437-4b83849794cc h1:ABV7VAK65YBkqL7VlNp5ryVXnRqkKQ+U/NZfUO3ypqA= +github.com/gptscript-ai/go-gptscript v0.0.0-20240625134437-4b83849794cc/go.mod h1:Dh6vYRAiVcyC3ElZIGzTvNF1FxtYwA07BHfSiFKQY7s= +github.com/gptscript-ai/tui v0.0.0-20240625175717-1e6eca7a66c1 h1:sx/dJ0IRh3P9Ehr1g1TQ/jEw83KISmQyjrssVgPGUbE= +github.com/gptscript-ai/tui v0.0.0-20240625175717-1e6eca7a66c1/go.mod h1:R33cfOnNaqsEn9es5jLKR39wvDyHvsIVgeTMNqtzCb8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= diff --git a/pkg/cli/credential.go b/pkg/cli/credential.go index 6bfb1ed6..14f832eb 100644 --- a/pkg/cli/credential.go +++ b/pkg/cli/credential.go @@ -8,7 +8,7 @@ import ( "text/tabwriter" "time" - cmd2 "github.com/acorn-io/cmd" + cmd2 "github.com/gptscript-ai/cmd" "github.com/gptscript-ai/gptscript/pkg/cache" "github.com/gptscript-ai/gptscript/pkg/config" "github.com/gptscript-ai/gptscript/pkg/credentials" diff --git a/pkg/cli/gptscript.go b/pkg/cli/gptscript.go index 34cf8766..353967cd 100644 --- a/pkg/cli/gptscript.go +++ b/pkg/cli/gptscript.go @@ -11,8 +11,8 @@ import ( "strconv" "strings" - "github.com/acorn-io/cmd" "github.com/fatih/color" + "github.com/gptscript-ai/cmd" "github.com/gptscript-ai/gptscript/pkg/assemble" "github.com/gptscript-ai/gptscript/pkg/auth" "github.com/gptscript-ai/gptscript/pkg/builtin" @@ -330,7 +330,7 @@ func (r *GPTScript) Run(cmd *cobra.Command, args []string) (retErr error) { // If the user is trying to launch the chat-builder UI, then set up the tool and options here. if r.UI { - args = append([]string{env.VarOrDefault("GPTSCRIPT_CHAT_UI_TOOL", "github.com/gptscript-ai/ui@v0.8.4")}, args...) + args = append([]string{env.VarOrDefault("GPTSCRIPT_CHAT_UI_TOOL", "github.com/gptscript-ai/ui@v0.8.5")}, args...) // If args has more than one element, then the user has provided a file. if len(args) > 1 { diff --git a/pkg/cli/main.go b/pkg/cli/main.go index b4b55928..d06f614f 100644 --- a/pkg/cli/main.go +++ b/pkg/cli/main.go @@ -3,7 +3,7 @@ package cli import ( "os" - "github.com/acorn-io/cmd" + "github.com/gptscript-ai/cmd" "github.com/gptscript-ai/gptscript/pkg/daemon" "github.com/gptscript-ai/gptscript/pkg/mvl" ) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 2c7c729d..5cbc87a8 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -165,8 +165,13 @@ 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, error) { +func ToolCategoryFromContext(ctx context.Context) ToolCategory { category, _ := ctx.Value(toolCategoryKey{}).(ToolCategory) + return category +} + +func NewContext(ctx context.Context, prg *types.Program, input string) (Context, error) { + category := ToolCategoryFromContext(ctx) callCtx := Context{ commonContext: commonContext{ diff --git a/pkg/gptscript/gptscript.go b/pkg/gptscript/gptscript.go index a083afa1..63cce7ba 100644 --- a/pkg/gptscript/gptscript.go +++ b/pkg/gptscript/gptscript.go @@ -103,6 +103,9 @@ func New(o ...Options) (*GPTScript, error) { if err := opts.Runner.RuntimeManager.SetUpCredentialHelpers(context.Background(), cliCfg, opts.Env); err != nil { return nil, err } + if err := opts.Runner.RuntimeManager.EnsureCredentialHelpers(context.Background()); err != nil { + return nil, err + } oaiClient, err := openai.NewClient(credStore, opts.OpenAI, openai.Options{ Cache: cacheClient, diff --git a/pkg/loader/url.go b/pkg/loader/url.go index 95249478..c050edba 100644 --- a/pkg/loader/url.go +++ b/pkg/loader/url.go @@ -133,6 +133,20 @@ func loadURL(ctx context.Context, cache *cache.Client, base *source, name string func getWithDefaults(req *http.Request) ([]byte, error) { originalPath := req.URL.Path + + // First, try to get the original path as is. It might be an OpenAPI definition. + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusOK { + if toolBytes, err := io.ReadAll(resp.Body); err == nil && isOpenAPI(toolBytes) != 0 { + return toolBytes, nil + } + } + for i, def := range types.DefaultFiles { base := path.Base(originalPath) if !strings.Contains(base, ".") { diff --git a/pkg/monitor/display.go b/pkg/monitor/display.go index 167498c7..73a15006 100644 --- a/pkg/monitor/display.go +++ b/pkg/monitor/display.go @@ -38,9 +38,7 @@ type Console struct { callLock sync.Mutex } -var ( - prettyIDCounter int64 -) +var prettyIDCounter int64 func (c *Console) Start(_ context.Context, prg *types.Program, _ []string, input string) (runner.Monitor, error) { id := counter.Next() @@ -290,7 +288,7 @@ func (d *display) Event(event runner.Event) { d.dump.Calls[currentIndex] = currentCall } -func (d *display) Stop(output string, err error) { +func (d *display) Stop(_ context.Context, output string, err error) { d.callLock.Lock() defer d.callLock.Unlock() diff --git a/pkg/monitor/fd.go b/pkg/monitor/fd.go index 8cfeeede..9136936a 100644 --- a/pkg/monitor/fd.go +++ b/pkg/monitor/fd.go @@ -139,7 +139,7 @@ func (f *fd) event(event Event) { } } -func (f *fd) Stop(output string, err error) { +func (f *fd) Stop(_ context.Context, output string, err error) { e := Event{ Event: runner.Event{ Time: time.Now(), diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go index 4a9550a3..c1b693be 100644 --- a/pkg/prompt/prompt.go +++ b/pkg/prompt/prompt.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -75,6 +76,17 @@ func SysPrompt(ctx context.Context, envs []string, input string, _ chan<- string func sysPrompt(ctx context.Context, req types.Prompt) (_ string, err error) { defer context2.GetPauseFuncFromCtx(ctx)()() + if req.Message != "" && len(req.Fields) == 1 && strings.TrimSpace(req.Fields[0]) == "" { + var errs []error + _, err := fmt.Fprintln(os.Stderr, req.Message) + errs = append(errs, err) + _, err = fmt.Fprintln(os.Stderr, "Press enter to continue...") + errs = append(errs, err) + _, err = fmt.Fscanln(os.Stdin) + errs = append(errs, err) + return "", errors.Join(errs...) + } + if req.Message != "" && len(req.Fields) != 1 { _, _ = fmt.Fprintln(os.Stderr, req.Message) } diff --git a/pkg/runner/monitor.go b/pkg/runner/monitor.go index 48e64b0b..363ed62b 100644 --- a/pkg/runner/monitor.go +++ b/pkg/runner/monitor.go @@ -6,8 +6,7 @@ import ( "github.com/gptscript-ai/gptscript/pkg/types" ) -type noopFactory struct { -} +type noopFactory struct{} func (n noopFactory) Start(context.Context, *types.Program, []string, string) (Monitor, error) { return noopMonitor{}, nil @@ -17,13 +16,12 @@ func (n noopFactory) Pause() func() { return func() {} } -type noopMonitor struct { -} +type noopMonitor struct{} func (n noopMonitor) Event(Event) { } -func (n noopMonitor) Stop(string, error) {} +func (n noopMonitor) Stop(context.Context, string, error) {} func (n noopMonitor) Pause() func() { return func() {} diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index e4794535..466eddb7 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -26,7 +26,7 @@ type MonitorFactory interface { type Monitor interface { Event(event Event) Pause() func() - Stop(output string, err error) + Stop(ctx context.Context, output string, err error) } type Options struct { @@ -162,7 +162,7 @@ func (r *Runner) Chat(ctx context.Context, prevState ChatState, prg types.Progra return resp, err } defer func() { - monitor.Stop(resp.Content, err) + monitor.Stop(ctx, resp.Content, err) }() callCtx, err := engine.NewContext(ctx, &prg, input) @@ -425,9 +425,7 @@ func (r *Runner) start(callCtx engine.Context, state *State, monitor Monitor, en } } - var ( - newState *State - ) + var newState *State callCtx.InputContext, newState, err = r.getContext(callCtx, state, monitor, env, input) if err != nil { return nil, err @@ -567,7 +565,7 @@ func (r *Runner) resume(callCtx engine.Context, monitor Monitor, env []string, s Time: time.Now(), CallContext: callCtx.GetCallContext(), Type: EventTypeCallFinish, - Content: getFinishEventContent(*state, callCtx), + Content: getEventContent(*state.Continuation.Result, callCtx), }) if callCtx.Tool.Chat { return &State{ @@ -632,9 +630,7 @@ func (r *Runner) resume(callCtx engine.Context, monitor Monitor, env []string, s Env: env, } - var ( - contentInput string - ) + var contentInput string if state.Continuation != nil && state.Continuation.State != nil { contentInput = state.Continuation.State.Input @@ -681,7 +677,7 @@ func streamProgress(callCtx *engine.Context, monitor Monitor) (chan<- types.Comp CallContext: callCtx.GetCallContext(), Type: EventTypeCallProgress, ChatCompletionID: status.CompletionID, - Content: message.String(), + Content: getEventContent(message.String(), *callCtx), }) } else { monitor.Event(Event{ @@ -745,9 +741,7 @@ func (r *Runner) newDispatcher(ctx context.Context) dispatcher { } func (r *Runner) subCalls(callCtx engine.Context, monitor Monitor, env []string, state *State, toolCategory engine.ToolCategory) (_ *State, callResults []SubCallResult, _ error) { - var ( - resultLock sync.Mutex - ) + var resultLock sync.Mutex if state.Continuation != nil { callCtx.LastReturn = state.Continuation @@ -821,13 +815,13 @@ func (r *Runner) subCalls(callCtx engine.Context, monitor Monitor, env []string, return state, callResults, nil } -func getFinishEventContent(state State, callCtx engine.Context) string { - // If it is a credential tool, the finish event contains its output, which is sensitive, so we don't return it. +func getEventContent(content string, callCtx engine.Context) string { + // If it is a credential tool, the progress and finish events may contain its output, which is sensitive, so we don't return it. if callCtx.ToolCategory == engine.CredentialToolCategory { return "" } - return *state.Continuation.Result + return content } func (r *Runner) handleCredentials(callCtx engine.Context, monitor Monitor, env []string) ([]string, error) { diff --git a/pkg/sdkserver/monitor.go b/pkg/sdkserver/monitor.go index 5b06771c..a5b0236b 100644 --- a/pkg/sdkserver/monitor.go +++ b/pkg/sdkserver/monitor.go @@ -5,7 +5,8 @@ import ( "sync" "time" - "github.com/acorn-io/broadcaster" + "github.com/gptscript-ai/broadcaster" + "github.com/gptscript-ai/gptscript/pkg/engine" "github.com/gptscript-ai/gptscript/pkg/runner" gserver "github.com/gptscript-ai/gptscript/pkg/server" "github.com/gptscript-ai/gptscript/pkg/types" @@ -23,16 +24,19 @@ func NewSessionFactory(events *broadcaster.Broadcaster[event]) *SessionFactory { func (s SessionFactory) Start(ctx context.Context, prg *types.Program, env []string, input string) (runner.Monitor, error) { id := gserver.RunIDFromContext(ctx) + category := engine.ToolCategoryFromContext(ctx) - s.events.C <- event{ - Event: gserver.Event{ - Event: runner.Event{ - Time: time.Now(), - Type: runner.EventTypeRunStart, + if category == engine.NoCategory { + s.events.C <- event{ + Event: gserver.Event{ + Event: runner.Event{ + Time: time.Now(), + Type: runner.EventTypeRunStart, + }, + RunID: id, + Program: prg, }, - RunID: id, - Program: prg, - }, + } } return &Session{ @@ -69,7 +73,13 @@ func (s *Session) Event(e runner.Event) { } } -func (s *Session) Stop(output string, err error) { +func (s *Session) Stop(ctx context.Context, output string, err error) { + category := engine.ToolCategoryFromContext(ctx) + + if category != engine.NoCategory { + return + } + e := event{ Event: gserver.Event{ Event: runner.Event{ diff --git a/pkg/sdkserver/routes.go b/pkg/sdkserver/routes.go index d6205ece..0380cff4 100644 --- a/pkg/sdkserver/routes.go +++ b/pkg/sdkserver/routes.go @@ -12,7 +12,7 @@ import ( "sync" "time" - "github.com/acorn-io/broadcaster" + "github.com/gptscript-ai/broadcaster" "github.com/gptscript-ai/gptscript/pkg/cache" gcontext "github.com/gptscript-ai/gptscript/pkg/context" "github.com/gptscript-ai/gptscript/pkg/gptscript" diff --git a/pkg/sdkserver/server.go b/pkg/sdkserver/server.go index 297a6e92..c51e21e4 100644 --- a/pkg/sdkserver/server.go +++ b/pkg/sdkserver/server.go @@ -13,8 +13,8 @@ import ( "syscall" "time" - "github.com/acorn-io/broadcaster" "github.com/google/uuid" + "github.com/gptscript-ai/broadcaster" "github.com/gptscript-ai/gptscript/pkg/gptscript" "github.com/gptscript-ai/gptscript/pkg/mvl" "github.com/gptscript-ai/gptscript/pkg/runner" diff --git a/pkg/types/credential_test.go b/pkg/types/credential_test.go index 74e74e55..b6f70ee3 100644 --- a/pkg/types/credential_test.go +++ b/pkg/types/credential_test.go @@ -125,10 +125,12 @@ func TestParseCredentialArgs(t *testing.T) { wantErr: true, }, { - name: "invalid input", - toolName: "myCredentialTool", - input: `{"asdf":"asdf"`, - wantErr: true, + name: "invalid input", + toolName: "myCredentialTool", + input: `{"asdf":"asdf"`, + expectedName: "myCredentialTool", + expectedAlias: "", + wantErr: false, }, } diff --git a/pkg/types/tool.go b/pkg/types/tool.go index a5124796..b0af5183 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -255,10 +255,10 @@ func ParseCredentialArgs(toolName string, input string) (string, string, map[str inputMap := make(map[string]any) if input != "" { - err := json.Unmarshal([]byte(input), &inputMap) - if err != nil { - return "", "", nil, fmt.Errorf("failed to unmarshal input: %w", err) - } + // Sometimes this function can be called with input that is not a JSON string. + // This typically happens during chat mode. + // That's why we ignore the error if this fails to unmarshal. + _ = json.Unmarshal([]byte(input), &inputMap) } fields, err := shlex.Split(toolName)