feat: add @agentic/search to http e2e fixtures

pull/715/head
Travis Fischer 2025-06-25 02:30:22 -05:00
rodzic 34d73481d7
commit 4a49cd3e42
11 zmienionych plików z 91 dodań i 31 usunięć

Wyświetl plik

@ -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=

Wyświetl plik

@ -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

Wyświetl plik

@ -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}"`)

Wyświetl plik

@ -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>

Wyświetl plik

@ -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())
} }
) )

Wyświetl plik

@ -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
}
}
]
} }
] ]

Wyświetl plik

@ -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:",

Wyświetl plik

@ -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: [],

Wyświetl plik

@ -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
}
} }

Wyświetl plik

@ -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)

Wyświetl plik

@ -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?