Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
704b002
[docs] Add AI Agent docs
VaguelySerious Nov 26, 2025
0a65357
Fix scrolling of left sidebar
VaguelySerious Nov 26, 2025
eb49e18
Polish
VaguelySerious Nov 26, 2025
e83bbf3
Empty changeset
VaguelySerious Nov 26, 2025
8e8acab
Polish
VaguelySerious Nov 26, 2025
51e7aac
Move to new section
VaguelySerious Nov 26, 2025
108ac78
Polish
VaguelySerious Nov 26, 2025
b04412d
Show more code snippets and full state
VaguelySerious Nov 26, 2025
4811a94
Fix
VaguelySerious Nov 26, 2025
da6e94e
Delete previous
VaguelySerious Nov 26, 2025
2b3c672
fix
VaguelySerious Nov 26, 2025
7f3514f
Fix routing
VaguelySerious Nov 26, 2025
11edb5b
Add nice graphic
VaguelySerious Nov 26, 2025
64d7265
Polish
VaguelySerious Nov 26, 2025
afdb0b1
Package install polish
VaguelySerious Nov 26, 2025
465c18d
CHanges
VaguelySerious Nov 26, 2025
5dada91
Human in the loop polish
VaguelySerious Nov 27, 2025
6db66ec
Polish sleep docs
VaguelySerious Nov 27, 2025
596f7ad
Tool polish
VaguelySerious Nov 27, 2025
756a11c
Move sections
VaguelySerious Nov 27, 2025
739f732
love these graphs
VaguelySerious Nov 27, 2025
dad2a63
remove auto-close example
VaguelySerious Nov 27, 2025
249bf54
Queueing
VaguelySerious Nov 27, 2025
634df7f
prepareStep, queueing, and modeling
VaguelySerious Nov 27, 2025
bbe7df9
Small polish
VaguelySerious Nov 27, 2025
7e50e2e
remove unneeded file
VaguelySerious Nov 27, 2025
e97a2b3
Polish pass
VaguelySerious Nov 27, 2025
9a1a2b5
Update multi-turn example
VaguelySerious Nov 27, 2025
87aa49f
Empty commit
VaguelySerious Nov 27, 2025
719700e
Merge branch 'main' into peter/agent-docs
VaguelySerious Nov 27, 2025
1bb9007
Merge branch 'main' into peter/agent-docs
VaguelySerious Nov 29, 2025
e7da651
Polish
VaguelySerious Nov 29, 2025
6a083cb
Rename and link
VaguelySerious Nov 29, 2025
a07664d
Make web the default viewer for observability in getting-started guide
VaguelySerious Nov 30, 2025
5d7907e
Remove "defining tools" page in favor of adding a small section to th…
VaguelySerious Nov 30, 2025
7656c9c
Highlight selected header items
VaguelySerious Nov 30, 2025
239c671
New example query for docs search
VaguelySerious Nov 30, 2025
ee0ed68
Add all of the example and setup code
VaguelySerious Nov 30, 2025
1db89f9
Split out section about streaming updates from tools
VaguelySerious Nov 30, 2025
36229c7
Updates
VaguelySerious Nov 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/three-hands-open.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
151 changes: 151 additions & 0 deletions docs/app/guides/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import {
DocsBody as FumadocsDocsBody,
DocsDescription as FumadocsDocsDescription,
DocsPage as FumadocsDocsPage,
DocsTitle as FumadocsDocsTitle,
} from 'fumadocs-ui/page';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { notFound, redirect } from 'next/navigation';
import type { CSSProperties } from 'react';
import { AskAI } from '@/components/geistdocs/ask-ai';
import { CopyPage } from '@/components/geistdocs/copy-page';
import { EditSource } from '@/components/geistdocs/edit-source';
import { Feedback } from '@/components/geistdocs/feedback';
import { getMDXComponents } from '@/components/geistdocs/mdx-components';
import { AgentTraces } from '@/components/guides/agent-traces';
import { OpenInChat } from '@/components/geistdocs/open-in-chat';
import { ScrollTop } from '@/components/geistdocs/scroll-top';
import { TableOfContents } from '@/components/geistdocs/toc';
import * as AccordionComponents from '@/components/ui/accordion';
import { Badge } from '@/components/ui/badge';
import {
getGuidesLLMText,
getPageImage,
guidesSource,
} from '@/lib/geistdocs/source';
import { TSDoc } from '@/lib/tsdoc';
import { cn } from '@/lib/utils';
import type { Metadata } from 'next';

