A microservice plugin template for the Open Agent Kit (OAK) ecosystem. This plugin communicates with the OAK core system and provides a foundation for building custom tools and interfaces.
This plugin is built using React Router v7 and serves as a federated microservice that integrates with the OAK core. It exposes both API endpoints and federated UI components that can be consumed by the main OAK application.
app/
├── routes/ # API endpoints and route handlers
│ ├── admin/ # Admin interface routes
│ ├── user/ # User interface routes
│ ├── knowledge/ # Knowledge provider routes (optional)
│ ├── tools.ts # Tool execution endpoint (required)
│ └── meta.ts # Plugin metadata endpoint (required)
├── components/
│ ├── tools/ # Federated tool components
│ └── ui/ # Reusable UI components
├── tools.definition.ts # Tool definitions and schemas
├── context.ts # Bridge context for OAK integration
└── bridgeMiddleware.ts # Middleware for OAK communication
These routes are mandatory for OAK integration:
Returns the list of available tools defined in this plugin.
- Handler:
app/routes/tools.ts - Response: Tool definitions with schemas and metadata
Executes a specific tool with provided parameters.
- Handler:
app/routes/tools.ts - Body: Tool execution request with identifier and parameters
Returns plugin metadata and information.
- Handler:
app/routes/meta.ts - Response: Plugin name, version, description, author, website
Main user interface for the plugin.
- Handler:
app/routes/user/index.tsx - Purpose: Primary user interaction interface
Administrative interface for plugin configuration.
- Handler:
app/routes/admin/index.tsx - Purpose: Plugin administration and settings
If your plugin provides knowledge/document capabilities:
Lists available documents for an agent.
- Handler:
app/routes/knowledge/listDocuments.ts - Response: Array of document metadata
Retrieves a specific document by ID.
- Handler:
app/routes/knowledge/getDocument.ts - Response: Document content and metadata
Edit app/tools.definition.ts to register new tools:
import { Tools } from "@open-agent-kit/bridge";
import z from "zod";
const toolDefinition = new Tools();
// Define parameter schema
const myToolSchema = z.object({
input: z.string(),
options: z
.object({
setting1: z.boolean().optional(),
setting2: z.number().optional(),
})
.optional(),
});
// Register the tool
toolDefinition.registerTool({
identifier: "myTool",
name: "My Custom Tool",
description: "Description of what this tool does",
params: myToolSchema,
federatedToolComponentName: "./myToolComponent", // Optional UI component
execute: async (params) => {
// Tool implementation
return { result: "Tool output" };
},
});
export default toolDefinition;If your tool needs a custom UI, create a federated component in app/components/tools/:
// app/components/tools/myToolComponent.tsx
import type { MyToolParams, MyToolResult } from "~/tools.definition";
const MyToolComponent = ({
input,
output,
}: {
input: MyToolParams;
output?: MyToolResult;
}) => {
return (
<div>
<div>Input: {JSON.stringify(input)}</div>
<div>Output: {output ? JSON.stringify(output) : "Processing..."}</div>
</div>
);
};
export default MyToolComponent;Add your component to the federation configuration in vite.federated.ts:
// vite.federated.ts
export default defineConfig({
plugins: [
federation({
filename: "remoteEntry.js",
name: "remoteOAKPlugin",
exposes: {
"./translatorTool": "./app/components/tools/translatorTool.tsx",
"./myToolComponent": "./app/components/tools/myToolComponent.tsx", // Add your component
},
shared: ["react", "react-dom"],
}),
],
// ... rest of config
});The federatedToolComponentName in your tool definition must match the key in the exposes object.
Add your route to app/routes.ts:
export default [
// ... existing routes
route("/my-endpoint/:param", "routes/myEndpoint.ts"),
] satisfies RouteConfig;Create the handler file:
// app/routes/myEndpoint.ts
import type { LoaderFunctionArgs, ActionFunctionArgs } from "react-router";
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
// Handle GET requests
return { data: "response" };
};
export const action = async ({ params, request }: ActionFunctionArgs) => {
// Handle POST/PUT/DELETE requests
const body = await request.json();
return { success: true };
};Use the bridge middleware for OAK integration:
import type { MiddlewareFunction } from "react-router";
import { bridgeMiddleware } from "~/bridgeMiddleware";
export const middleware: MiddlewareFunction[] = [bridgeMiddleware];Access OAK bridge context in components:
import { bridgeContext } from "~/context";
// In your component
const bridge = bridgeContext.use();
// Use bridge methods for OAK communicationnpm installnpm run devStarts the development server on port 8001.
npm run buildBuilds both the main application and federated components.
npm run typecheckThe plugin can be deployed as a standalone microservice. The build output includes:
build/server/- Server-side applicationbuild/client/- Client-side assetspublic/assets/- Federated component assets
@open-agent-kit/bridge- OAK integration bridgereact-router- Routing and server-side renderingzod- Schema validation for tool parameters@originjs/vite-plugin-federation- Module federation for UI components
- Tool Definitions: Always use Zod schemas for parameter validation
- Error Handling: Implement proper error handling in tool execution
- Type Safety: Export TypeScript types for tool parameters and results
- UI Components: Keep federated components lightweight and self-contained
- Bridge Integration: Use the provided middleware for all routes that need OAK integration
- Ensure all required routes (
/tools,/meta) are implemented - Check that tool identifiers are unique across your plugin
- Verify federated component exports match the
federatedToolComponentName - Use the bridge context for proper OAK communication