kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: improve web examples
rodzic
7759aa43d3
commit
7b5f7e8f97
|
@ -79,7 +79,10 @@ export function registerV1CreateDeployment(
|
||||||
|
|
||||||
if (!project) {
|
if (!project) {
|
||||||
// Used for testing e2e fixtures in the development marketplace
|
// Used for testing e2e fixtures in the development marketplace
|
||||||
const isPrivate = !(user.username === 'dev' && env.isDev)
|
const isPrivate = !(
|
||||||
|
(user.username === 'dev' && env.isDev) ||
|
||||||
|
user.username === 'agentic'
|
||||||
|
)
|
||||||
|
|
||||||
// Upsert the project if it doesn't already exist
|
// Upsert the project if it doesn't already exist
|
||||||
// The typecast is necessary here because we're not populating the
|
// The typecast is necessary here because we're not populating the
|
||||||
|
|
|
@ -63,7 +63,10 @@ export function registerV1CreateProject(
|
||||||
)
|
)
|
||||||
|
|
||||||
// Used for testing e2e fixtures in the development marketplace
|
// Used for testing e2e fixtures in the development marketplace
|
||||||
const isPrivate = !(user.username === 'dev' && env.isDev)
|
const isPrivate = !(
|
||||||
|
(user.username === 'dev' && env.isDev) ||
|
||||||
|
user.username === 'agentic'
|
||||||
|
)
|
||||||
|
|
||||||
const [project] = await db
|
const [project] = await db
|
||||||
.insert(schema.projects)
|
.insert(schema.projects)
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { sha256 } from '@agentic/platform-core'
|
import { sha256 } from '@agentic/platform-core'
|
||||||
|
|
||||||
export async function createConsumerToken(): Promise<string> {
|
export async function createConsumerToken(): Promise<string> {
|
||||||
const hash = await sha256()
|
return sha256()
|
||||||
|
|
||||||
return hash.slice(0, 24)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
import { DemandSideCTA } from '@/components/demand-side-cta'
|
import { DemandSideCTA } from '@/components/demand-side-cta'
|
||||||
|
import { ExampleUsage } from '@/components/example-usage'
|
||||||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||||
import { githubUrl, twitterUrl } from '@/lib/config'
|
import { githubUrl, twitterUrl } from '@/lib/config'
|
||||||
|
|
||||||
import { ExampleUsage } from './example-usage'
|
|
||||||
|
|
||||||
export default function TheBestDamnLandingPageEver() {
|
export default function TheBestDamnLandingPageEver() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
|
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
|
||||||
import { Fragment, type JSX, useEffect, useState } from 'react'
|
import { CheckIcon, CopyIcon } from 'lucide-react'
|
||||||
|
import {
|
||||||
|
Fragment,
|
||||||
|
type JSX,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react'
|
||||||
import { jsx, jsxs } from 'react/jsx-runtime'
|
import { jsx, jsxs } from 'react/jsx-runtime'
|
||||||
import { type BundledLanguage, codeToHast } from 'shiki/bundle/web'
|
import { type BundledLanguage, codeToHast } from 'shiki/bundle/web'
|
||||||
|
|
||||||
|
import { toastError } from '@/lib/notifications'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
import { LoadingIndicator } from './loading-indicator'
|
import { LoadingIndicator } from './loading-indicator'
|
||||||
|
import { Button } from './ui/button'
|
||||||
|
|
||||||
export async function highlight({
|
export async function highlight({
|
||||||
code,
|
code,
|
||||||
|
@ -51,10 +63,62 @@ export function CodeBlock({
|
||||||
className?: string
|
className?: string
|
||||||
}) {
|
}) {
|
||||||
const [nodes, setNodes] = useState(initial)
|
const [nodes, setNodes] = useState(initial)
|
||||||
|
const [isCopied, setIsCopied] = useState(false)
|
||||||
|
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void highlight({ code, lang, theme, className }).then(setNodes)
|
void highlight({
|
||||||
}, [code, lang, theme, className])
|
code,
|
||||||
|
lang,
|
||||||
|
theme,
|
||||||
|
className: 'rounded-sm w-full text-wrap p-4 text-sm'
|
||||||
|
}).then(setNodes)
|
||||||
|
}, [code, lang, theme])
|
||||||
|
|
||||||
return nodes ?? <LoadingIndicator />
|
const onCopy = useCallback(() => {
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(code)
|
||||||
|
setIsCopied(true)
|
||||||
|
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current)
|
||||||
|
timeoutRef.current = null
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
timeoutRef.current = null
|
||||||
|
setIsCopied(false)
|
||||||
|
}, 2000)
|
||||||
|
} catch {
|
||||||
|
setIsCopied(true)
|
||||||
|
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current)
|
||||||
|
timeoutRef.current = null
|
||||||
|
}
|
||||||
|
void toastError('Error copying code to clipboard')
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [code, timeoutRef])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('relative group rounded-sm w-full', className)}>
|
||||||
|
{nodes ? (
|
||||||
|
<>
|
||||||
|
{nodes}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant='outline'
|
||||||
|
className='absolute top-4 right-4 px-2.5! opacity-0 group-hover:opacity-100 group-hover:duration-0 transition-opacity duration-150'
|
||||||
|
onClick={onCopy}
|
||||||
|
>
|
||||||
|
{isCopied ? <CheckIcon /> : <CopyIcon />}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<LoadingIndicator />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
import { useLocalStorage } from 'react-use'
|
import { useLocalStorage } from 'react-use'
|
||||||
|
|
||||||
|
import { useAgentic } from '@/components/agentic-provider'
|
||||||
import { CodeBlock } from '@/components/code-block'
|
import { CodeBlock } from '@/components/code-block'
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
import {
|
import {
|
||||||
defaultConfig,
|
defaultConfig,
|
||||||
type DeveloperConfig,
|
type DeveloperConfig,
|
||||||
|
getCodeForDeveloperConfig,
|
||||||
type HTTPTarget,
|
type HTTPTarget,
|
||||||
httpTargetLabels,
|
httpTargetLabels,
|
||||||
httpTargets,
|
httpTargets,
|
||||||
|
@ -23,16 +25,85 @@ import {
|
||||||
tsFrameworkTargetLabels,
|
tsFrameworkTargetLabels,
|
||||||
tsFrameworkTargets
|
tsFrameworkTargets
|
||||||
} from '@/lib/developer-config'
|
} from '@/lib/developer-config'
|
||||||
|
import { useQuery } from '@/lib/query-client'
|
||||||
|
|
||||||
|
import { LoadingIndicator } from './loading-indicator'
|
||||||
|
|
||||||
export function ExampleUsage() {
|
export function ExampleUsage() {
|
||||||
|
const ctx = useAgentic()
|
||||||
|
|
||||||
const [config, setConfig] = useLocalStorage<DeveloperConfig>(
|
const [config, setConfig] = useLocalStorage<DeveloperConfig>(
|
||||||
'config',
|
'config',
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: make this configurable
|
||||||
|
// TODO: allow to take the project and/or consumer in as props
|
||||||
|
// TODO: need a way of fetching a project and target deployment; same as in `AgenticToolClient.fromIdentifier` (currently only supports latest)
|
||||||
|
const projectIdentifier = '@agentic/search'
|
||||||
|
|
||||||
|
// Load the public project
|
||||||
|
const {
|
||||||
|
data: project,
|
||||||
|
isLoading,
|
||||||
|
isError
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ['project', projectIdentifier],
|
||||||
|
queryFn: () =>
|
||||||
|
ctx!.api.getPublicProjectByIdentifier({
|
||||||
|
projectIdentifier,
|
||||||
|
populate: ['lastPublishedDeployment']
|
||||||
|
}),
|
||||||
|
enabled: !!ctx
|
||||||
|
})
|
||||||
|
|
||||||
|
// If the user is authenticated, check if they have an active subscription to
|
||||||
|
// this project
|
||||||
|
// TODO: use consumer for apiKey
|
||||||
|
// const {
|
||||||
|
// data: consumer,
|
||||||
|
// isLoading: isConsumerLoading
|
||||||
|
// // isError: isConsumerError
|
||||||
|
// } = useQuery({
|
||||||
|
// queryKey: [
|
||||||
|
// 'project',
|
||||||
|
// projectIdentifier,
|
||||||
|
// 'user',
|
||||||
|
// ctx?.api.authSession?.user.id
|
||||||
|
// ],
|
||||||
|
// queryFn: () =>
|
||||||
|
// ctx!.api.getConsumerByProjectIdentifier({
|
||||||
|
// projectIdentifier
|
||||||
|
// }),
|
||||||
|
// enabled: !!ctx?.isAuthenticated
|
||||||
|
// })
|
||||||
|
|
||||||
|
if (isLoading || !config) {
|
||||||
|
return <LoadingIndicator className='w-full max-w-3xl' />
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: allow to target a specific deployment
|
||||||
|
const deployment = project?.lastPublishedDeployment
|
||||||
|
|
||||||
|
if (isError || !project || !deployment) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Error loading project. Please refresh the page or contact{' '}
|
||||||
|
<a href='mailto:support@agentic.so'>support@agentic.so</a>.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeSnippet = getCodeForDeveloperConfig({
|
||||||
|
config,
|
||||||
|
project,
|
||||||
|
deployment,
|
||||||
|
identifier: projectIdentifier
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={config!.target}
|
defaultValue={config.target}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setConfig({
|
setConfig({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
|
@ -40,7 +111,7 @@ export function ExampleUsage() {
|
||||||
target: value as Target
|
target: value as Target
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className='w-full max-w-2xl'
|
className='w-full max-w-3xl'
|
||||||
>
|
>
|
||||||
<TabsList>
|
<TabsList>
|
||||||
{targets.map((target) => (
|
{targets.map((target) => (
|
||||||
|
@ -52,7 +123,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
<TabsContent value='mcp' className='w-full'>
|
<TabsContent value='mcp' className='w-full'>
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={config!.mcpClientTarget}
|
defaultValue={config.mcpClientTarget}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setConfig({
|
setConfig({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
|
@ -80,11 +151,7 @@ export function ExampleUsage() {
|
||||||
value={mcpClientTarget}
|
value={mcpClientTarget}
|
||||||
className='w-full'
|
className='w-full'
|
||||||
>
|
>
|
||||||
<CodeBlock
|
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
|
||||||
code={JSON.stringify(config, null, 2)}
|
|
||||||
lang='json'
|
|
||||||
className='p-4 rounded-sm w-full'
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -92,7 +159,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
<TabsContent value='typescript' className='w-full'>
|
<TabsContent value='typescript' className='w-full'>
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={config!.tsFrameworkTarget ?? 'ai'}
|
defaultValue={config.tsFrameworkTarget ?? 'ai'}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setConfig({
|
setConfig({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
|
@ -102,12 +169,12 @@ export function ExampleUsage() {
|
||||||
}
|
}
|
||||||
className='w-full'
|
className='w-full'
|
||||||
>
|
>
|
||||||
<TabsList className='h-auto flex-wrap'>
|
<TabsList className='w-full h-auto flex-wrap'>
|
||||||
{tsFrameworkTargets.map((framework) => (
|
{tsFrameworkTargets.map((framework) => (
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
key={framework}
|
key={framework}
|
||||||
value={framework}
|
value={framework}
|
||||||
className='cursor-pointer'
|
className='cursor-pointer text-xs!'
|
||||||
>
|
>
|
||||||
{tsFrameworkTargetLabels[framework]}
|
{tsFrameworkTargetLabels[framework]}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
|
@ -116,11 +183,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
{tsFrameworkTargets.map((framework) => (
|
{tsFrameworkTargets.map((framework) => (
|
||||||
<TabsContent key={framework} value={framework} className='w-full'>
|
<TabsContent key={framework} value={framework} className='w-full'>
|
||||||
<CodeBlock
|
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
|
||||||
code={JSON.stringify(config, null, 2)}
|
|
||||||
lang='ts'
|
|
||||||
className='p-4 rounded-sm w-full'
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -128,7 +191,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
<TabsContent value='python' className='w-full'>
|
<TabsContent value='python' className='w-full'>
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={config!.pyFrameworkTarget}
|
defaultValue={config.pyFrameworkTarget}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setConfig({
|
setConfig({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
|
@ -152,11 +215,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
{pyFrameworkTargets.map((framework) => (
|
{pyFrameworkTargets.map((framework) => (
|
||||||
<TabsContent key={framework} value={framework} className='w-full'>
|
<TabsContent key={framework} value={framework} className='w-full'>
|
||||||
<CodeBlock
|
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
|
||||||
code={JSON.stringify(config, null, 2)}
|
|
||||||
lang='py'
|
|
||||||
className='p-4 rounded-sm w-full'
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -164,7 +223,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
<TabsContent value='http' className='w-full'>
|
<TabsContent value='http' className='w-full'>
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={config!.httpTarget}
|
defaultValue={config.httpTarget}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setConfig({
|
setConfig({
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
|
@ -188,11 +247,7 @@ export function ExampleUsage() {
|
||||||
|
|
||||||
{httpTargets.map((httpTarget) => (
|
{httpTargets.map((httpTarget) => (
|
||||||
<TabsContent key={httpTarget} value={httpTarget} className='w-full'>
|
<TabsContent key={httpTarget} value={httpTarget} className='w-full'>
|
||||||
<CodeBlock
|
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
|
||||||
code={JSON.stringify(config, null, 2)}
|
|
||||||
lang='bash'
|
|
||||||
className='p-4 rounded-sm w-full'
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
|
@ -5,6 +5,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fill {
|
.fill {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Deployment, Project } from '@agentic/platform-types'
|
import type { Deployment, Project } from '@agentic/platform-types'
|
||||||
|
import type { BundledLanguage } from 'shiki/bundle/web'
|
||||||
import { assert } from '@agentic/platform-core'
|
import { assert } from '@agentic/platform-core'
|
||||||
|
|
||||||
import { gatewayBaseUrl } from './config'
|
import { gatewayBaseUrl } from './config'
|
||||||
|
@ -24,7 +25,7 @@ export const httpTargets: (keyof typeof httpTargetLabels)[] = Object.keys(
|
||||||
export type HTTPTarget = (typeof httpTargets)[number]
|
export type HTTPTarget = (typeof httpTargets)[number]
|
||||||
|
|
||||||
export const mcpClientTargetLabels = {
|
export const mcpClientTargetLabels = {
|
||||||
any: 'Any MCP Client',
|
url: 'MCP Server URL',
|
||||||
'claude-desktop': 'Claude Desktop',
|
'claude-desktop': 'Claude Desktop',
|
||||||
raycast: 'Raycast',
|
raycast: 'Raycast',
|
||||||
cursor: 'Cursor',
|
cursor: 'Cursor',
|
||||||
|
@ -41,8 +42,8 @@ export const tsFrameworkTargetLabels = {
|
||||||
'openai-chat': 'OpenAI Chat',
|
'openai-chat': 'OpenAI Chat',
|
||||||
'openai-responses': 'OpenAI Responses',
|
'openai-responses': 'OpenAI Responses',
|
||||||
langchain: 'LangChain',
|
langchain: 'LangChain',
|
||||||
mastra: 'Mastra',
|
|
||||||
llamaindex: 'LlamaIndex',
|
llamaindex: 'LlamaIndex',
|
||||||
|
mastra: 'Mastra',
|
||||||
'firebase-genkit': 'Firebase GenKit',
|
'firebase-genkit': 'Firebase GenKit',
|
||||||
xsai: 'xsAI'
|
xsai: 'xsAI'
|
||||||
} as const
|
} as const
|
||||||
|
@ -69,19 +70,25 @@ export type DeveloperConfig = {
|
||||||
|
|
||||||
export const defaultConfig: DeveloperConfig = {
|
export const defaultConfig: DeveloperConfig = {
|
||||||
target: 'typescript',
|
target: 'typescript',
|
||||||
mcpClientTarget: 'any',
|
mcpClientTarget: 'url',
|
||||||
tsFrameworkTarget: 'ai',
|
tsFrameworkTarget: 'ai',
|
||||||
pyFrameworkTarget: 'openai',
|
pyFrameworkTarget: 'openai',
|
||||||
httpTarget: 'curl'
|
httpTarget: 'curl'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CodeSnippet = {
|
||||||
|
code: string
|
||||||
|
lang: BundledLanguage
|
||||||
|
// install?: string // TODO
|
||||||
|
}
|
||||||
|
|
||||||
export function getCodeForDeveloperConfig(opts: {
|
export function getCodeForDeveloperConfig(opts: {
|
||||||
config: DeveloperConfig
|
config: DeveloperConfig
|
||||||
project: Project
|
project: Project
|
||||||
deployment: Deployment
|
deployment: Deployment
|
||||||
identifier: string
|
identifier: string
|
||||||
tool?: string
|
tool?: string
|
||||||
}): string {
|
}): CodeSnippet {
|
||||||
const { config } = opts
|
const { config } = opts
|
||||||
|
|
||||||
switch (config.target) {
|
switch (config.target) {
|
||||||
|
@ -90,8 +97,7 @@ export function getCodeForDeveloperConfig(opts: {
|
||||||
case 'typescript':
|
case 'typescript':
|
||||||
return getCodeForTSFrameworkConfig(opts)
|
return getCodeForTSFrameworkConfig(opts)
|
||||||
case 'python':
|
case 'python':
|
||||||
return 'Python support is coming soon...'
|
return getCodeForPythonFrameworkConfig(opts)
|
||||||
// return getCodeForPythonFrameworkConfig(opts)
|
|
||||||
case 'http':
|
case 'http':
|
||||||
return getCodeForHTTPConfig(opts)
|
return getCodeForHTTPConfig(opts)
|
||||||
}
|
}
|
||||||
|
@ -101,21 +107,27 @@ export function getCodeForMCPClientConfig({
|
||||||
identifier
|
identifier
|
||||||
}: {
|
}: {
|
||||||
identifier: string
|
identifier: string
|
||||||
}): string {
|
}): CodeSnippet {
|
||||||
return `${gatewayBaseUrl}/${identifier}/mcp`
|
return {
|
||||||
|
code: `${gatewayBaseUrl}/${identifier}/mcp`,
|
||||||
|
lang: 'bash'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCodeForTSFrameworkConfig({
|
export function getCodeForTSFrameworkConfig({
|
||||||
config,
|
config,
|
||||||
identifier
|
identifier,
|
||||||
|
prompt = 'What is the latest news about AI?'
|
||||||
}: {
|
}: {
|
||||||
config: DeveloperConfig
|
config: DeveloperConfig
|
||||||
identifier: string
|
identifier: string
|
||||||
}): string {
|
prompt?: string
|
||||||
|
}): CodeSnippet {
|
||||||
switch (config.tsFrameworkTarget) {
|
switch (config.tsFrameworkTarget) {
|
||||||
case 'ai':
|
case 'ai':
|
||||||
return `
|
return {
|
||||||
import { createAISDKTools } from '@agentic/ai'
|
code: `
|
||||||
|
import { createAISDKTools } from '@agentic/ai-sdk'
|
||||||
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
import { openai } from '@ai-sdk/openai'
|
import { openai } from '@ai-sdk/openai'
|
||||||
import { generateText } from 'ai'
|
import { generateText } from 'ai'
|
||||||
|
@ -126,66 +138,221 @@ const result = await generateText({
|
||||||
model: openai('gpt-4o-mini'),
|
model: openai('gpt-4o-mini'),
|
||||||
tools: createAISDKTools(searchTool),
|
tools: createAISDKTools(searchTool),
|
||||||
toolChoice: 'required',
|
toolChoice: 'required',
|
||||||
temperature: 0,
|
prompt: '${prompt}'
|
||||||
system: 'You are a helpful assistant. Be as concise as possible.',
|
|
||||||
prompt: 'What is the latest news about AI?'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(result.toolResults[0])
|
console.log(result.toolResults[0])
|
||||||
`.trim()
|
`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
case 'openai-chat':
|
case 'openai-chat':
|
||||||
return `
|
return {
|
||||||
|
code: `
|
||||||
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
import OpenAI from 'openai'
|
import OpenAI from 'openai'
|
||||||
|
|
||||||
const openai = new OpenAI()
|
const openai = new OpenAI()
|
||||||
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
// This example uses OpenAI's Chat Completions API
|
||||||
const res = await openai.chat.completions.create({
|
const res = await openai.chat.completions.create({
|
||||||
|
model: 'gpt-4o-mini',
|
||||||
messages: [
|
messages: [
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content: 'You are a helpful assistant. Be as concise as possible.'
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: 'What is the latest news about AI?'
|
content: '${prompt}'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
model: 'gpt-4o-mini',
|
|
||||||
temperature: 0,
|
|
||||||
tools: searchTool.functions.toolSpecs,
|
tools: searchTool.functions.toolSpecs,
|
||||||
tool_choice: 'required'
|
tool_choice: 'required'
|
||||||
})
|
})
|
||||||
|
|
||||||
const message = res.choices[0]!.message!
|
const message = res.choices[0]!.message!
|
||||||
const toolCall = message.tool_calls![0]!
|
const toolCall = message.tool_calls![0]!.function!
|
||||||
|
const toolResult = await searchTool.callTool(toolCall.name, toolCall.arguments)
|
||||||
const tool = searchTool.functions.get(toolCall.function.name)!
|
|
||||||
const toolResult = await tool(toolCall.function.arguments)
|
|
||||||
|
|
||||||
console.log(toolResult)
|
console.log(toolResult)
|
||||||
`.trim()
|
`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
case 'openai-responses':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import OpenAI from 'openai'
|
||||||
|
|
||||||
|
const openai = new OpenAI()
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
// This example uses OpenAI's newer Responses API
|
||||||
|
const res = await openai.responses.create({
|
||||||
|
model: 'gpt-4o-mini',
|
||||||
|
tools: searchTool.functions.responsesToolSpecs,
|
||||||
|
tool_choice: 'required',
|
||||||
|
input: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: '${prompt}'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const toolCall = res.output[0]
|
||||||
|
const toolResult = await searchTool.callTool(toolCall.name, toolCall.arguments)
|
||||||
|
|
||||||
|
console.log(toolResult)
|
||||||
|
`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'langchain':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { createLangChainTools } from '@agentic/langchain'
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import { ChatPromptTemplate } from '@langchain/core/prompts'
|
||||||
|
import { ChatOpenAI } from '@langchain/openai'
|
||||||
|
import { AgentExecutor, createToolCallingAgent } from 'langchain/agents'
|
||||||
|
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
const agent = createToolCallingAgent({
|
||||||
|
llm: new ChatOpenAI({ model: 'gpt-4o-mini' }),
|
||||||
|
tools: createLangChainTools(searchTool),
|
||||||
|
prompt: ChatPromptTemplate.fromMessages([
|
||||||
|
['placeholder', '{chat_history}'],
|
||||||
|
['human', '{input}'],
|
||||||
|
['placeholder', '{agent_scratchpad}']
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
const agentExecutor = new AgentExecutor({ agent, tools })
|
||||||
|
|
||||||
|
const result = await agentExecutor.invoke({
|
||||||
|
input: '${prompt}'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(result.output)
|
||||||
|
`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'llamaindex':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { createLlamaIndexTools } from '@agentic/llamaindex'
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import { openai } from '@llamaindex/openai'
|
||||||
|
import { agent } from '@llamaindex/workflow'
|
||||||
|
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
const exampleAgent = agent({
|
||||||
|
llm: openai({ model: 'gpt-4o-mini', temperature: 0 }),
|
||||||
|
tools: createLlamaIndexTools(searchTool)
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await exampleAgent.run(
|
||||||
|
'${prompt}'
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(response.data.result)
|
||||||
|
`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'mastra':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { createMastraTools } from '@agentic/mastra'
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import { openai } from '@ai-sdk/openai'
|
||||||
|
import { Agent } from '@mastra/core/agent'
|
||||||
|
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
const exampleAgent = new Agent({
|
||||||
|
name: 'Example Agent',
|
||||||
|
model: openai('gpt-4o-mini') as any,
|
||||||
|
instructions: 'You are a helpful assistant. Be as concise as possible.',
|
||||||
|
tools: createMastraTools(searchTool)
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await exampleAgent.generate(
|
||||||
|
'${prompt}'
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(res.text)`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'firebase-genkit':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { createGenkitTools } from '@agentic/genkit'
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import { genkit } from 'genkit'
|
||||||
|
import { gpt4oMini, openAI } from 'genkitx-openai'
|
||||||
|
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
const ai = genkit({
|
||||||
|
plugins: [openAI()]
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await ai.generate({
|
||||||
|
model: gpt4oMini,
|
||||||
|
tools: createGenkitTools(ai, searchTool),
|
||||||
|
prompt: '${prompt}'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(result)`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'xsai':
|
||||||
|
return {
|
||||||
|
code: `
|
||||||
|
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||||
|
import { createXSAITools } from '@agentic/xsai'
|
||||||
|
import { generateText } from 'xsai'
|
||||||
|
|
||||||
|
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||||
|
|
||||||
|
const result = await generateText({
|
||||||
|
apiKey: process.env.OPENAI_API_KEY!,
|
||||||
|
baseURL: 'https://api.openai.com/v1/',
|
||||||
|
model: 'gpt-4o-mini',
|
||||||
|
tools: await createXSAITools(searchTool),
|
||||||
|
toolChoice: 'required',
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: '${prompt}'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(JSON.stringify(result, null, 2))`.trim(),
|
||||||
|
lang: 'ts'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export function getCodeForPythonFrameworkConfig({
|
export function getCodeForPythonFrameworkConfig(_opts: {
|
||||||
// config,
|
config: DeveloperConfig
|
||||||
// project,
|
project: Project
|
||||||
// deployment,
|
deployment: Deployment
|
||||||
// tool
|
identifier: string
|
||||||
// }: {
|
tool?: string
|
||||||
// config: DeveloperConfig
|
}): CodeSnippet {
|
||||||
// project: Project
|
return {
|
||||||
// deployment: Deployment
|
code: 'Python SDK is coming soon. For now, use the MCP or HTTP examples',
|
||||||
// identifier: string
|
lang: 'md'
|
||||||
// tool?: string
|
}
|
||||||
// }): string {
|
}
|
||||||
// return ''
|
|
||||||
// }
|
|
||||||
|
|
||||||
export function getCodeForHTTPConfig({
|
export function getCodeForHTTPConfig({
|
||||||
config,
|
config,
|
||||||
|
@ -197,7 +364,7 @@ export function getCodeForHTTPConfig({
|
||||||
deployment: Deployment
|
deployment: Deployment
|
||||||
identifier: string
|
identifier: string
|
||||||
tool?: string
|
tool?: string
|
||||||
}): string {
|
}): CodeSnippet {
|
||||||
tool ??= deployment.tools[0]?.name
|
tool ??= deployment.tools[0]?.name
|
||||||
assert(tool, 'tool is required')
|
assert(tool, 'tool is required')
|
||||||
// TODO: need a way of getting example tool args
|
// TODO: need a way of getting example tool args
|
||||||
|
@ -206,9 +373,15 @@ export function getCodeForHTTPConfig({
|
||||||
|
|
||||||
switch (config.httpTarget) {
|
switch (config.httpTarget) {
|
||||||
case 'curl':
|
case 'curl':
|
||||||
return `curl -X POST -H "Content-Type: application/json" -d '{"query": "example google search"}' ${url}`
|
return {
|
||||||
|
code: `curl -X POST -H "Content-Type: application/json" -d '{"query": "example google search"}' ${url}`,
|
||||||
|
lang: 'bash'
|
||||||
|
}
|
||||||
|
|
||||||
case 'httpie':
|
case 'httpie':
|
||||||
return `http -j ${url} query='example google search'`
|
return {
|
||||||
|
code: `http -j ${url} query='example google search'`,
|
||||||
|
lang: 'bash'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,12 @@ export class AgenticToolClient extends AIFunctionsProvider {
|
||||||
return this._functions
|
return this._functions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async callTool(toolName: string, args: string | Record<string, any>) {
|
||||||
|
const tool = this.functions.get(toolName)
|
||||||
|
assert(tool, `Tool "${toolName}" not found`)
|
||||||
|
return tool(typeof args === 'string' ? args : JSON.stringify(args))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an Agentic tool client from a project or deployment identifier.
|
* Creates an Agentic tool client from a project or deployment identifier.
|
||||||
*
|
*
|
||||||
|
@ -84,8 +90,6 @@ export class AgenticToolClient extends AIFunctionsProvider {
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* const searchTool = await AgenticToolClient.fromIdentifier('@agentic/search')
|
* const searchTool = await AgenticToolClient.fromIdentifier('@agentic/search')
|
||||||
* const searchToolV1 = await AgenticToolClient.fromIdentifier('@agentic/search@v1.0.0')
|
|
||||||
* const searchToolLatest = await AgenticToolClient.fromIdentifier('@agentic/search@latest')
|
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static async fromIdentifier(
|
static async fromIdentifier(
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
- consider using [neon serverless driver](https://orm.drizzle.team/docs/connect-neon) for production
|
- consider using [neon serverless driver](https://orm.drizzle.team/docs/connect-neon) for production
|
||||||
- can this also be used locally?
|
- can this also be used locally?
|
||||||
- may need to update our `drizzle-orm` fork
|
- may need to update our `drizzle-orm` fork
|
||||||
|
- simplify `AgenticToolClient` and only require one package per TS LLM SDK
|
||||||
|
- `createAISDKToolsFromIdentifier(projectIdentifier)`
|
||||||
|
|
||||||
## TODO: Post-MVP
|
## TODO: Post-MVP
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue