Skip to content

Commit a53fa73

Browse files
chore: add shell
1 parent 6559344 commit a53fa73

File tree

9 files changed

+302
-0
lines changed

9 files changed

+302
-0
lines changed

Diff for: docker-shell-id/tool.gpt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Name: Docker Shell ID
2+
Description: Launches a shell using docker for the specific obot thread and returns the container ID.
3+
Params: start: Set to false to just get the ID and not start the container. (optional)
4+
5+
#!/bin/bash
6+
set -e
7+
8+
ID=$OBOT_THREAD_ID
9+
10+
if [ -z "$ID" ]; then
11+
echo "OBOT_THREAD_ID is not set"
12+
exit 1
13+
fi
14+
15+
# Find docker container from thread.obot.ai label
16+
CID=$(docker ps -qa --filter label=thread.obot.ai="$ID")
17+
18+
if [ -n "$CID" ]; then
19+
if [ "${START}" = "false" ]; then
20+
echo $CID
21+
exit 0
22+
fi
23+
docker start $CID
24+
exit 0
25+
fi
26+
27+
DATADIR=$(echo "$GPTSCRIPT_WORKSPACE_ID" | sed 's!directory://!!')
28+
if [ -d "$DATADIR" ]; then
29+
OBOT_SHELL_RUN_ARGS="${OBOT_SHELL_RUN_ARGS} -v ${DATADIR}/files:/mnt/data"
30+
fi
31+
32+
CMD="run -d"
33+
if [ "${START}" = "false" ]; then
34+
CMD=create
35+
fi
36+
37+
docker $CMD --label thread.obot.ai="$ID" --name "obot-shell-$ID" -q -it ${OBOT_SHELL_RUN_ARGS} ${OBOT_SHELL_IMAGE:-alpine}

Diff for: docker/go.mod

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module github.com/obot-platform/tools/docker
2+
3+
go 1.23.4
4+
5+
require (
6+
github.com/google/safeopen v0.0.0-20240125081138-66b54d5181c6
7+
github.com/gptscript-ai/go-gptscript v0.9.6-0.20241216211344-79a66826cf82
8+
github.com/gptscript-ai/gptscript v0.9.5
9+
)
10+
11+
require (
12+
github.com/getkin/kin-openapi v0.128.0 // indirect
13+
github.com/go-openapi/jsonpointer v0.21.0 // indirect
14+
github.com/go-openapi/swag v0.23.0 // indirect
15+
github.com/invopop/yaml v0.3.1 // indirect
16+
github.com/josharian/intern v1.0.0 // indirect
17+
github.com/mailru/easyjson v0.9.0 // indirect
18+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
19+
github.com/perimeterx/marshmallow v1.1.5 // indirect
20+
github.com/sirupsen/logrus v1.9.3 // indirect
21+
golang.org/x/sys v0.22.0 // indirect
22+
gopkg.in/yaml.v3 v3.0.1 // indirect
23+
)