const containerStyle = {
'--fd-nav-height': '4rem',
} as CSSProperties;

const Page = async (props: PageProps<'/guides/[[...slug]]'>) => {
const params = await props.params;

// Redirect /guides to /guides/ai-agents
if (!params.slug || params.slug.length === 0) {
redirect('/guides/ai-agents');
}

const page = guidesSource.getPage(params.slug);

if (!page) {
notFound();
}

const markdown = await getGuidesLLMText(page);
const MDX = page.data.body;

return (
<FumadocsDocsPage
full={page.data.full}
toc={page.data.toc}
article={{ className: 'max-w-[754px]' }}
container={{
style: containerStyle,
className: 'col-span-2',
}}
tableOfContent={{
component: (
<TableOfContents>
<EditSource path={page.path} />
<ScrollTop />
<Feedback />
<CopyPage text={markdown} />
<AskAI href={page.url} />
<OpenInChat href={page.url} />
</TableOfContents>
),
}}
>
<FumadocsDocsTitle className={cn('text-4xl tracking-tight')}>
{page.data.title}
</FumadocsDocsTitle>
<FumadocsDocsDescription>{page.data.description}</FumadocsDocsDescription>
<FumadocsDocsBody className={cn('mx-auto w-full')}>
<MDX
components={getMDXComponents({
a: createRelativeLink(guidesSource, page),

// Add your custom components here
AgentTraces,
Badge,
TSDoc,
Step,
Steps,
...AccordionComponents,
Tabs,
Tab,
})}
/>
</FumadocsDocsBody>
</FumadocsDocsPage>
);
};

export const generateStaticParams = () => [
{ slug: [] }, // Root redirect
...guidesSource.generateParams().map((params) => ({
slug: params.slug,
})),
];

export const generateMetadata = async (
props: PageProps<'/guides/[[...slug]]'>
): Promise<Metadata> => {
const params = await props.params;

// Root path redirects, no metadata needed
if (!params.slug || params.slug.length === 0) {
return { title: 'Guides' };
}

const page = guidesSource.getPage(params.slug);

if (!page) {
notFound();
}

const { segments, url } = getPageImage(page);

return {
title: page.data.title,
description: page.data.description,
openGraph: {
title: page.data.title,
description: page.data.description,
type: 'article',
url: page.url,
images: [
{
url,
width: 1200,
height: 630,
alt: segments.join(' - '),
},
],
},
twitter: {
card: 'summary_large_image',
title: page.data.title,
description: page.data.description,
images: [url],
},
};
};

export default Page;
43 changes: 43 additions & 0 deletions docs/app/guides/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { DocsLayout as FumadocsDocsLayout } from 'fumadocs-ui/layouts/docs';
import { Folder, Item, Separator } from '@/components/geistdocs/sidebar';
import { guidesSource } from '@/lib/geistdocs/source';

export const GuidesLayout = ({
children,
}: Pick<LayoutProps<'/guides'>, 'children'>) => (
<FumadocsDocsLayout
containerProps={{
className:
'md:grid md:grid-cols-[286px_1fr_286px] md:pl-0! md:mx-auto! md:w-full md:max-w-(--fd-layout-width)!',
}}
nav={{
enabled: false,
}}
searchToggle={{
enabled: false,
}}
sidebar={{
className:
'md:static md:sticky md:top-16 md:max-h-[calc(100vh-4rem)] md:overflow-y-auto md:w-auto! bg-background! md:bg-transparent! border-none transition-none',
collapsible: false,
components: {
Folder,
Item,
Separator,
},
}}
tabMode="auto"
themeSwitch={{
enabled: false,
}}
tree={guidesSource.pageTree}
>
{children}
</FumadocsDocsLayout>
);

