From 680d983e3c9688aff281821b430423bb9bb530d7 Mon Sep 17 00:00:00 2001 From: Kibin Shin Date: Tue, 4 Jun 2024 09:43:44 +0900 Subject: [PATCH 1/4] Add allganize feature: history, break, GPTSCRIPT_PROGRESS_TIME_STEP_MS --- .gitignore | 2 ++ Makefile | 12 ++++++++++++ examples/sh.gpt | 26 ++++++++++++++++++++++++++ go.mod | 2 ++ pkg/engine/control.go | 20 ++++++++++++++++++++ pkg/engine/engine.go | 42 ++++++++++++++++++++++++++++++++++++++++++ pkg/runner/runner.go | 29 ++++++++++++++++++++++------- pkg/types/tool.go | 5 +++++ 8 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 examples/sh.gpt create mode 100644 pkg/engine/control.go diff --git a/.gitignore b/.gitignore index 759e3286..dc885955 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ /binaries /checksums.txt /.env* +ui/ +gptscript.code-workspace diff --git a/Makefile b/Makefile index 4a52694a..20362360 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,12 @@ all: build build-exe: GOOS=windows go build -o bin/gptscript.exe -tags "${GO_TAGS}" . +build-linux-amd64: + GOOS=linux GOARCH=amd64 go build -o bin/gptscript_linux_amd64 -tags "${GO_TAGS}" . + +build-linux-arm64: + GOOS=linux GOARCH=arm64 go build -o bin/gptscript_linux_arm64 -tags "${GO_TAGS}" . + build: CGO_ENABLED=0 go build -o bin/gptscript -tags "${GO_TAGS}" -ldflags "-s -w" . @@ -23,6 +29,12 @@ smoke: go test -v -tags='smoke' ./pkg/tests/smoke/... GOLANGCI_LINT_VERSION ?= v1.60.1 + +cp: build-linux-amd64 build-linux-arm64 + cp bin/gptscript_linux_amd64 ~/Workspace/streamlit-gptscript/gptscript/bin/gptscript + cp bin/gptscript_linux_amd64 ~/Workspace/streamlit-gptscript/gptscript/bin/gptscript_linux_amd64 + cp bin/gptscript_linux_arm64 ~/Workspace/streamlit-gptscript/gptscript/bin/gptscript_linux_arm64 + lint: if ! command -v golangci-lint &> /dev/null; then \ echo "Could not find golangci-lint, installing version $(GOLANGCI_LINT_VERSION)."; \ diff --git a/examples/sh.gpt b/examples/sh.gpt new file mode 100644 index 00000000..7494cb1e --- /dev/null +++ b/examples/sh.gpt @@ -0,0 +1,26 @@ +name: main +tools: answer, extract_hashtag +Chat: True + +당신은 주어진 툴을 이용해서 사용자의 질문에 대답하는 agent입니다. +처음에는 "안녕"이라 말해주세요. + +--- +name: answer +description: 사용자의 질문에 대해서 답해줍니다. +args: question : 사용자의 질문 +args: hashtags : example) ["postgres", "mysql"]. 이 인자를 얻기위해서는 반드시 extract_hashtag tool을 사용한 결과로 해야합니다. +tools: extract_hashtag + +#!/usr/bin/env python + +print("melong") + +--- +name: extract_hashtag +description: 사용자의 질문에서 해시태그를 추출합니다. +args: question : 사용자의 질문 + +#!/usr/bin/env python + +print("hash1, hash2") diff --git a/go.mod b/go.mod index 83146eeb..386d7fc4 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/bodgit/plumbing v1.2.0 // indirect github.com/bodgit/sevenzip v1.3.0 // indirect github.com/bodgit/windows v1.0.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/charmbracelet/glamour v0.7.0 // indirect github.com/charmbracelet/lipgloss v0.11.0 // indirect github.com/charmbracelet/x/ansi v0.1.1 // indirect @@ -62,6 +63,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/dsnet/compress v0.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect diff --git a/pkg/engine/control.go b/pkg/engine/control.go new file mode 100644 index 00000000..7bb45c0a --- /dev/null +++ b/pkg/engine/control.go @@ -0,0 +1,20 @@ +package engine + +import ( + "encoding/json" + "fmt" + + "github.com/gptscript-ai/gptscript/pkg/types" +) + +func (e *Engine) runBreak(tool types.Tool, input string) (cmdOut *Return, cmdErr error) { + info, err := json.Marshal(tool) + if err != nil { + return nil, err + } + var dict map[string]interface{} + json.Unmarshal(info, &dict) + dict["input"] = input + info, err = json.Marshal(dict) + return nil, fmt.Errorf("TOOL_BREAK: %s", info) +} diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index d028d50b..0bd861db 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -1,9 +1,12 @@ package engine import ( + "bufio" "context" "encoding/json" "fmt" + "log/slog" + "os" "strings" "sync" @@ -281,6 +284,39 @@ func populateMessageParams(ctx Context, completion *types.CompletionRequest, too return nil } +func putHistory(messages []types.CompletionMessage) []types.CompletionMessage { + prevHistoryFile := strings.TrimSpace(os.Getenv("GPTSCRIPT_PREVIOUS_HISTORY_FILE")) + + if prevHistoryFile == "" { + return messages + } + fp, err := os.Open(prevHistoryFile) + if err != nil { + slog.Error("Open Error", err) + return messages + } + defer fp.Close() + + scanner := bufio.NewScanner(fp) + + prevMessages := []types.CompletionMessage{} + for scanner.Scan() { + var message types.CompletionMessage + line := scanner.Text() + err := json.Unmarshal([]byte(line), &message) + if err != nil { + slog.Error("Unmarshal Error", err) + return messages + } + if message.Role == "system" { + continue + } + prevMessages = append(prevMessages, message) + } + + return append(messages, prevMessages...) +} + func (e *Engine) Start(ctx Context, input string) (ret *Return, _ error) { tool := ctx.Tool @@ -299,6 +335,8 @@ func (e *Engine) Start(ctx Context, input string) (ret *Return, _ error) { return e.runOpenAPI(tool, input) } else if tool.IsEcho() { return e.runEcho(tool) + } else if tool.IsBreak() { + return e.runBreak(tool, input) } s, err := e.runCommand(ctx, tool, input, ctx.ToolCategory) if err != nil { @@ -322,6 +360,10 @@ func (e *Engine) Start(ctx Context, input string) (ret *Return, _ error) { input = "" } + if ctx.Parent == nil { + completion.Messages = putHistory(completion.Messages) + } + if input != "" { completion.Messages = append(completion.Messages, types.CompletionMessage{ Role: types.CompletionMessageRoleTypeUser, diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index c843b6b5..02c5224e 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -5,7 +5,9 @@ import ( "encoding/json" "errors" "fmt" + "os" "sort" + "strconv" "strings" "sync" "time" @@ -636,17 +638,29 @@ func streamProgress(callCtx *engine.Context, monitor Monitor) (chan<- types.Comp wg := sync.WaitGroup{} wg.Add(1) + progressTimeStepMs, err := strconv.Atoi(os.Getenv("GPTSCRIPT_PROGRESS_TIME_STEP_MS")) + if err != nil { + // 기본값 250ms를 사용하거나 오류를 처리합니다. + progressTimeStepMs = 250 + } + progressTimeStep := time.Duration(progressTimeStepMs) * time.Millisecond go func() { defer wg.Done() + lastSentTimeMap := make(map[string]time.Time) for status := range progress { if message := status.PartialResponse; message != nil { - monitor.Event(Event{ - Time: time.Now(), - CallContext: callCtx.GetCallContext(), - Type: EventTypeCallProgress, - ChatCompletionID: status.CompletionID, - Content: getEventContent(message.String(), *callCtx), - }) + now := time.Now() + lastSentTime, ok := lastSentTimeMap[status.CompletionID] + if !ok || now.Sub(lastSentTime) > progressTimeStep { + lastSentTimeMap[status.CompletionID] = now + monitor.Event(Event{ + Time: time.Now(), + CallContext: callCtx.GetCallContext(), + Type: EventTypeCallProgress, + ChatCompletionID: status.CompletionID, + Content: getEventContent(message.String(), *callCtx), + }) + } } else { monitor.Event(Event{ Time: time.Now(), @@ -658,6 +672,7 @@ func streamProgress(callCtx *engine.Context, monitor Monitor) (chan<- types.Comp Usage: status.Usage, ChatResponseCached: status.Cached, }) + delete(lastSentTimeMap, status.CompletionID) } } }() diff --git a/pkg/types/tool.go b/pkg/types/tool.go index d9d59837..80000b62 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -19,6 +19,7 @@ const ( DaemonPrefix = "#!sys.daemon" OpenAPIPrefix = "#!sys.openapi" EchoPrefix = "#!sys.echo" + BreakPrefix = "#!sys.break" CommandPrefix = "#!" ) @@ -778,6 +779,10 @@ func (t Tool) IsEcho() bool { return strings.HasPrefix(t.Instructions, EchoPrefix) } +func (t Tool) IsBreak() bool { + return strings.HasPrefix(t.Instructions, BreakPrefix) +} + func (t Tool) IsHTTP() bool { return strings.HasPrefix(t.Instructions, "#!http://") || strings.HasPrefix(t.Instructions, "#!https://") From 03d32a801cab5d7708507a290256628adcd6465a Mon Sep 17 00:00:00 2001 From: Kibin Shin Date: Mon, 22 Jul 2024 14:43:55 +0900 Subject: [PATCH 2/4] Change event message format --- .gitignore | 1 + pkg/openai/client.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index dc885955..707d130f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /.env* ui/ gptscript.code-workspace +examples/ diff --git a/pkg/openai/client.go b/pkg/openai/client.go index 61a7ec77..5200ed7c 100644 --- a/pkg/openai/client.go +++ b/pkg/openai/client.go @@ -378,7 +378,7 @@ func (c *Client) Call(ctx context.Context, messageRequest types.CompletionReques id := counter.Next() status <- types.CompletionStatus{ CompletionID: id, - Request: request, + Request: messageRequest.Messages, } var cacheResponse bool From cef8bd649d8fb30fe703c25dcc1d0e61b8d3ed89 Mon Sep 17 00:00:00 2001 From: Kibin Shin Date: Wed, 5 Feb 2025 17:58:26 +0900 Subject: [PATCH 3/4] Remove break tool (#7) --- pkg/engine/control.go | 20 -------------------- pkg/engine/engine.go | 2 -- pkg/types/tool.go | 4 ---- 3 files changed, 26 deletions(-) delete mode 100644 pkg/engine/control.go diff --git a/pkg/engine/control.go b/pkg/engine/control.go deleted file mode 100644 index 7bb45c0a..00000000 --- a/pkg/engine/control.go +++ /dev/null @@ -1,20 +0,0 @@ -package engine - -import ( - "encoding/json" - "fmt" - - "github.com/gptscript-ai/gptscript/pkg/types" -) - -func (e *Engine) runBreak(tool types.Tool, input string) (cmdOut *Return, cmdErr error) { - info, err := json.Marshal(tool) - if err != nil { - return nil, err - } - var dict map[string]interface{} - json.Unmarshal(info, &dict) - dict["input"] = input - info, err = json.Marshal(dict) - return nil, fmt.Errorf("TOOL_BREAK: %s", info) -} diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 0bd861db..59766dcf 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -335,8 +335,6 @@ func (e *Engine) Start(ctx Context, input string) (ret *Return, _ error) { return e.runOpenAPI(tool, input) } else if tool.IsEcho() { return e.runEcho(tool) - } else if tool.IsBreak() { - return e.runBreak(tool, input) } s, err := e.runCommand(ctx, tool, input, ctx.ToolCategory) if err != nil { diff --git a/pkg/types/tool.go b/pkg/types/tool.go index 80000b62..b6e0b77f 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -779,10 +779,6 @@ func (t Tool) IsEcho() bool { return strings.HasPrefix(t.Instructions, EchoPrefix) } -func (t Tool) IsBreak() bool { - return strings.HasPrefix(t.Instructions, BreakPrefix) -} - func (t Tool) IsHTTP() bool { return strings.HasPrefix(t.Instructions, "#!http://") || strings.HasPrefix(t.Instructions, "#!https://") From 3c34e9ae3585b5453a6382ce9e76e2cdf3fde40a Mon Sep 17 00:00:00 2001 From: Kibin Shin Date: Wed, 5 Feb 2025 18:37:50 +0900 Subject: [PATCH 4/4] Remove automatically add credential tool for openapi tool (#8) --- pkg/loader/openapi.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pkg/loader/openapi.go b/pkg/loader/openapi.go index e62fc5ef..66adce31 100644 --- a/pkg/loader/openapi.go +++ b/pkg/loader/openapi.go @@ -298,17 +298,6 @@ func getOpenAPITools(t *openapi3.T, defaultHost, source, targetToolName string) return nil, err } - if len(infos) > 0 { - // Set up credential tools for the first set of infos. - for _, info := range infos[0] { - operationServerURL, err := url.Parse(operationServer) - if err != nil { - return nil, fmt.Errorf("failed to parse operation server URL: %w", err) - } - tool.Credentials = append(tool.Credentials, info.GetCredentialToolStrings(operationServerURL.Hostname())...) - } - } - // Register toolNames = append(toolNames, tool.Parameters.Name) tools = append(tools, tool)