Diff for: docker/go.sum

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4=
5+
github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
6+
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
7+
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
8+
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
9+
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
10+
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
11+
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
12+
github.com/google/safeopen v0.0.0-20240125081138-66b54d5181c6 h1:XBC2BmsUTvyeeahMA2wdvIaaKpYrr7za7F6lNK+0oL8=
13+
github.com/google/safeopen v0.0.0-20240125081138-66b54d5181c6/go.mod h1:D59KewtQCiD2Avi8N/v2zb/xTYaefwJl+ux2ejB58GQ=
14+
github.com/gptscript-ai/go-gptscript v0.9.6-0.20241216211344-79a66826cf82 h1:BEN268Z92gqeDc51XVvWdJWdQ47BuuWH3MUysHzilfI=
15+
github.com/gptscript-ai/go-gptscript v0.9.6-0.20241216211344-79a66826cf82/go.mod h1:/FVuLwhz+sIfsWUgUHWKi32qT0i6+IXlUlzs70KKt/Q=
16+
github.com/gptscript-ai/gptscript v0.9.5 h1:EWq+AyJ6CBdU9hS6xOnqBQGpWIy74Zx/Fd6tN0I6Bxc=
17+
github.com/gptscript-ai/gptscript v0.9.5/go.mod h1:+CC86EbcmMMBgvv5NBqHzep63SobtB5vhNOq4i6aPrA=
18+
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
19+
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
20+
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
21+
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
22+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
23+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
24+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
25+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
26+
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
27+
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
28+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
29+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
30+
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
31+
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
32+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
33+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
34+
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
35+
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
36+
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
37+
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
38+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
39+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
40+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
41+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
42+
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
43+
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
44+
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
45+
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
46+
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
47+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
48+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
49+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
50+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
51+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
52+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Diff for: docker/main.go

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"os"
8+
"os/exec"
9+
"strings"
10+
11+
"github.com/google/safeopen"
12+
"github.com/gptscript-ai/go-gptscript"
13+
"github.com/gptscript-ai/gptscript/pkg/env"
14+
)
15+
16+
var ctx = context.Background()
17+
18+
func main() {
19+
if err := mainErr(); err != nil {
20+
fmt.Println("ERROR:", err)
21+
os.Exit(1)
22+
}
23+
}
24+
25+
func writeFiles(ctx context.Context, c *gptscript.GPTScript, workspaceDir string) error {
26+
files, err := c.ListFilesInWorkspace(ctx)
27+
if err != nil {
28+
return fmt.Errorf("failed to list files in workspace: %w", err)
29+
}
30+
31+
for _, file := range files {
32+
data, err := c.ReadFileInWorkspace(ctx, file)
33+
if err != nil {
34+
return fmt.Errorf("failed to read file %q: %w", file, err)
35+
}
36+
f, err := safeopen.CreateBeneath(workspaceDir, file)
37+
if err != nil {
38+
return err
39+
}
40+
_, err = f.Write(data)
41+
if err != nil {
42+
f.Close()
43+
return fmt.Errorf("failed to write file %q: %w", file, err)
44+
}
45+
46+
if err := f.Close(); err != nil {
47+
return fmt.Errorf("failed to close file %q: %w", file, err)
48+
}
49+
}
50+
51+
f, err := safeopen.CreateBeneath(workspaceDir, ".stamp")
52+
if err != nil {
53+
return fmt.Errorf("failed to create stamp file: %w", err)
54+
}
55+
if err := f.Close(); err != nil {
56+
return fmt.Errorf("failed to close stamp file: %w", err)
57+
}
58+
return nil
59+
}
60+
61+
func getWorkspaceDir() (string, func(), error) {
62+
workspaceDir := os.Getenv("GPTSCRIPT_WORKSPACE_DIR")
63+
if workspaceDir != "" {
64+
return workspaceDir, func() {}, nil
65+
}
66+
67+
workspaceDir, err := os.MkdirTemp("", "docker-tool-workspace")
68+
if err != nil {
69+
return "", nil, fmt.Errorf("failed to create temporary workspace directory: %w", err)
70+
}
71+
return workspaceDir, func() {
72+
os.RemoveAll(workspaceDir)
73+
}, nil
74+
}
75+
76+
func mainErr() (err error) {
77+
workspaceDir, close, err := getWorkspaceDir()
78+
if err != nil {
79+
return err
80+
}
81+
defer close()
82+
83+
c, err := gptscript.NewGPTScript()
84+
if err != nil {
85+
return err
86+
}
87+
defer c.Close()
88+
89+
if err := writeFiles(ctx, c, workspaceDir); err != nil {
90+
return err
91+
}
92+
93+
var (
94+
image = gptscript.GetEnv("IMAGE", "")
95+
envs = gptscript.GetEnv("ENVS", "")
96+
)
97+
98+
if image == "" {
99+
return fmt.Errorf("missing IMAGE environment variable")
100+
}
101+
102+
args := []string{
103+
"run", "--rm",
104+
"-v", workspaceDir + ":/mnt/data",
105+
}
106+
107+
moreArgs := os.Getenv("OBOT_DOCKER_ARGS")
108+
for _, arg := range strings.Fields(moreArgs) {
109+
if arg != "" {
110+
args = append(args, arg)
111+
}
112+
}
113+
114+
for _, env := range strings.Split(envs, ",") {
115+
env = strings.TrimSpace(env)
116+
if env == "" {
117+
continue
118+
}
119+
args = append(args, "-e", env)
120+
}
121+
122+
inputString := gptscript.GetEnv("GPTSCRIPT_INPUT", "")
123+
input := map[string]any{}
124+
125+
if inputString != "" {
126+
if err := json.Unmarshal([]byte(inputString), &input); err != nil {
127+
// ignore
128+
}
129+
args = append(args, "-e", "GPTSCRIPT_INPUT="+inputString)
130+
}
131+
132+
for k, v := range input {
133+
if s, _ := v.(string); s != "" {
134+
k = strings.ToUpper(env.ToEnvLike(k))
135+
args = append(args, "-e", fmt.Sprintf("%s=%s", k, s))
136+
}
137+
}
138+
139+
args = append(args, image)
140+
141+
cmd := exec.Command("docker", args...)
142+
cmd.Stdout = os.Stdout
143+
cmd.Stderr = os.Stderr
144+
145+
return cmd.Run()
146+
}

