@gram-ai/create-function 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +42 -8
- package/dist/main.js.map +1 -1
- package/gram-template-gram/NEXT_STEPS.txt +14 -0
- package/gram-template-gram/README.md +58 -0
- package/gram-template-gram/package.json +5 -2
- package/gram-template-gram/src/server.ts +44 -0
- package/package.json +2 -2
- package/src/main.ts +46 -13
package/dist/main.js
CHANGED
|
@@ -9,6 +9,25 @@ import pkg from "../package.json" with { type: "json" };
|
|
|
9
9
|
import { confirmOrClack, selectOrClack, textOrClack, yn, } from "./prompts/helpers.js";
|
|
10
10
|
const packageNameRE = /^(@?[a-z0-9-_]+\/)?[a-z0-9-_]+$/;
|
|
11
11
|
const knownPackageManagers = new Set(["npm", "yarn", "pnpm", "bun", "deno"]);
|
|
12
|
+
function printUsage(packageManager) {
|
|
13
|
+
console.log(`
|
|
14
|
+
Usage:
|
|
15
|
+
${packageManager} create @gram-ai/function [options]
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--template <name> Template to use (gram, mcp)
|
|
19
|
+
--name <name> Project name
|
|
20
|
+
--dir <path> Directory to create project in
|
|
21
|
+
--git <yes|no> Initialize git repository
|
|
22
|
+
--install <yes|no> Install dependencies
|
|
23
|
+
-y, --yes Skip all prompts and use defaults
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
${packageManager} create @gram-ai/function
|
|
27
|
+
${packageManager} create @gram-ai/function --template mcp --name ecommerce
|
|
28
|
+
${packageManager} create @gram-ai/function --yes --template gram
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
12
31
|
async function init(argv) {
|
|
13
32
|
let packageManager = "npm";
|
|
14
33
|
let detectedPM = process.env["npm_config_user_agent"]?.split("/")[0] || "";
|
|
@@ -16,10 +35,14 @@ async function init(argv) {
|
|
|
16
35
|
packageManager = detectedPM;
|
|
17
36
|
}
|
|
18
37
|
const args = parse(argv, {
|
|
19
|
-
alias: { y: "yes" },
|
|
38
|
+
alias: { y: "yes", h: "help" },
|
|
20
39
|
string: ["template", "name", "dir", "git", "install"],
|
|
21
|
-
boolean: ["yes"],
|
|
40
|
+
boolean: ["yes", "help"],
|
|
22
41
|
});
|
|
42
|
+
if (args.help) {
|
|
43
|
+
printUsage(packageManager);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
23
46
|
const template = await selectOrClack({
|
|
24
47
|
message: "Pick a framework",
|
|
25
48
|
options: [
|
|
@@ -98,14 +121,19 @@ async function init(argv) {
|
|
|
98
121
|
const tlog = taskLog({
|
|
99
122
|
title: "Setting up project",
|
|
100
123
|
});
|
|
124
|
+
const isLocalDev = yn(process.env["GRAM_DEV"]);
|
|
101
125
|
tlog.message("Scaffolding");
|
|
102
126
|
const dirname = import.meta.dirname;
|
|
103
127
|
const templateDir = resolve(join(dirname, "..", `gram-template-${template}`));
|
|
104
128
|
await fs.cp(templateDir, dir, {
|
|
105
129
|
recursive: true,
|
|
106
|
-
filter: (src) =>
|
|
107
|
-
|
|
108
|
-
|
|
130
|
+
filter: (src) => {
|
|
131
|
+
let banned = src.includes(".git") || src.includes("NEXT_STEPS.txt");
|
|
132
|
+
if (isLocalDev) {
|
|
133
|
+
banned ||= src.includes("node_modules") || src.includes("dist");
|
|
134
|
+
}
|
|
135
|
+
return !banned;
|
|
136
|
+
},
|
|
109
137
|
});
|
|
110
138
|
let gramFuncsVersion = pkg.devDependencies["@gram-ai/functions"];
|
|
111
139
|
if (gramFuncsVersion == null || gramFuncsVersion.startsWith("workspace:")) {
|
|
@@ -113,8 +141,7 @@ async function init(argv) {
|
|
|
113
141
|
// lockstep so we can just use the matching version.
|
|
114
142
|
gramFuncsVersion = `^${pkg.version}`;
|
|
115
143
|
}
|
|
116
|
-
if (
|
|
117
|
-
existsSync(resolve(dirname, "..", "..", "functions"))) {
|
|
144
|
+
if (isLocalDev && existsSync(resolve(dirname, "..", "..", "functions"))) {
|
|
118
145
|
// For local development, use the local version of `@gram-ai/functions`
|
|
119
146
|
// if it exists.
|
|
120
147
|
const localPkgPath = resolve(dirname, "..", "..", "functions");
|
|
@@ -144,7 +171,14 @@ async function init(argv) {
|
|
|
144
171
|
tlog.message(`Installing dependencies with ${packageManager}`);
|
|
145
172
|
await $ `cd ${dir} && ${packageManager} install`;
|
|
146
173
|
}
|
|
147
|
-
|
|
174
|
+
let successMessage = `All done! Run \`cd ${dir} && ${packageManager} run build\` to build your first Gram Function.`;
|
|
175
|
+
successMessage = await fs
|
|
176
|
+
.readFile(join(templateDir, "NEXT_STEPS.txt"), "utf-8")
|
|
177
|
+
.catch(() => successMessage);
|
|
178
|
+
successMessage = successMessage
|
|
179
|
+
.replaceAll("$PACKAGE_MANAGER", packageManager)
|
|
180
|
+
.replaceAll("$DIR", dir);
|
|
181
|
+
tlog.success(successMessage);
|
|
148
182
|
}
|
|
149
183
|
try {
|
|
150
184
|
await init(process.argv);
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAExD,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,EAAE,GACH,MAAM,sBAAsB,CAAC;AAE9B,MAAM,aAAa,GAAG,iCAAiC,CAAC;AAExD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7E,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3E,IAAI,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,cAAc,GAAG,UAAU,CAAC;IAC9B,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
All done! Jump in with `cd $DIR`.
|
|
2
|
+
|
|
3
|
+
Some next steps:
|
|
4
|
+
|
|
5
|
+
- Build your function with `$PACKAGE_MANAGER run build` and deploy it with the Gram CLI: https://www.speakeasy.com/docs/gram/command-line/installation.
|
|
6
|
+
|
|
7
|
+
- Run the provided Hono server to simulate tool calls over HTTP with `$PACKAGE_MANAGER run dev` and:
|
|
8
|
+
|
|
9
|
+
curl \
|
|
10
|
+
--data '{"name": "greet", "input": {"name": "Friend"}}' \
|
|
11
|
+
-H "Content-Type: application/json" \
|
|
12
|
+
http://localhost:3000/tool-call
|
|
13
|
+
|
|
14
|
+
Have fun 🚀
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Hello from Gram Functions!
|
|
2
|
+
|
|
3
|
+
This project builds and deploys [Gram Functions](https://getgram.ai) using a
|
|
4
|
+
tiny TypeScript framework that looks like this:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { Gram } from "@gram-ai/functions";
|
|
8
|
+
import * as z from "zod/mini";
|
|
9
|
+
|
|
10
|
+
const gram = new Gram().tool({
|
|
11
|
+
name: "greet",
|
|
12
|
+
description: "Greet someone special",
|
|
13
|
+
inputSchema: { name: z.string() },
|
|
14
|
+
async execute(ctx, input) {
|
|
15
|
+
return ctx.json({ message: `Hello, ${input.name}!` });
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default gram;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Gram Functions are tools for LLMs and MCP servers that can do arbitrary tasks
|
|
23
|
+
such as fetching data from APIs, performing calculations, or interacting with
|
|
24
|
+
hosted databases.
|
|
25
|
+
|
|
26
|
+
## Getting Started
|
|
27
|
+
|
|
28
|
+
To get started, install dependencies and run the development server:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To build a zip file that can be deployed to Gram, run:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If you want to poke at the tools you've built during local development, you can
|
|
41
|
+
start a Hono server with:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm dev
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Now you can simulate tool calls with:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl \
|
|
51
|
+
--data '{"name": "greet", "input": {"name": "Georges"}}' \
|
|
52
|
+
-H "Content-Type: application/json" \
|
|
53
|
+
http://localhost:3000/tool-call
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## What next?
|
|
57
|
+
|
|
58
|
+
To learn more about using the framework, check out [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"node": ">=22.18.0"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
+
"dev": "node ./src/server.ts",
|
|
22
23
|
"lint": "tsc --noEmit",
|
|
23
24
|
"build": "node ./src/build.ts",
|
|
24
25
|
"prebuild": "tsc -p tsconfig.json",
|
|
@@ -29,7 +30,9 @@
|
|
|
29
30
|
"zod": "^4"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
|
-
"
|
|
33
|
-
"@types/node": "22.x"
|
|
33
|
+
"@hono/node-server": "^1.19.5",
|
|
34
|
+
"@types/node": "22.x",
|
|
35
|
+
"hono": "^4",
|
|
36
|
+
"typescript": "^5"
|
|
34
37
|
}
|
|
35
38
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import gram from "./functions.ts";
|
|
4
|
+
|
|
5
|
+
const app = new Hono();
|
|
6
|
+
|
|
7
|
+
app.post("/tool-call", async (c) => {
|
|
8
|
+
const req = await c.req.json();
|
|
9
|
+
return await gram.handleToolCall(req, {
|
|
10
|
+
signal: AbortSignal.timeout(1 * 60 * 1000),
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
app.get("/manifest", async () => {
|
|
15
|
+
const manifest = gram.manifest();
|
|
16
|
+
return new Response(JSON.stringify(manifest, null, 2), {
|
|
17
|
+
headers: { "Content-Type": "application/json" },
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export function startServer(port: number = 3000) {
|
|
22
|
+
const server = serve({ fetch: app.fetch, port }, (info) => {
|
|
23
|
+
console.log(`Listening on http://localhost:${info.port}`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const onClose = () => {
|
|
27
|
+
console.log("Shutting down server...");
|
|
28
|
+
server.close((err) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
console.error(err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
process.exit(0);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
process.on("SIGINT", onClose);
|
|
37
|
+
process.on("SIGTERM", onClose);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (import.meta.main) {
|
|
41
|
+
startServer();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default app;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gram-ai/create-function",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "Build AI tools and deploy them to getgram.ai",
|
|
6
6
|
"keywords": [],
|
|
7
7
|
"homepage": "https://github.com/speakeasy-api/gram",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"prettier": "^3.6.2",
|
|
39
39
|
"typescript": "5.9.2",
|
|
40
40
|
"zod": "^3.25.76",
|
|
41
|
-
"@gram-ai/functions": "^0.
|
|
41
|
+
"@gram-ai/functions": "^0.2.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc --noEmit false"
|
package/src/main.ts
CHANGED
|
@@ -18,6 +18,26 @@ const packageNameRE = /^(@?[a-z0-9-_]+\/)?[a-z0-9-_]+$/;
|
|
|
18
18
|
|
|
19
19
|
const knownPackageManagers = new Set(["npm", "yarn", "pnpm", "bun", "deno"]);
|
|
20
20
|
|
|
21
|
+
function printUsage(packageManager: string): void {
|
|
22
|
+
console.log(`
|
|
23
|
+
Usage:
|
|
24
|
+
${packageManager} create @gram-ai/function [options]
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--template <name> Template to use (gram, mcp)
|
|
28
|
+
--name <name> Project name
|
|
29
|
+
--dir <path> Directory to create project in
|
|
30
|
+
--git <yes|no> Initialize git repository
|
|
31
|
+
--install <yes|no> Install dependencies
|
|
32
|
+
-y, --yes Skip all prompts and use defaults
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
${packageManager} create @gram-ai/function
|
|
36
|
+
${packageManager} create @gram-ai/function --template mcp --name ecommerce
|
|
37
|
+
${packageManager} create @gram-ai/function --yes --template gram
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
async function init(argv: string[]): Promise<void> {
|
|
22
42
|
let packageManager = "npm";
|
|
23
43
|
let detectedPM = process.env["npm_config_user_agent"]?.split("/")[0] || "";
|
|
@@ -26,11 +46,16 @@ async function init(argv: string[]): Promise<void> {
|
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
const args = parse(argv, {
|
|
29
|
-
alias: { y: "yes" },
|
|
49
|
+
alias: { y: "yes", h: "help" },
|
|
30
50
|
string: ["template", "name", "dir", "git", "install"],
|
|
31
|
-
boolean: ["yes"],
|
|
51
|
+
boolean: ["yes", "help"],
|
|
32
52
|
});
|
|
33
53
|
|
|
54
|
+
if (args.help) {
|
|
55
|
+
printUsage(packageManager);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
34
59
|
const template = await selectOrClack<string>({
|
|
35
60
|
message: "Pick a framework",
|
|
36
61
|
options: [
|
|
@@ -117,15 +142,20 @@ async function init(argv: string[]): Promise<void> {
|
|
|
117
142
|
title: "Setting up project",
|
|
118
143
|
});
|
|
119
144
|
|
|
145
|
+
const isLocalDev = yn(process.env["GRAM_DEV"]);
|
|
146
|
+
|
|
120
147
|
tlog.message("Scaffolding");
|
|
121
148
|
const dirname = import.meta.dirname;
|
|
122
149
|
const templateDir = resolve(join(dirname, "..", `gram-template-${template}`));
|
|
123
150
|
await fs.cp(templateDir, dir, {
|
|
124
151
|
recursive: true,
|
|
125
|
-
filter: (src) =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
152
|
+
filter: (src) => {
|
|
153
|
+
let banned = src.includes(".git") || src.includes("NEXT_STEPS.txt");
|
|
154
|
+
if (isLocalDev) {
|
|
155
|
+
banned ||= src.includes("node_modules") || src.includes("dist");
|
|
156
|
+
}
|
|
157
|
+
return !banned;
|
|
158
|
+
},
|
|
129
159
|
});
|
|
130
160
|
|
|
131
161
|
let gramFuncsVersion = pkg.devDependencies["@gram-ai/functions"];
|
|
@@ -134,10 +164,7 @@ async function init(argv: string[]): Promise<void> {
|
|
|
134
164
|
// lockstep so we can just use the matching version.
|
|
135
165
|
gramFuncsVersion = `^${pkg.version}`;
|
|
136
166
|
}
|
|
137
|
-
if (
|
|
138
|
-
yn(process.env["GRAM_DEV"]) &&
|
|
139
|
-
existsSync(resolve(dirname, "..", "..", "functions"))
|
|
140
|
-
) {
|
|
167
|
+
if (isLocalDev && existsSync(resolve(dirname, "..", "..", "functions"))) {
|
|
141
168
|
// For local development, use the local version of `@gram-ai/functions`
|
|
142
169
|
// if it exists.
|
|
143
170
|
const localPkgPath = resolve(dirname, "..", "..", "functions");
|
|
@@ -176,9 +203,15 @@ async function init(argv: string[]): Promise<void> {
|
|
|
176
203
|
await $`cd ${dir} && ${packageManager} install`;
|
|
177
204
|
}
|
|
178
205
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
206
|
+
let successMessage = `All done! Run \`cd ${dir} && ${packageManager} run build\` to build your first Gram Function.`;
|
|
207
|
+
successMessage = await fs
|
|
208
|
+
.readFile(join(templateDir, "NEXT_STEPS.txt"), "utf-8")
|
|
209
|
+
.catch(() => successMessage);
|
|
210
|
+
successMessage = successMessage
|
|
211
|
+
.replaceAll("$PACKAGE_MANAGER", packageManager)
|
|
212
|
+
.replaceAll("$DIR", dir);
|
|
213
|
+
|
|
214
|
+
tlog.success(successMessage);
|
|
182
215
|
}
|
|
183
216
|
|
|
184
217
|
try {
|