Skip to content

Commit

Permalink
feat: Tool / Tool Renderer Components and Hooks (#262)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yonom authored Jun 20, 2024
1 parent 86d4f7f commit 40347b2
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 7 deletions.
2 changes: 1 addition & 1 deletion apps/www/components/docs/ParametersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const ParametersList = ({
};
const ParametersBox: FC<ParametersTableProps> = ({ type, parameters }) => {
return (
<div className="relative m-2 mb-0 flex flex-col rounded-lg border">
<div className="relative m-2 mb-1 flex flex-col rounded-lg border">
{!!type && (
<h3 className="-translate-y-1/2 absolute right-3 z-10 rounded-md border bg-background px-4 py-2 font-mono font-semibold text-foreground/70 text-xs">
{type}
Expand Down
96 changes: 96 additions & 0 deletions apps/www/pages/docs/advanced/ToolRenderers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: Tool Renderers
---

You can show a custom UI when a tool is called to let the user know what is happening.

### Tool Renderer Components

```tsx
import { makeToolRenderer } from '@assistant-ui/react/experimental';

type WebSearchArgs = {
query: string;
};

type WebSearchResult = {
title: string;
description: string;
url: string;
};

const WebSearch = makeToolRenderer<WebSearchArgs, WebSearchResult>({
name: 'web_search',
render: ({ part, status }) => {
return (
<p>web_search({part.args.query})</p>
);
},
});
```

You can put this component anywhere in your app inside the `<AssistantRuntimeProvider />` component.

```tsx {1, 8}
import { useWebSearch } from '@/tools/useWebSearch';

const MyApp = () => {
...
return (
<AssistantRuntimeProvider runtime={runtime}>
...
<WebSearch />
...
</AssistantRuntimeProvider>
);
};
```

### Tool Renderer Hooks


```tsx
import { makeToolRenderer } from '@assistant-ui/react/experimental';

type WebSearchArgs = {
query: string;
};

type WebSearchResult = {
title: string;
description: string;
url: string;
};

const useWebSearch = makeToolRenderer<WebSearchArgs, WebSearchResult>({
name: 'web_search',
render: ({ part, status }) => {
return (
<p>web_search({part.args.query})</p>
);
},
});
```


You can use this hook anywhere in your app inside the `<AssistantRuntimeProvider />` component.

```tsx {1, 4}
import { useWebSearch } from '@/tools/useWebSearch';

const MyComponent = () => {
useWebSearch();

...
};

const MyApp = () => {
...
return (
<AssistantRuntimeProvider runtime={runtime}>
...
<MyComponent />
...
</AssistantRuntimeProvider>
);
};
1 change: 1 addition & 0 deletions apps/www/pages/docs/advanced/_meta.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
ToolRenderers: "Tool Renderers",
Branching: "Branching",
Editing: "Editing",
};
2 changes: 2 additions & 0 deletions apps/www/pages/reference/runtime.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const MyApp = () => {
#### Properties

<ParametersTable
type="AssistantRuntimeProviderProps"
parameters={[
{
name: "runtime",
Expand All @@ -35,6 +36,7 @@ const MyApp = () => {
description: "The runtime to provide to the rest of your app.",
children: [
{
type: "AssistantRuntime",
parameters: [
{
name: "messages",
Expand Down
12 changes: 10 additions & 2 deletions packages/react/src/experimental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,13 @@ export type {

export * from "./context";
export { useAssistantInstructions } from "./model-config/useAssistantInstructions";
export { useAssistantTool } from "./model-config/useAssistantTool";
export { useAssistantToolRenderer } from "./model-config/useAssistantToolRenderer";
export {
useAssistantTool,
type AssistantToolProps,
} from "./model-config/useAssistantTool";
export {
useAssistantToolRenderer,
type AssistantToolRendererProps,
} from "./model-config/useAssistantToolRenderer";
export { makeTool } from "./model-config/makeTool";
export { makeToolRenderer } from "./model-config/makeToolRenderer";
12 changes: 12 additions & 0 deletions packages/react/src/model-config/makeTool.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client";
import { type AssistantToolProps, useAssistantTool } from "./useAssistantTool";

export const makeTool = <TArgs, TResult>(
tool: AssistantToolProps<TArgs, TResult>,
) => {
const Tool = () => {
useAssistantTool(tool);
return null;
};
return Tool;
};
15 changes: 15 additions & 0 deletions packages/react/src/model-config/makeToolRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";
import {
type AssistantToolRendererProps,
useAssistantToolRenderer,
} from "./useAssistantToolRenderer";

export const makeToolRenderer = <TArgs, TResult>(
tool: AssistantToolRendererProps<TArgs, TResult>,
) => {
const ToolRenderer = () => {
useAssistantToolRenderer(tool);
return null;
};
return ToolRenderer;
};
4 changes: 2 additions & 2 deletions packages/react/src/model-config/useAssistantTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { useAssistantContext } from "../context/AssistantContext";
import type { ToolCallContentPartComponent } from "../primitives/message/ContentPartComponentTypes";
import type { Tool } from "../utils/ModelConfigTypes";

export type UseAssistantTool<TArgs, TResult> = Tool<TArgs, TResult> & {
export type AssistantToolProps<TArgs, TResult> = Tool<TArgs, TResult> & {
name: string;
render?: ToolCallContentPartComponent<TArgs, TResult>;
};

export const useAssistantTool = <TArgs, TResult>(
tool: UseAssistantTool<TArgs, TResult>,
tool: AssistantToolProps<TArgs, TResult>,
) => {
const { useModelConfig, useToolRenderers } = useAssistantContext();
const registerModelConfigProvider = useModelConfig(
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/model-config/useAssistantToolRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { useEffect } from "react";
import { useAssistantContext } from "../context/AssistantContext";
import type { ToolCallContentPartComponent } from "../primitives/message/ContentPartComponentTypes";

type UseAssistantToolRenderer<TArgs, TResult> = {
export type AssistantToolRendererProps<TArgs, TResult> = {
name: string;
render: ToolCallContentPartComponent<TArgs, TResult>;
};

export const useAssistantToolRenderer = (
// biome-ignore lint/suspicious/noExplicitAny: intentional any
tool: UseAssistantToolRenderer<any, any> | null,
tool: AssistantToolRendererProps<any, any> | null,
) => {
const { useToolRenderers } = useAssistantContext();
const setToolRenderer = useToolRenderers((s) => s.setToolRenderer);
Expand Down

0 comments on commit 40347b2

Please sign in to comment.