Diff for: docker/test/Dockerfile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM cgr.dev/chainguard/wolfi-base
2+
WORKDIR /mnt/data
3+
RUN apk add -U kubectl helm jq wget curl procps openssh-client bash coreutils k3d
4+
RUN apk add -U git gh
5+
COPY --chmod=0777 <<"EOF" /run.sh
6+
#!/bin/bash
7+
set -x
8+
if [ -n "$KUBECONFIG" ]; then
9+
mkdir $HOME/.kube
10+
echo "$KUBECONFIG" | sed 's/[\n ]//g' | base64 -d > $HOME/.kube/config
11+
export KUBECONFIG=$HOME/.kube/config
12+
fi
13+
bash -c "${CMD}"
14+
EOF
15+
CMD ["/run.sh"]

Diff for: docker/tool.gpt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: Docker Container
2+
description: Runs a docker container with the specified image.
3+
Params: image: The image to run.
4+
Params: envs: Optional comma separated list of environment variables to pass to the container
5+
6+
#!${GPTSCRIPT_TOOL_DIR}/bin/gptscript-go-tool

Diff for: existing-credential/tool.gpt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name: Existing Credential
2+
description: Returns an ephemeral empty credential enabling the use of existing externally managed credentials
3+
4+
#!sys.echo
5+
{"ephemeral":true}

Diff for: index.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ tools:
5656
reference: ./tasks
5757
knowledge:
5858
reference: ./knowledge
59+
shell:
60+
reference: ./shell
5961

6062
knowledgeDataSources:
6163
notion-data-source:
@@ -84,6 +86,12 @@ system:
8486
reference: ./result-formatter
8587
obot-model-provider:
8688
reference: ./obot-model-provider
89+
existing-credential:
90+
reference: ./existing-credential
91+
docker-shell-id:
92+
reference: ./docker-shell-id
93+
docker:
94+
reference: ./docker
8795

8896
modelProviders:
8997
openai-model-provider:

Diff for: shell/tool.gpt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Name: Shell
2+
Description: Runs a shell command in a Linux console.
3+
Metadata: icon: https://cdn.jsdelivr.net/npm/@phosphor-icons/core@2/assets/duotone/terminal-window-duotone.svg
4+
Metadata: category: Capability
5+
Context: ../docker-shell-id
6+
Params: CMD: The shell command to run
7+
8+
#!/bin/bash
9+
10+
exec docker exec ${OBOT_SHELL_RUN_ARGS} ${GPTSCRIPT_CONTEXT} ${OBOT_SHELL:-/bin/sh} -c "${CMD}"

0 commit comments

Comments
 (0)