pull/715/head
Travis Fischer 2025-06-06 04:21:43 +07:00
rodzic 8f028bf538
commit e13308f801
11 zmienionych plików z 113 dodań i 62 usunięć

Wyświetl plik

@ -65,7 +65,7 @@ export function registerV1DeploymentsCreateDeployment(
const logger = c.get('logger')
const namespace = teamMember ? teamMember.teamSlug : user.username
const projectIdentifier = `${namespace}/${body.name}`
const projectIdentifier = `@${namespace}/${body.name}`
assert(
isValidProjectIdentifier(projectIdentifier),
400,

Wyświetl plik

@ -1,4 +1,5 @@
import { assert, parseZodSchema, sha256 } from '@agentic/platform-core'
import { isValidProjectIdentifier } from '@agentic/platform-validators'
import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
import type { AuthenticatedHonoEnv } from '@/lib/types'
@ -52,7 +53,12 @@ export function registerV1ProjectsCreateProject(
const teamMember = c.get('teamMember')
const namespace = teamMember ? teamMember.teamSlug : user.username
const identifier = `${namespace}/${body.name}`
const identifier = `@${namespace}/${body.name}`
assert(
isValidProjectIdentifier(identifier),
400,
`Invalid project identifier "${identifier}"`
)
const [project] = await db
.insert(schema.projects)

Wyświetl plik

@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Basic GET caching > 3.0: GET dev/test-basic-openapi@b6e21206/getPost 1`] = `
exports[`Basic GET caching > 3.0: GET @dev/test-basic-openapi@fc856666/getPost 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -12,7 +12,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Basic GET caching > 3.1: GET dev/test-basic-openapi@b6e21206/getPost?postId=9 1`] = `
exports[`Basic GET caching > 3.1: GET @dev/test-basic-openapi@fc856666/getPost?postId=9 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -24,7 +24,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Basic GET caching > 3.2: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = `
exports[`Basic GET caching > 3.2: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -36,7 +36,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Basic OpenAPI getPost success > 0.0: POST dev/test-basic-openapi/getPost 1`] = `
exports[`Basic OpenAPI getPost success > 0.0: POST @dev/test-basic-openapi/getPost 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -48,7 +48,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic OpenAPI getPost success > 0.1: POST dev/test-basic-openapi@latest/getPost 1`] = `
exports[`Basic OpenAPI getPost success > 0.1: POST @dev/test-basic-openapi@latest/getPost 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -60,7 +60,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic OpenAPI getPost success > 0.2: GET dev/test-basic-openapi/getPost 1`] = `
exports[`Basic OpenAPI getPost success > 0.2: GET @dev/test-basic-openapi/getPost 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -72,7 +72,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic OpenAPI getPost success > 0.3: GET dev/test-basic-openapi@b6e21206/getPost?postId=1 1`] = `
exports[`Basic OpenAPI getPost success > 0.3: GET @dev/test-basic-openapi@fc856666/getPost?postId=1 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -84,7 +84,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic OpenAPI getPost success > 0.4: GET dev/test-basic-openapi@b6e21206/get_post?postId=1 1`] = `
exports[`Basic OpenAPI getPost success > 0.4: GET @dev/test-basic-openapi@fc856666/get_post?postId=1 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -96,7 +96,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic OpenAPI getPost success > 0.5: GET dev/test-basic-openapi@b6e21206/getPost 1`] = `
exports[`Basic OpenAPI getPost success > 0.5: GET @dev/test-basic-openapi@fc856666/getPost 1`] = `
{
"body": "quia et suscipit
suscipit recusandae consequuntur expedita et cum
@ -108,7 +108,7 @@ nostrum rerum est autem sunt rem eveniet architecto",
}
`;
exports[`Basic POST caching > 4.0: POST dev/test-basic-openapi@b6e21206/get_post 1`] = `
exports[`Basic POST caching > 4.0: POST @dev/test-basic-openapi@fc856666/get_post 1`] = `
{
"body": "aut dicta possimus sint mollitia voluptas commodi quo doloremque
iste corrupti reiciendis voluptatem eius rerum
@ -120,7 +120,7 @@ perferendis recusandae assumenda consectetur porro architecto ipsum ipsam",
}
`;
exports[`Basic POST caching > 4.1: POST dev/test-basic-openapi@b6e21206/get_post 1`] = `
exports[`Basic POST caching > 4.1: POST @dev/test-basic-openapi@fc856666/get_post 1`] = `
{
"body": "aut dicta possimus sint mollitia voluptas commodi quo doloremque
iste corrupti reiciendis voluptatem eius rerum
@ -132,7 +132,7 @@ perferendis recusandae assumenda consectetur porro architecto ipsum ipsam",
}
`;
exports[`Bypass caching > 2.0: GET dev/test-basic-openapi@b6e21206/getPost 1`] = `
exports[`Bypass caching > 2.0: GET @dev/test-basic-openapi@fc856666/getPost 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -144,7 +144,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Bypass caching > 2.1: GET dev/test-basic-openapi@b6e21206/getPost?postId=9 1`] = `
exports[`Bypass caching > 2.1: GET @dev/test-basic-openapi@fc856666/getPost?postId=9 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -156,7 +156,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Bypass caching > 2.2: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = `
exports[`Bypass caching > 2.2: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad
@ -168,7 +168,7 @@ et est aut quod aut provident voluptas autem voluptas",
}
`;
exports[`Bypass caching > 2.3: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = `
exports[`Bypass caching > 2.3: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = `
{
"body": "consectetur animi nesciunt iure dolore
enim quia ad

Wyświetl plik

@ -49,7 +49,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
compareResponseBodies: true,
fixtures: [
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'POST',
json: {
@ -58,7 +58,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi@latest/getPost',
path: '@dev/test-basic-openapi@latest/getPost',
request: {
method: 'POST',
json: {
@ -67,7 +67,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
searchParams: {
// all of these GET requests implicitly test type coercion since
@ -78,13 +78,13 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi@b6e21206/getPost?postId=1'
path: '@dev/test-basic-openapi@fc856666/getPost?postId=1'
},
{
path: 'dev/test-basic-openapi@b6e21206/get_post?postId=1'
path: '@dev/test-basic-openapi@fc856666/get_post?postId=1'
},
{
path: 'dev/test-basic-openapi@b6e21206/getPost',
path: '@dev/test-basic-openapi@fc856666/getPost',
request: {
searchParams: {
postId: 1
@ -97,7 +97,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
title: 'Basic OpenAPI getPost errors',
fixtures: [
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
response: {
// Missing `postId` parameter.
@ -105,19 +105,19 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi@b6e21206/getPost?postId=foo',
path: '@dev/test-basic-openapi@fc856666/getPost?postId=foo',
response: {
status: 400
}
},
{
path: 'dev/test-basic-openapi@000000/getPost',
path: '@dev/test-basic-openapi@00000000/getPost',
response: {
status: 404
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'PUT',
json: {
@ -129,13 +129,13 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi@latest/get_kittens?postId=1',
path: '@dev/test-basic-openapi@latest/get_kittens?postId=1',
response: {
status: 404
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
searchParams: {
// invalid `postId` field type
@ -147,7 +147,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'POST',
json: {
@ -159,7 +159,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'POST',
json: {
@ -172,7 +172,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'POST',
json: {
@ -185,7 +185,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
method: 'POST',
json: {
@ -199,7 +199,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi/getPost',
path: '@dev/test-basic-openapi/getPost',
request: {
searchParams: {
postId: 1,
@ -219,7 +219,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
fixtures: [
{
// ensure we bypass the cache for requests with `pragma: no-cache`
path: 'dev/test-basic-openapi@b6e21206/getPost',
path: '@dev/test-basic-openapi@fc856666/getPost',
request: {
headers: {
pragma: 'no-cache'
@ -236,7 +236,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
},
{
// ensure we bypass the cache for requests with `pragma: no-cache`
path: 'dev/test-basic-openapi@b6e21206/getPost?postId=9',
path: '@dev/test-basic-openapi@fc856666/getPost?postId=9',
request: {
headers: {
'cache-control': 'no-cache'
@ -250,7 +250,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
},
{
// ensure we bypass the cache for requests with `cache-control: no-store`
path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9',
path: '@dev/test-basic-openapi@fc856666/get_post?postId=9',
request: {
headers: {
'cache-control': 'no-store'
@ -263,7 +263,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
},
{
path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9',
path: '@dev/test-basic-openapi@fc856666/get_post?postId=9',
request: {
headers: {
'cache-control': 'max-age=0, must-revalidate, no-cache'
@ -284,7 +284,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
fixtures: [
{
// first request to ensure the cache is populated
path: 'dev/test-basic-openapi@b6e21206/getPost',
path: '@dev/test-basic-openapi@fc856666/getPost',
request: {
searchParams: {
postId: 9
@ -293,7 +293,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
},
{
// second request should hit the cache
path: 'dev/test-basic-openapi@b6e21206/getPost?postId=9',
path: '@dev/test-basic-openapi@fc856666/getPost?postId=9',
response: {
headers: {
'cf-cache-status': 'HIT'
@ -302,7 +302,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
},
{
// normalized request should also hit the cache
path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9',
path: '@dev/test-basic-openapi@fc856666/get_post?postId=9',
response: {
headers: {
'cf-cache-status': 'HIT'
@ -318,7 +318,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
fixtures: [
{
// first request to ensure the cache is populated
path: 'dev/test-basic-openapi@b6e21206/get_post',
path: '@dev/test-basic-openapi@fc856666/get_post',
request: {
method: 'POST',
json: {
@ -328,7 +328,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
},
{
// second request should hit the cache
path: 'dev/test-basic-openapi@b6e21206/get_post',
path: '@dev/test-basic-openapi@fc856666/get_post',
request: {
method: 'POST',
json: {
@ -343,4 +343,19 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [
}
]
}
// {
// title: 'Basic MCP origin tool call success',
// compareResponseBodies: true,
// fixtures: [
// {
// path: '@dev/test-basic-openapi@fc856666/get_post',
// request: {
// method: 'POST',
// json: {
// postId: 13
// }
// }
// },
// ]
// }
]

Wyświetl plik

@ -35,16 +35,13 @@ export async function resolveOriginRequest(
const { method } = ctx.req
const requestUrl = new URL(ctx.req.url)
const { pathname } = requestUrl
const requestPathParts = pathname.split('/')
// TODO: the isMCPRequest logic needs to be completely redone.
const isMCPRequest = requestPathParts[0] === 'mcp'
const requestPath = isMCPRequest
? requestPathParts.slice(1).join('/')
: pathname
const parsedToolIdentifier = parseToolIdentifier(requestPath)
assert(parsedToolIdentifier, 404, `Invalid tool identifier "${requestPath}"`)
const requestedToolIdentifier = pathname.replace(/^\//, '')
const parsedToolIdentifier = parseToolIdentifier(requestedToolIdentifier)
assert(
parsedToolIdentifier,
404,
`Invalid tool identifier "${requestedToolIdentifier}"`
)
const { toolName } = parsedToolIdentifier
const deployment = await getAdminDeployment(

Wyświetl plik

@ -7,7 +7,7 @@ import { AuthStore } from './auth-store'
export async function resolveDeployment({
client,
deploymentIdentifier,
fuzzyDeploymentIdentifierVersion = 'latest',
fuzzyDeploymentIdentifierVersion,
cwd,
populate
}: {
@ -27,7 +27,7 @@ export async function resolveDeployment({
// TODO: resolve deploymentIdentifier; config name may include namespace?
// TODO: this needs work...
deploymentIdentifier = `${namespace}/${config.name}@${fuzzyDeploymentIdentifierVersion}`
deploymentIdentifier = `@${namespace}/${config.name}${fuzzyDeploymentIdentifierVersion ? `@${fuzzyDeploymentIdentifierVersion}` : ''}`
}
const deployment = await client.getDeploymentByIdentifier({

Wyświetl plik

@ -33,7 +33,7 @@ export function errorHandler(
if (status >= 500) {
logger.error(status, err)
captureException(err)
} else if (isProd) {
} else {
logger.warn(status, err)
}

Wyświetl plik

@ -1,5 +1,34 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`loadAgenticConfig > basic-mcp 1`] = `
{
"name": "test-basic-mcp",
"originAdapter": {
"location": "external",
"type": "mcp",
},
"originUrl": "https://agentic-basic-mcp-test.onrender.com/stream",
"pricingIntervals": [
"month",
],
"pricingPlans": [
{
"lineItems": [
{
"amount": 0,
"slug": "base",
"usageType": "licensed",
},
],
"name": "Free",
"slug": "free",
},
],
"toolConfigs": [],
"version": undefined,
}
`;
exports[`loadAgenticConfig > basic-openapi 1`] = `
{
"name": "test-basic-openapi",
@ -88,15 +117,15 @@ exports[`loadAgenticConfig > basic-raw-free-ts 1`] = `
}
`;
exports[`loadAgenticConfig > invalid: invalid-name-0 1`] = `[Error: Invalid project name "Test Invalid Name 0". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-0 1`] = `[Error: Invalid project name "Test Invalid Name 0". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-1 1`] = `[Error: Invalid project name "Test-Invalid-Name-1". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-1 1`] = `[Error: Invalid project name "Test-Invalid-Name-1". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-2 1`] = `[Error: Invalid project name "test_invalid_name_2". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-2 1`] = `[Error: Invalid project name "test_invalid_name_2". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-3 1`] = `[ZodValidationError: Validation error: Required at "name"]`;
exports[`loadAgenticConfig > invalid: invalid-name-4 1`] = `[Error: Invalid project name "@foo/bar". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-name-4 1`] = `[Error: Invalid project name "@foo/bar". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`;
exports[`loadAgenticConfig > invalid: invalid-origin-url-0 1`] = `[Error: Invalid originUrl: must be a valid https URL]`;

Wyświetl plik

@ -13,7 +13,8 @@ const fixtures = [
'pricing-3-plans',
'pricing-monthly-annual',
'pricing-custom-0',
'basic-openapi'
'basic-openapi',
'basic-mcp'
]
const invalidFixtures = [

Wyświetl plik

@ -12,7 +12,7 @@ export function resolveMetadata({
> {
assert(
isValidProjectName(name),
`Invalid project name "${name}". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"`
`Invalid project name "${name}". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"`
)
if (version) {

Wyświetl plik

@ -37,6 +37,9 @@
- how to handle binary bodies and responses?
- add requestId to all JSON error responses
- add support for `immutable` in `toolConfigs`
- mcp origin servers
- ignore sse for now
- only support [streamable http](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) like smithery does
## TODO Post-MVP