Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 1x 1x 1x 1x 1x 1x 1x 20x 13x 13x 13x 13x 13x 4x 4x 4x 4x 2x 2x 2x 2x 4x 4x 4x 4x 9x 13x 1x 1x 13x 13x 6x 6x 6x 6x 6x 2x 13x 13x 13x 13x 13x 13x 13x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 13x 1x 1x 1x 13x 13x 13x 20x 1x | import type { AppContext } from '@api/types/hono';
import type { HttpMethod } from '@api/types/http';
import { SuperAgentsConfigPreProcessed } from '@shared/types/api/request/headers';
import {
InvalidRequestBodyError,
isKnownRoute,
produceSuperAgentsRequestData,
} from '@shared/utils/sa-request-data';
import { parseAgentSkillPath } from '@shared/utils/url';
import type { Next } from 'hono';
import { createMiddleware } from 'hono/factory';
import z from 'zod';
/**
* Middleware to set common variables in the context
*/
export const commonVariablesMiddleware = createMiddleware(
async (c: AppContext, next: Next) => {
// Only set variables for API requests
if (c.req.url.includes('/v1/')) {
// Don't set variables for Super Agents API requests
if (!c.req.url.includes('/v1/super-agents')) {
// The agent and skill can be named in the path
// (`/v1/agents/:agent_name/skills/:skill_name/chat/completions`) instead
// of in the `sa-config` header. When they are, the header is optional.
const { pathname } = new URL(c.req.url);
const agentSkillScope = parseAgentSkillPath(pathname);
const method = c.req.method as HttpMethod;
// Answer an unroutable path before asking for credentials or config, so
// a mistyped URL reads as a mistyped URL.
if (!isKnownRoute(method, c.req.url)) {
return c.json(
{
error: `No API route matches ${method} ${pathname}`,
// The scoped form is easy to mistype, so point at it whenever the
// path looks like an attempt at it.
...(pathname.startsWith('/v1/agents/') && !agentSkillScope
? {
hint: 'Expected /v1/agents/{agent_name}/skills/{skill_name}/{endpoint}',
}
: {}),
},
404,
);
}
const configString = c.req.header('sa-config');
if (!configString && !agentSkillScope) {
return c.json({ error: 'Missing Super Agents config' }, 422);
}
const rawConfig = configString ? JSON.parse(configString) : {};
// The path always wins over the header so that a client pointed at a
// skill's base URL cannot accidentally target another skill.
const config = agentSkillScope
? {
...rawConfig,
agent_name: agentSkillScope.agent_name,
skill_name: agentSkillScope.skill_name,
}
: rawConfig;
const saConfigPreProcessed = SuperAgentsConfigPreProcessed.safeParse(
config,
{
error: (error) => `Invalid Super Agents config as ${error.message}`,
},
);
if (saConfigPreProcessed.error) {
const prettyError = z.prettifyError(saConfigPreProcessed.error);
return c.json(
{
error: `--Invalid Super Agents config--\n ${prettyError}`,
details: saConfigPreProcessed.error.message,
},
422,
);
}
c.set('sa_config_pre_processed', saConfigPreProcessed.data);
const body = await c.req.json();
try {
const saRequestData = produceSuperAgentsRequestData(
method,
c.req.url,
c.req.header(),
body,
);
c.set('sa_request_data', saRequestData);
} catch (err) {
// `isKnownRoute` ignores the body, so a route can still be ruled out
// here by the request's stream mode or by its schema.
if (err instanceof InvalidRequestBodyError) {
return c.json({ error: err.message }, 422);
}
throw err;
}
}
}
await next();
},
);
|