feat(web): improving stuff and things

pull/720/head
Travis Fischer 2025-07-04 21:31:41 -05:00
rodzic 2e16139860
commit c3d39f1d62
15 zmienionych plików z 281 dodań i 124 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import { toast } from 'sonner'
import { useAuthenticatedAgentic } from '@/components/agentic-provider'
import { useConfettiFireworks } from '@/components/confetti'
import { LoadingIndicator } from '@/components/loading-indicator'
import { PageContainer } from '@/components/page-container'
import { Button } from '@/components/ui/button'
import { toastError } from '@/lib/notifications'
import { useQuery } from '@/lib/query-client'
@ -93,38 +94,42 @@ export function AppConsumerIndex({ consumerId }: { consumerId: string }) {
}, [ctx, consumer])
return (
<section className='flex flex-col gap-16'>
{!ctx || isLoading ? (
<LoadingIndicator />
) : isError ? (
<p>Error fetching customer subscription "{consumerId}"</p>
) : !consumer ? (
<p>Customer subscription "{consumerId}" not found</p>
) : (
<>
<h1
className='text-center text-balance leading-snug md:leading-none
<PageContainer>
<section className='flex flex-col gap-16'>
{!ctx || isLoading ? (
<LoadingIndicator />
) : isError ? (
<p>Error fetching customer subscription "{consumerId}"</p>
) : !consumer ? (
<p>Customer subscription "{consumerId}" not found</p>
) : (
<>
<h1
className='text-center text-balance leading-snug md:leading-none
text-4xl font-extrabold'
>
Subscription to {consumer.project.name}
</h1>
>
Subscription to {consumer.project.name}
</h1>
<div className=''>
<pre className='max-w-lg'>{JSON.stringify(consumer, null, 2)}</pre>
</div>
<div className=''>
<pre className='max-w-lg'>
{JSON.stringify(consumer, null, 2)}
</pre>
</div>
<Button
onClick={onManageSubscription}
disabled={isLoadingStripeBillingPortal}
>
{isLoadingStripeBillingPortal && (
<Loader2Icon className='animate-spin mr-2' />
)}
<Button
onClick={onManageSubscription}
disabled={isLoadingStripeBillingPortal}
>
{isLoadingStripeBillingPortal && (
<Loader2Icon className='animate-spin mr-2' />
)}
<span>Manage Subscription</span>
</Button>
</>
)}
</section>
<span>Manage Subscription</span>
</Button>
</>
)}
</section>
</PageContainer>
)
}

Wyświetl plik

@ -5,6 +5,7 @@ import { useCallback, useState } from 'react'
import { useAuthenticatedAgentic } from '@/components/agentic-provider'
import { AppConsumersList } from '@/components/app-consumers-list'
import { PageContainer } from '@/components/page-container'
import { Button } from '@/components/ui/button'
import { toastError } from '@/lib/notifications'
@ -31,7 +32,7 @@ export function AppConsumersIndex() {
}, [ctx])
return (
<>
<PageContainer>
<h1
className='text-center text-balance leading-snug md:leading-none
text-4xl font-extrabold'
@ -48,6 +49,6 @@ export function AppConsumersIndex() {
</Button>
<AppConsumersList />
</>
</PageContainer>
)
}

Wyświetl plik

