@artinet/sdk
Version:
A TypeScript SDK for building collaborative AI agents.
96 lines (95 loc) • 3.46 kB
JavaScript
/**
* Copyright 2025 The Artinet Project
* SPDX-License-Identifier: Apache-2.0
*/
import express from "express";
import cors from "cors";
import { logger } from "../../config/index.js";
import { native } from "../adapters/a2a_request_handler.js";
import { jsonRpcHandler, UserBuilder } from "@a2a-js/sdk/server/express";
import { ensureAgent, registerAgent, } from "../params.js";
/**
* @note Best used with the `cr8` builder.
* @param {ServerParams} params - The server parameters
* @returns {ExpressAgentServer} - The express agent server
* @example
* ```typescript
* const { app, agent, start } = serve({
* agent: cr8("MyAgent")
* .text("Hello, world!")
* .agent,
* basePath: "/a2a",
* });
* ```
*/
export function serve({ app = express(), basePath = "/", agentCardPath = "/.well-known/agent-card.json", agent, corsOptions, extendedAgentCard, register = false, port, userBuilder = UserBuilder.noAuthentication, }) {
const agentInstance = ensureAgent(agent);
/**
* Now that agents are services we can wrap them in any kind of transport layer
* or in express we can use json-rpc, but we could also use websockets, etc
*/
agentInstance.getAgentCard().then((card) => {
const url = new URL(card.url);
if (!url.pathname.startsWith(basePath)) {
logger.warn(`AgentCard may be misconfigured: URL pathname ${url.pathname} does not start with base path ${basePath}, this may cause issues with the client.`);
}
});
const router = express.Router();
router.use(cors(corsOptions));
if (agentCardPath !== "/.well-known/agent-card.json") {
// todo: align with emerging multi-agent standards
router.use(`/.well-known/agent-card.json`, (_, res) => {
res.json(agentInstance.agentCard);
});
}
router.use(`${agentCardPath}`, (_, res) => {
// mount at the custom path
res.json(agentInstance.agentCard);
});
// mount at the old agent card path for backwards compatibility
router.use(`/.well-known/agent.json`, (_, res) => {
res.json(agentInstance.agentCard);
});
router.use(jsonRpcHandler({
requestHandler: native(agentInstance, undefined, extendedAgentCard),
userBuilder: userBuilder,
}));
app.use(basePath, router);
/** this is an example of using trpc as express middleware
app.use(
`${basePath}`,
trpcExpress.createExpressMiddleware({
router: agentRouter,
createContext: async (ctx: trpcExpress.CreateExpressContextOptions) => {
return {
...ctx,
service: serviceInstance,
engine: agent,
};
},
})
);
* we could also use trpc directly or any other transport layer
*/
const start = (_port) => {
try {
const listenPort = _port ?? port;
const server = app.listen(listenPort, () => {
logger.info(`Agent server started on port ${listenPort}`);
});
if (register) {
registerAgent(agentInstance.agentCard);
}
return server;
}
catch (error) {
logger.error(`Failed to start agent server`, error);
throw error;
}
};
return { app, agent: agentInstance, start };
}
/**
* @deprecated Use `cr8.serve` instead.
*/
export const createAgentServer = serve;