kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add tool-client and search example; refactor e2e
rodzic
e388bcee46
commit
cf4a404fd0
|
@ -14,7 +14,8 @@ import {
|
|||
import { deploymentIdentifierAndPopulateSchema } from './schemas'
|
||||
|
||||
const route = createRoute({
|
||||
description: 'Gets a deployment by its public identifier',
|
||||
description:
|
||||
'Gets a deployment by its identifier (eg, "@username/project-name@latest").',
|
||||
tags: ['deployments'],
|
||||
operationId: 'getDeploymentByIdentifier',
|
||||
method: 'get',
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import type { DefaultHonoEnv } from '@agentic/platform-hono'
|
||||
import { assert, parseZodSchema } from '@agentic/platform-core'
|
||||
import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
|
||||
|
||||
import { schema } from '@/db'
|
||||
import { aclPublicProject } from '@/lib/acl-public-project'
|
||||
import { tryGetDeploymentByIdentifier } from '@/lib/deployments/try-get-deployment-by-identifier'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponse404,
|
||||
openapiErrorResponses
|
||||
} from '@/lib/openapi-utils'
|
||||
|
||||
import { deploymentIdentifierAndPopulateSchema } from './schemas'
|
||||
|
||||
const route = createRoute({
|
||||
description:
|
||||
'Gets a public deployment by its identifier (eg, "@username/project-name@latest").',
|
||||
tags: ['deployments'],
|
||||
operationId: 'getPublicDeploymentByIdentifier',
|
||||
method: 'get',
|
||||
path: 'deployments/public/by-identifier',
|
||||
security: openapiAuthenticatedSecuritySchemas,
|
||||
request: {
|
||||
query: deploymentIdentifierAndPopulateSchema
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'A deployment object',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: schema.deploymentSelectSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
...openapiErrorResponses,
|
||||
...openapiErrorResponse404
|
||||
}
|
||||
})
|
||||
|
||||
export function registerV1GetPublicDeploymentByIdentifier(
|
||||
app: OpenAPIHono<DefaultHonoEnv>
|
||||
) {
|
||||
return app.openapi(route, async (c) => {
|
||||
const { deploymentIdentifier, populate = [] } = c.req.valid('query')
|
||||
|
||||
const deployment = await tryGetDeploymentByIdentifier(c, {
|
||||
deploymentIdentifier,
|
||||
with: {
|
||||
project: true,
|
||||
...Object.fromEntries(populate.map((field) => [field, true]))
|
||||
}
|
||||
})
|
||||
assert(deployment, 404, `Deployment not found "${deploymentIdentifier}"`)
|
||||
assert(
|
||||
deployment.project,
|
||||
404,
|
||||
`Project not found for deployment "${deploymentIdentifier}"`
|
||||
)
|
||||
await aclPublicProject(deployment.project!)
|
||||
|
||||
return c.json(parseZodSchema(schema.deploymentSelectSchema, deployment))
|
||||
})
|
||||
}
|
|
@ -27,6 +27,7 @@ import { registerV1AdminGetDeploymentByIdentifier } from './deployments/admin-ge
|
|||
import { registerV1CreateDeployment } from './deployments/create-deployment'
|
||||
import { registerV1GetDeployment } from './deployments/get-deployment'
|
||||
import { registerV1GetDeploymentByIdentifier } from './deployments/get-deployment-by-identifier'
|
||||
import { registerV1GetPublicDeploymentByIdentifier } from './deployments/get-public-deployment-by-identifier'
|
||||
import { registerV1ListDeployments } from './deployments/list-deployments'
|
||||
import { registerV1PublishDeployment } from './deployments/publish-deployment'
|
||||
import { registerV1UpdateDeployment } from './deployments/update-deployment'
|
||||
|
@ -133,6 +134,7 @@ registerV1ListConsumers(privateRouter)
|
|||
registerV1ListConsumersForProject(privateRouter)
|
||||
|
||||
// Deployments
|
||||
registerV1GetPublicDeploymentByIdentifier(publicRouter)
|
||||
registerV1GetDeploymentByIdentifier(privateRouter) // must be before `registerV1GetDeployment`
|
||||
registerV1GetDeployment(privateRouter)
|
||||
registerV1CreateDeployment(privateRouter)
|
||||
|
|
|
@ -248,9 +248,23 @@ export const projectSelectSchema = createSelectSchema(projects, {
|
|||
return deploymentSelectSchema.parse(deployment)
|
||||
})
|
||||
.optional(),
|
||||
// .openapi('Deployment', { type: 'object' }),
|
||||
|
||||
lastDeployment: z
|
||||
.any()
|
||||
.refine(
|
||||
(deployment): boolean =>
|
||||
!deployment || deploymentSelectSchema.safeParse(deployment).success,
|
||||
{
|
||||
message: 'Invalid lastDeployment'
|
||||
}
|
||||
)
|
||||
.transform((deployment): any => {
|
||||
if (!deployment) return undefined
|
||||
return deploymentSelectSchema.parse(deployment)
|
||||
})
|
||||
.optional(),
|
||||
|
||||
deployment: z
|
||||
.any()
|
||||
.refine(
|
||||
(deployment): boolean =>
|
||||
|
@ -264,7 +278,6 @@ export const projectSelectSchema = createSelectSchema(projects, {
|
|||
return deploymentSelectSchema.parse(deployment)
|
||||
})
|
||||
.optional()
|
||||
// .openapi('Deployment', { type: 'object' })
|
||||
})
|
||||
.strip()
|
||||
// TODO
|
||||
|
|
|
@ -28,9 +28,11 @@ export const users = pgTable(
|
|||
username: username().unique().notNull(),
|
||||
role: userRoleEnum().default('user').notNull(),
|
||||
|
||||
name: text(),
|
||||
email: text().notNull().unique(),
|
||||
isEmailVerified: boolean().default(false).notNull(),
|
||||
|
||||
name: text(),
|
||||
bio: text(),
|
||||
image: text(),
|
||||
|
||||
//isStripeConnectEnabledByDefault: boolean().default(true).notNull(),
|
||||
|
@ -57,6 +59,7 @@ export const userSelectSchema = createSelectSchema(users)
|
|||
export const userUpdateSchema = createUpdateSchema(users)
|
||||
.pick({
|
||||
name: true,
|
||||
bio: true,
|
||||
image: true
|
||||
//isStripeConnectEnabledByDefault: true
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { DefaultHonoContext } from '@agentic/platform-hono'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
import { parseDeploymentIdentifier } from '@agentic/platform-validators'
|
||||
|
||||
import type { AuthenticatedHonoContext } from '@/lib/types'
|
||||
import {
|
||||
and,
|
||||
db,
|
||||
|
@ -12,6 +12,8 @@ import {
|
|||
} from '@/db'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
|
||||
import type { AuthenticatedHonoContext } from '../types'
|
||||
|
||||
/**
|
||||
* Attempts to find the Deployment matching the given deployment ID or
|
||||
* identifier.
|
||||
|
@ -21,7 +23,7 @@ import { setPublicCacheControl } from '@/lib/cache-control'
|
|||
* Does not take care of ACLs.
|
||||
*/
|
||||
export async function tryGetDeploymentByIdentifier(
|
||||
ctx: AuthenticatedHonoContext,
|
||||
ctx: AuthenticatedHonoContext | DefaultHonoContext,
|
||||
{
|
||||
deploymentIdentifier,
|
||||
strict = false,
|
||||
|
|
|
@ -13,3 +13,6 @@ AGENTIC_GATEWAY_BASE_URL='http://localhost:8787'
|
|||
AGENTIC_DEV_EMAIL=
|
||||
AGENTIC_DEV_PASSWORD=
|
||||
AGENTIC_DEV_ACCESS_TOKEN=
|
||||
|
||||
AGENTIC_AGENTIC_EMAIL=
|
||||
AGENTIC_AGENTIC_PASSWORD=
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { deployFixtures } from '../src/project-fixtures'
|
||||
import { deployProjects } from '../src/deploy-projects'
|
||||
import { devClient } from '../src/dev-client'
|
||||
import { fixtures } from '../src/dev-fixtures'
|
||||
|
||||
async function main() {
|
||||
console.log('\n\nDeploying fixtures...\n\n')
|
||||
console.log('\n\nDeploying dev fixtures...\n\n')
|
||||
|
||||
const deployments = await deployFixtures()
|
||||
const deployments = await deployProjects(fixtures, { client: devClient })
|
||||
console.log(JSON.stringify(deployments, null, 2))
|
||||
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import { deployFixtures, publishDeployments } from '../src/project-fixtures'
|
||||
import { deployProjects } from '../src/deploy-projects'
|
||||
import { devClient } from '../src/dev-client'
|
||||
import { fixtures } from '../src/dev-fixtures'
|
||||
import { publishDeployments } from '../src/publish-deployments'
|
||||
|
||||
async function main() {
|
||||
console.log('\n\nDeploying fixtures...\n\n')
|
||||
console.log('\n\nDeploying dev fixtures...\n\n')
|
||||
|
||||
const deployments = await deployFixtures()
|
||||
const deployments = await deployProjects(fixtures, { client: devClient })
|
||||
console.log(JSON.stringify(deployments, null, 2))
|
||||
|
||||
console.log('\n\nPublishing deployments...\n\n')
|
||||
console.log('\n\nPublishing dev fixture deployments...\n\n')
|
||||
|
||||
const publishedDeployments = await publishDeployments(deployments)
|
||||
const publishedDeployments = await publishDeployments(deployments, {
|
||||
client: devClient
|
||||
})
|
||||
console.log(JSON.stringify(publishedDeployments, null, 2))
|
||||
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { AgenticApiClient } from '@agentic/platform-api-client'
|
||||
|
||||
import { examples } from '../src/agentic-examples'
|
||||
import { deployProjects } from '../src/deploy-projects'
|
||||
import { fixtures } from '../src/dev-fixtures'
|
||||
import { env, isProd } from '../src/env'
|
||||
import { deployFixtures, publishDeployments } from '../src/project-fixtures'
|
||||
import { publishDeployments } from '../src/publish-deployments'
|
||||
|
||||
export const client = new AgenticApiClient({
|
||||
apiBaseUrl: env.AGENTIC_API_BASE_URL
|
||||
|
@ -10,28 +13,55 @@ export const client = new AgenticApiClient({
|
|||
async function main() {
|
||||
// TODO: clear existing tables? and include prompt to double check if so...
|
||||
|
||||
console.log('\n\nCreating dev user...\n\n')
|
||||
{
|
||||
console.log('\n\nCreating "dev" user...\n\n')
|
||||
|
||||
const devAuthSession = await client.signUpWithPassword({
|
||||
username: 'dev',
|
||||
email: env.AGENTIC_DEV_EMAIL,
|
||||
password: env.AGENTIC_DEV_PASSWORD
|
||||
})
|
||||
console.log(JSON.stringify(devAuthSession, null, 2))
|
||||
const devAuthSession = await client.signUpWithPassword({
|
||||
username: 'dev',
|
||||
email: env.AGENTIC_DEV_EMAIL,
|
||||
password: env.AGENTIC_DEV_PASSWORD
|
||||
})
|
||||
console.log(JSON.stringify(devAuthSession, null, 2))
|
||||
|
||||
console.warn(
|
||||
`\n\nREMEMBER TO UPDATE "AGENTIC_DEV_ACCESS_TOKEN" in e2e/.env${isProd ? '.production' : ''}\n\n`
|
||||
)
|
||||
console.warn(
|
||||
`\n\nREMEMBER TO UPDATE "AGENTIC_DEV_ACCESS_TOKEN" in e2e/.env${isProd ? '.production' : ''}\n\n`
|
||||
)
|
||||
|
||||
console.log('\n\nDeploying fixtures...\n\n')
|
||||
console.log('\n\nDeploying dev fixtures...\n\n')
|
||||
|
||||
const deployments = await deployFixtures()
|
||||
console.log(JSON.stringify(deployments, null, 2))
|
||||
const deployments = await deployProjects(fixtures, { client })
|
||||
console.log(JSON.stringify(deployments, null, 2))
|
||||
|
||||
console.log('\n\nPublishing deployments...\n\n')
|
||||
console.log('\n\nPublishing dev fixture deployments...\n\n')
|
||||
|
||||
const publishedDeployments = await publishDeployments(deployments)
|
||||
console.log(JSON.stringify(publishedDeployments, null, 2))
|
||||
const publishedDeployments = await publishDeployments(deployments, {
|
||||
client
|
||||
})
|
||||
console.log(JSON.stringify(publishedDeployments, null, 2))
|
||||
}
|
||||
|
||||
{
|
||||
console.log('\n\nCreating "agentic" user...\n\n')
|
||||
|
||||
const agenticAuthSession = await client.signUpWithPassword({
|
||||
username: 'agentic',
|
||||
email: env.AGENTIC_AGENTIC_EMAIL,
|
||||
password: env.AGENTIC_AGENTIC_PASSWORD
|
||||
})
|
||||
console.log(JSON.stringify(agenticAuthSession, null, 2))
|
||||
|
||||
console.log('\n\nDeploying example projects...\n\n')
|
||||
|
||||
const deployments = await deployProjects(examples, { client })
|
||||
console.log(JSON.stringify(deployments, null, 2))
|
||||
|
||||
console.log('\n\nPublishing example project deployments...\n\n')
|
||||
|
||||
const publishedDeployments = await publishDeployments(deployments, {
|
||||
client
|
||||
})
|
||||
console.log(JSON.stringify(publishedDeployments, null, 2))
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(0)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const exampleProjectNames = ['search']
|
||||
|
||||
const examplesDir = path.join(
|
||||
fileURLToPath(import.meta.url),
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'examples'
|
||||
)
|
||||
|
||||
export const examples = exampleProjectNames.map((name) =>
|
||||
path.join(examplesDir, name)
|
||||
)
|
|
@ -0,0 +1,30 @@
|
|||
import type { AgenticApiClient } from '@agentic/platform-api-client'
|
||||
import { loadAgenticConfig } from '@agentic/platform'
|
||||
import pMap from 'p-map'
|
||||
|
||||
export async function deployProjects(
|
||||
projects: string[],
|
||||
{
|
||||
client,
|
||||
concurrency = 1
|
||||
}: {
|
||||
client: AgenticApiClient
|
||||
concurrency?: number
|
||||
}
|
||||
) {
|
||||
const deployments = await pMap(
|
||||
projects,
|
||||
async (project) => {
|
||||
const config = await loadAgenticConfig({ cwd: project })
|
||||
const deployment = await client.createDeployment(config)
|
||||
console.log(`Deployed ${project} => ${deployment.identifier}`)
|
||||
|
||||
return deployment
|
||||
},
|
||||
{
|
||||
concurrency
|
||||
}
|
||||
)
|
||||
|
||||
return deployments
|
||||
}
|
|
@ -2,7 +2,7 @@ import { AgenticApiClient } from '@agentic/platform-api-client'
|
|||
|
||||
import { env } from './env'
|
||||
|
||||
export const client = new AgenticApiClient({
|
||||
export const devClient = new AgenticApiClient({
|
||||
apiBaseUrl: env.AGENTIC_API_BASE_URL,
|
||||
apiKey: env.AGENTIC_DEV_ACCESS_TOKEN
|
||||
})
|
|
@ -0,0 +1,31 @@
|
|||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const fixtureNames = [
|
||||
// TODO: re-add these
|
||||
// 'basic-raw-free-ts',
|
||||
// 'basic-raw-free-json',
|
||||
// 'pricing-freemium',
|
||||
// 'pricing-pay-as-you-go',
|
||||
// 'pricing-3-plans',
|
||||
// 'pricing-monthly-annual',
|
||||
// 'pricing-custom-0',
|
||||
'basic-openapi',
|
||||
'basic-mcp',
|
||||
'everything-openapi'
|
||||
]
|
||||
|
||||
const fixturesDir = path.join(
|
||||
fileURLToPath(import.meta.url),
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'packages',
|
||||
'fixtures'
|
||||
)
|
||||
const validFixturesDir = path.join(fixturesDir, 'valid')
|
||||
|
||||
export const fixtures = fixtureNames.map((name) =>
|
||||
path.join(validFixturesDir, name)
|
||||
)
|
|
@ -14,9 +14,12 @@ export const envSchema = z.object({
|
|||
|
||||
AGENTIC_API_BASE_URL: z.string().url().optional(),
|
||||
|
||||
AGENTIC_DEV_ACCESS_TOKEN: z.string().nonempty(),
|
||||
AGENTIC_DEV_EMAIL: z.string().email(),
|
||||
AGENTIC_DEV_PASSWORD: z.string().nonempty(),
|
||||
AGENTIC_DEV_ACCESS_TOKEN: z.string().nonempty(),
|
||||
|
||||
AGENTIC_AGENTIC_EMAIL: z.string().email(),
|
||||
AGENTIC_AGENTIC_PASSWORD: z.string().nonempty(),
|
||||
|
||||
AGENTIC_GATEWAY_BASE_URL: z
|
||||
.string()
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import type { Deployment } from '@agentic/platform-types'
|
||||
import { loadAgenticConfig } from '@agentic/platform'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
import pMap from 'p-map'
|
||||
import semver from 'semver'
|
||||
|
||||
import { client } from './client'
|
||||
|
||||
const fixtures = [
|
||||
// TODO: re-add these
|
||||
// 'basic-raw-free-ts',
|
||||
// 'basic-raw-free-json',
|
||||
// 'pricing-freemium',
|
||||
// 'pricing-pay-as-you-go',
|
||||
// 'pricing-3-plans',
|
||||
// 'pricing-monthly-annual',
|
||||
// 'pricing-custom-0',
|
||||
'basic-openapi',
|
||||
'basic-mcp',
|
||||
'everything-openapi'
|
||||
]
|
||||
|
||||
const fixturesDir = path.join(
|
||||
fileURLToPath(import.meta.url),
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'packages',
|
||||
'fixtures'
|
||||
)
|
||||
const validFixturesDir = path.join(fixturesDir, 'valid')
|
||||
|
||||
export async function deployFixtures({
|
||||
concurrency = 1
|
||||
}: {
|
||||
concurrency?: number
|
||||
} = {}) {
|
||||
const deployments = await pMap(
|
||||
fixtures,
|
||||
async (fixture) => {
|
||||
const fixtureDir = path.join(validFixturesDir, fixture)
|
||||
|
||||
const config = await loadAgenticConfig({ cwd: fixtureDir })
|
||||
const deployment = await client.createDeployment(config)
|
||||
console.log(`Deployed ${fixture} => ${deployment.identifier}`)
|
||||
|
||||
return deployment
|
||||
},
|
||||
{
|
||||
concurrency
|
||||
}
|
||||
)
|
||||
|
||||
return deployments
|
||||
}
|
||||
|
||||
export async function publishDeployments(
|
||||
deployments: Deployment[],
|
||||
{
|
||||
concurrency = 1
|
||||
}: {
|
||||
concurrency?: number
|
||||
} = {}
|
||||
) {
|
||||
const publishedDeployments = await pMap(
|
||||
deployments,
|
||||
async (deployment) => {
|
||||
const project = await client.getProject({
|
||||
projectId: deployment.projectId,
|
||||
populate: ['lastDeployment']
|
||||
})
|
||||
|
||||
const baseVersion = project.lastPublishedDeploymentVersion || '0.0.0'
|
||||
const version = semver.inc(baseVersion, 'patch')
|
||||
assert(version, `Failed to increment deployment version "${baseVersion}"`)
|
||||
|
||||
const publishedDeployment = await client.publishDeployment(
|
||||
{ version },
|
||||
{
|
||||
deploymentId: deployment.id
|
||||
}
|
||||
)
|
||||
console.log(`Published ${deployment.identifier} => ${version}`)
|
||||
|
||||
return publishedDeployment
|
||||
},
|
||||
{
|
||||
concurrency
|
||||
}
|
||||
)
|
||||
|
||||
return publishedDeployments
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import type { AgenticApiClient } from '@agentic/platform-api-client'
|
||||
import type { Deployment } from '@agentic/platform-types'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
import pMap from 'p-map'
|
||||
import semver from 'semver'
|
||||
|
||||
export async function publishDeployments(
|
||||
deployments: Deployment[],
|
||||
{
|
||||
client,
|
||||
concurrency = 1
|
||||
}: {
|
||||
client: AgenticApiClient
|
||||
concurrency?: number
|
||||
}
|
||||
) {
|
||||
const publishedDeployments = await pMap(
|
||||
deployments,
|
||||
async (deployment) => {
|
||||
const project = await client.getProject({
|
||||
projectId: deployment.projectId,
|
||||
populate: ['lastDeployment']
|
||||
})
|
||||
|
||||
const baseVersion = project.lastPublishedDeploymentVersion || '0.0.0'
|
||||
const version = semver.inc(baseVersion, 'patch')
|
||||
assert(version, `Failed to increment deployment version "${baseVersion}"`)
|
||||
|
||||
const publishedDeployment = await client.publishDeployment(
|
||||
{ version },
|
||||
{
|
||||
deploymentId: deployment.id
|
||||
}
|
||||
)
|
||||
console.log(`Published ${deployment.identifier} => ${version}`)
|
||||
|
||||
return publishedDeployment
|
||||
},
|
||||
{
|
||||
concurrency
|
||||
}
|
||||
)
|
||||
|
||||
return publishedDeployments
|
||||
}
|
|
@ -12,11 +12,6 @@
|
|||
},
|
||||
"type": "module",
|
||||
"source": "./src/worker.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/worker.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"deploy": "wrangler deploy --outdir dist --upload-source-maps --var SENTRY_RELEASE:$(sentry-cli releases propose-version)",
|
||||
"dev": "wrangler dev",
|
||||
|
@ -35,7 +30,6 @@
|
|||
"@agentic/platform-hono": "workspace:*",
|
||||
"@agentic/platform-types": "workspace:*",
|
||||
"@agentic/platform-validators": "workspace:*",
|
||||
"@cloudflare/workers-oauth-provider": "^0.0.5",
|
||||
"@hono/zod-validator": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "catalog:",
|
||||
"@sentry/cloudflare": "catalog:",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { AgenticMcpRequestMetadata } from '@agentic/platform-types'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
import { Client as McpClient } from '@modelcontextprotocol/sdk/client/index.js'
|
||||
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
||||
|
@ -5,7 +6,6 @@ import * as Sentry from '@sentry/cloudflare'
|
|||
import { DurableObject } from 'cloudflare:workers'
|
||||
|
||||
import type { RawEnv } from './env'
|
||||
import type { AgenticMcpRequestMetadata } from './types'
|
||||
|
||||
export type DurableMcpClientInfo = {
|
||||
url: string
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type {
|
||||
AdminDeployment,
|
||||
AgenticMcpRequestMetadata,
|
||||
PricingPlan,
|
||||
Tool
|
||||
} from '@agentic/platform-types'
|
||||
|
@ -11,7 +12,6 @@ import type { DurableMcpClientBase } from './durable-mcp-client'
|
|||
import type { RawEnv } from './env'
|
||||
import type {
|
||||
AdminConsumer,
|
||||
AgenticMcpRequestMetadata,
|
||||
CacheStatus,
|
||||
McpToolCallResponse,
|
||||
RateLimitResult,
|
||||
|
|
|
@ -112,47 +112,3 @@ export type ResolvedOriginToolCallResult = {
|
|||
toolCallResponse: McpToolCallResponse
|
||||
}
|
||||
)
|
||||
|
||||
export type AgenticMcpRequestMetadata = {
|
||||
agenticProxySecret: string
|
||||
sessionId: string
|
||||
isCustomerSubscriptionActive: boolean
|
||||
|
||||
customerId?: string
|
||||
customerSubscriptionStatus?: string
|
||||
customerSubscriptionPlan?: string
|
||||
|
||||
userId?: string
|
||||
userEmail?: string
|
||||
userUsername?: string
|
||||
userName?: string
|
||||
userCreatedAt?: string
|
||||
userUpdatedAt?: string
|
||||
|
||||
deploymentId: string
|
||||
deploymentIdentifier: string
|
||||
projectId: string
|
||||
projectIdentifier: string
|
||||
|
||||
ip?: string
|
||||
} & (
|
||||
| {
|
||||
// If the customer has an active subscription, these fields are guaranteed
|
||||
// to be present in the metadata.
|
||||
isCustomerSubscriptionActive: true
|
||||
|
||||
customerId: string
|
||||
customerSubscriptionStatus: string
|
||||
|
||||
userId: string
|
||||
userEmail: string
|
||||
userUsername: string
|
||||
userCreatedAt: string
|
||||
userUpdatedAt: string
|
||||
}
|
||||
| {
|
||||
// If the customer does not have an active subscription, then the customer
|
||||
// fields may or may not be present.
|
||||
isCustomerSubscriptionActive: false
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
NEXT_PUBLIC_API_BASE_URL=
|
||||
NEXT_PUBLIC_AGENTIC_API_BASE_URL=
|
||||
NEXT_PUBLIC_AGENTIC_GATEWAY_BASE_URL=
|
||||
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
||||
STRIPE_SECRET_KEY=
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
"@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-tabs": "^1.1.12",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@react-three/cannon": "^6.6.0",
|
||||
"@react-three/drei": "^10.2.0",
|
||||
|
@ -43,6 +44,7 @@
|
|||
"canvas-confetti": "^1.9.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||
"ky": "catalog:",
|
||||
"lucide-react": "^0.518.0",
|
||||
"motion": "^12.18.1",
|
||||
|
@ -54,6 +56,7 @@
|
|||
"react-infinite-scroll-hook": "^6.0.1",
|
||||
"react-lottie-player": "^2.1.0",
|
||||
"react-use": "^17.6.0",
|
||||
"shiki": "^3.7.0",
|
||||
"sonner": "^2.0.5",
|
||||
"stripe": "catalog:",
|
||||
"suspend-react": "^0.1.3",
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
'use client'
|
||||
|
||||
import { useLocalStorage } from 'react-use'
|
||||
|
||||
import { CodeBlock } from '@/components/code-block'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import {
|
||||
defaultConfig,
|
||||
type DeveloperConfig,
|
||||
type HTTPTarget,
|
||||
httpTargetLabels,
|
||||
httpTargets,
|
||||
type MCPClientTarget,
|
||||
mcpClientTargetLabels,
|
||||
mcpClientTargets,
|
||||
type PyFrameworkTarget,
|
||||
pyFrameworkTargetLabels,
|
||||
pyFrameworkTargets,
|
||||
type Target,
|
||||
targetLabels,
|
||||
targets,
|
||||
type TsFrameworkTarget,
|
||||
tsFrameworkTargetLabels,
|
||||
tsFrameworkTargets
|
||||
} from '@/lib/developer-config'
|
||||
|
||||
export function ExampleUsage() {
|
||||
const [config, setConfig] = useLocalStorage<DeveloperConfig>(
|
||||
'config',
|
||||
defaultConfig
|
||||
)
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
defaultValue={config!.target}
|
||||
onValueChange={(value) =>
|
||||
setConfig({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
target: value as Target
|
||||
})
|
||||
}
|
||||
className='w-full max-w-2xl'
|
||||
>
|
||||
<TabsList>
|
||||
{targets.map((target) => (
|
||||
<TabsTrigger key={target} value={target} className='cursor-pointer'>
|
||||
{targetLabels[target]}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value='mcp' className='w-full'>
|
||||
<Tabs
|
||||
defaultValue={config!.mcpClientTarget}
|
||||
onValueChange={(value) =>
|
||||
setConfig({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
mcpClientTarget: value as MCPClientTarget
|
||||
})
|
||||
}
|
||||
className='w-full'
|
||||
>
|
||||
<TabsList className='h-auto flex-wrap'>
|
||||
{mcpClientTargets.map((mcpClientTarget) => (
|
||||
<TabsTrigger
|
||||
key={mcpClientTarget}
|
||||
value={mcpClientTarget}
|
||||
className='cursor-pointer'
|
||||
>
|
||||
{mcpClientTargetLabels[mcpClientTarget]}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
{mcpClientTargets.map((mcpClientTarget) => (
|
||||
<TabsContent
|
||||
key={mcpClientTarget}
|
||||
value={mcpClientTarget}
|
||||
className='w-full'
|
||||
>
|
||||
<CodeBlock
|
||||
code={JSON.stringify(config, null, 2)}
|
||||
lang='json'
|
||||
className='p-4 rounded-sm w-full'
|
||||
/>
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value='typescript' className='w-full'>
|
||||
<Tabs
|
||||
defaultValue={config!.tsFrameworkTarget ?? 'ai'}
|
||||
onValueChange={(value) =>
|
||||
setConfig({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
tsFrameworkTarget: value as TsFrameworkTarget
|
||||
})
|
||||
}
|
||||
className='w-full'
|
||||
>
|
||||
<TabsList className='h-auto flex-wrap'>
|
||||
{tsFrameworkTargets.map((framework) => (
|
||||
<TabsTrigger
|
||||
key={framework}
|
||||
value={framework}
|
||||
className='cursor-pointer'
|
||||
>
|
||||
{tsFrameworkTargetLabels[framework]}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
{tsFrameworkTargets.map((framework) => (
|
||||
<TabsContent key={framework} value={framework} className='w-full'>
|
||||
<CodeBlock
|
||||
code={JSON.stringify(config, null, 2)}
|
||||
lang='ts'
|
||||
className='p-4 rounded-sm w-full'
|
||||
/>
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value='python' className='w-full'>
|
||||
<Tabs
|
||||
defaultValue={config!.pyFrameworkTarget}
|
||||
onValueChange={(value) =>
|
||||
setConfig({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
pyFrameworkTarget: value as PyFrameworkTarget
|
||||
})
|
||||
}
|
||||
className='w-full'
|
||||
>
|
||||
<TabsList className='h-auto flex-wrap'>
|
||||
{pyFrameworkTargets.map((framework) => (
|
||||
<TabsTrigger
|
||||
key={framework}
|
||||
value={framework}
|
||||
className='cursor-pointer'
|
||||
>
|
||||
{pyFrameworkTargetLabels[framework]}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
{pyFrameworkTargets.map((framework) => (
|
||||
<TabsContent key={framework} value={framework} className='w-full'>
|
||||
<CodeBlock
|
||||
code={JSON.stringify(config, null, 2)}
|
||||
lang='py'
|
||||
className='p-4 rounded-sm w-full'
|
||||
/>
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value='http' className='w-full'>
|
||||
<Tabs
|
||||
defaultValue={config!.httpTarget}
|
||||
onValueChange={(value) =>
|
||||
setConfig({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
httpTarget: value as HTTPTarget
|
||||
})
|
||||
}
|
||||
className='w-full'
|
||||
>
|
||||
<TabsList className='h-auto flex-wrap'>
|
||||
{httpTargets.map((httpTarget) => (
|
||||
<TabsTrigger
|
||||
key={httpTarget}
|
||||
value={httpTarget}
|
||||
className='cursor-pointer'
|
||||
>
|
||||
{httpTargetLabels[httpTarget]}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
{httpTargets.map((httpTarget) => (
|
||||
<TabsContent key={httpTarget} value={httpTarget} className='w-full'>
|
||||
<CodeBlock
|
||||
code={JSON.stringify(config, null, 2)}
|
||||
lang='bash'
|
||||
className='p-4 rounded-sm w-full'
|
||||
/>
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
|
@ -4,6 +4,8 @@ import { DemandSideCTA } from '@/components/demand-side-cta'
|
|||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||
import { githubUrl, twitterUrl } from '@/lib/config'
|
||||
|
||||
import { ExampleUsage } from './example-usage'
|
||||
|
||||
export default function TheBestDamnLandingPageEver() {
|
||||
return (
|
||||
<>
|
||||
|
@ -35,7 +37,7 @@ export default function TheBestDamnLandingPageEver() {
|
|||
How It Works
|
||||
</h2>
|
||||
|
||||
<div>TODO</div>
|
||||
<ExampleUsage />
|
||||
</section>
|
||||
|
||||
{/* Marketplace section */}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
|
||||
import { Fragment, type JSX, useEffect, useState } from 'react'
|
||||
import { jsx, jsxs } from 'react/jsx-runtime'
|
||||
import { type BundledLanguage, codeToHast } from 'shiki/bundle/web'
|
||||
|
||||
import { LoadingIndicator } from './loading-indicator'
|
||||
|
||||
export async function highlight({
|
||||
code,
|
||||
lang = 'ts',
|
||||
theme = 'github-dark',
|
||||
className
|
||||
}: {
|
||||
code: string
|
||||
lang?: BundledLanguage
|
||||
theme?: string
|
||||
className?: string
|
||||
}) {
|
||||
const out = await codeToHast(code, {
|
||||
lang,
|
||||
theme,
|
||||
transformers: [
|
||||
{
|
||||
pre(node) {
|
||||
if (className) {
|
||||
this.addClassToHast(node, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
return toJsxRuntime(out, {
|
||||
Fragment,
|
||||
jsx,
|
||||
jsxs
|
||||
}) as JSX.Element
|
||||
}
|
||||
|
||||
export function CodeBlock({
|
||||
initial,
|
||||
code,
|
||||
lang,
|
||||
theme,
|
||||
className
|
||||
}: {
|
||||
initial?: JSX.Element
|
||||
code: string
|
||||
lang?: BundledLanguage
|
||||
theme?: string
|
||||
className?: string
|
||||
}) {
|
||||
const [nodes, setNodes] = useState(initial)
|
||||
|
||||
useEffect(() => {
|
||||
void highlight({ code, lang, theme, className }).then(setNodes)
|
||||
}, [code, lang, theme, className])
|
||||
|
||||
return nodes ?? <LoadingIndicator />
|
||||
}
|
|
@ -15,7 +15,7 @@ export function DemandSideCTA() {
|
|||
|
||||
<Button variant='outline' asChild className='h-full'>
|
||||
<Link href={docsMarketplaceUrl} className='font-mono'>
|
||||
readDocs();
|
||||
readTheDocs();
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
'use client'
|
||||
|
||||
import * as TabsPrimitive from '@radix-ui/react-tabs'
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot='tabs'
|
||||
className={cn('flex flex-col gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot='tabs-list'
|
||||
className={cn(
|
||||
'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsTrigger({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot='tabs-trigger'
|
||||
className={cn(
|
||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
<TabsPrimitive.Content
|
||||
data-slot='tabs-content'
|
||||
className={cn('flex-1 outline-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tabs, TabsContent,TabsList, TabsTrigger }
|
|
@ -59,7 +59,8 @@ export const url = isDev ? `http://localhost:${port}` : prodUrl
|
|||
export const vercelUrl =
|
||||
process.env.VERCEL_URL ?? process.env.NEXT_PUBLIC_VERCEL_URL
|
||||
// export const webBaseUrl = isDev || !vercelUrl ? url : `https://${vercelUrl}`
|
||||
export const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL!
|
||||
export const apiBaseUrl = process.env.NEXT_PUBLIC_AGENTIC_API_BASE_URL!
|
||||
export const gatewayBaseUrl = process.env.NEXT_PUBLIC_AGENTIC_GATEWAY_BASE_URL!
|
||||
|
||||
export const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY!
|
||||
export const posthogHost =
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
import type { Deployment, Project } from '@agentic/platform-types'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
|
||||
import { gatewayBaseUrl } from './config'
|
||||
|
||||
export const targetLabels = {
|
||||
mcp: 'MCP',
|
||||
typescript: 'TypeScript',
|
||||
python: 'Python',
|
||||
http: 'HTTP'
|
||||
} as const
|
||||
export const targets: (keyof typeof targetLabels)[] = Object.keys(
|
||||
targetLabels
|
||||
) as any
|
||||
export type Target = (typeof targets)[number]
|
||||
|
||||
export const httpTargetLabels = {
|
||||
curl: 'cURL',
|
||||
httpie: 'HTTPie'
|
||||
} as const
|
||||
export const httpTargets: (keyof typeof httpTargetLabels)[] = Object.keys(
|
||||
httpTargetLabels
|
||||
) as any
|
||||
export type HTTPTarget = (typeof httpTargets)[number]
|
||||
|
||||
export const mcpClientTargetLabels = {
|
||||
any: 'Any MCP Client',
|
||||
'claude-desktop': 'Claude Desktop',
|
||||
raycast: 'Raycast',
|
||||
cursor: 'Cursor',
|
||||
windsurf: 'Windsurf',
|
||||
cline: 'Cline',
|
||||
goose: 'Goose'
|
||||
} as const
|
||||
export const mcpClientTargets: (keyof typeof mcpClientTargetLabels)[] =
|
||||
Object.keys(mcpClientTargetLabels) as any
|
||||
export type MCPClientTarget = (typeof mcpClientTargets)[number]
|
||||
|
||||
export const tsFrameworkTargetLabels = {
|
||||
ai: 'Vercel AI SDK',
|
||||
'openai-chat': 'OpenAI Chat',
|
||||
'openai-responses': 'OpenAI Responses',
|
||||
langchain: 'LangChain',
|
||||
mastra: 'Mastra',
|
||||
llamaindex: 'LlamaIndex',
|
||||
'firebase-genkit': 'Firebase GenKit',
|
||||
xsai: 'xsAI'
|
||||
} as const
|
||||
export const tsFrameworkTargets: (keyof typeof tsFrameworkTargetLabels)[] =
|
||||
Object.keys(tsFrameworkTargetLabels) as any
|
||||
export type TsFrameworkTarget = (typeof tsFrameworkTargets)[number]
|
||||
|
||||
export const pyFrameworkTargetLabels = {
|
||||
openai: 'OpenAI',
|
||||
langchain: 'LangChain',
|
||||
llamaindex: 'LlamaIndex'
|
||||
} as const
|
||||
export const pyFrameworkTargets: (keyof typeof pyFrameworkTargetLabels)[] =
|
||||
Object.keys(pyFrameworkTargetLabels) as any
|
||||
export type PyFrameworkTarget = (typeof pyFrameworkTargets)[number]
|
||||
|
||||
export type DeveloperConfig = {
|
||||
target: Target
|
||||
mcpClientTarget: MCPClientTarget
|
||||
tsFrameworkTarget: TsFrameworkTarget
|
||||
pyFrameworkTarget: PyFrameworkTarget
|
||||
httpTarget: HTTPTarget
|
||||
}
|
||||
|
||||
export const defaultConfig: DeveloperConfig = {
|
||||
target: 'typescript',
|
||||
mcpClientTarget: 'any',
|
||||
tsFrameworkTarget: 'ai',
|
||||
pyFrameworkTarget: 'openai',
|
||||
httpTarget: 'curl'
|
||||
}
|
||||
|
||||
export function getCodeForDeveloperConfig(opts: {
|
||||
config: DeveloperConfig
|
||||
project: Project
|
||||
deployment: Deployment
|
||||
identifier: string
|
||||
tool?: string
|
||||
}): string {
|
||||
const { config } = opts
|
||||
|
||||
switch (config.target) {
|
||||
case 'mcp':
|
||||
return getCodeForMCPClientConfig(opts)
|
||||
case 'typescript':
|
||||
return getCodeForTSFrameworkConfig(opts)
|
||||
case 'python':
|
||||
return 'Python support is coming soon...'
|
||||
// return getCodeForPythonFrameworkConfig(opts)
|
||||
case 'http':
|
||||
return getCodeForHTTPConfig(opts)
|
||||
}
|
||||
}
|
||||
|
||||
export function getCodeForMCPClientConfig({
|
||||
identifier
|
||||
}: {
|
||||
identifier: string
|
||||
}): string {
|
||||
return `${gatewayBaseUrl}/${identifier}/mcp`
|
||||
}
|
||||
|
||||
export function getCodeForTSFrameworkConfig({
|
||||
config,
|
||||
identifier
|
||||
}: {
|
||||
config: DeveloperConfig
|
||||
identifier: string
|
||||
}): string {
|
||||
switch (config.tsFrameworkTarget) {
|
||||
case 'ai':
|
||||
return `
|
||||
import { createAISDKTools } from '@agentic/ai'
|
||||
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
import { generateText } from 'ai'
|
||||
|
||||
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4o-mini'),
|
||||
tools: createAISDKTools(searchTool),
|
||||
toolChoice: 'required',
|
||||
temperature: 0,
|
||||
system: 'You are a helpful assistant. Be as concise as possible.',
|
||||
prompt: 'What is the latest news about AI?'
|
||||
})
|
||||
|
||||
console.log(result.toolResults[0])
|
||||
`.trim()
|
||||
|
||||
case 'openai-chat':
|
||||
return `
|
||||
import { AgenticToolClient } from '@agentic/platform-tool-client'
|
||||
import OpenAI from 'openai'
|
||||
|
||||
const openai = new OpenAI()
|
||||
const searchTool = await AgenticToolClient.fromIdentifier('${identifier}')
|
||||
|
||||
const res = await openai.chat.completions.create({
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant. Be as concise as possible.'
|
||||
}
|
||||
{
|
||||
role: 'user',
|
||||
content: 'What is the latest news about AI?'
|
||||
}
|
||||
],
|
||||
model: 'gpt-4o-mini',
|
||||
temperature: 0,
|
||||
tools: searchTool.functions.toolSpecs,
|
||||
tool_choice: 'required'
|
||||
})
|
||||
|
||||
const message = res.choices[0]!.message!
|
||||
const toolCall = message.tool_calls![0]!
|
||||
|
||||
const tool = searchTool.functions.get(toolCall.function.name)!
|
||||
const toolResult = await tool(toolCall.function.arguments)
|
||||
|
||||
console.log(toolResult)
|
||||
`.trim()
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
// export function getCodeForPythonFrameworkConfig({
|
||||
// config,
|
||||
// project,
|
||||
// deployment,
|
||||
// tool
|
||||
// }: {
|
||||
// config: DeveloperConfig
|
||||
// project: Project
|
||||
// deployment: Deployment
|
||||
// identifier: string
|
||||
// tool?: string
|
||||
// }): string {
|
||||
// return ''
|
||||
// }
|
||||
|
||||
export function getCodeForHTTPConfig({
|
||||
config,
|
||||
identifier,
|
||||
deployment,
|
||||
tool
|
||||
}: {
|
||||
config: DeveloperConfig
|
||||
deployment: Deployment
|
||||
identifier: string
|
||||
tool?: string
|
||||
}): string {
|
||||
tool ??= deployment.tools[0]?.name
|
||||
assert(tool, 'tool is required')
|
||||
// TODO: need a way of getting example tool args
|
||||
|
||||
const url = `${gatewayBaseUrl}/${identifier}/${tool}`
|
||||
|
||||
switch (config.httpTarget) {
|
||||
case 'curl':
|
||||
return `curl -X POST -H "Content-Type: application/json" -d '{"query": "example google search"}' ${url}`
|
||||
|
||||
case 'httpie':
|
||||
return `http -j ${url} query='example google search'`
|
||||
}
|
||||
}
|
|
@ -24,7 +24,8 @@ export default [
|
|||
files: [
|
||||
'packages/cli/src/**/*.ts',
|
||||
'**/*.test.ts',
|
||||
'packages/fixtures/valid/**/*.ts'
|
||||
'packages/fixtures/valid/**/*.ts',
|
||||
'examples/**/*.ts'
|
||||
],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
SERPER_API_KEY=
|
||||
|
||||
AGENTIC_PROXY_SECRET=
|
|
@ -0,0 +1 @@
|
|||
MCP_ORIGIN_URL=
|
|
@ -0,0 +1,17 @@
|
|||
import 'dotenv/config'
|
||||
|
||||
import { defineConfig } from '@agentic/platform'
|
||||
|
||||
export default defineConfig({
|
||||
name: 'search',
|
||||
originUrl: process.env.MCP_ORIGIN_URL!,
|
||||
originAdapter: {
|
||||
type: 'mcp'
|
||||
},
|
||||
toolConfigs: [
|
||||
{
|
||||
name: 'search',
|
||||
cacheControl: 'public, max-age=60, s-maxage=60 stale-while-revalidate=10'
|
||||
}
|
||||
]
|
||||
})
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "@agentic/examples-search",
|
||||
"private": true,
|
||||
"author": "Travis Fischer <travis@transitivebullsh.it>",
|
||||
"license": "AGPL-3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/transitive-bullshit/agentic-platform.git",
|
||||
"directory": "examples/search"
|
||||
},
|
||||
"type": "module",
|
||||
"source": "./src/worker.ts",
|
||||
"scripts": {
|
||||
"dev": "wrangler dev",
|
||||
"deploy": "wrangler deploy --outdir dist --upload-source-maps",
|
||||
"test": "run-s test:*",
|
||||
"test:typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentic/platform": "workspace:*",
|
||||
"@agentic/serper": "^7.6.7",
|
||||
"@hono/mcp": "^0.1.0",
|
||||
"@modelcontextprotocol/sdk": "catalog:",
|
||||
"dotenv": "^16.5.0",
|
||||
"hono": "catalog:",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "catalog:",
|
||||
"wrangler": "catalog:"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { z } from 'zod'
|
||||
|
||||
export const envSchema = z.object({
|
||||
SERPER_API_KEY: z.string().nonempty()
|
||||
})
|
||||
|
||||
export type Env = z.infer<typeof envSchema>
|
||||
|
||||
export function parseEnv(inputEnv: Record<string, unknown>): Env {
|
||||
return envSchema.parse(inputEnv)
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
import { SerperClient } from '@agentic/serper'
|
||||
import { StreamableHTTPTransport } from '@hono/mcp'
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { Hono } from 'hono'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { type Env, parseEnv } from './env'
|
||||
|
||||
const app = new Hono()
|
||||
|
||||
const mcpServer = new McpServer({
|
||||
name: 'search',
|
||||
version: '1.0.0'
|
||||
})
|
||||
|
||||
let serper: SerperClient
|
||||
|
||||
mcpServer.registerTool(
|
||||
'search',
|
||||
{
|
||||
description:
|
||||
'Uses Google Search to return the most relevant web pages for a given query. Useful for finding up-to-date news and information about any topic.',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('Search query'),
|
||||
num: z
|
||||
.number()
|
||||
.int()
|
||||
.default(5)
|
||||
.optional()
|
||||
.describe('Number of results to return'),
|
||||
type: z
|
||||
.enum(['search', 'images', 'videos', 'places', 'news', 'shopping'])
|
||||
.default('search')
|
||||
.optional()
|
||||
.describe('Type of Google search to perform')
|
||||
}).shape,
|
||||
outputSchema: z.object({}).passthrough().shape
|
||||
},
|
||||
async (args, { _meta }) => {
|
||||
// (_meta.agentic as any).agenticProxySecret
|
||||
|
||||
const result: any = await serper!.search({
|
||||
q: args.query,
|
||||
num: args.num,
|
||||
type: args.type
|
||||
})
|
||||
|
||||
delete result.topStories
|
||||
delete result.peopleAlsoAsk
|
||||
delete result.searchParameters
|
||||
delete result.credits
|
||||
|
||||
return {
|
||||
content: [],
|
||||
structuredContent: result
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
app.all('/mcp', async (c) => {
|
||||
const transport = new StreamableHTTPTransport()
|
||||
await mcpServer.connect(transport)
|
||||
return transport.handleRequest(c)
|
||||
})
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
const parsedEnv = parseEnv(env)
|
||||
|
||||
if (!serper) {
|
||||
serper = new SerperClient({ apiKey: parsedEnv.SERPER_API_KEY })
|
||||
}
|
||||
|
||||
return app.fetch(request, parsedEnv, ctx)
|
||||
}
|
||||
} satisfies ExportedHandler<Env>
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "@fisch0920/config/tsconfig-node",
|
||||
"compilerOptions": {
|
||||
"types": ["@cloudflare/workers-types"]
|
||||
},
|
||||
"include": ["src", "*.config.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* https://developers.cloudflare.com/workers/wrangler/configuration/
|
||||
*/
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "agentic-mcp-search",
|
||||
"main": "src/worker.ts",
|
||||
"compatibility_date": "2025-05-25",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"placement": { "mode": "smart" },
|
||||
"upload_source_maps": true
|
||||
}
|
|
@ -7,14 +7,14 @@
|
|||
"type": "git",
|
||||
"url": "git+https://github.com/transitive-bullshit/agentic-platform.git"
|
||||
},
|
||||
"packageManager": "pnpm@10.12.1",
|
||||
"packageManager": "pnpm@10.12.2",
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "turbo build --filter=!web",
|
||||
"dev": "turbo dev --continue",
|
||||
"dev": "turbo dev --continue --filter=!./examples/*",
|
||||
"clean": "turbo clean",
|
||||
"fix": "run-s fix:*",
|
||||
"fix:format": "prettier --write \"**/*.{js,ts,tsx}\"",
|
||||
|
|
|
@ -37,7 +37,7 @@ export class AgenticApiClient {
|
|||
apiKey?: string
|
||||
ky?: KyInstance
|
||||
onUpdateAuth?: OnUpdateAuthSessionFunction
|
||||
}) {
|
||||
} = {}) {
|
||||
assert(apiBaseUrl, 'AgenticApiClient missing required "apiBaseUrl"')
|
||||
|
||||
this.apiBaseUrl = apiBaseUrl
|
||||
|
@ -655,7 +655,7 @@ export class AgenticApiClient {
|
|||
.json()
|
||||
}
|
||||
|
||||
/** Gets a deployment by its public identifier. */
|
||||
/** Gets a deployment by its identifier. */
|
||||
async getDeploymentByIdentifier<
|
||||
TPopulate extends NonNullable<
|
||||
OperationParameters<'getDeploymentByIdentifier'>['populate']
|
||||
|
@ -672,6 +672,23 @@ export class AgenticApiClient {
|
|||
.json()
|
||||
}
|
||||
|
||||
/** Gets a public deployment by its identifier. */
|
||||
async getPublicDeploymentByIdentifier<
|
||||
TPopulate extends NonNullable<
|
||||
OperationParameters<'getPublicDeploymentByIdentifier'>['populate']
|
||||
>[number]
|
||||
>(
|
||||
searchParams: OperationParameters<'getPublicDeploymentByIdentifier'> & {
|
||||
populate?: TPopulate[]
|
||||
}
|
||||
): Promise<PopulateDeployment<TPopulate>> {
|
||||
return this.ky
|
||||
.get(`v1/deployments/public/by-identifier`, {
|
||||
searchParams: sanitizeSearchParams(searchParams)
|
||||
})
|
||||
.json()
|
||||
}
|
||||
|
||||
/** Updates a deployment. */
|
||||
async updateDeployment(
|
||||
deployment: OperationBody<'updateDeployment'>,
|
||||
|
|
|
@ -22,20 +22,17 @@
|
|||
"test:unit": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentic/core": "^7.6.7",
|
||||
"@agentic/platform-core": "workspace:*",
|
||||
"@agentic/platform-openapi-utils": "workspace:*",
|
||||
"@agentic/platform-types": "workspace:*",
|
||||
"@agentic/platform-validators": "workspace:*",
|
||||
"@hono/zod-openapi": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "catalog:",
|
||||
"semver": "catalog:",
|
||||
"unconfig": "catalog:",
|
||||
"zod": "catalog:"
|
||||
"unconfig": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "catalog:",
|
||||
"restore-cursor": "catalog:",
|
||||
"zod-to-json-schema": "catalog:"
|
||||
"@types/semver": "catalog:"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "@agentic/platform-tool-client",
|
||||
"version": "0.1.0",
|
||||
"description": "Tool client for the Agentic platform.",
|
||||
"author": "Travis Fischer <travis@transitivebullsh.it>",
|
||||
"license": "AGPL-3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/transitive-bullshit/agentic-platform.git",
|
||||
"directory": "packages/tool-client"
|
||||
},
|
||||
"type": "module",
|
||||
"source": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "run-s test:*",
|
||||
"test:typecheck": "tsc --noEmit",
|
||||
"test:unit": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentic/core": "^7.6.7",
|
||||
"@agentic/platform-api-client": "workspace:*",
|
||||
"@agentic/platform-core": "workspace:*",
|
||||
"@agentic/platform-types": "workspace:*",
|
||||
"@agentic/platform-validators": "workspace:*",
|
||||
"ky": "catalog:"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
## Project Identifier
|
||||
|
||||
`@namespace/project-name`
|
||||
|
||||
## Deployment Identifier
|
||||
|
||||
`${projectIdentifier}` => `${projectIdentifier}@latest`
|
||||
`${projectIdentifier}@latest`
|
||||
`${projectIdentifier}@dev`
|
||||
`${projectIdentifier}@deploymentHash`
|
||||
`${projectIdentifier}@version`
|
||||
|
||||
## Tool Identifier
|
||||
|
||||
`${deploymentIdentifier}/tool_name`
|
||||
|
||||
## Tool Names
|
||||
|
||||
- Must start with a letter or underscore
|
||||
- Can include only letters, numbers, and underscores
|
||||
- Use either camelCase or snake_case consistently across all tools
|
||||
|
||||
[OpenAI vs Anthropic vs Google vs MCP tool name restrictions](https://chatgpt.com/share/68419382-73a0-8007-afce-0ded7d9f05e7)
|
|
@ -0,0 +1,139 @@
|
|||
import type { Deployment, Project } from '@agentic/platform-types'
|
||||
import {
|
||||
AIFunctionSet,
|
||||
AIFunctionsProvider,
|
||||
createAIFunction,
|
||||
createJsonSchema
|
||||
} from '@agentic/core'
|
||||
import { AgenticApiClient } from '@agentic/platform-api-client'
|
||||
import { assert } from '@agentic/platform-core'
|
||||
import { parseDeploymentIdentifier } from '@agentic/platform-validators'
|
||||
import defaultKy, { type KyInstance } from 'ky'
|
||||
|
||||
/**
|
||||
* Agentic tool client which makes it easy to use an Agentic tools product with
|
||||
* all of the major TypeScript LLM SDKs.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const client = await AgenticToolClient.fromIdentifier('@agentic/search')
|
||||
* const result = await client.functions.get('search').execute('search query')
|
||||
* ```
|
||||
*/
|
||||
export class AgenticToolClient extends AIFunctionsProvider {
|
||||
readonly project: Project
|
||||
readonly deployment: Deployment
|
||||
readonly agenticGatewayBaseUrl: string
|
||||
readonly ky: KyInstance
|
||||
|
||||
protected constructor({
|
||||
project,
|
||||
deployment,
|
||||
deploymentIdentifier,
|
||||
agenticGatewayBaseUrl,
|
||||
ky
|
||||
}: {
|
||||
project: Project
|
||||
deployment: Deployment
|
||||
deploymentIdentifier: string
|
||||
agenticGatewayBaseUrl: string
|
||||
ky: KyInstance
|
||||
}) {
|
||||
super()
|
||||
|
||||
this.project = project
|
||||
this.deployment = deployment
|
||||
this.agenticGatewayBaseUrl = agenticGatewayBaseUrl
|
||||
this.ky = ky
|
||||
|
||||
this._functions = new AIFunctionSet(
|
||||
deployment.tools.map((tool) => {
|
||||
return createAIFunction({
|
||||
name: tool.name,
|
||||
description: tool.description ?? '',
|
||||
inputSchema: createJsonSchema(tool.inputSchema),
|
||||
execute: async (json) => {
|
||||
return ky
|
||||
.post(
|
||||
`${agenticGatewayBaseUrl}/${deploymentIdentifier}/${tool.name}`,
|
||||
{
|
||||
json
|
||||
}
|
||||
)
|
||||
.json()
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
override get functions(): AIFunctionSet {
|
||||
assert(this._functions)
|
||||
return this._functions
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Agentic tool client from a project or deployment identifier.
|
||||
*
|
||||
* You'll generally use a project identifier, which will automatically use
|
||||
* that project's `latest` deployment, but if you want to target a specific
|
||||
* version or preview deployment, you can use a fully-qualified deployment
|
||||
* identifier.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const client1 = await AgenticToolClient.fromIdentifier('@agentic/search')
|
||||
* const client2 = await AgenticToolClient.fromIdentifier('@agentic/search@v1.0.0')
|
||||
* const client3 = await AgenticToolClient.fromIdentifier('@agentic/search@latest')
|
||||
* ```
|
||||
*/
|
||||
static async fromIdentifier(
|
||||
projectOrDeploymentIdentifier: string,
|
||||
{
|
||||
agenticApiClient = new AgenticApiClient(),
|
||||
agenticGatewayBaseUrl = 'https://gateway.agentic.so',
|
||||
ky = defaultKy
|
||||
}: {
|
||||
agenticApiClient?: AgenticApiClient
|
||||
agenticGatewayBaseUrl?: string
|
||||
ky?: KyInstance
|
||||
} = {}
|
||||
): Promise<AgenticToolClient> {
|
||||
const { projectIdentifier, deploymentIdentifier, deploymentVersion } =
|
||||
parseDeploymentIdentifier(projectOrDeploymentIdentifier, {
|
||||
strict: false
|
||||
})
|
||||
|
||||
const [project, rawDeployment] = await Promise.all([
|
||||
agenticApiClient.getPublicProjectByIdentifier({
|
||||
projectIdentifier,
|
||||
populate:
|
||||
deploymentVersion === 'latest' ? ['lastPublishedDeployment'] : []
|
||||
}),
|
||||
|
||||
// Only make 1 API call in the 95% case where the deployment version is
|
||||
// set to the default value of `latest`.
|
||||
deploymentVersion === 'latest'
|
||||
? Promise.resolve(undefined)
|
||||
: agenticApiClient.getPublicDeploymentByIdentifier({
|
||||
deploymentIdentifier
|
||||
})
|
||||
])
|
||||
|
||||
const deployment =
|
||||
deploymentVersion === 'latest'
|
||||
? project?.lastPublishedDeployment
|
||||
: rawDeployment
|
||||
|
||||
assert(project, `Project "${projectIdentifier}" not found`)
|
||||
assert(deployment, `Deployment "${deploymentIdentifier}" not found`)
|
||||
|
||||
return new AgenticToolClient({
|
||||
project,
|
||||
deployment,
|
||||
deploymentIdentifier,
|
||||
agenticGatewayBaseUrl,
|
||||
ky
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './agentic-tool-client'
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "@fisch0920/config/tsconfig-node",
|
||||
"include": ["src", "*.config.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
|
@ -140,6 +140,23 @@ export interface paths {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/deployments/public/by-identifier": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** @description Gets a public deployment by its identifier (eg, "@username/project-name@latest"). */
|
||||
get: operations["getPublicDeploymentByIdentifier"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/users/{userId}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
@ -428,7 +445,7 @@ export interface paths {
|
|||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** @description Gets a deployment by its public identifier */
|
||||
/** @description Gets a deployment by its identifier (eg, "@username/project-name@latest"). */
|
||||
get: operations["getDeploymentByIdentifier"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
|
@ -600,46 +617,6 @@ export interface components {
|
|||
team?: components["schemas"]["Team"];
|
||||
lastPublishedDeployment?: unknown;
|
||||
lastDeployment?: unknown;
|
||||
};
|
||||
TeamMember: {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string;
|
||||
userId: string;
|
||||
teamSlug: string;
|
||||
teamId: string;
|
||||
/** @enum {string} */
|
||||
role: "user" | "admin";
|
||||
confirmed: boolean;
|
||||
confirmedAt?: string;
|
||||
};
|
||||
/** @description A Consumer represents a user who has subscribed to a Project and is used
|
||||
* to track usage and billing.
|
||||
*
|
||||
* Consumers are linked to a corresponding Stripe Customer and Subscription.
|
||||
* The Stripe customer will either be the user's default Stripe Customer if the
|
||||
* project uses the default Agentic platform account, or a customer on the project
|
||||
* owner's connected Stripe account if the project has Stripe Connect enabled. */
|
||||
Consumer: {
|
||||
/** @description Consumer id (e.g. "csmr_tz4a98xxat96iws9zmbrgj3a") */
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string;
|
||||
token: string;
|
||||
plan?: string;
|
||||
activated: boolean;
|
||||
source?: string;
|
||||
/** @description User id (e.g. "user_tz4a98xxat96iws9zmbrgj3a") */
|
||||
userId: string;
|
||||
/** @description Project id (e.g. "proj_tz4a98xxat96iws9zmbrgj3a") */
|
||||
projectId: string;
|
||||
/** @description Deployment id (e.g. "depl_tz4a98xxat96iws9zmbrgj3a") */
|
||||
deploymentId: string;
|
||||
stripeStatus: string;
|
||||
isStripeSubscriptionActive: boolean;
|
||||
user?: components["schemas"]["User"];
|
||||
project?: components["schemas"]["Project"];
|
||||
deployment?: unknown;
|
||||
};
|
||||
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
|
||||
|
@ -899,6 +876,47 @@ export interface components {
|
|||
defaultRateLimit?: components["schemas"]["RateLimit"] & unknown;
|
||||
project?: unknown;
|
||||
};
|
||||
TeamMember: {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string;
|
||||
userId: string;
|
||||
teamSlug: string;
|
||||
teamId: string;
|
||||
/** @enum {string} */
|
||||
role: "user" | "admin";
|
||||
confirmed: boolean;
|
||||
confirmedAt?: string;
|
||||
};
|
||||
/** @description A Consumer represents a user who has subscribed to a Project and is used
|
||||
* to track usage and billing.
|
||||
*
|
||||
* Consumers are linked to a corresponding Stripe Customer and Subscription.
|
||||
* The Stripe customer will either be the user's default Stripe Customer if the
|
||||
* project uses the default Agentic platform account, or a customer on the project
|
||||
* owner's connected Stripe account if the project has Stripe Connect enabled. */
|
||||
Consumer: {
|
||||
/** @description Consumer id (e.g. "csmr_tz4a98xxat96iws9zmbrgj3a") */
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string;
|
||||
token: string;
|
||||
plan?: string;
|
||||
activated: boolean;
|
||||
source?: string;
|
||||
/** @description User id (e.g. "user_tz4a98xxat96iws9zmbrgj3a") */
|
||||
userId: string;
|
||||
/** @description Project id (e.g. "proj_tz4a98xxat96iws9zmbrgj3a") */
|
||||
projectId: string;
|
||||
/** @description Deployment id (e.g. "depl_tz4a98xxat96iws9zmbrgj3a") */
|
||||
deploymentId: string;
|
||||
stripeStatus: string;
|
||||
isStripeSubscriptionActive: boolean;
|
||||
user?: components["schemas"]["User"];
|
||||
project?: components["schemas"]["Project"];
|
||||
deployment?: unknown;
|
||||
};
|
||||
/**
|
||||
* @description Origin adapter is used to configure the origin API server downstream from Agentic's API gateway. It specifies whether the origin API server denoted by `originUrl` is hosted externally or deployed internally to Agentic's infrastructure. It also specifies the format for how origin tools are defined: either an OpenAPI spec, an MCP server, or a raw HTTP REST API.
|
||||
*
|
||||
|
@ -1269,6 +1287,34 @@ export interface operations {
|
|||
404: components["responses"]["404"];
|
||||
};
|
||||
};
|
||||
getPublicDeploymentByIdentifier: {
|
||||
parameters: {
|
||||
query: {
|
||||
populate?: ("user" | "team" | "project") | ("user" | "team" | "project")[];
|
||||
/** @description Public deployment identifier (e.g. "@namespace/project-name@{hash|version|latest}") */
|
||||
deploymentIdentifier: components["schemas"]["DeploymentIdentifier"];
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A deployment object */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Deployment"];
|
||||
};
|
||||
};
|
||||
400: components["responses"]["400"];
|
||||
401: components["responses"]["401"];
|
||||
403: components["responses"]["403"];
|
||||
404: components["responses"]["404"];
|
||||
};
|
||||
};
|
||||
getUser: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
@ -67,3 +67,47 @@ export type AdminConsumer = Simplify<
|
|||
deployment?: Deployment
|
||||
}
|
||||
>
|
||||
|
||||
export type AgenticMcpRequestMetadata = {
|
||||
agenticProxySecret: string
|
||||
sessionId: string
|
||||
isCustomerSubscriptionActive: boolean
|
||||
|
||||
customerId?: string
|
||||
customerSubscriptionStatus?: string
|
||||
customerSubscriptionPlan?: string
|
||||
|
||||
userId?: string
|
||||
userEmail?: string
|
||||
userUsername?: string
|
||||
userName?: string
|
||||
userCreatedAt?: string
|
||||
userUpdatedAt?: string
|
||||
|
||||
deploymentId: string
|
||||
deploymentIdentifier: string
|
||||
projectId: string
|
||||
projectIdentifier: string
|
||||
|
||||
ip?: string
|
||||
} & (
|
||||
| {
|
||||
// If the customer has an active subscription, these fields are guaranteed
|
||||
// to be present in the metadata.
|
||||
isCustomerSubscriptionActive: true
|
||||
|
||||
customerId: string
|
||||
customerSubscriptionStatus: string
|
||||
|
||||
userId: string
|
||||
userEmail: string
|
||||
userUsername: string
|
||||
userCreatedAt: string
|
||||
userUpdatedAt: string
|
||||
}
|
||||
| {
|
||||
// If the customer does not have an active subscription, then the customer
|
||||
// fields may or may not be present.
|
||||
isCustomerSubscriptionActive: false
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
export const namespaceBlacklist = new Set([
|
||||
// restricted because they would be confusing
|
||||
'agentic',
|
||||
'admin',
|
||||
'root',
|
||||
'sudo',
|
||||
|
|
969
pnpm-lock.yaml
969
pnpm-lock.yaml
Plik diff jest za duży
Load Diff
|
@ -1,6 +1,7 @@
|
|||
packages:
|
||||
- packages/*
|
||||
- apps/*
|
||||
- examples/*
|
||||
- packages/fixtures/valid/*
|
||||
|
||||
catalog:
|
||||
|
@ -13,7 +14,7 @@ catalog:
|
|||
'@fisch0920/config': ^1.1.2
|
||||
'@fisch0920/drizzle-orm': ^0.43.7
|
||||
'@fisch0920/drizzle-zod': ^0.7.9
|
||||
'@hono/node-server': ^1.14.4
|
||||
'@hono/node-server': 1.14.4
|
||||
'@hono/sentry': ^1.2.2
|
||||
'@hono/zod-openapi': ^0.19.8
|
||||
'@hono/zod-validator': ^0.7.0
|
||||
|
@ -52,7 +53,7 @@ catalog:
|
|||
fastmcp: ^3.4.0
|
||||
get-port: ^7.1.0
|
||||
hash-object: ^5.0.1
|
||||
hono: ^4.8.1
|
||||
hono: 4.8.1
|
||||
is-relative-url: ^4.0.0
|
||||
knip: ^5.61.2
|
||||
ky: 1.8.1
|
||||
|
@ -88,7 +89,7 @@ catalog:
|
|||
unconfig: ^7.3.2
|
||||
vite-tsconfig-paths: ^5.1.4
|
||||
vitest: ^3.2.4
|
||||
wrangler: ^4.20.3
|
||||
wrangler: ^4.21.0
|
||||
zod: ^3.25.67
|
||||
zod-to-json-schema: ^3.24.5
|
||||
zod-validation-error: ^3.5.2
|
||||
|
|
Ładowanie…
Reference in New Issue