Readme

Allows for automatic generation of Hono API comatible with GPTs. Endpoints' inputs and outputs need to be specified via types from which the Open API spec is generated automatically and available via /gpt/schema endpoint.

Usage example:

Create valimport { GptApi } from "https://esm.town/v/xkonti/gptApiFramework"; import { z } from "npm:zod"; /** * COMMON TYPES */ const ResponseCommandSchema = z.object({ feedback: z.string().describe("Feedback regarding submitted action"), command: z.string().describe("The command for the Mediator AI to follow strictly"), data: z.string().optional().describe("Additional data related to the given command"), }).describe("Contains feedback and further instructions to follow"); export type ResponseCommand = z.infer<typeof ResponseCommandSchema>; /** * INITIALIZE API */ const api = new GptApi({ url: "https://xkonti-planoverseerai.web.val.run", title: "Overseer AI API", description: "The API for interacting with the Overseer AI", version: "1.0.0", }); /** * REQUIREMENTS GATHERING ENDPOINTS */ api.nothingToJson<ResponseCommand>({ verb: "POST", path: "/newproblem", operationId: "new-problem", desc: "Endpoint for informing Overseer AI about a new problem presented by the User", requestSchema: null, requestDesc: null, responseSchema: ResponseCommandSchema, responseDesc: "Instruction on how to proceed with the new problem", }, async (ctx) => { return { feedback: "User input downloaded. Problem analysis is required.", command: await getPrompt("analyze-problem"), data: "", }; }); export default api.serve();
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
import { EndpointDefinition, getOpenApiSpec } from "https://esm.town/v/xkonti/gptApiSchemaBuilder";
import { HttpVerb } from "https://esm.town/v/xkonti/httpUtils";
import { Hono } from "npm:hono@3";
import { z } from "npm:zod";
export interface ApiInfo {
url: string;
title: string;
description: string;
version: string;
}
export class GptApi {
app = new Hono();
info: ApiInfo;
endpoints: EndpointDefinition[] = [];
constructor(info: ApiInfo) {
this.info = info;
this.app.get("/gpt/schema", async (ctx) => {
const spec = getOpenApiSpec(
this.info.url,
this.info.title,
this.info.description,
this.info.version,
this.endpoints,
);
return ctx.text(JSON.stringify(spec, null, 2));
});
}
/**
* Register endpoint that ignores all inputs and returns a specific JSON response.
*/
nothingToJson<TResponse>(
endpointDef: EndpointDefinition,
handler: (ctx) => Promise<TResponse>,
) {
endpointDef.requestDesc = null;
endpointDef.requestSchema = null;
const handlerWrapper = async (ctx) => {
const response = await handler(ctx);
return ctx.json(response);
};
// TODO: Verify response stuff is in place
this.registerHandler(endpointDef, handlerWrapper);
}
/**
* Register endpoint that accepts a JSON DTO and returns a specific JSON response.
*/
jsonToJson<TRequest, TResponse>(
endpointDef: EndpointDefinition,
handler: (ctx, dto: TRequest) => Promise<TResponse>,
) {
// TODO: Verify request and response is in place
const handlerWrapper = async (ctx) => {
const data = await ctx.req.json() as TRequest;
// TODO: Handle invalid data format
const response = await handler(ctx, data);
return ctx.json(response);
};
this.registerHandler(endpointDef, handlerWrapper);
}
// Registers a handler for a verb + path combo.
registerHandler(
endpointDef: EndpointDefinition,
handler: (ctx) => any,
) {
this.endpoints.push(endpointDef);
const verb = endpointDef.verb;
const path = endpointDef.path;
switch (verb) {
case "GET":
this.app.get(path, handler);
break;
case "POST":
this.app.post(path, handler);
break;
case "PUT":
this.app.put(path, handler);
break;
case "DELETE":
this.app.delete(path, handler);
break;
case "PATCH":
this.app.patch(path, handler);
break;
default:
throw new Error(`HTTP verb ${verb} not supported`);
}
}
/**
* Usage: `export default gptApi.serve();`
👆 This is a val. Vals are TypeScript snippets of code, written in the browser and run on our servers. Create scheduled functions, email yourself, and persist small pieces of data — all from the browser.