const Layout = ({ children }: LayoutProps<'/guides'>) => (
<GuidesLayout>{children}</GuidesLayout>
);

export default Layout;
4 changes: 4 additions & 0 deletions docs/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const links = [
label: 'Docs',
href: '/docs',
},
{
label: 'Guides',
href: '/guides',
},
{
label: 'Examples',
href: 'https://github.com/vercel/workflow-examples',
Expand Down
2 changes: 1 addition & 1 deletion docs/components/geistdocs/docs-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DocsLayout = ({
}}
sidebar={{
className:
'md:static md:sticky md:top-16 md:h-fit md:w-auto! bg-background! md:bg-transparent! border-none transition-none',
'md:static md:sticky md:top-16 md:max-h-[calc(100vh-4rem)] md:overflow-y-auto md:w-auto! bg-background! md:bg-transparent! border-none transition-none',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an issue with the sidebar not scrolling until the main content is scrolled to the bottom, which only now became apparent since we have enough sidebar items to fill a small screen (if they're all expanded)

collapsible: false,
components: {
Folder,
Expand Down
94 changes: 94 additions & 0 deletions docs/components/guides/agent-traces.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use client';

import { motion } from 'motion/react';
import { cn } from '@/lib/utils';

const rows = [
{
label: 'chatWorkflow',
className:
'bg-[#E1F0FF] dark:bg-[#00254D] border-[#99CEFF] text-[#0070F3] dark:border-[#0067D6] dark:text-[#52AEFF]',
start: 0,
duration: 100,
},
{
label: 'agent.stream',
className:
'bg-[#DCF6DC] dark:bg-[#1B311E] border-[#99E59F] text-[#46A758] dark:border-[#297C3B] dark:text-[#6CDA76]',
start: 2,
duration: 16,
},
{
label: 'searchWeb',
className:
'bg-[#FFF4E5] dark:bg-[#3D2800] border-[#FFCC80] text-[#F5A623] dark:border-[#9A6700] dark:text-[#FFCA28]',
start: 20,
duration: 13,
},
{
label: 'agent.stream',
className:
'bg-[#DCF6DC] dark:bg-[#1B311E] border-[#99E59F] text-[#46A758] dark:border-[#297C3B] dark:text-[#6CDA76]',
start: 37,
duration: 16,
},
{
label: 'waitForHumanApproval',
className:
'bg-[#FCE7F3] dark:bg-[#4A1D34] border-[#F9A8D4] text-[#EC4899] dark:border-[#BE185D] dark:text-[#F472B6]',
start: 57,
duration: 24,
},
{
label: 'agent.stream',
className:
'bg-[#DCF6DC] dark:bg-[#1B311E] border-[#99E59F] text-[#46A758] dark:border-[#297C3B] dark:text-[#6CDA76]',
start: 84,
duration: 16,
},
];

export const AgentTraces = () => (
<div className="not-prose my-8 rounded-lg border bg-card p-4 sm:p-6">
<div className="space-y-2 w-full">
{rows.map((row, index) => (
<div
key={`${row.label}-${index}`}
className="flex flex-col overflow-hidden"
style={{
marginLeft: `${row.start}%`,
width: `${row.duration}%`,
}}
>
<div className="relative h-6 w-full">
<motion.div
initial={{ width: 0, opacity: 0 }}
whileInView={{ width: 'auto', opacity: 1 }}
viewport={{ once: true, amount: 0.8 }}
transition={{
duration: 0.55,
delay: index * 0.12,
ease: [0.22, 1, 0.36, 1],
}}
className={cn(
'h-full rounded-sm border overflow-hidden',
row.className
)}
>
<div className="flex justify-between items-center h-full px-2">
<span className="text-[10px] sm:text-[11px] font-mono font-medium text-foreground truncate leading-none">
{row.label}
</span>
{index === 0 && (
<span className="text-[10px] sm:text-[11px] hidden sm:inline leading-none">
{row.duration}ms
</span>
)}
</div>
</motion.div>
</div>
</div>
))}
</div>
</div>
);
Loading
Loading