-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
36 additions
and
194 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,54 +1,39 @@ | ||
import { Inferable } from "inferable"; | ||
import { z } from "zod"; | ||
import { execFile } from "child_process"; | ||
import { promisify } from "util"; | ||
|
||
// Some mock functions to register | ||
import * as functions from "./functions"; | ||
const execFilePromise = promisify(execFile); | ||
|
||
// Instantiate the Inferable client. | ||
const client = new Inferable({ | ||
// To get a new key, run: | ||
// npx @inferable/cli auth keys create 'My New Machine Key' --type='cluster_machine' | ||
// Get your key from https://app.inferable.ai/clusters | ||
apiSecret: process.env.INFERABLE_API_SECRET, | ||
}); | ||
|
||
// Register some demo functions | ||
client.default.register({ | ||
name: "getUrlContent", | ||
func: functions.getUrlContent, | ||
description: "Gets the content of a URL", | ||
schema: { | ||
input: z.object({ | ||
url: z.string().describe("The URL to get the content of"), | ||
}), | ||
}, | ||
}); | ||
|
||
client.default.register({ | ||
name: "generatePage", | ||
func: functions.generatePage, | ||
description: "Generates a page from markdown", | ||
schema: { | ||
input: z.object({ | ||
markdown: z.string().describe("The markdown to generate a page from"), | ||
}), | ||
name: "exec", | ||
func: async ({ command, arg }: { command: string; arg?: string }) => { | ||
const args = arg ? [arg] : []; | ||
const { stdout, stderr } = await execFilePromise(command, args); | ||
return { | ||
stdout: stdout.trim(), | ||
stderr: stderr.trim(), | ||
}; | ||
}, | ||
}); | ||
|
||
client.default.register({ | ||
name: "scoreHNPost", | ||
func: functions.scoreHNPost, | ||
description: | ||
"Calculates a score for a Hacker News post given its comment count and upvotes", | ||
description: "Executes a system command", | ||
schema: { | ||
input: z.object({ | ||
commentCount: z.number().describe("The number of comments"), | ||
upvotes: z.number().describe("The number of upvotes"), | ||
command: z | ||
.enum(["pwd", "ls", "cat", "echo"]) // This prevents arbitrary commands | ||
.describe("The command to execute"), | ||
arg: z | ||
.string() | ||
.describe("The argument to pass to the command") | ||
.optional(), | ||
}), | ||
}, | ||
}); | ||
|
||
client.default.start().then(() => { | ||
console.log("Inferable demo service started"); | ||
}); | ||
|
||
// To trigger a run: tsx -r dotenv/config src/run.ts |
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 |
---|---|---|
@@ -1,114 +1,29 @@ | ||
import { Inferable } from "inferable"; | ||
import { z } from "zod"; | ||
import { exec } from "child_process"; | ||
|
||
const client = new Inferable({ | ||
apiSecret: process.env.INFERABLE_API_SECRET, | ||
}); | ||
|
||
const postsSchema = z.object({ | ||
id: z.string().describe("The id of the post"), | ||
title: z.string().describe("The title of the post"), | ||
points: z.string().describe("The key points from the comments"), | ||
commentsUrl: z | ||
.string() | ||
.describe( | ||
"The URL of the comments. This is typically https://news.ycombinator.com/item?id=<post-id>", | ||
), | ||
const reportSchema = z.object({ | ||
name: z.string(), | ||
capabilities: z | ||
.array(z.string()) | ||
.describe("The capabilities of the program. What it can do."), | ||
}); | ||
|
||
// Trigger a Run programmatically | ||
// https://docs.inferable.ai/pages/runs | ||
|
||
const extract = async () => | ||
client | ||
.run({ | ||
initialPrompt: ` | ||
Hacker News has a homepage at https://news.ycombinator.com/ | ||
Each post has a id, title, a link, and a score, and is voted on by users. | ||
Score the top 10 posts and pick the top 3 according to the internal scoring function. | ||
`, | ||
resultSchema: z.object({ | ||
posts: postsSchema.array(), | ||
}), | ||
callSummarization: false, | ||
}) | ||
.then( | ||
(r) => | ||
r.poll() as Promise<{ | ||
result: { | ||
posts?: z.infer<typeof postsSchema>[]; | ||
}; | ||
}>, | ||
); | ||
|
||
const summarizePost = async ({ data }: { data: object }) => | ||
client | ||
.run({ | ||
initialPrompt: ` | ||
<data> | ||
${JSON.stringify(data).substring(0, 20_000)} | ||
</data> | ||
You are given a post from Hacker News, and a url for the post's comments. | ||
Summarize the comments. You should visit the comments URL to get the comments. | ||
Produce a list of the key points from the comments. | ||
`, | ||
resultSchema: z.object({ | ||
id: z.string().describe("The id of the post"), | ||
title: z.string().describe("The title of the post"), | ||
keyPoints: z | ||
.array(z.string()) | ||
.describe("The key points from the comments"), | ||
}), | ||
}) | ||
.then((r) => r.poll()); | ||
|
||
const generatePage = async ({ data }: { data: object }) => | ||
client | ||
.run({ | ||
initialPrompt: ` | ||
<data> | ||
${JSON.stringify(data)} | ||
</data> | ||
You are given a list of posts from Hacker News, and a summary of the comments for each post. | ||
Generate a web page with the following structure: | ||
- A header with the title of the page | ||
- A list of posts, with the title, a link to the post, and the key points from the comments in a ul | ||
- A footer with a link to the original Hacker News page | ||
`, | ||
resultSchema: z.object({ | ||
pagePath: z.string().describe("The path of the generated web page"), | ||
}), | ||
}) | ||
.then((r) => r.poll()); | ||
|
||
const url = process.env.INFERABLE_CLUSTER_ID | ||
? `https://app.inferable.ai/clusters/${process.env.INFERABLE_CLUSTER_ID}/runs` | ||
: "https://app.inferable.ai/clusters"; | ||
|
||
// open the page in the browser | ||
exec(`open ${url}`, (error) => { | ||
if (error) { | ||
console.error("Failed to open browser:", error); | ||
} | ||
}); | ||
|
||
extract() | ||
.then(({ result }) => { | ||
if (!result.posts) { | ||
throw new Error("No posts found"); | ||
} | ||
|
||
return Promise.all( | ||
result.posts.map((post) => summarizePost({ data: post })), | ||
); | ||
client | ||
.run({ | ||
initialPrompt: ` | ||
Iteratively inspect the files at the current directory, and produce a report. | ||
You may selectively inspect the contents of files. | ||
`.trim(), | ||
resultSchema: reportSchema, | ||
}) | ||
.then((r) => r.poll()) | ||
.then((result) => { | ||
return generatePage({ data: result }); | ||
console.log(result); | ||
}) | ||
.then((result) => { | ||
console.log("Generated page", result); | ||
.catch((error) => { | ||
console.error(error); | ||
}); |