Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic server #36

Merged
merged 8 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pretty-planes-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inngest/agent-kit": minor
---

Add basic AgentKit server to serve agents and networks as Inngest functions for easy testing
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@
"require": "./dist/index.js",
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./server": {
"require": "./dist/server.js",
"import": "./dist/server.js",
"types": "./dist/server.d.ts"
}
},
"dependencies": {
"express": "^4.21.1",
"inngest": "^3.28.0",
"inngest": "^3.29.0",
"openai-zod-to-json-schema": "^1.0.3",
"zod": "^3.23.8"
},
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 18 additions & 5 deletions src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ export const createNetwork = (opts: Network.Constructor) => new Network(opts);
* Network represents a network of agents.
*/
export class Network {
/**
* The name for the system of agents
*/
name: string;

description?: string;

/**
* agents are all publicly available agents in the netwrok
*/
Expand Down Expand Up @@ -56,12 +63,16 @@ export class Network {
protected _agents: Map<string, Agent>;

constructor({
name,
description,
agents,
defaultModel,
maxIter,
defaultState,
defaultRouter,
}: Network.Constructor) {
this.name = name;
this.description = description;
this.agents = new Map();
this._agents = new Map();
this.defaultModel = defaultModel;
Expand All @@ -82,7 +93,7 @@ export class Network {
}

async availableAgents(
networkRun: NetworkRun = new NetworkRun(this, new State()),
networkRun: NetworkRun = new NetworkRun(this, new State())
): Promise<Agent[]> {
const available: Agent[] = [];
const all = Array.from(this.agents.values());
Expand Down Expand Up @@ -169,7 +180,7 @@ export const getDefaultRoutingAgent = () => {
handler: ({ name }, { network }) => {
if (!network) {
throw new Error(
"The routing agent can only be used within a network of agents",
"The routing agent can only be used within a network of agents"
);
}

Expand All @@ -180,7 +191,7 @@ export const getDefaultRoutingAgent = () => {
const agent = network.agents.get(name);
if (agent === undefined) {
throw new Error(
`The routing agent requested an agent that doesn't exist: ${name}`,
`The routing agent requested an agent that doesn't exist: ${name}`
);
}

Expand All @@ -196,7 +207,7 @@ export const getDefaultRoutingAgent = () => {
system: async ({ network }): Promise<string> => {
if (!network) {
throw new Error(
"The routing agent can only be used within a network of agents",
"The routing agent can only be used within a network of agents"
);
}

Expand Down Expand Up @@ -234,6 +245,8 @@ Follow the set of instructions:

export namespace Network {
export type Constructor = {
name: string;
description?: string;
agents: Agent[];
defaultModel?: AiAdapter.Any;
maxIter?: number;
Expand Down Expand Up @@ -270,7 +283,7 @@ export namespace Network {
*
*/
export type FnRouter = (
args: Args,
args: Args
) => MaybePromise<RoutingAgent | Agent | Agent[] | undefined>;

export interface Args {
Expand Down
12 changes: 7 additions & 5 deletions src/networkRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export class NetworkRun extends Network {

constructor(network: Network, state: State) {
super({
name: network.name,
description: network.description,
agents: Array.from(network.agents.values()),
defaultModel: network.defaultModel,
defaultState: network.defaultState,
Expand Down Expand Up @@ -43,7 +45,7 @@ export class NetworkRun extends Network {
// off of the network.
const next = await this.getNextAgents(
input,
overrides?.router || this.defaultRouter,
overrides?.router || this.defaultRouter
);
if (!next) {
// TODO: If call count is 0, error.
Expand Down Expand Up @@ -92,7 +94,7 @@ export class NetworkRun extends Network {
// custom code.
const next = await this.getNextAgents(
input,
overrides?.router || this.defaultRouter,
overrides?.router || this.defaultRouter
);
for (const a of next || []) {
this.schedule(a.name);
Expand All @@ -104,7 +106,7 @@ export class NetworkRun extends Network {

private async getNextAgents(
input: string,
router?: Network.Router,
router?: Network.Router
): Promise<Agent[] | undefined> {
// A router may do one of two things:
//
Expand All @@ -114,7 +116,7 @@ export class NetworkRun extends Network {
// It can do this by using code, or by calling routing agents directly.
if (!router && !this.defaultModel) {
throw new Error(
"No router or model defined in network. You must pass a router or a default model to use the built-in agentic router.",
"No router or model defined in network. You must pass a router or a default model to use the built-in agentic router."
);
}
if (!router) {
Expand Down Expand Up @@ -162,7 +164,7 @@ export class NetworkRun extends Network {

private async getNextAgentsViaRoutingAgent(
routingAgent: RoutingAgent,
input: string,
input: string
): Promise<Agent[] | undefined> {
const result = await routingAgent.run(input, {
network: this,
Expand Down
69 changes: 69 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Inngest, slugify, type InngestFunction } from "inngest";
import { createServer as createInngestServer } from "inngest/node";
import { type Agent } from "./agent";
import { type Network } from "./network";

/**
* Create a server to serve Agents and Networks as Inngest functions
*
* @example
* ```ts
* import { createServer, createAgent, createNetwork } from "@inngest/agent-kit";
*
* const myAgent = createAgent(...);
* const myNetwork = createNetwork(...);
* const server = createServer({
* agents: [myAgent],
* networks: [myNetworks],
* });
* server.listen(3000)
* ```
*
* @public
*/
export const createServer = ({
appId = "agent-kit",
networks = [],
agents = [],
}: {
appId?: string;
networks?: Network[];
agents?: Agent[];
}) => {
const inngest = new Inngest({ id: appId });

const functions: { [keyof: string]: InngestFunction.Any } = {};

for (const agent of agents) {
const slug = slugify(agent.name);
const id = `agent-${slug}`;

functions[id] = inngest.createFunction(
{ id, name: agent.name },
{ event: `${appId}/${id}` },
async ({ event }) => {
// eslint-disable-next-line
return agent.run(event.data.input);
}
);
}

for (const network of networks) {
const slug = slugify(network.name);
const id = `network-${slug}`;

functions[id] = inngest.createFunction(
{ id, name: network.name },
{ event: `${appId}/${id}` },
async ({ event }) => {
// eslint-disable-next-line
return network.run(event.data.input);
}
);
}

return createInngestServer({
client: inngest,
functions: Object.values(functions),
});
};
Loading