Skip to main content

Integration Walkthrough

This walkthrough shows the standard OpenBox CopilotKit SDK path: keep your CopilotKit Runtime v2 route, pass its runtime options into withOpenBoxRuntime(), and configure OpenBox middleware options for frontend tools, enforcement, and optional multi-agent handoff.

Short path

Need the shorter version? Start with Add OpenBox to CopilotKit.

Part 1: Register Your Agent In OpenBox

  1. Open the OpenBox Dashboard.
  2. Go to Agents.
  3. Create or open the agent you want to govern.
  4. Generate an agent runtime key.
  5. Copy the generated DID and private key unless Require signing is disabled.

See Registering Agents for the full dashboard flow.

Part 2: Configure Trust Controls

Configure the OpenBox controls this CopilotKit app should evaluate in Authorize:

  • Use guardrails for prompt, tool, and output checks.
  • Use policies for allow, block, halt, approval, and transformation behavior.
  • Use behavior rules for natural-language instructions that shape how the registered agent should operate.

These controls live in OpenBox. CopilotKit provides the assistant UI and runtime path; the SDK sends CopilotKit runtime events to the registered OpenBox agent.

Part 3: Install The SDK

The SDK is published on npm as @openbox-ai/openbox-copilotkit.

npm install @openbox-ai/openbox-copilotkit

If your app does not already include CopilotKit's runtime peers:

npm install @copilotkit/runtime @ag-ui/client

Part 4: Configure Environment

.env.local
OPENBOX_URL=https://core.openbox.ai
OPENBOX_API_KEY=obx_live_or_obx_test_agent_runtime_key

# Required by default for newly created agents unless Require signing is disabled.
OPENBOX_AGENT_DID=did:aip:550e8400-e29b-41d4-a716-446655440000
OPENBOX_AGENT_PRIVATE_KEY=base64_raw_ed25519_private_key

Use explicit parent and child variable names in your own app when you configure multi-agent mode, for example OPENBOX_COPILOTKIT_API_KEY and OPENBOX_MASTRA_API_KEY.

Part 5: Configure Next.js For A Server Route

The SDK is server-only and uses Node AsyncLocalStorage. Keep the CopilotKit route on Node:

src/app/api/copilotkit/[[...slug]]/route.ts
export const runtime = "nodejs";

Keep server-only packages external:

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
serverExternalPackages: [
"@copilotkit/runtime",
"@openbox-ai/openbox-copilotkit",
],
};

export default nextConfig;

Part 6: Wrap The CopilotKit Runtime

Start from the CopilotKit runtime options your app already uses. The backend agent framework is up to your app; the wrapper only needs the CopilotKit Runtime v2 options.

src/app/api/copilotkit/[[...slug]]/route.ts
import {
CopilotRuntime,
InMemoryAgentRunner,
createCopilotEndpoint,
} from "@copilotkit/runtime/v2";
import { withOpenBoxRuntime } from "@openbox-ai/openbox-copilotkit";
import { handle } from "hono/vercel";

export const runtime = "nodejs";

const options = {
agents,
runner: new InMemoryAgentRunner(),
} satisfies ConstructorParameters<typeof CopilotRuntime>[0];

const { runtime: copilotRuntime, shutdown } = await withOpenBoxRuntime(
options,
{
middlewareOptions: {
frontendToolNames: ["setThemeColor"],
enforceApprovals: false,
},
},
);

process.on("SIGTERM", async () => {
await shutdown();
});

const app = createCopilotEndpoint({
runtime: copilotRuntime,
basePath: "/api/copilotkit",
});

export const GET = handle(app);
export const POST = handle(app);

withOpenBoxRuntime() reads OPENBOX_URL, OPENBOX_API_KEY, OPENBOX_AGENT_DID, and OPENBOX_AGENT_PRIVATE_KEY automatically. You can pass those values explicitly when your app uses custom variable names.

Part 7: Label Frontend Tools

CopilotKit frontend tools and backend tools can both appear in the AG-UI event stream. OpenBox records frontend: true only when you explicitly allowlist the tool name:

const { runtime: copilotRuntime } = await withOpenBoxRuntime(options, {
middlewareOptions: {
frontendToolNames: ["setThemeColor", "showSnackbar", "go_to_moon"],
},
});

Use isFrontendTool when the frontend tool registry is dynamic:

const frontendTools = new Set(["setThemeColor", "showSnackbar"]);

const { runtime: copilotRuntime } = await withOpenBoxRuntime(options, {
middlewareOptions: {
isFrontendTool: ({ name }) => frontendTools.has(name),
},
});

Part 8: Choose Enforcement Behavior

Telemetry-only mode:

middlewareOptions: {
enforceApprovals: false,
}

Enforcement mode:

middlewareOptions: {
enforceApprovals: true,
}

In enforcement mode, block or halt verdicts stop the stream after full tool-call input is known. The browser receives:

{
"type": "RUN_ERROR",
"code": "governance_blocked",
"correlationId": "<governanceEventId or approvalId>"
}

Assistant output is recorded after it streams. This SDK version does not rewrite already-streamed assistant output.

Part 9: Optional Multi-Agent Handoff

Use multi-agent mode only when a CopilotKit tool delegates to another OpenBox-governed child agent.

src/app/api/copilotkit/[[...slug]]/route.ts
import type {
OpenBoxMultiAgentContext,
} from "@openbox-ai/openbox-copilotkit";

const pendingChildContext = new Map<string, OpenBoxMultiAgentContext>();

const { runtime: copilotRuntime } = await withOpenBoxRuntime(options, {
apiKey: process.env.OPENBOX_COPILOTKIT_API_KEY,
apiUrl: process.env.OPENBOX_URL,
agentDid: process.env.OPENBOX_COPILOTKIT_AGENT_DID,
agentPrivateKey: process.env.OPENBOX_COPILOTKIT_AGENT_PRIVATE_KEY,
middlewareOptions: {
multiAgent: {
enabled: true,
parentAgentDid: process.env.OPENBOX_COPILOTKIT_AGENT_DID,
handoffTools: {
weatherTool: {
childAgentName: "mastra-weather-agent",
childWorkflowType: "weather-agent",
childTaskQueue: "mastra",
childApiKey: process.env.OPENBOX_MASTRA_API_KEY,
childAgentDid: process.env.OPENBOX_MASTRA_AGENT_DID,
childAgentPrivateKey:
process.env.OPENBOX_MASTRA_AGENT_PRIVATE_KEY,
},
},
forwardContext: (ctx) => {
pendingChildContext.set(ctx.parentActivityId, ctx);
return { correlation_id: ctx.parentActivityId };
},
},
},
});

This emits the parent-side context and, when child credentials are configured, sends the Handoff request authenticated as the child. Your app still needs to pass pendingChildContext.get(parentActivityId) into the child runtime invocation so the child events stamp the same multi_agent_session_id and parent_workflow_id.

Part 10: Verify A Live Run

Trigger one real CopilotKit request, then check OpenBox for:

  • a workflow_type: "copilotkit" session
  • SignalReceived(user_input) and SignalReceived(agent_output)
  • ActivityStarted and ActivityCompleted for AG-UI tool calls
  • frontend: true for allowlisted frontend tools
  • a redacted governance_blocked error if enforcement blocks or halts
  • a child-authenticated Handoff when multi-agent mode is enabled and a mapped delegation tool fires

Next Steps