ref: 01c530c683dd814db02f49d733fbdabd7dcea5fb
dir: /oai.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <json.h>
#include <String.h>
#include "oai.h"
static void
usage(void)
{
fprint(2, "usage: %s [-dq] [-k apikey] [-m model] [-u baseurl] [-s sysprompt]\n", argv0);
exits("usage");
}
static int trusted = 0;
static int quiet = 0;
static int
allowed(OToolcall toolcall)
{
JSON *j;
char buf[3];
int n;
fprint(2, "Attempt to call command: %s\n", toolcall.name);
j = jsonparse(toolcall.arguments);
if (j) {
fprint(2, "%J\n", j);
jsonfree(j);
}
if (trusted)
return 1;
Again:
fprint(2, "Continue? (y/n) ");
n = read(0, buf, 3);
if (n < 0)
sysfatal("lost connection");
if (!n)
goto Again;
switch (buf[0]) {
case 'y':
return 1;
case 'n':
return 0;
}
goto Again;
}
static char*
abortcall(OToolcall tc)
{
return smprint("%s request aborted by user!", tc.name);
}
static char*
list_files(OToolcall tc, void*)
{
String *str;
int n, i, fd;
Dir *dirbuf;
char *s;
JSON *j, *jf;
if (!allowed(tc))
return abortcall(tc);
j = jsonparse(tc.arguments);
jf = jsonbyname(j, "folder");
s = jsonstr(jf);
if (!(s && s[0])) {
fprint(2, "list_files: invalid folder!");
jsonfree(j);
return strdup("list_files: invalid folder");
}
fd = open(s, OREAD);
if (fd < 0)
return strdup("");
jsonfree(j);
n = dirreadall(fd, &dirbuf);
close(fd);
if (n < 0)
return strdup("");
str = s_new();
for (i = 0; i < n; i++) {
str = s_append(str, dirbuf[i].name);
str = s_append(str, "\n");
}
s = strdup(s_to_c(str));
s_free(str);
return s;
}
static char* listfilesdesc = "list all files in the specified directory, similar to `ls` command. Paths are relative to the current working directory. Use `.` for the current directory.";
static char* listfilesargs = "{"
" \"type\": \"object\","
" \"properties\": {"
" \"folder\": {"
" \"type\": \"string\","
" \"description\": \"relative or absolute path to the folder.\""
" }"
" },"
" \"required\": [ \"folder\" ]"
"}";
static char*
read_file(OToolcall toolcall, void*)
{
JSON *j, *fj;
char *file;
Biobuf *io;
char *s;
if (!allowed(toolcall))
return abortcall(toolcall);
j = jsonparse(toolcall.arguments);
fj = jsonbyname(j, "file");
if (!fj) {
fprint(2, "no file in read_file request!\n");
jsonfree(j);
return strdup("bad request in read_file!\n");
}
file = jsonstr(fj);
if (!(file && file[0])) {
fprint(2, "invalid file in read_file request!\n");
jsonfree(j);
return strdup("bad request in read_file: no file!\n");
}
io = Bopen(file, OREAD);
if (!io) {
fprint(2, "open file: %r\n");
return smprint("open file in read_file: %r");
}
fprint(2, "read_file: %s\n", file);
s = Brdstr(io, 0, 0);
jsonfree(j);
Bterm(io);
return s;
}
static char *readfiledesc = "read the contents of a specified file, similar to the `cat` unix command. Especially useful on a Plan 9 system for interaction with filesystems.";
static char *readfileargs = "{"
" \"type\": \"object\","
" \"properties\": {"
" \"file\": {"
" \"type\": \"string\","
" \"description\": \"relative or absolute path to the file\""
" }"
" },"
" \"required\": [ \"file\" ]"
"}";
OTool *tools = nil;
static void
inittools(void)
{
tools = maketool(tools, Function, "list_files", listfilesdesc, listfilesargs, list_files, nil);
maketool(tools, Function, "read_file", readfiledesc, readfileargs, read_file, nil);
}
static char*
callfunc(char *s)
{
int pin[2];
Biobuf *bin;
pipe(pin);
switch (fork()) {
default:
/* parent */
break;
case 0:
/* child */
dup(pin[1], 1);
close(pin[1]);
close(pin[0]);
execl("/bin/rc", "rc", "-c", s, nil);
break;
case -1:
sysfatal("fork: %r");
}
close(pin[1]);
bin = Bfdopen(pin[0], OREAD);
s = Brdstr(bin, 0, 0);
Bterm(bin);
close(pin[0]);
wait();
return s;
}
static char*
readconsole(Biobuf *bin)
{
char *s, *result;
print(">>> ");
while (s = Brdstr(bin, '\n', 1)) {
if (!s[0]) {
free(s);
print(">>> ");
continue;
}
switch (s[0]) {
case '':
free(s);
return nil;
case '!':
result = callfunc(s+1);
free(s);
return result;
default:
result = callfunc(s);
free(s);
print("%s", result);
free(result);
print(">>> ");
}
}
return nil;
}
#define COMMONPROMPT "When writing code or text, you are serious and helpful. Your replies are NOT formatted as markdown. You DO NOT make a lot of words. Do NOT assume this is a unix or linux system. You first plan your steps before executing them. DO NOT simulate running commands. DO NOT invent files, folders or commands. Use the provided tools to proactively increase the context. Use the tools to solve the problem."
char *plan9prompt = "You are a helpful AI assistant on a Plan 9 system. Your name is Glenda. Your tone is serious. Be friendly and concise.\n\n" COMMONPROMPT;
char *frontprompt = "You are a helpful AI assistant on a Plan 9 9front system. Your name is Glenda. You are sometimes trolling. Be concise.\n\n" COMMONPROMPT;
void
main(int argc, char **argv)
{
Biobuf *bin;
char *s;
ORequest req;
OResult res;
char *sysprompt;
int bflag = 0;
char *url = nil;
char *key = nil;
req.model = nil;
if (!(access("/dist/9front", AEXIST) && access("/dist/plan9front", AEXIST))) {
/* 9front system */
sysprompt = frontprompt;
} else {
/* other plan 9 system */
sysprompt = plan9prompt;
}
ARGBEGIN{
case 'h':
usage();
case 'k':
key = EARGF(usage());
break;
case 'm':
req.model = EARGF(usage());
break;
case 'u':
url = EARGF(usage());
break;
case 's':
sysprompt = EARGF(usage());
break;
case '9':
sysprompt = plan9prompt;
break;
case 'q':
quiet++;
break;
case 'd':
oaidebug++;
break;
case 'b':
bflag++;
break;
}ARGEND;
if (bflag > 1)
trusted = 1;
if (!initoai(url, key))
usage();
bin = Bfdopen(0, OREAD);
assert(bin);
inittools();
req.prompts = nil;
req.tools = tools;
if (sysprompt)
addstrprompt(&req, "system", "%s", sysprompt);
if (!quiet) print("user: ");
while (s = Brdstr(bin, '\n', 1)) {
if (s[0] == '') {
free(s);
s = readconsole(bin);
}
if (!(s && s[0])) {
free(s);
goto Next;
}
addstrprompt(&req, "user", s);
res = makerequest(&req);
if (!res.success) {
fprint(2, "exiting!\n");
exits("fail");
}
print("%s%s%s\n\n", res.role, (quiet ? "" : ": "), res.message);
addprompt(&req, res.asprompt);
Next:
if (!quiet) print("user: ");
}
exits(nil);
}