Skip to content

Commit

Permalink
Add basic server (#36)
Browse files Browse the repository at this point in the history
* Add basic server

* Add changeset

* Move `createServer()` to a separate `@inngest/agent-kit/server` export

* Add `name` as required to `Network`

* Add `description` to `Network`

* Simplify `createServer()` if `Network#name` is present

Also use `slugify` from `inngest`

* Fix build error; provide all `Network` opts

---------

Co-authored-by: Jack Williams <[email protected]>
  • Loading branch information
djfarrelly and jpwilliams authored Jan 9, 2025
1 parent d4a0d26 commit c8343c0
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 16 deletions.
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),
});
};

0 comments on commit c8343c0

Please sign in to comment.