@aiteammate/agent-widget
v0.0.9
Published
React widget for embedding a Trugen agent by agent id.
Readme
@aiteammate/agent-widget
Embed a Trugen AI teammate in any React app.
This package gives you:
- the widget launcher
- the avatar/chat/talk experience
- runtime widget styling
- support for package-side client tools that your own app can render
Install
npm install @aiteammate/agent-widgetImport styles once
The widget depends on the package stylesheet. Import it once at your app entry.
import "@aiteammate/agent-widget/styles.css";For Next.js App Router:
import "@aiteammate/agent-widget/styles.css";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "My App",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}Quick start
"use client";
import "@aiteammate/agent-widget/styles.css";
import { TrugenAgentWidget } from "@aiteammate/agent-widget";
export default function Page() {
return (
<TrugenAgentWidget
agentId="your-agent-id"
userName="Jane Doe"
userId="[email protected]"
identityPrompt={false}
context="User is viewing the pricing page."
/>
);
}Widget props
| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| agentId | string | Yes | Published Trugen agent id. |
| context | string | No | Extra runtime context passed to the agent session. |
| userName | string | No | Display name for the current user. |
| userId | string | No | Stable user identifier, usually email or app user id. |
| identityPrompt | boolean | No | Shows a name/email prompt before session start. Defaults to false. |
Next.js example
"use client";
import "@aiteammate/agent-widget/styles.css";
import { TrugenAgentWidget } from "@aiteammate/agent-widget";
export function SupportTeammate() {
return (
<TrugenAgentWidget
agentId={process.env.NEXT_PUBLIC_TRUGEN_AGENT_ID ?? ""}
userName="Customer"
userId="[email protected]"
context="Customer is inside the support portal."
/>
);
}Client tools
Client tools let your npm package render custom UI when the agent calls a tool.
This is useful when:
- you want the agent to open a package-owned panel
- you want the UI to render inside your app, not inside a public preview
- you want to keep tool behavior in React components you control
Important
Client tools are package-side runtime features.
They are meant to work inside your app where @aiteammate/agent-widget is installed and running. They are not a public hosted tool runtime by themselves.
Register a client tool
Use createLeftPanelClientTool plus useRegisterClientTool.
"use client";
import {
TrugenAgentWidget,
createLeftPanelClientTool,
useRegisterClientTool,
type ClientToolPanelProps,
} from "@aiteammate/agent-widget";
type GreetingPayload = {
message?: string;
};
function GreetingToolPanel({
payload,
close,
}: ClientToolPanelProps<GreetingPayload>) {
return (
<div className="h-full w-full bg-[#0f1316] p-6 text-white">
<h2 className="text-2xl font-semibold">Greeting Tool</h2>
<p className="mt-3 text-white/70">
{payload.message ?? "Hello from your client tool."}
</p>
<button
type="button"
onClick={close}
className="mt-6 rounded-md border border-white/15 px-4 py-2"
>
Close
</button>
</div>
);
}
const greetingTool = createLeftPanelClientTool(GreetingToolPanel, {
parsePayload: (rawPayload) => {
if (!rawPayload.trim()) return {};
return JSON.parse(rawPayload) as GreetingPayload;
},
});
function WidgetWithClientTools() {
useRegisterClientTool("greet_tool", greetingTool);
return (
<TrugenAgentWidget
agentId="your-agent-id"
userName="Jane Doe"
userId="[email protected]"
/>
);
}
export default WidgetWithClientTools;Register multiple client tools
"use client";
import {
TrugenAgentWidget,
createLeftPanelClientTool,
useRegisterClientTools,
} from "@aiteammate/agent-widget";
function FirstTool() {
return <div className="h-full w-full bg-black text-white">First tool</div>;
}
function SecondTool() {
return <div className="h-full w-full bg-black text-white">Second tool</div>;
}
export default function WidgetWithManyTools() {
useRegisterClientTools({
first_tool: createLeftPanelClientTool(FirstTool),
second_tool: createLeftPanelClientTool(SecondTool),
});
return <TrugenAgentWidget agentId="your-agent-id" />;
}Client tool payloads
When the agent calls a registered tool, the widget passes the tool payload into your panel component.
By default:
- valid JSON objects are passed through as objects
- other JSON values are wrapped as
{ value: parsed } - invalid JSON is wrapped as
{ value: rawPayload }
If you want stricter behavior, provide your own parsePayload.
const scheduleTool = createLeftPanelClientTool(SchedulePanel, {
parsePayload: (rawPayload) => {
const parsed = JSON.parse(rawPayload) as {
date: string;
participants: string[];
};
return {
date: parsed.date,
participants: parsed.participants ?? [],
};
},
});Client tool display options
You can customize how the built-in agent/tool switch behaves.
const myTool = createLeftPanelClientTool(MyPanel, {
display: {
controlsHoverOnly: true,
topLeftHoverOnly: true,
},
});display options
| Field | Type | Description |
| --- | --- | --- |
| controlsHoverOnly | boolean | Show panel controls only on hover. |
| topLeftHoverOnly | boolean | Show the top-left display toggle only on hover. |
| showBuiltInToggle | boolean | Hide the built-in toggle if set to false. |
| renderToggle | (props) => ReactNode | Fully replace the built-in toggle UI. |
Use the built-in toggle in your own custom UI
The package exports the default toggle components too.
import {
ClientToolModeToggle,
DisplayModeToggle,
} from "@aiteammate/agent-widget";Most apps do not need this. It is mainly useful when you want a custom wrapper while keeping the same internal interaction pattern.
How the tool flow works
- Your app renders
TrugenAgentWidget - Your app registers one or more client tools
- The agent calls a tool by name
- The widget matches that tool name against your registered tool
- Your React panel renders inside the widget
If the tool name does not match a registered client tool, nothing custom will render in your package.
Best practices
- Keep tool names stable and exact
- Keep payloads small and structured
- Use
parsePayloadfor validation and normalization - Treat client tools as app-owned UI, not public preview UI
- Prefer one focused React component per tool
Troubleshooting
The widget looks unstyled
Make sure this import exists once in your app:
import "@aiteammate/agent-widget/styles.css";The widget does not start
Check that:
agentIdis valid- the agent is published
- the current app can reach the runtime it needs
My client tool is not rendering
Check all of the following:
- the component is rendered in a client component
- the tool is registered before the agent calls it
- the tool name in your registration exactly matches the tool name the agent uses
- your
parsePayloadis not throwing
Next.js says this must be a client component
Add this at the top of the file:
"use client";License
Proprietary. All rights reserved.
