Skip to content

Commit

Permalink
docs: document more features (#694)
Browse files Browse the repository at this point in the history
Signed-off-by: Grant Linville <[email protected]>
Co-authored-by: Donnie Adams <[email protected]>
  • Loading branch information
g-linville and thedadams authored Aug 3, 2024
1 parent d6f6096 commit 7b53087
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 20 deletions.
37 changes: 37 additions & 0 deletions docs/docs/03-tools/08-workspace.md
Original file line number Diff line number Diff line change
@@ -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.
135 changes: 135 additions & 0 deletions docs/docs/03-tools/09-code-tool-guidelines.md
Original file line number Diff line number Diff line change
@@ -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/<user>/<repo>/<subdirectory>`.

### 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
```
108 changes: 108 additions & 0 deletions docs/docs/03-tools/10-daemon.md
Original file line number Diff line number Diff line change
@@ -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).
35 changes: 15 additions & 20 deletions docs/docs/09-faqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
```

0 comments on commit 7b53087

Please sign in to comment.