aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 435e0057a642851c62adc02242d12c91e793975f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# LLM Functions

This project allows you to enhance large language models (LLMs) with custom functions written in bash/js/python. Imagine your LLM being able to execute system commands, access web APIs, or perform other complex tasks – all triggered by simple, natural language prompts.

## Prerequisites

Make sure you have the following tools installed:

- [argc](https://github.com/sigoden/argc): A bash command-line framewrok and command runner
- [jq](https://github.com/jqlang/jq): A JSON processor

## Getting Started with AIChat

**1. Clone the repository:**

```sh
git clone https://github.com/sigoden/llm-functions
```

**2. Build function declarations file and bin dir:**

First, create a `./functions.txt` file with each function name on a new line.

Then, run `argc build` to build function declarations file `./functions.json` and bin dir `./bin/`.

**3. Configure your AIChat:**

Symlink this repo directory to aichat **functions_dir**:

```sh
ln -s "$(pwd)" "$(aichat --info | grep functions_dir | awk '{print $2}')"
# OR
argc install
```

Don't forget to add the following config to your AIChat `config.yaml` file:

```yaml
function_calling: true
```

AIChat will automatically load `functions.json` and execute functions located in the `./bin` directory based on your prompts.

**4. Start using your functions:**

Now you can interact with your LLM using natural language prompts that trigger your defined functions.

![function-showcase](https://github.com/sigoden/llm-functions/assets/4012553/391867dd-577c-4aaa-9ff2-c9e67fb0f3a3)


## Function Types

### Retrieve Type

The function returns JSON data to LLM for further processing.

AIChat does not ask permission to run the function or print the output.

![retrieve-type-showcase](https://github.com/sigoden/llm-functions/assets/4012553/7e628834-9863-444a-bad8-7b51bfb18dff)

### Execute Type

The function does not have to return JSON data.

The function can perform dangerous tasks like creating/deleting files, changing network adapter, and setting a scheduled task...

AIChat will ask permission before running the function.

![execute-type-showcase](https://github.com/sigoden/llm-functions/assets/4012553/1dbc345f-daf9-4d65-a49f-3df8c7df1727)

**AIChat categorizes functions starting with `may_` as `execute type` and all others as `retrieve type`.**

## Writing Your Own Functions

The project supports write functions in bash/js/python.

### Bash

Create a new bashscript in the [./tools/](./tools/) directory (.e.g. `may_execute_command.sh`).

```sh
#!/usr/bin/env bash
set -e

# @describe Runs a shell command.
# @option --command! The command to execute.

main() {
    eval "$argc_command"
}

eval "$(argc --argc-eval "$0" "$@")"
```

`llm-functions` will automatic generate function declaration.json from [comment tags](https://github.com/sigoden/argc?tab=readme-ov-file#comment-tags).

The relationship between comment tags and parameters in function declarations is as follows:

```sh
# @flag --boolean                   Parameter `{"type": "boolean"}`
# @option --string                  Parameter `{"type": "string"}`
# @option --string-enum[foo|bar]    Parameter `{"type": "string", "enum": ["foo", "bar"]}`
# @option --integer <INT>           Parameter `{"type": "integer"}`
# @option --number <NUM>            Parameter `{"type": "number"}`
# @option --array* <VALUE>          Parameter `{"type": "array", "items": {"type":"string"}}`
# @option --scalar-required!        Use `!` to mark a scalar parameter as required.
# @option --array-required+         Use `+` to mark a array parameter as required
```

### Javascript

Create a new javascript in the [./tools/](./tools/) directory (.e.g. `may_execute_js_code.js`).

```js
exports.declarate = function declarate() {
  return {
    "name": "may_execute_js_code",
    "description": "Runs the javascript code in node.js.",
    "parameters": {
      "type": "object",
      "properties": {
        "code": {
          "type": "string",
          "description": "Javascript code to execute, such as `console.log(\"hello world\")`"
        }
      },
      "required": [
        "code"
      ]
    }
  }
}

exports.execute = function execute(data) {
  eval(data.code)
}

```

### Python

Create a new python script in the [./tools/](./tools/) directory (e.g., `may_execute_py_code.py`).

```py
def declarate():
  return {
    "name": "may_execute_py_code",
    "description": "Runs the python code.",
    "parameters": {
      "type": "object",
      "properties": {
        "code": {
          "type": "string",
          "description": "python code to execute, such as `print(\"hello world\")`"
        }
      },
      "required": [
        "code"
      ]
    }
  }


def execute(data):
  exec(data["code"])
```

## License

The project is under the MIT License, Refer to the [LICENSE](https://github.com/sigoden/llm-functions/blob/main/LICENSE) file for detailed information.