-
Notifications
You must be signed in to change notification settings - Fork 282
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Grant Linville <[email protected]> Co-authored-by: Donnie Adams <[email protected]>
- Loading branch information
1 parent
d6f6096
commit 7b53087
Showing
4 changed files
with
295 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters