diff --git a/docs/docs/03-tools/08-workspace.md b/docs/docs/03-tools/08-workspace.md new file mode 100644 index 00000000..8756cb2a --- /dev/null +++ b/docs/docs/03-tools/08-workspace.md @@ -0,0 +1,37 @@ +# Workspace + +One concept in GPTScript is the workspace directory. +This is a directory meant to be used by tools that need to interact with the local file system. +By default, the workspace directory is a one-off temporary directory. +The workspace directory can be set with the `--workspace` argument when running GPTScript, like this: + +```bash +gptscript --workspace . my-script.gpt +``` + +In the above example, the user’s current directory (denoted by `.`) will be set as the workspace. +The workspace directory is no longer temporary if it is explicitly set, and everything in it will persist after the script has finished running. +Both absolute and relative paths are supported. + +Regardless of whether it is set implicitly or explicitly, the workspace is then made available to the script execution as the `GPTSCRIPT_WORKSPACE_DIR` environment variable. + +:::info +GPTScript does not force scripts or tools to write to, read from, or otherwise use the workspace. +The tools must decide to make use of the workspace environment variable. +::: + +## The Workspace Context Tool + +To make a non-code tool that uses the LLM aware of the workspace, you can reference the workspace context tool: + +``` +Context: github.com/gptscript-ai/context/workspace +``` + +This tells the LLM (by way of a [system message](https://platform.openai.com/docs/guides/text-generation/chat-completions-api)) what the workspace directory is, +what its initial contents are, and that if it decides to create a file or directory, it should do so in the workspace directory. +This will not, however, have any impact on code-based tools (i.e. Python, Bash, or Go tools). +Such tools will have the `GPTSCRIPT_WORKSPACE_DIR` environment variable available to them, but they must be written in such a way that they make use of it. + +This context tool also automatically shares the `sys.ls`, `sys.read`, and `sys.write` tools with the tool that is using it as a context. +This is because if a tool intends to interact with the workspace, it minimally needs these tools. diff --git a/docs/docs/03-tools/09-code-tool-guidelines.md b/docs/docs/03-tools/09-code-tool-guidelines.md new file mode 100644 index 00000000..0f13ac7f --- /dev/null +++ b/docs/docs/03-tools/09-code-tool-guidelines.md @@ -0,0 +1,135 @@ +# Code Tool Guidelines + +GPTScript can handle the packaging and distribution of code-based tools via GitHub repos. +For more information on how this works, see the [authoring guide](02-authoring.md#sharing-tools). + +This guide provides guidelines for setting up GitHub repos for proper tool distribution. + +## Common Guidelines + +### `tool.gpt` or `agent.gpt` file + +Every repo should have a `tool.gpt` or `agent.gpt` file. This is the main logic of the tool. +If both files exist, GPTScript will use the `agent.gpt` file and ignore the `tool.gpt` file. +Your repo can have other `.gpt` files that are referenced by the main file, but there must be a `tool.gpt` or `agent.gpt` file present. + +Under most circumstances, this file should live in the root of the repo. +If you are using a single repo for the distribution of multiple tools (see [gptscript-ai/context](https://github.com/gptscript-ai/context) for an example), +then you can have the `tool.gpt`/`agent.gpt` file in a subdirectory, and the tool will now be able to be referenced as `github.com///`. + +### Name and Description directives + +We recommend including a `Name` and `Description` directive for your tool. +This is useful for both people and LLMs to understand what the tool will do and when to use it. + +### Parameters + +Any parameters specified in the tool will be available as environment variables in your code. +We recommend handling parameters that way, rather than using command-line arguments. + +## Python Guidelines + +### Calling Python in the tool body + +The body of the `tool.gpt`/`agent.gpt` file needs to call Python. This can be done as an inline script like this: + +``` +Name: my-python-tool + +#!python3 + +print('hello world') +``` + +An inline script like this is only recommended for simple use cases that don't need external dependencies. + +If your use case is more complex or requires external dependencies, you can reference a Python script in your repo, like this: + +``` +Name: my-python-tool + +#!/usr/bin/env python3 ${GPTSCRIPT_TOOL_DIR}/tool.py +``` + +(This example assumes that your entrypoint to your Python program is in a file called `tool.py`. You can call it what you want.) + +### `requirements.txt` file + +If your Python program needs any external dependencies, you can create a `requirements.txt` file at the same level as +your `tool.gpt`/`agent.gpt` file. GPTScript will handle downloading the dependencies before it runs the tool. + +The file structure should look something like this: + +``` +. +├── requirements.txt +├── tool.py +└── tool.gpt +``` + +## JavaScript (Node.js) Guidelines + +### Calling Node.js in the tool body + +The body of the `tool.gpt`/`agent.gpt` file needs to call Node. This can be done as an inline script like this: + +``` +Name: my-node-tool + +#!node + +console.log('hello world') +``` + +An inline script like this is only recommended for simple use cases that don't need external dependencies. + +If your use case is more complex or requires external dependencies, you can reference a Node script in your repo, like this: + +``` +Name: my-node-tool + +#!/usr/bin/env node ${GPTSCRIPT_TOOL_DIR}/tool.js +``` + +(This example assumes that your entrypoint to your Node program is in a file called `tool.js`. You can call it what you want.) + +### `package.json` file + +If your Node program needs any external dependencies, you can create a `package.json` file at the same level as +your `tool.gpt`/`agent.gpt` file. GPTScript will handle downloading the dependencies before it runs the tool. + +The file structure should look something like this: + +``` +. +├── package.json +├── tool.js +└── tool.gpt +``` + +## Go Guidelines + +GPTScript does not support inline code for Go, so you must call to an external program from the tool body like this: + +``` +Name: my-go-tool + +#!${GPTSCRIPT_TOOL_DIR}/bin/gptscript-go-tool +``` + +:::important +Unlike the Python and Node cases above where you can name the file anything you want, Go tools must be `#!${GPTSCRIPT_TOOL_DIR}/bin/gptscript-go-tool`. +::: + +GPTScript will build the Go program located at `./main.go` to a file called `./bin/gptscript-go-tool` before running the tool. +All of your dependencies need to be properly specified in a `go.mod` file. + +The file structure should look something like this: + +``` +. +├── go.mod +├── go.sum +├── main.go +└── tool.gpt +``` diff --git a/docs/docs/03-tools/10-daemon.md b/docs/docs/03-tools/10-daemon.md new file mode 100644 index 00000000..128c161a --- /dev/null +++ b/docs/docs/03-tools/10-daemon.md @@ -0,0 +1,108 @@ +# Daemon Tools (Advanced) + +One advanced use case that GPTScript supports is daemon tools. +A daemon tool is a tool that starts a long-running HTTP server in the background, that will continue running until GPTScript is done executing. +Other tools can easily send HTTP POST requests to the daemon tool. + +## Example + +Here is an example of a daemon tool with a simple echo server written in an inline Node.js script: + +``` +Tools: my-daemon +Param: first: the first parameter +Param: second: the second parameter + +#!http://my-daemon.daemon.gptscript.local/myPath + +--- +Name: my-daemon + +#!sys.daemon node + +const http = require('http'); + +const server = http.createServer((req, res) => { + if (req.method === 'GET' || req.method === 'POST') { + // Extract the path from the request URL + const path = req.url; + + let body = ''; + + req.on('data', chunk => { + body += chunk.toString(); + }) + + // Respond with the path and body + req.on('end', () => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write(`Body: ${body}\n`); + res.end(`Path: ${path}`); + }) + } else { + res.writeHead(405, { 'Content-Type': 'text/plain' }); + res.end('Method Not Allowed'); + } +}); + +const PORT = process.env.PORT || 3000; +server.listen(PORT, () => { + console.log(`Server is listening on port ${PORT}`); +}); +``` + +Let's talk about the daemon tool, called `my-daemon`, first. + +### The Daemon Tool + +The body of this tool begins with `#!sys.daemon`. This tells GPTScript to take the rest of the body as a command to be +run in the background that will listen for HTTP requests. GPTScript will run this command (in this case, a Node script). +GPTScript will assign a port number for the server and set the `PORT` environment variable to that number, so the +server needs to check that variable and listen on the proper port. + +After GPTScript runs the daemon, it will send it an HTTP GET request to make sure that it is running properly. +The daemon needs to respond with a 200 OK to this request. +By default, the request goes to `/`, but this can be configured with the following syntax: + +``` +#!sys.daemon (path=/api/ready) node + +// (node script here) +``` + +### The Entrypoint Tool + +The entrypoint tool at the top of this script sends an HTTP request to the daemon tool. +There are a few important things to note here: + +- The `Tools: my-daemon` directive is needed to show that this tool requires the `my-daemon` tool to already be running. + - When the entrypoint tool runs, GPTScript will check if `my-daemon` is already running. If it is not, GPTScript will start it. +- The `#!http://my-daemon.daemon.gptscript.local/myPath` in the body tells GPTScript to send an HTTP request to the daemon tool. + - The request will be a POST request, with the body of the request being a JSON string of the parameters passed to the entrypoint tool. + - For example, if the script is run like `gptscript script.gpt '{"first":"hello","second":"world"}'`, then the body of the request will be `{"first":"hello","second":"world"}`. + - The path of the request will be `/myPath`. + - The hostname is `my-daemon.daemon.gptscript.local`. When sending a request to a daemon tool, the hostname must always start with the daemon tool's name, followed by `.daemon.gptscript.local`. + - GPTScript recognizes this hostname and determines the correct port number to send the request to, on localhost. + +### Running the Example + +Now let's try running it: + +```bash +gptscript script.gpt '{"first":"hello","second":"world"}' +``` + +``` +OUTPUT: + +Body: {"first":"hello","second":"world"} +Path: /myPath +``` + +This is exactly what we expected. This is a silly, small example just to demonstrate how this feature works. +A real-world situation would involve several different tools sending different HTTP requests to the daemon tool, +likely with an LLM determining when to call which tool. + +## Real-World Example + +To see a real-world example of a daemon tool, check out the [GPTScript Browser tool](https://github.com/gptscript-ai/browser). diff --git a/docs/docs/09-faqs.md b/docs/docs/09-faqs.md index e8e15cb5..20196011 100644 --- a/docs/docs/09-faqs.md +++ b/docs/docs/09-faqs.md @@ -54,26 +54,7 @@ By default, this directory is a one-off temp directory, but you can override thi gptscript --workspace . my-script.gpt ``` -In the above example, the user's current directory (denoted by `.`) will be set as the workspace. Both absolute and relative paths are supported. - -Regardless of whether it is set implicitly or explicitly, the workspace is then made available to the script execution as the `GPTSCRIPT_WORKSPACE_DIR` environment variable. - -:::info -GPTScript does not force scripts or tools to write to, read from, or otherwise use the workspace. The tools must decide to make use of the workspace environment variable. -::: - -To make prompt-based tools workspace aware, you can reference our workspace context tool, like so: - -``` -Context: github.com/gptscript-ai/context/workspace -``` - -This tells the LLM (by way of a [system message](https://platform.openai.com/docs/guides/text-generation/chat-completions-api)) what the workspace directory is, what its initial contents are, and that if it decides to create a file or directory, it should do so in the workspace directory. -This will not, however, have any impact on code-based tools (ie python, bash, or go tools). -Such tools will have the `GPTSCRIPT_WORKSPACE_DIR` environment variable available to them, but they must be written in such a way that they make use of it. - -This context also automatically shares the `sys.ls`, `sys.read`, and `sys.write` tools with the tool that is using it as a context. -This is because if a tool intends to interact with the workspace, it minimally needs these tools. +For more info, see the [Workspace](03-tools/08-workspace.md) page. ### I'm hitting GitHub's rate limit for unauthenticated requests when using GPTScript. @@ -85,3 +66,17 @@ If you're already authenticated with the `gh` CLI, you can use its token by runn ```bash export GITHUB_AUTH_TOKEN="$(gh auth token)" ``` + +### Can I save my chat and resume it later? + +Yes! When you run GPTScript, be sure to specify the `--save-chat-state-file` argument like this: + +```bash +gptscript --save-chat-state-file chat-state.json my-script.gpt +``` + +Then, when you want to resume your chat, you can use the `--chat-state` argument to specify the file you saved: + +```bash +gptscript --chat-state chat-state.json my-script.gpt +```