kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add @agentic/search to http e2e fixtures
rodzic
34d73481d7
commit
4a49cd3e42
|
@ -21,6 +21,11 @@ STRIPE_WEBHOOK_SECRET=
|
||||||
GITHUB_CLIENT_ID=
|
GITHUB_CLIENT_ID=
|
||||||
GITHUB_CLIENT_SECRET=
|
GITHUB_CLIENT_SECRET=
|
||||||
|
|
||||||
|
RESEND_API_KEY=
|
||||||
|
|
||||||
|
# Used to make admin API calls from the API gateway
|
||||||
AGENTIC_ADMIN_API_KEY=
|
AGENTIC_ADMIN_API_KEY=
|
||||||
|
|
||||||
RESEND_API_KEY=
|
# Used to simplify recreating the demo `@agentic/search` project during
|
||||||
|
# development while we're frequently resetting the database
|
||||||
|
AGENTIC_SEARCH_PROXY_SECRET=
|
||||||
|
|
|
@ -84,6 +84,13 @@ export function registerV1CreateDeployment(
|
||||||
user.username === 'agentic'
|
user.username === 'agentic'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Used to simplify recreating the demo `@agentic/search` project during
|
||||||
|
// development while we're frequently resetting the database
|
||||||
|
const secret =
|
||||||
|
projectIdentifier === '@agentic/search'
|
||||||
|
? env.AGENTIC_SEARCH_PROXY_SECRET
|
||||||
|
: await sha256()
|
||||||
|
|
||||||
// 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
|
||||||
// lastPublishedDeployment, but that's fine because it's a new project
|
// lastPublishedDeployment, but that's fine because it's a new project
|
||||||
|
@ -98,7 +105,7 @@ export function registerV1CreateDeployment(
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
teamId: teamMember?.teamId,
|
teamId: teamMember?.teamId,
|
||||||
private: isPrivate,
|
private: isPrivate,
|
||||||
_secret: await sha256()
|
_secret: secret
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
)[0] as typeof project
|
)[0] as typeof project
|
||||||
|
|
|
@ -55,12 +55,8 @@ export function registerV1CreateProject(
|
||||||
const teamMember = c.get('teamMember')
|
const teamMember = c.get('teamMember')
|
||||||
const namespace = teamMember ? teamMember.teamSlug : user.username
|
const namespace = teamMember ? teamMember.teamSlug : user.username
|
||||||
const identifier = `@${namespace}/${body.name}`
|
const identifier = `@${namespace}/${body.name}`
|
||||||
const parsedProjectIdentifier = parseProjectIdentifier(identifier)
|
const { projectIdentifier, projectNamespace, projectName } =
|
||||||
assert(
|
parseProjectIdentifier(identifier)
|
||||||
parsedProjectIdentifier,
|
|
||||||
400,
|
|
||||||
`Invalid project identifier "${identifier}"`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Used for testing e2e fixtures in the development marketplace
|
// Used for testing e2e fixtures in the development marketplace
|
||||||
const isPrivate = !(
|
const isPrivate = !(
|
||||||
|
@ -68,17 +64,24 @@ export function registerV1CreateProject(
|
||||||
user.username === 'agentic'
|
user.username === 'agentic'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Used to simplify recreating the demo `@agentic/search` project during
|
||||||
|
// development while we're frequently resetting the database
|
||||||
|
const secret =
|
||||||
|
projectIdentifier === '@agentic/search'
|
||||||
|
? env.AGENTIC_SEARCH_PROXY_SECRET
|
||||||
|
: await sha256()
|
||||||
|
|
||||||
const [project] = await db
|
const [project] = await db
|
||||||
.insert(schema.projects)
|
.insert(schema.projects)
|
||||||
.values({
|
.values({
|
||||||
...body,
|
...body,
|
||||||
identifier: parsedProjectIdentifier.projectIdentifier,
|
identifier: projectIdentifier,
|
||||||
namespace: parsedProjectIdentifier.projectNamespace,
|
namespace: projectNamespace,
|
||||||
name: parsedProjectIdentifier.projectName,
|
name: projectName,
|
||||||
teamId: teamMember?.teamId,
|
teamId: teamMember?.teamId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
private: isPrivate,
|
private: isPrivate,
|
||||||
_secret: await sha256()
|
_secret: secret
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
assert(project, 500, `Failed to create project "${body.name}"`)
|
assert(project, 500, `Failed to create project "${body.name}"`)
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const envSchema = baseEnvSchema
|
||||||
|
|
||||||
JWT_SECRET: z.string().nonempty(),
|
JWT_SECRET: z.string().nonempty(),
|
||||||
|
|
||||||
PORT: z.number().default(3001),
|
PORT: z.coerce.number().default(3001),
|
||||||
|
|
||||||
STRIPE_SECRET_KEY: z.string().nonempty(),
|
STRIPE_SECRET_KEY: z.string().nonempty(),
|
||||||
STRIPE_WEBHOOK_SECRET: z.string().nonempty(),
|
STRIPE_WEBHOOK_SECRET: z.string().nonempty(),
|
||||||
|
@ -23,9 +23,14 @@ export const envSchema = baseEnvSchema
|
||||||
GITHUB_CLIENT_ID: z.string().nonempty(),
|
GITHUB_CLIENT_ID: z.string().nonempty(),
|
||||||
GITHUB_CLIENT_SECRET: z.string().nonempty(),
|
GITHUB_CLIENT_SECRET: z.string().nonempty(),
|
||||||
|
|
||||||
|
RESEND_API_KEY: z.string().nonempty(),
|
||||||
|
|
||||||
|
// Used to make admin API calls from the API gateway
|
||||||
AGENTIC_ADMIN_API_KEY: z.string().nonempty(),
|
AGENTIC_ADMIN_API_KEY: z.string().nonempty(),
|
||||||
|
|
||||||
RESEND_API_KEY: z.string().nonempty()
|
// Used to simplify recreating the demo `@agentic/search` project during
|
||||||
|
// development while we're frequently resetting the database
|
||||||
|
AGENTIC_SEARCH_PROXY_SECRET: z.string().nonempty()
|
||||||
})
|
})
|
||||||
.strip()
|
.strip()
|
||||||
export type RawEnv = z.infer<typeof envSchema>
|
export type RawEnv = z.infer<typeof envSchema>
|
||||||
|
|
|
@ -137,8 +137,8 @@ for (const [i, fixtureSuite] of fixtureSuites.entries()) {
|
||||||
if (debugFixture) {
|
if (debugFixture) {
|
||||||
console.log(
|
console.log(
|
||||||
`${repeatIterationPrefix}${fixtureName} => ${res.status}`,
|
`${repeatIterationPrefix}${fixtureName} => ${res.status}`,
|
||||||
|
body,
|
||||||
{
|
{
|
||||||
body,
|
|
||||||
headers: Object.fromEntries(res.headers.entries())
|
headers: Object.fromEntries(res.headers.entries())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -716,5 +716,24 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'HTTP => Production MCP origin "search" tool',
|
||||||
|
// NOTE: this one actually hits a production service and costs a small
|
||||||
|
// amount of $ per request.
|
||||||
|
fixtures: [
|
||||||
|
{
|
||||||
|
path: '@agentic/search/search',
|
||||||
|
request: {
|
||||||
|
method: 'POST',
|
||||||
|
json: {
|
||||||
|
query: 'latest ai news'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
snapshot: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agentic/platform": "workspace:*",
|
"@agentic/platform": "workspace:*",
|
||||||
"@agentic/platform-core": "workspace:*",
|
|
||||||
"@agentic/serper": "catalog:",
|
"@agentic/serper": "catalog:",
|
||||||
"@hono/mcp": "catalog:",
|
"@hono/mcp": "catalog:",
|
||||||
"@modelcontextprotocol/sdk": "catalog:",
|
"@modelcontextprotocol/sdk": "catalog:",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { assert } from '@agentic/platform-core'
|
|
||||||
import { SerperClient } from '@agentic/serper'
|
import { SerperClient } from '@agentic/serper'
|
||||||
import { StreamableHTTPTransport } from '@hono/mcp'
|
import { StreamableHTTPTransport } from '@hono/mcp'
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||||
|
@ -59,21 +58,42 @@ export default {
|
||||||
.optional()
|
.optional()
|
||||||
.describe('Type of Google search to perform')
|
.describe('Type of Google search to perform')
|
||||||
}).shape,
|
}).shape,
|
||||||
outputSchema: z.object({}).passthrough().shape
|
outputSchema: z
|
||||||
|
.object({
|
||||||
|
results: z.any(),
|
||||||
|
answerBox: z.any().optional(),
|
||||||
|
knowledgeGraph: z.any().optional(),
|
||||||
|
images: z.any().optional(),
|
||||||
|
videos: z.any().optional(),
|
||||||
|
places: z.any().optional(),
|
||||||
|
news: z.any().optional(),
|
||||||
|
shopping: z.any().optional()
|
||||||
|
})
|
||||||
|
.passthrough().shape
|
||||||
},
|
},
|
||||||
async (args, { _meta }) => {
|
async (args, { _meta }) => {
|
||||||
|
console.log('search call', {
|
||||||
|
args,
|
||||||
|
_meta
|
||||||
|
})
|
||||||
|
|
||||||
// Make sure the request is coming from Agentic
|
// Make sure the request is coming from Agentic
|
||||||
assert(
|
if (
|
||||||
(_meta?.agentic as any)?.agenticProxySecret ===
|
(_meta?.agentic as any)?.agenticProxySecret !==
|
||||||
parsedEnv.AGENTIC_PROXY_SECRET,
|
parsedEnv.AGENTIC_PROXY_SECRET
|
||||||
400,
|
) {
|
||||||
'Invalid request'
|
return {
|
||||||
)
|
content: [],
|
||||||
|
structuredContent: {
|
||||||
|
error: 'Invalid request'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result: any = await serper!.search({
|
const result: any = await serper!.search({
|
||||||
q: args.query,
|
q: args.query,
|
||||||
num: args.num,
|
num: args.num ?? 5,
|
||||||
type: args.type
|
type: args.type ?? 'search'
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simplify search results to optimize for LLM usage
|
// Simplify search results to optimize for LLM usage
|
||||||
|
@ -83,6 +103,7 @@ export default {
|
||||||
delete result.peopleAlsoAsk
|
delete result.peopleAlsoAsk
|
||||||
delete result.searchParameters
|
delete result.searchParameters
|
||||||
delete result.credits
|
delete result.credits
|
||||||
|
delete result.relatedSearches
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [],
|
content: [],
|
||||||
|
|
|
@ -8,5 +8,9 @@
|
||||||
"compatibility_date": "2025-05-25",
|
"compatibility_date": "2025-05-25",
|
||||||
"compatibility_flags": ["nodejs_compat"],
|
"compatibility_flags": ["nodejs_compat"],
|
||||||
"placement": { "mode": "smart" },
|
"placement": { "mode": "smart" },
|
||||||
"upload_source_maps": true
|
"upload_source_maps": true,
|
||||||
|
"observability": {
|
||||||
|
"enabled": true,
|
||||||
|
"head_sampling_rate": 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,9 +834,6 @@ importers:
|
||||||
'@agentic/platform':
|
'@agentic/platform':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/platform
|
version: link:../../packages/platform
|
||||||
'@agentic/platform-core':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../packages/core
|
|
||||||
'@agentic/serper':
|
'@agentic/serper':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 7.6.7(zod@3.25.67)
|
version: 7.6.7(zod@3.25.67)
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
- merge with current agentic repo
|
- merge with current agentic repo
|
||||||
- publish packages to npm
|
- publish packages to npm
|
||||||
- api
|
- api
|
||||||
- deploy to prod
|
- **deploy to prod**
|
||||||
- database
|
- database
|
||||||
- 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?
|
||||||
|
|
Ładowanie…
Reference in New Issue