Other Frameworks
Remix
Remix applications use the @yak-io/react package for the client-side widget and @yak-io/javascript for server handlers.
Installation
npm install @yak-io/react @yak-io/javascriptpnpm add @yak-io/react @yak-io/javascriptyarn add @yak-io/react @yak-io/javascriptbun add @yak-io/react @yak-io/javascriptClient Setup
Add the provider and widget to your root layout:
// app/root.tsx
import { useNavigate } from "@remix-run/react";
import { YakProvider, YakWidget } from "@yak-io/react";
export default function App() {
const navigate = useNavigate();
return (
<html>
<body>
<YakProvider
appId={ENV.YAK_APP_ID}
getConfig={async () => {
const res = await fetch("/api/yak");
return res.json();
}}
onToolCall={async (name, args) => {
const res = await fetch("/api/yak", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, args }),
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);
return data.result;
}}
onRedirect={(path) => navigate(path)}
>
<Outlet />
<YakWidget />
</YakProvider>
</body>
</html>
);
}Server Handler
Create a resource route for the API:
// app/routes/api.yak.ts
import { json, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
import { createYakHandler } from "@yak-io/javascript/server";
const { GET, POST } = createYakHandler({
routes: [
{ path: "/", title: "Home" },
{ path: "/dashboard", title: "Dashboard" },
{ path: "/settings", title: "Settings" },
],
tools: [
// Add your tool adapters here
],
});
export async function loader({ request }: LoaderFunctionArgs) {
const response = await GET(request);
const data = await response.json();
return json(data);
}
export async function action({ request }: ActionFunctionArgs) {
const response = await POST(request);
const data = await response.json();
return json(data);
}Dynamic Routes
Fetch routes from your Remix configuration or a CMS:
// app/routes/api.yak.ts
import { getRoutes } from "~/utils/routes";
export async function loader({ request }: LoaderFunctionArgs) {
const routes = await getRoutes();
const { GET } = createYakHandler({
routes,
});
const response = await GET(request);
const data = await response.json();
return json(data);
}Adding Tools
Integrate with your data layer:
// app/routes/api.yak.ts
import { db } from "~/utils/db.server";
const databaseTools = {
id: "database",
getTools: async () => [
{
name: "db.getUser",
description: "Get user profile information",
input_schema: {
type: "object",
properties: { userId: { type: "string" } },
required: ["userId"],
},
},
],
executeTool: async (name: string, args: Record<string, unknown>) => {
if (name === "db.getUser") {
return db.user.findUnique({ where: { id: args.userId as string } });
}
throw new Error(`Unknown tool: ${name}`);
},
};
const { GET, POST } = createYakHandler({
routes: [...],
tools: [databaseTools],
});Programmatic Control
Use the useYak hook in any component:
// app/components/HelpButton.tsx
import { useYak } from "@yak-io/react";
export function HelpButton() {
const { openWithPrompt } = useYak();
return (
<button onClick={() => openWithPrompt("Help me with this page")}>
Get Help
</button>
);
}The onRedirect prop integrates with Remix's useNavigate for client-side navigation without full page reloads.