-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathinngest.ts
153 lines (130 loc) · 4.75 KB
/
inngest.ts
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
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
createAgent,
createNetwork,
createTool,
defaultRoutingAgent,
} from "@inngest/agent-kit";
import { EventSchemas, Inngest, openai } from "inngest";
import { z } from "zod";
export const inngest = new Inngest({
id: "agents",
schemas: new EventSchemas().fromZod({
"agent/run": {
data: z.object({
input: z.string(),
}),
},
}),
});
export const fn = inngest.createFunction(
{ id: "agent", retries: 0 },
{ event: "agent/run" },
async ({ event }) => {
// 1. Single agent
// Run a single agent as a prompt without a network.
// await codeWritingAgent.run(event.data.input, {
// model,
// });
// A network of agents that works together.
//
// This uses the defaut agentic router to determine which agent to handle
// first. You can optionally specifiy the agent that should execute first,
// and provide your own logic for handling logic in between agent calls.
return network.run(event.data.input);
}
);
const model = openai({ model: "gpt-4" });
const systemPrompt =
"You are an expert TypeScript programmer. You can create files with idiomatic TypeScript code, with comments and associated tests.";
const codeWritingAgent = createAgent({
name: "Code writer",
// description helps LLM routers choose the right agents to run.
description: "An expert TypeScript programmer which can write and debug code",
// system defines a system prompt generated each time the agent is called by a network.
system: ({ network }) => {
if (!network?.state) {
return systemPrompt;
}
// Each time this agent runs, it may produce "file" content. Check if any
// content has already been produced in an agentic workflow.
const files = network?.state.kv.get<Record<string, string>>("files");
if (files === undefined) {
// Use the default system prompt.
return systemPrompt;
}
// There are files present in the network's state, so add them to the prompt to help
// provide previous context automatically.
let prompt = systemPrompt + "The following code already exists:";
for (const [name, contents] of Object.entries(files)) {
prompt += `<file name='${name}'>${contents}</file>`;
}
return prompt;
},
tools: [
// This tool forces the model to generate file content as structured data. Other options
// are to use XML tags in a prompt, eg:
// "Do not respond with anything else other than the following XML tags:" +
// "- If you would like to write code, add all code within the following tags (replace $filename and $contents appropriately):" +
// " <file name='$filename.ts'>$contents</file>";
createTool({
name: "create_files",
description: "Create files with the given filenames and contents",
parameters: z
.object({
files: z.array(
z
.object({
filename: z.string(),
content: z.string(),
})
.required()
),
})
.required(),
handler: (output, { network }) => {
// files is the output from the model's response in the format above.
// Here, we store OpenAI's generated files in the response.
const files =
network?.state.kv.get<Record<string, string>>("files") || {};
for (const file of output.files) {
files[file.filename] = file.content;
}
network?.state.kv.set<Record<string, string>>("files", files);
},
}),
],
});
const executingAgent = createAgent({
name: "Test execution agent",
description: "Executes written TypeScript tests",
lifecycle: {
enabled: ({ network }) => {
// Only allow executing of tests if there are files available.
return network?.state.kv.get("files") !== undefined;
},
},
system: `You are an expert TypeScript engineer that can execute commands, run tests, debug the output, and make modifications to code.
Think carefully about the request that the user is asking for. Do not respond with anything else other than the following XML tags:
- If you would like to write code, add all code within the following tags (replace $filename and $contents appropriately):
<file name="$filename.ts">
$contents
</file>
- If you would like to run commands, respond with the following tags:
<command>
$command
</command>
`,
});
const network = createNetwork({
agents: [codeWritingAgent.withModel(model), executingAgent.withModel(model)],
defaultModel: model,
maxIter: 4,
defaultRouter: ({ network }) => {
if (network.state.kv.has("files")) {
// Okay, we have some files. Did an agent run tests?
return executingAgent;
}
return defaultRoutingAgent.withModel(model);
},
});