@ -2,6 +2,7 @@
import { useAuthenticatedAgentic } from '@/components/agentic-provider'
import { LoadingIndicator } from '@/components/loading-indicator'
import { PageContainer } from '@/components/page-container'
import { useQuery } from '@/lib/query-client'
export function AppProjectIndex({
@ -27,27 +28,29 @@ export function AppProjectIndex({
// TODO: show deployments
return (
<section>
{!ctx || isLoading ? (
<LoadingIndicator />
) : isError ? (
<p>Error fetching project</p>
) : !project ? (
<p>Project "{projectIdentifier}" not found</p>
) : (
<>
<h1
className='text-center text-balance leading-snug md:leading-none
<PageContainer>
<section>
{!ctx || isLoading ? (
<LoadingIndicator />
) : isError ? (
<p>Error fetching project</p>
) : !project ? (
<p>Project "{projectIdentifier}" not found</p>
) : (
<>
<h1
className='text-center text-balance leading-snug md:leading-none
text-4xl font-extrabold'
>
{project.name}
</h1>
>
{project.name}
</h1>
<div className='mt-8'>
<pre className='max-w-lg'>{JSON.stringify(project, null, 2)}</pre>
</div>
</>
)}
</section>
<div className='mt-8'>
<pre className='max-w-lg'>{JSON.stringify(project, null, 2)}</pre>
</div>
</>
)}
</section>
</PageContainer>
)
}

Wyświetl plik

@ -1,13 +1,14 @@
import { AppProjectsList } from '@/components/app-projects-list'
import { PageContainer } from '@/components/page-container'
export function AppProjectsIndex() {
return (
<>
<PageContainer>
<section>
<div className='flex gap-8 space-around'>
<AppProjectsList />
</div>
</section>
</>
</PageContainer>
)
}

Wyświetl plik

@ -51,7 +51,7 @@ export default function RootLayout({
<div className='relative w-full min-h-[100vh] flex flex-col items-center'>
<Header />
<main className='relative w-full flex-1 flex flex-col items-center gap-16 py-16 px-2 overflow-hidden'>
<main className='relative w-full flex-1 flex flex-col items-center gap-16 pt-8 pb-16 px-2 overflow-hidden'>
{children}
</main>

Wyświetl plik

@ -0,0 +1,30 @@
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@/components/ui/breadcrumb'
export function MarketplacePublicProjectDetailNav({
projectIdentifier
}: {
projectIdentifier: string
}) {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href='/marketplace'>Marketplace</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>{projectIdentifier}</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}

Wyświetl plik

@ -30,6 +30,7 @@ import { defaultAgenticApiClient } from '@/lib/default-agentic-api-client'
import { toast, toastError } from '@/lib/notifications'
import { useQuery } from '@/lib/query-client'
// import { MarketplacePublicProjectDetailNav } from './marketplace-nav'
import {
type MarketplacePublicProjectDetailTab,
marketplacePublicProjectDetailTabsSet,
@ -200,7 +201,7 @@ export function MarketplacePublicProjectDetail({
}, [deployment])
return (
<PageContainer>
<PageContainer compact>
<section>
{isLoading ? (
<LoadingIndicator />
@ -484,73 +485,79 @@ function ProjectHeader({
tab?: MarketplacePublicProjectDetailTab
}) {
return (
<div className='flex flex-col gap-2'>
<div className='w-full flex flex-row gap-2.5 items-center'>
<img
src={
project.lastPublishedDeployment?.iconUrl ||
project.user?.image ||
'/agentic-icon-circle-light.svg'
}
alt={project.name}
className='aspect-square w-10 h-10'
/>
<>
{/* <MarketplacePublicProjectDetailNav
projectIdentifier={project.identifier}
/> */}
<h1 className='flex-1 font-semibold text-balance text-3xl leading-tight'>
{project.name}
</h1>
<div className='flex flex-col gap-2'>
<div className='w-full flex flex-row gap-2.5 items-center'>
<img
src={
project.lastPublishedDeployment?.iconUrl ||
project.user?.image ||
'/agentic-icon-circle-light.svg'
}
alt={project.name}
className='aspect-square w-10 h-10'
/>
<HeroButton
heroVariant='orange'
className='justify-self-end'
disabled={tab === 'pricing'}
asChild={tab !== 'pricing'}
>
<Link
href={`/marketplace/projects/${project.identifier}?tab=pricing`}
<h1 className='flex-1 font-semibold text-balance text-3xl leading-tight'>
{project.name}
</h1>
<HeroButton
heroVariant='orange'
className='justify-self-end'
disabled={tab === 'pricing'}
asChild={tab !== 'pricing'}
>
Subscribe to {project.identifier}
</Link>
</HeroButton>
</div>
<div className='flex flex-row items-center'>
<div className='text-sm text-muted-foreground flex flex-row gap-0.5 items-center hover:no-underline! no-underline!'>
<span>{project.identifier}</span>
{/* TODO: <CopyIcon className='w-4 h-4' /> */}
<Link
href={`/marketplace/projects/${project.identifier}?tab=pricing`}
>
Subscribe to {project.identifier}
</Link>
</HeroButton>
</div>
{project.lastPublishedDeployment?.homepageUrl && (
<Button asChild variant='link'>
<Link
href={project.lastPublishedDeployment.homepageUrl}
className='text-sm flex flex-row gap-1.5! items-center text-muted-foreground! py-1! px-2!'
target='_blank'
rel='noopener noreferrer'
>
<ExternalLinkIcon className='w-4 h-4' />
<div className='flex flex-row items-center'>
<div className='text-sm text-muted-foreground flex flex-row gap-0.5 items-center hover:no-underline! no-underline!'>
<span>{project.identifier}</span>
<span>Homepage</span>
</Link>
</Button>
)}
{/* TODO: <CopyIcon className='w-4 h-4' /> */}
</div>
{project.lastPublishedDeployment?.sourceUrl && (
<Button asChild variant='link'>
<Link
href={project.lastPublishedDeployment.sourceUrl}
className='text-sm flex flex-row gap-1.5! items-center text-muted-foreground! py-1! px-2!'
target='_blank'
rel='noopener noreferrer'
>
<GitHubIcon className='w-4 h-4' />
{project.lastPublishedDeployment?.homepageUrl && (
<Button asChild variant='link'>
<Link
href={project.lastPublishedDeployment.homepageUrl}
className='text-sm flex flex-row gap-1.5! items-center text-muted-foreground! py-1! px-2!'
target='_blank'
rel='noopener noreferrer'
>
<ExternalLinkIcon className='w-4 h-4' />
<span>GitHub</span>
</Link>
</Button>
)}
<span>Homepage</span>
</Link>
</Button>
)}
{project.lastPublishedDeployment?.sourceUrl && (
<Button asChild variant='link'>
<Link
href={project.lastPublishedDeployment.sourceUrl}
className='text-sm flex flex-row gap-1.5! items-center text-muted-foreground! py-1! px-2!'
target='_blank'
rel='noopener noreferrer'
>
<GitHubIcon className='w-4 h-4' />
<span>GitHub</span>
</Link>
</Button>
)}
</div>
</div>
</div>
</>
)
}

Wyświetl plik

@ -2,10 +2,12 @@ import { cn } from '@/lib/utils'
export function PageContainer({
background = true,
compact = false,
className,
children
}: {
background?: boolean
compact?: boolean
className?: string
children: React.ReactNode
}) {
@ -18,6 +20,7 @@ export function PageContainer({
<div
className={cn(
'relative w-full flex-1 flex flex-col items-center max-w-[1200px] gap-16 z-10',
compact ? 'pt-4' : 'pt-8',
className
)}
>

Wyświetl plik

@ -0,0 +1,109 @@
import { Slot } from '@radix-ui/react-slot'
import { ChevronRight, MoreHorizontal } from 'lucide-react'
import * as React from 'react'
import { cn } from '@/lib/utils'
function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
return <nav aria-label='breadcrumb' data-slot='breadcrumb' {...props} />
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
return (
<ol
data-slot='breadcrumb-list'
className={cn(
'text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5',
className
)}
{...props}
/>
)
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
return (
<li
data-slot='breadcrumb-item'
className={cn('inline-flex items-center gap-1.5', className)}
{...props}
/>
)
}
function BreadcrumbLink({
asChild,
className,
...props
}: React.ComponentProps<'a'> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'a'
return (
<Comp
data-slot='breadcrumb-link'
className={cn('hover:text-foreground transition-colors', className)}
{...props}
/>
)
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
return (
<span
data-slot='breadcrumb-page'
role='link'
aria-disabled='true'
aria-current='page'
className={cn('text-foreground font-normal', className)}
{...props}
/>
)
}
function BreadcrumbSeparator({
children,
className,
...props
}: React.ComponentProps<'li'>) {
return (
<li
data-slot='breadcrumb-separator'
role='presentation'
aria-hidden='true'
className={cn('[&>svg]:size-3.5', className)}
{...props}
>
{children ?? <ChevronRight />}
</li>
)
}
function BreadcrumbEllipsis({
className,
...props
}: React.ComponentProps<'span'>) {
return (
<span
data-slot='breadcrumb-ellipsis'
role='presentation'
aria-hidden='true'
className={cn('flex size-9 items-center justify-center', className)}
{...props}
>
<MoreHorizontal className='size-4' />
<span className='sr-only'>More</span>
</span>
)
}
export {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
}

Wyświetl plik

@ -317,6 +317,7 @@ const result = await generateText({
model: openai('gpt-4o-mini'),
tools: createAISDKTools(searchTool),
toolChoice: 'required',
system: '${systemPrompt}',
prompt: '${prompt}'
})
@ -416,9 +417,10 @@ const searchTool = await AgenticToolClient.fromIdentifier('${identifier}'${
: ''
})
const tools = createLangChainTools(searchTool)
const agent = createToolCallingAgent({
llm: new ChatOpenAI({ model: 'gpt-4o-mini' }),
tools: createLangChainTools(searchTool),
tools,
prompt: ChatPromptTemplate.fromMessages([
['placeholder', '{chat_history}'],
['human', '{input}'],

Wyświetl plik

@ -2,12 +2,11 @@ import 'dotenv/config'
import { createAISDKTools } from '@agentic/ai-sdk'
import { AgenticToolClient } from '@agentic/platform-tool-client'
import { createOpenAI } from '@ai-sdk/openai'
import { openai } from '@ai-sdk/openai'
import { generateText } from 'ai'
async function main() {
const searchTool = await AgenticToolClient.fromIdentifier('@agentic/search')
const openai = createOpenAI({ compatibility: 'strict' })
const result = await generateText({
model: openai('gpt-4o-mini'),

Wyświetl plik

@ -10,9 +10,9 @@ async function main() {
const weatherAgent = new Agent({
name: 'Weather Agent',
instructions: 'You are a helpful assistant. Be as concise as possible.',
model: openai('gpt-4o-mini'),
tools: createMastraTools(searchTool)
tools: createMastraTools(searchTool),
instructions: 'You are a helpful assistant. Be as concise as possible.'
})
const res = await weatherAgent.generate(

Wyświetl plik

@ -109,7 +109,7 @@ catalogs:
specifier: ^2.1.7
version: 2.1.7
'@radix-ui/react-slot':
specifier: ^1.2.3
specifier: 1.2.3
version: 1.2.3
'@radix-ui/react-tabs':
specifier: ^1.1.12

Wyświetl plik

@ -45,7 +45,7 @@ catalog:
'@radix-ui/react-collapsible': ^1.1.11
'@radix-ui/react-dropdown-menu': 2.1.15
'@radix-ui/react-label': ^2.1.7
'@radix-ui/react-slot': ^1.2.3
'@radix-ui/react-slot': 1.2.3
'@radix-ui/react-tabs': ^1.1.12
'@radix-ui/react-tooltip': ^1.2.7
'@react-email/components': ^0.1.1

Wyświetl plik

@ -10,9 +10,6 @@
- double check stripe upgrade flow and add fireworks
- improve upgrade flow UX
- should we bypass stripe for `free` plans to increase conversions?
- example usage
- double check example usage for all TS sdks now that real examples are working
- fix mcp examples
- **replace json pricing plans and consumers with actual designs**
- double-check free-tier rate-limits for `@agentic/search`
- docs: add notes about constraints on mcp origin servers (static tools)