@tangle-network/agent-gateway 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -6
- package/dist/chunk-GITV7CPT.js +84 -0
- package/dist/chunk-GITV7CPT.js.map +1 -0
- package/dist/chunk-J5SDVHOL.js +104 -0
- package/dist/chunk-J5SDVHOL.js.map +1 -0
- package/dist/chunk-MP6IIAIA.js +5651 -0
- package/dist/chunk-MP6IIAIA.js.map +1 -0
- package/dist/index.d.ts +76 -12
- package/dist/index.js +307 -21
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts +7 -2
- package/dist/middleware.js +3 -2
- package/dist/nonce-store.d.ts +47 -11
- package/dist/nonce-store.js +9 -3
- package/dist/observer-types-A0RtA8uL.d.ts +95 -0
- package/dist/observer.d.ts +79 -0
- package/dist/observer.js +11 -0
- package/dist/observer.js.map +1 -0
- package/dist/{types-CX2V06cN.d.ts → types-BHISsm7D.d.ts} +423 -166
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/a2a/agent-card.ts +4 -3
- package/src/a2a/execution-fence.ts +162 -0
- package/src/a2a/handler.ts +507 -562
- package/src/a2a/message-send-execution.ts +241 -0
- package/src/a2a/message-stream-execution.ts +392 -0
- package/src/a2a/payment-recovery.ts +431 -0
- package/src/a2a/push-config-methods.ts +158 -0
- package/src/a2a/push-notifications.ts +172 -22
- package/src/a2a/task-cancellation.ts +50 -0
- package/src/a2a/task-finalization.ts +451 -0
- package/src/a2a/task-lifecycle.ts +54 -0
- package/src/a2a/task-methods.ts +163 -0
- package/src/a2a/task-push-delivery.ts +119 -0
- package/src/a2a/task-recovery.ts +11 -0
- package/src/a2a/task-state.ts +99 -0
- package/src/a2a/task-store-sql.ts +222 -24
- package/src/a2a/task-store.ts +58 -1
- package/src/a2a/task-submission-recovery.ts +178 -0
- package/src/a2a/types.ts +1 -0
- package/src/dispatch-authorization.ts +437 -0
- package/src/dispatch-payment-recovery.ts +248 -0
- package/src/dispatch-payment.ts +425 -0
- package/src/dispatch-pricing.ts +108 -0
- package/src/dispatch-sandbox.ts +422 -0
- package/src/dispatch-settlement.ts +139 -0
- package/src/dispatch-types.ts +81 -0
- package/src/dispatch.ts +35 -462
- package/src/index.ts +64 -2
- package/src/middleware.ts +313 -32
- package/src/mpp-payment.ts +117 -0
- package/src/nonce-store.ts +122 -20
- package/src/observer-types.ts +63 -0
- package/src/observer.ts +3 -63
- package/src/payment-operations.ts +485 -0
- package/src/payment-recovery-sql.ts +108 -0
- package/src/payment-recovery-worker.ts +488 -0
- package/src/payment-recovery.ts +331 -0
- package/src/payment-types.ts +48 -0
- package/src/types.ts +153 -42
- package/src/verify.ts +265 -36
- package/dist/chunk-3IKQWFKX.js +0 -1703
- package/dist/chunk-3IKQWFKX.js.map +0 -1
- package/dist/chunk-M7ZJAK4K.js +0 -53
- package/dist/chunk-M7ZJAK4K.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts","../src/filter.ts","../src/observer.ts","../src/verify.ts","../src/dispatch.ts","../src/a2a/agent-card.ts","../src/a2a/types.ts","../src/a2a/jsonrpc.ts","../src/a2a/push-notifications.ts","../src/a2a/translate.ts","../src/a2a/handler.ts","../src/a2a/task-store.ts"],"sourcesContent":["import { Hono } from 'hono'\n\nimport { createA2AHandlers } from './a2a/handler'\nimport { InMemoryTaskStore } from './a2a/task-store'\nimport {\n type AuthorizedRequest,\n type GatewayState,\n authenticateAndGuard,\n dispatchSandboxStream,\n estimateTokens,\n settleAndRecord,\n} from './dispatch'\nimport { MemoryNonceStore } from './nonce-store'\nimport { type GatewayObserver, type RequestContext, generateRequestId } from './observer'\nimport { MemoryRateLimitStore, type RateLimitStore } from './rate-limit'\nimport type { ChatCompletionChunk, ChatCompletionRequest, GatewayConfig } from './types'\n\n/**\n * Create a Hono router that serves the agent gateway.\n *\n * Mount at any path:\n * app.route('/v1/agents', createAgentGateway(config))\n *\n * Exposes:\n * GET /:slug/chat/completions — agent discovery metadata (Tangle-native shape)\n * POST /:slug/chat/completions — OpenAI-compatible chat endpoint (paid)\n */\nexport function createAgentGateway(config: GatewayConfig) {\n // Production gateways must verify x402 signatures. Tests and local\n // dev can opt into the explicit demo path.\n if (!config.x402.verifySigner && !config.x402.demoMode) {\n throw new Error(\n 'createAgentGateway: x402.verifySigner is required in production. ' +\n 'For tests, set x402.demoMode: true explicitly.',\n )\n }\n const gw = new Hono()\n const rateLimitStore: RateLimitStore = config.rateLimitStore ?? new MemoryRateLimitStore()\n const state: GatewayState = {\n rateLimitStore,\n nonceStore: config.nonceStore ?? new MemoryNonceStore(),\n globalRateLimit: config.rateLimit ?? { limit: 60, windowSeconds: 60 },\n requiredScope: config.requiredScope ?? 'chat',\n maxLen: config.maxMessageLength ?? 8000,\n obs: config.observer,\n }\n const obs: GatewayObserver | undefined = state.obs\n\n // --- Discovery endpoint (no auth) ---\n\n gw.get('/:slug/chat/completions', async (c) => {\n const slug = c.req.param('slug')\n const agent = await config.resolveAgent(slug)\n if (!agent) return c.json({ error: 'Agent not found or not published' }, 404)\n\n const paymentMethods: Array<Record<string, unknown>> = [\n {\n type: 'x402',\n operator: config.x402.operatorAddress,\n chain_id: config.x402.chainId,\n credits_contract: config.x402.creditsAddress,\n },\n ]\n if (config.mpp) {\n paymentMethods.push({\n type: 'mpp',\n realm: config.mpp.realm,\n method: config.mpp.method ?? 'blueprintevm',\n })\n }\n paymentMethods.push({ type: 'api_key', prefix: 'sk_agent_' })\n\n return c.json({\n slug: agent.slug,\n pricing: {\n per_token_usd: agent.pricePerTokenUsd,\n currency: 'USD',\n platform_fee_percent: agent.platformFeePercent,\n },\n hosting: {\n mode: agent.sandboxEndpoint ? 'sovereign' : 'centralized',\n endpoint: agent.sandboxEndpoint ?? config.baseUrl ?? 'tangle.tools',\n },\n payment_methods: paymentMethods,\n capabilities: ['chat.completions', 'streaming'],\n openai_compatible: true,\n })\n })\n\n // --- Chat completions endpoint (paid) ---\n\n gw.post('/:slug/chat/completions', async (c) => {\n const slug = c.req.param('slug')\n\n // Body size limit (before parsing — DoS prevention).\n const contentLength = Number.parseInt(c.req.header('Content-Length') ?? '0', 10)\n if (contentLength > 65536) {\n const requestId = generateRequestId()\n await obs?.onBodyTooLarge?.(\n { requestId, agentSlug: slug, startMs: Date.now() },\n contentLength,\n )\n return c.json(\n {\n error: {\n message: 'Request body too large (max 64KB)',\n type: 'invalid_request',\n },\n },\n 413,\n )\n }\n\n let body: ChatCompletionRequest\n try {\n body = await c.req.json()\n } catch {\n return c.json({ error: { message: 'Invalid JSON', type: 'invalid_request' } }, 400)\n }\n if (!body.messages?.length) {\n return c.json(\n { error: { message: 'messages array required', type: 'invalid_request' } },\n 400,\n )\n }\n\n const guard = await authenticateAndGuard(c, slug, body.messages, config, state)\n if (guard instanceof Response) return guard\n const authz = guard\n\n return streamChatCompletions(c, authz, config, obs)\n })\n\n // --- A2A protocol surface (Google Agent-to-Agent, JSON-RPC 2.0 + AgentCard) ---\n // Mounted alongside the OpenAI-compat routes so a single agent speaks both.\n // Both surfaces share authenticateAndGuard + dispatchSandboxStream +\n // settleAndRecord, so every security and billing guarantee applies uniformly\n // regardless of which protocol the caller used.\n const taskStore = config.a2a?.taskStore ?? new InMemoryTaskStore()\n const pushStore = config.a2a?.pushStore\n const a2a = createA2AHandlers({ config, state, taskStore, pushStore })\n gw.get('/:slug/.well-known/agent.json', a2a.handleAgentCard)\n gw.post('/:slug', a2a.handleJsonRpc)\n\n return gw\n}\n\n/**\n * Drain the sandbox stream into an OpenAI-shaped SSE response, settle the\n * payment, fire observer hooks. Identical pre-refactor behavior, just lifted\n * out of the handler so the A2A wrapper can reach the same dispatch path\n * without duplicating it.\n */\nfunction streamChatCompletions(\n c: import('hono').Context,\n authz: AuthorizedRequest,\n config: GatewayConfig,\n obs: GatewayObserver | undefined,\n): Response {\n const { agent, consumerId, paymentMethod, requestId, userMessage, rateLimitRemaining } = authz\n const inputTokens = estimateTokens(userMessage)\n let outputTokens = 0\n const ctx: RequestContext = {\n requestId,\n agentSlug: agent.slug,\n startMs: authz.startMs,\n }\n\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder()\n const sendChunk = (delta: string) => {\n outputTokens += estimateTokens(delta)\n const chunk: ChatCompletionChunk = {\n id: `chatcmpl-${Date.now()}`,\n object: 'chat.completion.chunk',\n created: Math.floor(Date.now() / 1000),\n model: agent.slug,\n choices: [{ index: 0, delta: { content: delta }, finish_reason: null }],\n }\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\\n\\n`))\n }\n\n try {\n for await (const delta of dispatchSandboxStream(agent, userMessage, consumerId, config)) {\n sendChunk(delta)\n }\n\n const done: ChatCompletionChunk = {\n id: `chatcmpl-${Date.now()}`,\n object: 'chat.completion.chunk',\n created: Math.floor(Date.now() / 1000),\n model: agent.slug,\n choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],\n }\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(done)}\\n\\n`))\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'))\n\n await settleAndRecord(agent, authz, inputTokens, outputTokens, config, obs)\n } catch (err) {\n const rawMessage = err instanceof Error ? err.message : String(err)\n // Never expose stack traces / absolute paths from sandbox internals.\n const safeMessage =\n rawMessage.includes('/') || rawMessage.includes('\\\\')\n ? 'Internal agent error'\n : rawMessage\n await obs?.onStreamError?.(ctx, { consumerId, errorMessage: rawMessage })\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ error: { message: safeMessage, type: 'server_error' } })}\\n\\n`,\n ),\n )\n } finally {\n controller.close()\n }\n },\n })\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'X-Request-Id': requestId,\n 'X-Agent-Slug': agent.slug,\n 'X-Agent-Hosting': agent.sandboxEndpoint ? 'sovereign' : 'centralized',\n 'X-Payment-Method': paymentMethod,\n 'X-Payment-Settled': paymentMethod === 'x402' ? 'pending' : 'true',\n ...(rateLimitRemaining !== undefined\n ? { 'X-RateLimit-Remaining': String(rateLimitRemaining) }\n : {}),\n },\n })\n}\n\n","import type { ChatMessage } from './types'\n\n// --- Injection detection patterns ---\n\nconst INJECTION_PATTERNS = [\n // Direct instruction override\n /ignore\\s+(all\\s+)?(previous|prior|above|earlier)\\s+(instructions?|prompts?|rules?|directives?)/i,\n /disregard\\s+(all\\s+)?(previous|prior|system)/i,\n /forget\\s+(everything|all|your)\\s+(previous|instructions?|training)/i,\n // Role assumption\n /you\\s+are\\s+now\\s+(a|an|the)\\s+/i,\n /pretend\\s+(you\\s+are|to\\s+be)\\s+/i,\n /act\\s+as\\s+(if\\s+you\\s+are|a|an|the)\\s+/i,\n /new\\s+instructions?:/i,\n /\\[system\\]/i,\n /\\[INST\\]/i,\n // Prompt extraction\n /what\\s+(is|are)\\s+your\\s+(system\\s+)?(prompt|instructions?|rules?|directives?)/i,\n /repeat\\s+(your|the)\\s+(system\\s+)?(prompt|instructions?)/i,\n /output\\s+(your|the)\\s+((system|initial|original|first|full|real|hidden|secret|raw|exact)\\s+)?(prompt|instructions?)/i,\n /show\\s+(me\\s+)?(your|the)\\s+((system|hidden|secret|initial|original)\\s+)?(prompt|instructions?|message|directives?)/i,\n /tell\\s+me\\s+(your|the)\\s+(system\\s+)?(prompt|instructions?|rules?)/i,\n // Developer/debug/admin/jailbreak mode override\n /(developer|debug|admin|god|sudo|jailbreak|unrestricted|maintenance)\\s+mode/i,\n // Safety/safeguard disablement\n /(disable|bypass|override|remove|turn\\s+off)\\s+(your\\s+|the\\s+)?(safety|safeguards?|guardrails?|filters?|restrictions?|rules?|limitations?|content\\s+policy)/i,\n // Role reversal\n /(from\\s+now\\s+on|starting\\s+now|now)\\s+you('re|\\s+are)\\s+(the\\s+)?(user|human|customer|assistant)/i,\n /i('m|\\s+am)\\s+(the\\s+)?(assistant|ai|model|llm|bot)/i,\n // Tool-call / JSON-shaped spoofs\n /\"(?:tool|function|action|call)\"\\s*:\\s*\"[^\"]*(exfiltrate|leak|reveal|dump|extract|steal)[^\"]*\"/i,\n /exfiltrate[_\\s]*(system|prompt|secret|vault|config|data)/i,\n // Data exfiltration\n /read\\s+(the\\s+)?(vault|workspace|config|secret|\\.env)/i,\n /cat\\s+\\/home\\/agent\\/(vault|config|\\.env|secrets?)/i,\n /list\\s+(all\\s+)?(vault|workspace|secret)\\s+(files?|contents?|data)/i,\n // i18n — Spanish\n /ignor[ae]\\s+(todas?\\s+)?(las\\s+)?(instrucciones?|indicaciones?|órdenes?)\\s+(previas?|anteriores?)/i,\n /olvid[ae]\\s+(todas?\\s+|tus\\s+)?(instrucciones?|indicaciones?)/i,\n /(ahora\\s+)?(tú\\s+)?eres\\s+(ahora\\s+)?(un|una|el|la)\\s+/i,\n /finge\\s+(que\\s+eres|ser)\\s+/i,\n // i18n — French\n /ignor(ez|e|es)\\s+(toutes?\\s+)?(les\\s+)?(instructions?|consignes?|directives?)\\s+(précédentes?|antérieures?)/i,\n /oublie(z|s)?\\s+(toutes?\\s+|vos\\s+|tes\\s+)?(instructions?|consignes?)/i,\n /(vous\\s+êtes|tu\\s+es)\\s+(maintenant|désormais)\\s+(un|une)\\s+/i,\n /prétend(ez|s)?\\s+(être|que\\s+vous\\s+êtes|que\\s+tu\\s+es)\\s+/i,\n // i18n — German\n /ignorier(e|en|t)\\s+(alle\\s+)?(vorherigen?|vorigen?|bisherigen?)\\s+(anweisungen|anordnungen|vorgaben)/i,\n /vergiss\\s+(alle\\s+|deine\\s+)?(anweisungen|vorgaben|regeln)/i,\n /du\\s+bist\\s+(jetzt|nun)\\s+(ein|eine)\\s+/i,\n /tu\\s+so\\s+als\\s+(wärst\\s+du|ob\\s+du)\\s+/i,\n]\n\n// Cyrillic + Greek confusables that look identical to Latin letters but\n// NFKC does NOT collapse (they are distinct characters in Unicode, not\n// compatibility equivalents). A payload like `ignоre аll previоus\n// instructiоns` (o's are Cyrillic U+043E) evades the pattern set\n// entirely because `ignore` written with Cyrillic chars never matches\n// the Latin `[o]` in our regexes even after NFKC.\n//\n// Mapping derived from Unicode's confusables.txt, intentionally limited\n// to letters that routinely appear in English prompt-injection payloads.\n// Not a full confusable table — adding every entry would risk mangling\n// legitimate Russian/Greek content that happens to contain these\n// letters. Our INJECTION_PATTERNS and redaction keywords are English\n// ASCII, so collapsing to ASCII only touches payloads impersonating\n// those tokens.\nconst HOMOGLYPHS: Record<string, string> = {\n 'а': 'a', 'е': 'e', 'о': 'o', 'р': 'p',\n 'с': 'c', 'у': 'y', 'х': 'x', 'і': 'i',\n 'ј': 'j', 'ѕ': 's', 'һ': 'h',\n 'А': 'A', 'В': 'B', 'Е': 'E', 'К': 'K',\n 'М': 'M', 'Н': 'H', 'О': 'O', 'Р': 'P',\n 'С': 'C', 'Т': 'T', 'Х': 'X', 'І': 'I',\n 'Ј': 'J', 'Ѕ': 'S',\n 'α': 'a', 'ε': 'e', 'ο': 'o', 'ρ': 'p',\n 'υ': 'y', 'ν': 'v', 'ι': 'i', 'τ': 't',\n 'κ': 'k', 'χ': 'x', 'η': 'n', 'μ': 'u',\n 'Α': 'A', 'Β': 'B', 'Ε': 'E', 'Ζ': 'Z',\n 'Η': 'H', 'Ι': 'I', 'Κ': 'K', 'Μ': 'M',\n 'Ν': 'N', 'Ο': 'O', 'Ρ': 'P', 'Τ': 'T',\n 'Χ': 'X', 'Υ': 'Y',\n}\n\nfunction collapseHomoglyphs(text: string): string {\n let out = ''\n for (const ch of text) out += HOMOGLYPHS[ch] ?? ch\n return out\n}\n\n// Unicode normalization for REDACTION.\n//\n// Strip zero-widths entirely (no space substitute) so cross-character\n// elisions like \"vault/secret\" → \"vault/secret\" are matched\n// by the redaction keyword pass. NFKC collapses compatibility chars\n// (fullwidth `ignore` → `ignore`). collapseHomoglyphs catches the\n// Cyrillic/Greek lookalikes NFKC leaves alone.\nfunction normalizeUnicode(text: string): string {\n return collapseHomoglyphs(\n text.replace(/[\\u200B-\\u200F\\u2028-\\u202F\\u2060\\uFEFF]/g, '').normalize('NFKC'),\n )\n}\n\n// Unicode normalization for DETECTION.\n//\n// Two adversarial concerns diverge from redaction:\n//\n// 1. Between-word zero-widths (\"ignoreallprevious\") — the\n// attacker separates tokens with ZWSP so \\s+-anchored regexes do\n// not fire. Strip-then-detect glues the tokens into one\n// unmatchable word; replace ZWSP with a real SPACE instead so\n// /ignore\\s+all\\s+previous/ fires.\n// 2. Punctuation noise (\"Ignore,,, all...previous!!!\") — collapse\n// punctuation runs to a single space. Preserve `[` `]` because\n// literal `[system]` / `[INST]` are first-class injection signals\n// we match directly.\nfunction normalizeForDetection(text: string): string {\n const spaced = text\n .replace(/[\\u200B\\u200C\\uFEFF]/g, ' ')\n .replace(/[\\u200D\\u200E\\u200F\\u2028-\\u202F\\u2060]/g, '')\n .normalize('NFKC')\n return collapseHomoglyphs(spaced)\n .replace(/[(){}<>,.!?:;\"`~]+/g, ' ')\n .replace(/\\s+/g, ' ')\n}\n\n// Third pass: also collapse square brackets. Literal `[system]` /\n// `[INST]` patterns are matched against the other two passes (which\n// preserve brackets); this pass catches the OPPOSITE evasion where\n// the attacker wraps tokens in brackets to split them for \\s+-anchored\n// regexes — e.g. `(ignore) [all] {previous} <instructions>` should\n// still match the baseline pattern.\nfunction normalizeForDetectionNoBrackets(text: string): string {\n return normalizeForDetection(text)\n .replace(/[\\[\\]]+/g, ' ')\n .replace(/\\s+/g, ' ')\n}\n\n/**\n * Detect prompt injection attempts.\n * Returns array of matched pattern descriptions, empty if clean.\n *\n * Patterns run against TWO normalizations so both within-word and\n * between-word zero-width evasions are caught, and so `[system]` /\n * `[INST]` literals are not lost to punctuation-collapse:\n * - normalizeUnicode — strips zero-widths, preserves brackets\n * - normalizeForDetection — spaces zero-widths, collapses punct\n */\nexport function detectInjection(content: string): string[] {\n const stripNorm = normalizeUnicode(content)\n const detectNorm = normalizeForDetection(content)\n const noBracketNorm = normalizeForDetectionNoBrackets(content)\n const matches: string[] = []\n\n for (const pattern of INJECTION_PATTERNS) {\n if (pattern.test(stripNorm) || pattern.test(detectNorm) || pattern.test(noBracketNorm)) {\n matches.push(pattern.source.slice(0, 60))\n }\n }\n\n // Check for base64-encoded injection attempts in either normalization.\n for (const norm of [stripNorm, detectNorm]) {\n const b64Matches = norm.match(/[A-Za-z0-9+/]{40,}={0,2}/g)\n if (!b64Matches) continue\n for (const b64 of b64Matches) {\n try {\n const decoded = atob(b64)\n if (INJECTION_PATTERNS.some(p => p.test(decoded))) {\n if (!matches.includes('base64-encoded injection')) {\n matches.push('base64-encoded injection')\n }\n }\n } catch { /* not valid b64 */ }\n }\n }\n\n return matches\n}\n\n/**\n * Security boundary — filter consumer messages before forwarding to agent.\n *\n * Defense in depth:\n * 1. Strip system messages (consumers cannot set system prompt)\n * 2. Normalize Unicode (collapse homoglyphs, remove zero-width chars)\n * 3. Detect injection patterns (instruction override, prompt extraction, data exfil)\n * 4. Redact sensitive keywords\n * 5. Cap message length\n *\n * Returns filtered messages and any injection warnings detected.\n */\nexport function filterConsumerMessages(\n messages: ChatMessage[],\n maxLength = 8000,\n): ChatMessage[] {\n return messages\n .filter((m) => m.role !== 'system')\n .map((m) => {\n const normalized = normalizeUnicode(m.content)\n const redacted = normalized\n .replace(/\\b(vault|workspace|owner|admin|secret|\\.env|config\\.json)[\\s/:][^\\s]*/gi, '[REDACTED]')\n .slice(0, maxLength)\n return { role: m.role, content: redacted }\n })\n}\n\n/**\n * Filter consumer messages with injection detection.\n * Returns { messages, injectionWarnings }.\n * If injectionWarnings is non-empty, the gateway should log and optionally reject.\n */\nexport function filterConsumerMessagesStrict(\n messages: ChatMessage[],\n maxLength = 8000,\n): { messages: ChatMessage[]; injectionWarnings: string[] } {\n const filtered = filterConsumerMessages(messages, maxLength)\n const allContent = filtered.map(m => m.content).join(' ')\n const injectionWarnings = detectInjection(allContent)\n return { messages: filtered, injectionWarnings }\n}\n\n/**\n * Redact system prompt content from agent output.\n * Prevents the agent from leaking its own instructions in responses.\n *\n * Strategy: if any chunk of the system prompt appears verbatim (>40 chars)\n * in the output, replace it with [REDACTED].\n */\nexport function redactSystemPromptFromOutput(\n output: string,\n systemPrompt: string | undefined,\n): string {\n if (!systemPrompt || systemPrompt.length < 40) return output\n\n // Split system prompt into meaningful chunks (sentences or lines)\n const chunks = systemPrompt\n .split(/[.\\n]/)\n .map(s => s.trim())\n .filter(s => s.length >= 40)\n\n let redacted = output\n for (const chunk of chunks) {\n // Case-insensitive substring match\n const idx = redacted.toLowerCase().indexOf(chunk.toLowerCase())\n if (idx >= 0) {\n redacted = redacted.slice(0, idx) + '[REDACTED — system instructions]' + redacted.slice(idx + chunk.length)\n }\n }\n\n return redacted\n}\n","/**\n * Observability hook surface.\n *\n * Consumers implement GatewayObserver to wire the gateway into their existing\n * telemetry stack (Langfuse, OTEL, structured logs, Prometheus, etc.) without\n * the gateway itself depending on any of those libraries.\n *\n * Every event carries a requestId so downstream metrics can correlate the\n * payment verification, sandbox execution, and settlement for one request.\n * When no observer is configured, the gateway stays silent.\n */\n\nimport type { PaymentMethod, GatewayUsageEvent } from './types'\n\nexport interface RequestContext {\n requestId: string\n agentSlug: string\n startMs: number\n}\n\nexport interface AuthFailureReason {\n method: 'x402' | 'mpp' | 'apikey' | 'none'\n code: string\n httpStatus: number\n}\n\nexport interface GatewayObserver {\n /** Called at the start of every chat completions POST. */\n onRequestStart?: (ctx: RequestContext) => void | Promise<void>\n\n /** Called when a payment method has been successfully verified. */\n onPaymentVerified?: (ctx: RequestContext, info: {\n method: PaymentMethod\n consumerId: string\n keyId?: string\n }) => void | Promise<void>\n\n /** Called when auth fails — every branch. */\n onAuthFailure?: (ctx: RequestContext, reason: AuthFailureReason) => void | Promise<void>\n\n /** Called when a consumer hits the rate limit. */\n onRateLimited?: (ctx: RequestContext, info: {\n consumerId: string\n retryAfterSeconds: number\n }) => void | Promise<void>\n\n /** Called when the request body exceeds the 64KB limit. */\n onBodyTooLarge?: (ctx: RequestContext, contentLength: number) => void | Promise<void>\n\n /**\n * Called when prompt-injection patterns are detected.\n * `blocked` is true when blockInjection config is on and the request was\n * rejected; false when the patterns were logged but the request proceeded.\n */\n onInjectionDetected?: (ctx: RequestContext, info: {\n consumerId: string\n patterns: string[]\n blocked: boolean\n }) => void | Promise<void>\n\n /** Called after a successful stream completes and recordUsage has fired. */\n onRequestComplete?: (ctx: RequestContext, usage: GatewayUsageEvent) => void | Promise<void>\n\n /** Called when the sandbox throws. The error message is pre-scrubbed. */\n onStreamError?: (ctx: RequestContext, info: {\n consumerId: string\n errorMessage: string\n }) => void | Promise<void>\n\n /** Called when settlement fails. Payment already occurred; this is async bookkeeping. */\n onSettlementError?: (ctx: RequestContext, info: {\n consumerId: string\n method: PaymentMethod\n errorMessage: string\n }) => void | Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Convenience implementations\n// ---------------------------------------------------------------------------\n\n/**\n * Structured-log observer. Emits one JSON line per event on the `log` function.\n * Default sink: console.log. Production consumers usually pipe their own\n * structured logger (pino, winston, the cf Logs binding).\n *\n * Usage:\n * new ConsoleObserver(({ level, event, ...rest }) => logger.info({ event, ...rest }))\n */\nexport class ConsoleObserver implements GatewayObserver {\n constructor(\n private readonly log: (entry: Record<string, unknown>) => void = (e) => console.log(JSON.stringify(e)),\n ) {}\n\n private emit(level: 'info' | 'warn' | 'error', event: string, ctx: RequestContext, rest: Record<string, unknown> = {}) {\n this.log({\n level,\n event,\n time: new Date().toISOString(),\n requestId: ctx.requestId,\n agentSlug: ctx.agentSlug,\n durationMs: Date.now() - ctx.startMs,\n ...rest,\n })\n }\n\n onRequestStart(ctx: RequestContext) { this.emit('info', 'gateway.request.start', ctx) }\n onPaymentVerified(ctx: RequestContext, info: { method: PaymentMethod; consumerId: string; keyId?: string }) {\n this.emit('info', 'gateway.payment.verified', ctx, info)\n }\n onAuthFailure(ctx: RequestContext, reason: AuthFailureReason) {\n this.emit('warn', 'gateway.auth.failure', ctx, reason as unknown as Record<string, unknown>)\n }\n onRateLimited(ctx: RequestContext, info: { consumerId: string; retryAfterSeconds: number }) {\n this.emit('warn', 'gateway.rate_limit', ctx, info)\n }\n onBodyTooLarge(ctx: RequestContext, contentLength: number) {\n this.emit('warn', 'gateway.body_too_large', ctx, { contentLength })\n }\n onInjectionDetected(ctx: RequestContext, info: { consumerId: string; patterns: string[]; blocked: boolean }) {\n this.emit('warn', 'gateway.injection', ctx, info)\n }\n onRequestComplete(ctx: RequestContext, usage: GatewayUsageEvent) {\n this.emit('info', 'gateway.request.complete', ctx, usage as unknown as Record<string, unknown>)\n }\n onStreamError(ctx: RequestContext, info: { consumerId: string; errorMessage: string }) {\n this.emit('error', 'gateway.stream.error', ctx, info)\n }\n onSettlementError(ctx: RequestContext, info: { consumerId: string; method: PaymentMethod; errorMessage: string }) {\n this.emit('error', 'gateway.settlement.error', ctx, info)\n }\n}\n\n/**\n * Compose multiple observers into one. Errors in any individual observer\n * don't break the others (fire-and-forget telemetry).\n */\nexport class CompositeObserver implements GatewayObserver {\n constructor(private readonly observers: GatewayObserver[]) {}\n\n private async fanOut<K extends keyof GatewayObserver>(event: K, ...args: unknown[]): Promise<void> {\n for (const obs of this.observers) {\n const fn = obs[event] as ((...a: unknown[]) => void | Promise<void>) | undefined\n if (!fn) continue\n try {\n await fn.apply(obs, args)\n } catch (err) {\n console.warn(`[agent-gateway] observer ${event} threw:`, err instanceof Error ? err.message : err)\n }\n }\n }\n\n onRequestStart = (ctx: RequestContext) => this.fanOut('onRequestStart', ctx)\n onPaymentVerified = (ctx: RequestContext, info: Parameters<Required<GatewayObserver>['onPaymentVerified']>[1]) =>\n this.fanOut('onPaymentVerified', ctx, info)\n onAuthFailure = (ctx: RequestContext, reason: AuthFailureReason) =>\n this.fanOut('onAuthFailure', ctx, reason)\n onRateLimited = (ctx: RequestContext, info: Parameters<Required<GatewayObserver>['onRateLimited']>[1]) =>\n this.fanOut('onRateLimited', ctx, info)\n onBodyTooLarge = (ctx: RequestContext, contentLength: number) =>\n this.fanOut('onBodyTooLarge', ctx, contentLength)\n onInjectionDetected = (ctx: RequestContext, info: Parameters<Required<GatewayObserver>['onInjectionDetected']>[1]) =>\n this.fanOut('onInjectionDetected', ctx, info)\n onRequestComplete = (ctx: RequestContext, usage: GatewayUsageEvent) =>\n this.fanOut('onRequestComplete', ctx, usage)\n onStreamError = (ctx: RequestContext, info: Parameters<Required<GatewayObserver>['onStreamError']>[1]) =>\n this.fanOut('onStreamError', ctx, info)\n onSettlementError = (ctx: RequestContext, info: Parameters<Required<GatewayObserver>['onSettlementError']>[1]) =>\n this.fanOut('onSettlementError', ctx, info)\n}\n\n/**\n * Generate a request-id. Crypto-random 16 bytes, hex-encoded with an `req_` prefix.\n * Works in Workers, Node, and browsers — all have globalThis.crypto.\n */\nexport function generateRequestId(): string {\n const bytes = new Uint8Array(16)\n globalThis.crypto.getRandomValues(bytes)\n const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')\n return `req_${hex}`\n}\n","import type { X402Config, MppConfig, ApiKeyInfo } from './types'\nimport type { NonceStore } from './nonce-store'\n\n/**\n * Verify x402 SpendAuth signature (EIP-712).\n * Returns the signer address (commitment) if valid, null otherwise.\n *\n * demoMode: true — accepts any well-formed header\n * shape after replay/expiry checks.\n * Tests + local dev only.\n * verifySigner present — production verification path.\n * neither — rejected by createAgentGateway and\n * by this function as defense-in-depth.\n */\nexport async function verifyX402(\n spendAuthHeader: string,\n config: X402Config,\n nonceStore?: NonceStore,\n): Promise<string | null> {\n try {\n const raw = JSON.parse(spendAuthHeader)\n if (!raw.commitment || !raw.signature || !raw.amount) return null\n if (raw.operator?.toLowerCase() !== config.operatorAddress.toLowerCase()) return null\n\n const amount = BigInt(raw.amount)\n const nonce = BigInt(raw.nonce)\n const expiry = BigInt(raw.expiry)\n\n // Reject expired payments\n if (expiry < BigInt(Math.floor(Date.now() / 1000))) return null\n\n // Reject zero-amount payments\n if (amount <= 0n) return null\n\n // Reject replayed nonces\n const nonceKey = `${raw.commitment}:${nonce.toString()}`\n if (nonceStore) {\n if (await nonceStore.hasSeen(nonceKey)) return null\n // Mark seen with TTL matching the expiry window (max 1 hour)\n const ttl = Math.min(Number(expiry) - Math.floor(Date.now() / 1000), 3600)\n await nonceStore.markSeen(nonceKey, Math.max(ttl, 60))\n }\n\n if (config.verifySigner) {\n const verified = await config.verifySigner(raw)\n if (!verified) return null\n } else if (!config.demoMode) {\n return null\n }\n\n return raw.commitment\n } catch {\n return null\n }\n}\n\n/**\n * Verify MPP (Machine Payments Protocol) Authorization: Payment header.\n *\n * MPP uses `Authorization: Payment <method> <credential>` format where\n * the credential is a base64url-encoded JSON wrapping the same EIP-3009\n * payment payload that x402 uses. This means existing x402 wallets work\n * unchanged over the MPP wire format.\n *\n * Returns the signer address if valid, null otherwise.\n * In demo mode, accepts any well-formed Payment header.\n */\nexport async function verifyMpp(\n authHeader: string,\n _config: MppConfig,\n x402Config: X402Config,\n): Promise<string | null> {\n // MPP format: \"Payment <method> <base64url-credential>\"\n const match = authHeader.match(/^Payment\\s+(\\S+)\\s+(\\S+)$/i)\n if (!match) return null\n\n const [, , credentialB64] = match\n\n try {\n // Decode base64url credential → JSON with the same EIP-3009 payload\n const decoded = Buffer.from(credentialB64, 'base64url').toString('utf-8')\n const credential = JSON.parse(decoded)\n\n // The credential payload wraps the same fields x402 uses\n const payload = credential.payload ?? credential\n if (!payload.commitment && !payload.from) return null\n\n // Validate operator match (same as x402)\n const operator = payload.operator ?? payload.to\n if (operator && operator.toLowerCase() !== x402Config.operatorAddress.toLowerCase()) return null\n\n // Validate bigint fields if present\n if (payload.amount) BigInt(payload.amount)\n if (payload.nonce) BigInt(payload.nonce)\n\n return payload.commitment ?? payload.from ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Default API key verifier — accepts any `sk_agent_*` key (demo mode).\n * Override in GatewayConfig.verifyApiKey for production.\n */\nexport async function defaultVerifyApiKey(\n authHeader: string,\n): Promise<ApiKeyInfo | null> {\n if (!authHeader.startsWith('Bearer sk_agent_')) return null\n const key = authHeader.slice(7)\n return {\n keyId: key.slice(0, 16),\n consumerId: `apikey:${key.slice(0, 16)}`,\n }\n}\n","/**\n * Shared inner pipeline used by every wire-format the gateway exposes\n * (OpenAI-compatible chat completions, A2A JSON-RPC). Each handler parses its\n * own protocol's request body into a canonical `messages[]` form + headers,\n * then calls into here for auth → rate-limit → injection filter →\n * authorize → sandbox stream → settle. Keeping the pipeline single-sourced\n * means every protocol surface gets the same security and billing guarantees\n * for free; bugs fixed here fix every wrapper.\n */\n\nimport type { Context } from 'hono'\n\nimport { filterConsumerMessagesStrict, redactSystemPromptFromOutput } from './filter'\nimport { type GatewayObserver, type RequestContext, generateRequestId } from './observer'\nimport { type RateLimitStore, checkRateLimit } from './rate-limit'\nimport type { NonceStore } from './nonce-store'\nimport type {\n AgentMeta,\n ApiKeyInfo,\n ChatMessage,\n GatewayConfig,\n PaymentMethod,\n} from './types'\nimport { defaultVerifyApiKey, verifyMpp, verifyX402 } from './verify'\n\n/** Single bundle of long-lived gateway state shared across all handlers in one createAgentGateway call. */\nexport interface GatewayState {\n rateLimitStore: RateLimitStore\n nonceStore: NonceStore\n globalRateLimit: { limit: number; windowSeconds: number }\n requiredScope: string\n maxLen: number\n obs?: GatewayObserver\n}\n\n/** Returned by {@link authenticateAndGuard} on the success path. */\nexport interface AuthorizedRequest {\n agent: AgentMeta\n consumerId: string\n paymentMethod: PaymentMethod\n keyInfo: ApiKeyInfo | null\n userMessage: string\n rateLimitRemaining: number | undefined\n requestId: string\n startMs: number\n}\n\n/**\n * Resolve the agent, then run the full pre-dispatch pipeline: payment +\n * rate-limit + injection filter + user-message extraction + optional\n * `authorizeConsumer` hook. Returns the success record on the happy path\n * or a fully-formed `Response` (402/404/429/400/403) on any short-circuit.\n *\n * Body parsing is the caller's responsibility — different wire formats\n * (OpenAI chat completions vs A2A JSON-RPC) have different envelopes; both\n * still ultimately produce a `ChatMessage[]`.\n */\nexport async function authenticateAndGuard(\n c: Context,\n slug: string,\n messages: ChatMessage[],\n config: GatewayConfig,\n state: GatewayState,\n): Promise<AuthorizedRequest | Response> {\n const startMs = Date.now()\n const requestId = generateRequestId()\n const ctx: RequestContext = { requestId, agentSlug: slug, startMs }\n await state.obs?.onRequestStart?.(ctx)\n\n const agent = await config.resolveAgent(slug)\n if (!agent) {\n return c.json({ error: { message: 'Agent not found', type: 'not_found' } }, 404)\n }\n if (!messages?.length) {\n return c.json(\n { error: { message: 'messages array required', type: 'invalid_request' } },\n 400,\n )\n }\n\n // Payment / auth.\n const spendAuthHeader = c.req.header('X-Payment-Signature')\n const authHeader = c.req.header('Authorization') ?? ''\n let consumerId: string | null = null\n let paymentMethod: PaymentMethod = 'none'\n let keyInfo: ApiKeyInfo | null = null\n\n if (spendAuthHeader) {\n const signer = await verifyX402(spendAuthHeader, config.x402, state.nonceStore)\n if (!signer) {\n await state.obs?.onAuthFailure?.(ctx, {\n method: 'x402',\n code: 'invalid_spend_auth',\n httpStatus: 402,\n })\n return c.json(\n {\n error: {\n message: 'Invalid X-Payment-Signature',\n type: 'authentication_error',\n code: 'invalid_spend_auth',\n },\n },\n {\n status: 402,\n headers: { 'X-Payment-Required': 'spendauth', 'X-Request-Id': requestId },\n },\n )\n }\n consumerId = signer\n paymentMethod = 'x402'\n } else if (config.mpp && authHeader.toLowerCase().startsWith('payment ')) {\n const signer = await verifyMpp(authHeader, config.mpp, config.x402)\n if (!signer) {\n const realm = config.mpp.realm\n const method = config.mpp.method ?? 'blueprintevm'\n await state.obs?.onAuthFailure?.(ctx, {\n method: 'mpp',\n code: 'invalid_mpp_credential',\n httpStatus: 401,\n })\n return c.json(\n {\n error: {\n message: 'Invalid Payment credential',\n type: 'authentication_error',\n code: 'invalid_mpp_credential',\n },\n },\n {\n status: 401,\n headers: {\n 'WWW-Authenticate': `Payment realm=\"${realm}\", method=\"${method}\"`,\n 'X-Request-Id': requestId,\n },\n },\n )\n }\n consumerId = signer\n paymentMethod = 'mpp'\n } else if (authHeader.startsWith('Bearer ')) {\n const verify = config.verifyApiKey ?? defaultVerifyApiKey\n const key = await verify(authHeader)\n if (!key) {\n await state.obs?.onAuthFailure?.(ctx, {\n method: 'apikey',\n code: 'invalid_api_key',\n httpStatus: 401,\n })\n return c.json(\n { error: { message: 'Invalid API key', type: 'authentication_error' } },\n { status: 401, headers: { 'X-Request-Id': requestId } },\n )\n }\n if (key.scopes && key.scopes.length > 0 && !key.scopes.includes(state.requiredScope)) {\n await state.obs?.onAuthFailure?.(ctx, {\n method: 'apikey',\n code: 'insufficient_scope',\n httpStatus: 403,\n })\n return c.json(\n {\n error: {\n message: `API key missing required scope: ${state.requiredScope}`,\n type: 'forbidden',\n code: 'insufficient_scope',\n },\n },\n { status: 403, headers: { 'X-Request-Id': requestId } },\n )\n }\n consumerId = key.consumerId\n paymentMethod = 'apikey'\n keyInfo = key\n } else {\n await state.obs?.onAuthFailure?.(ctx, {\n method: 'none',\n code: 'payment_required',\n httpStatus: 402,\n })\n const methods: string[] = ['x402']\n if (config.mpp) methods.push('mpp')\n methods.push('api_key')\n const headers: Record<string, string> = {\n 'X-Payment-Required': methods.join(', '),\n 'X-Request-Id': requestId,\n }\n if (config.mpp) {\n headers['WWW-Authenticate'] =\n `Payment realm=\"${config.mpp.realm}\", method=\"${config.mpp.method ?? 'blueprintevm'}\"`\n }\n return c.json(\n {\n error: {\n message: 'Payment required',\n type: 'payment_required',\n payment_methods: methods,\n x402: {\n operator: config.x402.operatorAddress,\n chain_id: config.x402.chainId,\n credits_address: config.x402.creditsAddress,\n estimated_amount_per_request: '20000',\n },\n ...(config.mpp\n ? { mpp: { realm: config.mpp.realm, method: config.mpp.method ?? 'blueprintevm' } }\n : {}),\n api_key: {\n purchase_url: config.baseUrl\n ? `${config.baseUrl}/agents/${slug}/api-keys`\n : undefined,\n },\n },\n },\n { status: 402, headers },\n )\n }\n\n await state.obs?.onPaymentVerified?.(ctx, {\n method: paymentMethod,\n consumerId: consumerId,\n keyId: keyInfo?.keyId,\n })\n\n // Rate limit.\n const effectiveRateLimit = keyInfo?.rateLimitPerMinute\n ? { limit: keyInfo.rateLimitPerMinute, windowSeconds: 60 }\n : state.globalRateLimit\n const rl = await checkRateLimit(consumerId, effectiveRateLimit, state.rateLimitStore)\n if (!rl.allowed) {\n await state.obs?.onRateLimited?.(ctx, {\n consumerId: consumerId,\n retryAfterSeconds: rl.retryAfterSeconds ?? 60,\n })\n return c.json(\n {\n error: {\n message: 'Rate limit exceeded',\n type: 'rate_limit_error',\n retry_after: rl.retryAfterSeconds,\n },\n },\n {\n status: 429,\n headers: {\n 'Retry-After': String(rl.retryAfterSeconds ?? 60),\n 'X-Request-Id': requestId,\n },\n },\n )\n }\n\n // Filter consumer messages — strip consumer-side system, length-cap, injection scan.\n const { messages: filtered, injectionWarnings } = filterConsumerMessagesStrict(\n messages,\n state.maxLen,\n )\n if (injectionWarnings.length > 0) {\n await state.obs?.onInjectionDetected?.(ctx, {\n consumerId: consumerId,\n patterns: injectionWarnings,\n blocked: !!config.blockInjection,\n })\n if (config.blockInjection) {\n return c.json(\n {\n error: {\n message: 'Request rejected: potential prompt injection detected',\n type: 'content_policy_violation',\n },\n },\n { status: 400, headers: { 'X-Request-Id': requestId } },\n )\n }\n }\n\n const userMessage = filtered\n .filter((m) => m.role === 'user')\n .map((m) => m.content)\n .join('\\n\\n')\n if (!userMessage) {\n return c.json(\n { error: { message: 'No user message provided', type: 'invalid_request' } },\n 400,\n )\n }\n\n if (config.authorizeConsumer) {\n const authz = await config.authorizeConsumer(agent, {\n method: paymentMethod,\n consumerId: consumerId,\n keyId: keyInfo?.keyId,\n requestId,\n })\n if (!authz.allow) {\n return c.json(\n {\n error: {\n message: authz.reason,\n type: 'authorization_denied',\n code: authz.code,\n },\n },\n { status: 403, headers: { 'X-Request-Id': requestId } },\n )\n }\n }\n\n return {\n agent,\n consumerId,\n paymentMethod,\n keyInfo,\n userMessage,\n rateLimitRemaining: rl.remaining,\n requestId,\n startMs,\n }\n}\n\n/**\n * Yield the inner sandbox's response as text deltas, applying the\n * system-prompt redaction filter on each delta so leakage of the agent's\n * system prompt back through the model's output is suppressed identically\n * whether the caller is on the OpenAI-compat path or A2A.\n *\n * Aborts when `signal` fires (used by A2A `tasks/cancel`).\n */\nexport async function* dispatchSandboxStream(\n agent: AgentMeta,\n userMessage: string,\n consumerId: string,\n config: GatewayConfig,\n signal?: AbortSignal,\n sessionId?: string,\n): AsyncIterable<string> {\n for await (const event of dispatchSandboxStreamRich(\n agent,\n userMessage,\n consumerId,\n config,\n signal,\n sessionId,\n )) {\n if (event.kind === 'text') yield event.delta\n }\n}\n\n/**\n * A2A-shaped dispatch event. Distinguishes text deltas from sandbox-signalled\n * pause-for-input events. The A2A handler uses this richer variant so it can\n * emit `input-required` status updates; the OpenAI-compat path consumes the\n * text-only `dispatchSandboxStream` adapter above.\n */\nexport type A2ADispatchEvent =\n | { kind: 'text'; delta: string }\n | { kind: 'input-required'; prompt?: string }\n\n/**\n * Like `dispatchSandboxStream` but yields a discriminated union so callers can\n * react to `input-required` signals from the sandbox. The sandbox opts in by\n * emitting `{ type: 'input-required', data: { inputRequired: { prompt? } } }`\n * (or by setting `data.inputRequired` on any event); sandboxes that don't\n * emit such events see identical behavior.\n *\n * `sessionId` defaults to `consumer:<id>` matching the existing single-turn\n * path; multi-turn continuations pass an explicit `taskId` so the sandbox can\n * keep per-task conversation memory.\n */\nexport async function* dispatchSandboxStreamRich(\n agent: AgentMeta,\n userMessage: string,\n consumerId: string,\n config: GatewayConfig,\n signal?: AbortSignal,\n sessionId?: string,\n): AsyncIterable<A2ADispatchEvent> {\n const box = await config.getSandbox(agent)\n const promptStream = box.streamPrompt(userMessage, {\n sessionId: sessionId ?? `consumer:${consumerId}`,\n systemPrompt: agent.systemPrompt,\n })\n for await (const event of promptStream) {\n if (signal?.aborted) return\n if (\n event.type === 'message.part.updated' &&\n event.data?.part?.type === 'text' &&\n event.data.delta\n ) {\n yield {\n kind: 'text',\n delta: redactSystemPromptFromOutput(event.data.delta, agent.systemPrompt),\n }\n continue\n }\n if (event.type === 'input-required' || event.data?.inputRequired) {\n yield { kind: 'input-required', prompt: event.data?.inputRequired?.prompt }\n // Terminal for the sandbox stream — sandbox SHOULD stop emitting until\n // the gateway dispatches a continuation message with the new user input.\n return\n }\n }\n}\n\n/**\n * Record usage event + settle payment + invoke the observer. Both wire\n * formats call this once their stream has drained, so settlement happens\n * exactly once per request regardless of protocol.\n */\nexport async function settleAndRecord(\n agent: AgentMeta,\n authz: AuthorizedRequest,\n inputTokens: number,\n outputTokens: number,\n config: GatewayConfig,\n obs: GatewayObserver | undefined,\n): Promise<void> {\n const totalCost = (inputTokens + outputTokens) * agent.pricePerTokenUsd\n const ownerEarned = totalCost * (1 - agent.platformFeePercent)\n const platformFee = totalCost * agent.platformFeePercent\n const usageEvent = {\n requestId: authz.requestId,\n agentId: agent.id,\n agentSlug: agent.slug,\n consumerId: authz.consumerId,\n paymentMethod: authz.paymentMethod,\n inputTokens,\n outputTokens,\n totalCostUsd: totalCost,\n ownerEarnedUsd: ownerEarned,\n platformFeeUsd: platformFee,\n durationMs: Date.now() - authz.startMs,\n }\n await config.recordUsage(usageEvent)\n const ctx: RequestContext = {\n requestId: authz.requestId,\n agentSlug: agent.slug,\n startMs: authz.startMs,\n }\n await obs?.onRequestComplete?.(ctx, usageEvent)\n if (config.settlePayment) {\n await config\n .settlePayment(\n {\n method: authz.paymentMethod,\n consumerId: authz.consumerId,\n requestId: authz.requestId,\n },\n totalCost,\n )\n .catch(async (err) => {\n const msg = err instanceof Error ? err.message : String(err)\n console.error(`[agent-gateway] settlement failed for ${authz.consumerId}: ${msg}`)\n await obs?.onSettlementError?.(ctx, {\n consumerId: authz.consumerId,\n method: authz.paymentMethod,\n errorMessage: msg,\n })\n })\n }\n}\n\n/** Token estimate matching the existing chat-completions handler (4 chars ≈ 1 token). */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n","/**\n * Build an A2A AgentCard from the gateway's existing AgentMeta + GatewayConfig.\n * The card's `url` MUST be the JSON-RPC endpoint a client POSTs to; clients\n * fetch the card from `<url>/.well-known/agent.json` per A2A convention.\n *\n * Auth schemes advertised reflect the gateway's actually-accepted payment\n * methods (x402 always; mpp when configured; Bearer for API keys). Skills\n * fall back to a single synthesized \"chat\" skill when the AgentMeta doesn't\n * declare its own — most consumers will override.\n */\n\nimport type { AgentMeta, GatewayConfig } from '../types'\nimport type { AgentCard, AgentSkill } from './types'\n\nexport function buildAgentCard(\n agent: AgentMeta,\n config: GatewayConfig,\n agentUrl: string,\n): AgentCard {\n const schemes: string[] = ['x402']\n if (config.mpp) schemes.push('mpp')\n schemes.push('Bearer')\n\n const skills: AgentSkill[] =\n agent.skills && agent.skills.length > 0\n ? agent.skills\n : [\n {\n id: 'chat',\n name: agent.slug,\n description: agent.description ?? `${agent.slug} agent`,\n tags: ['chat'],\n inputModes: ['text'],\n outputModes: ['text'],\n },\n ]\n\n return {\n name: agent.slug,\n description: agent.description ?? `${agent.slug} agent`,\n url: agentUrl,\n version: '1.0.0',\n provider: { organization: 'Tangle', url: 'https://tangle.tools' },\n capabilities: {\n streaming: true,\n pushNotifications: !!config.a2a?.pushStore,\n stateTransitionHistory: false,\n },\n authentication: { schemes },\n defaultInputModes: ['text'],\n defaultOutputModes: ['text'],\n skills,\n }\n}\n","/**\n * A2A protocol types (Google Agent-to-Agent, April 2025).\n *\n * Subset shipped by this gateway:\n * - Discovery: AgentCard via `.well-known/agent.json`\n * - Messaging: `message/send`, `message/stream`\n * - Task control: `tasks/get`, `tasks/cancel`, `tasks/resubscribe`\n * - Push: `tasks/pushNotificationConfig/{set,get,list,delete}` (gated on `pushStore`)\n * - Multi-turn: `input-required` state + follow-up `message/send` with the same `taskId`\n * - Capabilities: streaming = true; pushNotifications gated on config; stateTransitionHistory = false\n * - Parts: text only on input/output (data/file parts rejected with CONTENT_TYPE_NOT_SUPPORTED)\n *\n * Deferred until a real consumer needs them: authenticated extended card,\n * data/file parts, OAuth2/mTLS auth schemes.\n */\n\n// ── JSON-RPC 2.0 envelopes ───────────────────────────────────────────────\n\nexport interface JSONRPCRequest {\n jsonrpc: '2.0'\n id: string | number | null\n method: string\n params?: unknown\n}\n\nexport interface JSONRPCSuccessResponse<T = unknown> {\n jsonrpc: '2.0'\n id: string | number | null\n result: T\n}\n\nexport interface JSONRPCErrorResponse {\n jsonrpc: '2.0'\n id: string | number | null\n error: { code: number; message: string; data?: unknown }\n}\n\nexport type JSONRPCResponse<T = unknown> = JSONRPCSuccessResponse<T> | JSONRPCErrorResponse\n\n/** Standard JSON-RPC + A2A-specific codes. Negative ints per JSON-RPC spec. */\nexport const A2A_ERROR_CODES = {\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n TASK_NOT_FOUND: -32001,\n TASK_NOT_CANCELABLE: -32002,\n PUSH_NOT_SUPPORTED: -32003,\n UNSUPPORTED_OPERATION: -32004,\n CONTENT_TYPE_NOT_SUPPORTED: -32005,\n INVALID_AGENT_RESPONSE: -32006,\n AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED: -32007,\n} as const\n\n// ── Message parts ────────────────────────────────────────────────────────\n\nexport interface TextPart {\n kind: 'text'\n text: string\n metadata?: Record<string, unknown>\n}\n\nexport interface DataPart {\n kind: 'data'\n data: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface FilePart {\n kind: 'file'\n file: { name?: string; mimeType?: string; bytes?: string; uri?: string }\n metadata?: Record<string, unknown>\n}\n\nexport type Part = TextPart | DataPart | FilePart\n\n// ── Message + Task + Artifact ────────────────────────────────────────────\n\nexport interface Message {\n kind: 'message'\n role: 'user' | 'agent'\n parts: Part[]\n messageId: string\n taskId?: string\n contextId?: string\n metadata?: Record<string, unknown>\n}\n\nexport type TaskState =\n | 'submitted'\n | 'working'\n | 'input-required'\n | 'completed'\n | 'canceled'\n | 'failed'\n | 'rejected'\n | 'auth-required'\n\nexport interface TaskStatus {\n state: TaskState\n message?: Message\n timestamp: string\n}\n\nexport interface Artifact {\n artifactId: string\n name?: string\n description?: string\n parts: Part[]\n metadata?: Record<string, unknown>\n}\n\nexport interface Task {\n kind: 'task'\n id: string\n contextId: string\n status: TaskStatus\n history?: Message[]\n artifacts?: Artifact[]\n metadata?: Record<string, unknown>\n}\n\n// ── Streaming events (carried as JSON-RPC result over SSE) ──────────────\n\nexport interface TaskStatusUpdateEvent {\n kind: 'status-update'\n taskId: string\n contextId: string\n status: TaskStatus\n /** True on the terminal event; clients close the stream after this. */\n final: boolean\n metadata?: Record<string, unknown>\n}\n\nexport interface TaskArtifactUpdateEvent {\n kind: 'artifact-update'\n taskId: string\n contextId: string\n artifact: Artifact\n /** True when this artifact's parts should be appended to the prior emit (incremental streaming). */\n append?: boolean\n /** True on the artifact's final chunk. */\n lastChunk?: boolean\n metadata?: Record<string, unknown>\n}\n\nexport type StreamingEvent = TaskStatusUpdateEvent | TaskArtifactUpdateEvent\n\n// ── Method-specific params ───────────────────────────────────────────────\n\nexport interface MessageSendParams {\n message: Message\n configuration?: {\n acceptedOutputModes?: string[]\n blocking?: boolean\n historyLength?: number\n }\n}\n\nexport interface TaskIdParams {\n id: string\n metadata?: Record<string, unknown>\n}\n\nexport interface TaskPushNotificationConfigGetParams {\n /** Task id whose configs are being queried. */\n id: string\n /** Specific config id to fetch. Required for `set` and `delete`; omitted for `list`. */\n pushNotificationConfigId?: string\n metadata?: Record<string, unknown>\n}\n\n// ── Agent Card ──────────────────────────────────────────────────────────\n\nexport interface AgentSkill {\n id: string\n name: string\n description: string\n tags?: string[]\n examples?: string[]\n inputModes?: string[]\n outputModes?: string[]\n}\n\nexport interface AgentCapabilities {\n streaming?: boolean\n pushNotifications?: boolean\n stateTransitionHistory?: boolean\n}\n\nexport interface AgentProvider {\n organization: string\n url?: string\n}\n\nexport interface AgentCardAuthentication {\n /** Auth scheme names the agent accepts (e.g. 'Bearer', 'x402', 'mpp'). */\n schemes: string[]\n /** Optional human-readable hint about obtaining credentials. */\n credentials?: string\n}\n\nexport interface AgentCard {\n name: string\n description: string\n /** JSON-RPC endpoint URL — clients POST methods here. */\n url: string\n version: string\n documentationUrl?: string\n provider?: AgentProvider\n capabilities: AgentCapabilities\n authentication: AgentCardAuthentication\n defaultInputModes: string[]\n defaultOutputModes: string[]\n skills: AgentSkill[]\n}\n","/**\n * JSON-RPC 2.0 envelope parsing + response builders. Keeps the wire\n * format isolated from the method dispatcher so a fuzz harness can throw\n * malformed bodies at `parseEnvelope` directly.\n */\n\nimport {\n A2A_ERROR_CODES,\n type JSONRPCErrorResponse,\n type JSONRPCRequest,\n type JSONRPCSuccessResponse,\n} from './types'\n\nexport interface EnvelopeError {\n /** id is whatever the caller sent (or null when we can't recover it). */\n id: string | number | null\n code: number\n message: string\n}\n\n/**\n * Parse an inbound body. Returns the request envelope on success OR an\n * EnvelopeError that the caller renders as a JSONRPCErrorResponse. We never\n * throw — JSON-RPC says any malformed body becomes a -32700/-32600 response.\n */\nexport function parseEnvelope(raw: unknown): JSONRPCRequest | EnvelopeError {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return {\n id: null,\n code: A2A_ERROR_CODES.INVALID_REQUEST,\n message: 'request must be a JSON object',\n }\n }\n const req = raw as Record<string, unknown>\n const id = req.id === undefined ? null : (req.id as string | number | null)\n if (req.jsonrpc !== '2.0') {\n return { id, code: A2A_ERROR_CODES.INVALID_REQUEST, message: 'jsonrpc field must be \"2.0\"' }\n }\n if (typeof req.method !== 'string' || req.method.length === 0) {\n return { id, code: A2A_ERROR_CODES.INVALID_REQUEST, message: 'method field required' }\n }\n return {\n jsonrpc: '2.0',\n id,\n method: req.method,\n params: req.params,\n }\n}\n\nexport function ok<T>(id: string | number | null, result: T): JSONRPCSuccessResponse<T> {\n return { jsonrpc: '2.0', id, result }\n}\n\nexport function fail(\n id: string | number | null,\n code: number,\n message: string,\n data?: unknown,\n): JSONRPCErrorResponse {\n return {\n jsonrpc: '2.0',\n id,\n error: { code, message, ...(data !== undefined ? { data } : {}) },\n }\n}\n","/**\n * @stable\n *\n * A2A push notifications — a webhook delivery channel that fires when a task\n * reaches a terminal state (`completed`, `canceled`, `failed`, `rejected`).\n * The protocol specifies four JSON-RPC methods (`tasks/pushNotificationConfig/`\n * {set, get, list, delete}) for registering / inspecting / removing configs,\n * plus the delivery contract: an HTTP POST to the registered URL with the\n * task envelope as the body and an HMAC-SHA256 signature for verification.\n *\n * This is the minimum shape long-horizon agents need. A consumer that finishes\n * a task in 30 minutes can't keep an SSE stream open against a Worker (CPU\n * limits) or an unauthenticated browser tab (network drops) — they need a\n * fire-and-forget endpoint the gateway calls when the task is done.\n *\n * Out of scope for the first pass: retries, queue durability, partial-state\n * notifications. If the webhook returns non-2xx or the request fails, the\n * gateway logs and moves on — the consumer's endpoint should idempotently\n * pull state via `tasks/get` rather than rely on at-least-once delivery.\n *\n * @example registering a webhook\n * {\n * \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"tasks/pushNotificationConfig/set\",\n * \"params\": {\n * \"taskId\": \"task_abc\",\n * \"pushNotificationConfig\": {\n * \"id\": \"cfg_1\",\n * \"url\": \"https://my-consumer.example.com/agent/done\",\n * \"token\": \"my-shared-secret-not-the-hmac-secret\"\n * }\n * }\n * }\n *\n * @example webhook delivery\n * POST https://my-consumer.example.com/agent/done\n * X-A2A-Notification-Token: my-shared-secret-not-the-hmac-secret\n * X-A2A-Signature: sha256=<hex(HMAC-SHA256(webhookSecret, body))>\n * Content-Type: application/json\n * { \"taskId\": \"task_abc\", \"state\": \"completed\", \"task\": { ...full Task... } }\n */\n\nimport type { SqlAdapter } from './task-store-sql'\nimport type { Task } from './types'\n\n/**\n * Authentication metadata for the webhook itself. The A2A spec leaves this\n * to consumers — the most common shape is a bearer token the gateway sends as\n * `Authorization: <scheme> <credential>`. We pass it through verbatim.\n */\nexport interface PushNotificationAuthentication {\n schemes: string[]\n credentials?: string\n}\n\n/**\n * Per-task push notification configuration. A task can have multiple configs\n * (e.g. one for the consumer's own webhook + one for an audit log endpoint).\n */\nexport interface PushNotificationConfig {\n /** Stable id within the task's config set. Required for get/delete addressing. */\n id: string\n /** HTTPS URL the gateway will POST to. */\n url: string\n /**\n * Opaque token the gateway sends back as `X-A2A-Notification-Token` so the\n * webhook can verify the call originated from a registration the consumer\n * authorized. Distinct from the HMAC signature (which proves the body\n * wasn't tampered with) — this proves the registration is recognised.\n */\n token?: string\n /** Optional webhook-side auth metadata. */\n authentication?: PushNotificationAuthentication\n}\n\nexport interface TaskPushNotificationConfig {\n taskId: string\n pushNotificationConfig: PushNotificationConfig\n}\n\n/**\n * Storage for push configs. The default in-memory store is fine for single\n * Worker instances + tests; production multi-instance deployments need\n * `SqlPushNotificationStore` (or any other shared-state adapter) so a config\n * registered on instance A is visible to a delivery firing from instance B.\n */\nexport interface PushNotificationStore {\n set(taskId: string, config: PushNotificationConfig): Promise<void>\n get(taskId: string, configId: string): Promise<PushNotificationConfig | undefined>\n list(taskId: string): Promise<PushNotificationConfig[]>\n delete(taskId: string, configId: string): Promise<void>\n}\n\nexport class InMemoryPushNotificationStore implements PushNotificationStore {\n private readonly byTask = new Map<string, Map<string, PushNotificationConfig>>()\n\n async set(taskId: string, config: PushNotificationConfig): Promise<void> {\n let configs = this.byTask.get(taskId)\n if (!configs) {\n configs = new Map()\n this.byTask.set(taskId, configs)\n }\n configs.set(config.id, { ...config })\n }\n\n async get(taskId: string, configId: string): Promise<PushNotificationConfig | undefined> {\n const cfg = this.byTask.get(taskId)?.get(configId)\n return cfg ? { ...cfg } : undefined\n }\n\n async list(taskId: string): Promise<PushNotificationConfig[]> {\n const configs = this.byTask.get(taskId)\n if (!configs) return []\n return [...configs.values()].map((c) => ({ ...c }))\n }\n\n async delete(taskId: string, configId: string): Promise<void> {\n const configs = this.byTask.get(taskId)\n if (!configs) return\n configs.delete(configId)\n if (configs.size === 0) this.byTask.delete(taskId)\n }\n}\n\nconst PUSH_TABLE_DDL = (table: string) => `\n CREATE TABLE IF NOT EXISTS ${table} (\n task_id TEXT NOT NULL,\n config_id TEXT NOT NULL,\n url TEXT NOT NULL,\n token TEXT,\n authentication TEXT,\n PRIMARY KEY (task_id, config_id)\n )\n`\n\n/** SQL-backed push config store. Schema: one row per (taskId, configId). */\nexport class SqlPushNotificationStore implements PushNotificationStore {\n constructor(\n private readonly db: SqlAdapter,\n private readonly table: string = 'a2a_push_configs',\n ) {}\n\n async migrate(): Promise<void> {\n await this.db.exec(PUSH_TABLE_DDL(this.table))\n }\n\n async set(taskId: string, config: PushNotificationConfig): Promise<void> {\n const auth = config.authentication ? JSON.stringify(config.authentication) : null\n const updated = await this.db.exec(\n `UPDATE ${this.table} SET url = ?, token = ?, authentication = ? WHERE task_id = ? AND config_id = ?`,\n [config.url, config.token ?? null, auth, taskId, config.id],\n )\n if (updated.rowsAffected === 0) {\n await this.db.exec(\n `INSERT INTO ${this.table} (task_id, config_id, url, token, authentication) VALUES (?, ?, ?, ?, ?)`,\n [taskId, config.id, config.url, config.token ?? null, auth],\n )\n }\n }\n\n async get(taskId: string, configId: string): Promise<PushNotificationConfig | undefined> {\n const rows = await this.db.query<{\n config_id: string\n url: string\n token: string | null\n authentication: string | null\n }>(\n `SELECT config_id, url, token, authentication FROM ${this.table} WHERE task_id = ? AND config_id = ?`,\n [taskId, configId],\n )\n const row = rows[0]\n if (!row) return undefined\n return {\n id: row.config_id,\n url: row.url,\n token: row.token ?? undefined,\n authentication: row.authentication\n ? (JSON.parse(row.authentication) as PushNotificationAuthentication)\n : undefined,\n }\n }\n\n async list(taskId: string): Promise<PushNotificationConfig[]> {\n const rows = await this.db.query<{\n config_id: string\n url: string\n token: string | null\n authentication: string | null\n }>(\n `SELECT config_id, url, token, authentication FROM ${this.table} WHERE task_id = ?`,\n [taskId],\n )\n return rows.map((row) => ({\n id: row.config_id,\n url: row.url,\n token: row.token ?? undefined,\n authentication: row.authentication\n ? (JSON.parse(row.authentication) as PushNotificationAuthentication)\n : undefined,\n }))\n }\n\n async delete(taskId: string, configId: string): Promise<void> {\n await this.db.exec(\n `DELETE FROM ${this.table} WHERE task_id = ? AND config_id = ?`,\n [taskId, configId],\n )\n }\n}\n\n/**\n * Send the webhook for each registered config on a task. Signs the body with\n * HMAC-SHA256 against `webhookSecret` so the consumer can verify authenticity.\n * Fire-and-forget per the design note above — the function awaits delivery\n * (so observability hooks see the result) but does not retry on failure.\n *\n * The caller decides *when* to deliver — typically on terminal-state\n * transitions emitted from `message/send` and `message/stream`.\n */\nexport async function deliverPushNotifications(args: {\n task: Task\n store: PushNotificationStore\n webhookSecret: string | undefined\n /** Inject for tests. Defaults to global `fetch`. */\n fetcher?: typeof fetch\n /** Optional callback so the gateway's observer can log delivery outcomes. */\n onDelivery?: (result: PushDeliveryResult) => void\n}): Promise<PushDeliveryResult[]> {\n const fetcher = args.fetcher ?? fetch\n const configs = await args.store.list(args.task.id)\n const body = JSON.stringify({\n taskId: args.task.id,\n state: args.task.status.state,\n task: args.task,\n })\n const signature = args.webhookSecret\n ? `sha256=${await hmacSha256Hex(args.webhookSecret, body)}`\n : undefined\n\n const results: PushDeliveryResult[] = []\n for (const config of configs) {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (config.token) headers['X-A2A-Notification-Token'] = config.token\n if (signature) headers['X-A2A-Signature'] = signature\n if (config.authentication?.credentials) {\n const scheme = config.authentication.schemes[0] ?? 'Bearer'\n headers.Authorization = `${scheme} ${config.authentication.credentials}`\n }\n\n let result: PushDeliveryResult\n try {\n const res = await fetcher(config.url, { method: 'POST', headers, body })\n result = {\n taskId: args.task.id,\n configId: config.id,\n url: config.url,\n ok: res.ok,\n status: res.status,\n }\n } catch (err) {\n result = {\n taskId: args.task.id,\n configId: config.id,\n url: config.url,\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n args.onDelivery?.(result)\n results.push(result)\n }\n return results\n}\n\nexport interface PushDeliveryResult {\n taskId: string\n configId: string\n url: string\n ok: boolean\n status?: number\n error?: string\n}\n\n/**\n * HMAC-SHA256 via WebCrypto. Works on Workers, Node 19+, Bun, Deno. The\n * gateway requires WebCrypto for x402 verification already, so this adds no\n * new platform constraint.\n */\nasync function hmacSha256Hex(secret: string, body: string): Promise<string> {\n const enc = new TextEncoder()\n const key = await crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(body))\n return [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n","/**\n * A2A Message ↔ inner-agent (text-only) translation. Both directions are\n * intentionally narrow: callers send text parts, the inner sandbox produces\n * text. Data + file parts are rejected with `CONTENT_TYPE_NOT_SUPPORTED`\n * rather than silently dropped — the protocol's whole point is letting the\n * caller know exactly what an agent does and doesn't accept.\n */\n\nimport { A2A_ERROR_CODES, type Artifact, type Message } from './types'\n\nexport interface ExtractedText {\n text: string\n}\n\nexport interface ExtractError {\n error: { code: number; message: string }\n}\n\n/**\n * Pull `text` out of a Message's parts. Concatenates multi-text-part messages\n * with two newlines, mirroring the OpenAI-compat path's join of `user`\n * messages. Returns an A2A error code on any non-text part — text-only is the\n * declared capability of every agent this gateway fronts.\n */\nexport function extractTextFromMessage(message: Message): ExtractedText | ExtractError {\n if (!message || message.kind !== 'message') {\n return {\n error: {\n code: A2A_ERROR_CODES.INVALID_PARAMS,\n message: 'params.message must be an A2A Message ({ kind: \"message\", role, parts, messageId })',\n },\n }\n }\n if (!Array.isArray(message.parts) || message.parts.length === 0) {\n return {\n error: {\n code: A2A_ERROR_CODES.INVALID_PARAMS,\n message: 'message.parts must be a non-empty array',\n },\n }\n }\n const texts: string[] = []\n for (const part of message.parts) {\n if (part.kind === 'text') {\n if (typeof part.text !== 'string') {\n return {\n error: {\n code: A2A_ERROR_CODES.INVALID_PARAMS,\n message: 'text part .text must be a string',\n },\n }\n }\n texts.push(part.text)\n } else {\n return {\n error: {\n code: A2A_ERROR_CODES.CONTENT_TYPE_NOT_SUPPORTED,\n message: `part.kind '${(part as { kind: string }).kind}' not supported; this agent accepts text parts only`,\n },\n }\n }\n }\n return { text: texts.join('\\n\\n') }\n}\n\n/**\n * Wrap the agent's final response text as an A2A Artifact for the task's\n * `artifacts` field. `name='response'` is the convention for the primary\n * model output across A2A reference servers.\n */\nexport function responseTextToArtifact(text: string, artifactId: string): Artifact {\n return {\n artifactId,\n name: 'response',\n parts: [{ kind: 'text', text }],\n }\n}\n","/**\n * A2A JSON-RPC method dispatcher. Both `message/send` and `message/stream`\n * route through the shared `authenticateAndGuard` + `dispatchSandboxStream`\n * + `settleAndRecord` pipeline so every protocol surface gets the same\n * payment, rate-limit, injection, and authorization guarantees.\n *\n * State the dispatcher owns:\n * - the task store (durable record of every task we accepted)\n * - an in-process map of active AbortControllers so `tasks/cancel` can\n * interrupt a still-running `dispatchSandboxStream`\n */\n\nimport type { Context } from 'hono'\n\nimport {\n type A2ADispatchEvent,\n type AuthorizedRequest,\n type GatewayState,\n authenticateAndGuard,\n dispatchSandboxStreamRich,\n estimateTokens,\n settleAndRecord,\n} from '../dispatch'\nimport type { GatewayConfig } from '../types'\nimport { buildAgentCard } from './agent-card'\nimport { fail, ok, parseEnvelope } from './jsonrpc'\nimport {\n deliverPushNotifications,\n type PushNotificationStore,\n type TaskPushNotificationConfig,\n} from './push-notifications'\nimport type { TaskStore } from './task-store'\nimport { extractTextFromMessage, responseTextToArtifact } from './translate'\nimport {\n A2A_ERROR_CODES,\n type JSONRPCRequest,\n type Message,\n type MessageSendParams,\n type StreamingEvent,\n type Task,\n type TaskArtifactUpdateEvent,\n type TaskIdParams,\n type TaskPushNotificationConfigGetParams,\n type TaskStatusUpdateEvent,\n} from './types'\n\nexport interface A2AHandlerDeps {\n config: GatewayConfig\n state: GatewayState\n taskStore: TaskStore\n pushStore?: PushNotificationStore\n}\n\n/** Terminal task states — fire-once push delivery occurs on these transitions. */\nconst TERMINAL_STATES: ReadonlySet<Task['status']['state']> = new Set([\n 'completed',\n 'canceled',\n 'failed',\n 'rejected',\n])\n\n/**\n * Per-gateway in-process registry of cancellable runs. Keyed by task id;\n * absent = task already terminal or never streamed. Cleared by the streaming\n * handler on completion. Cancel is best-effort: a cancel arriving after the\n * stream finished is reported as `TASK_NOT_CANCELABLE`.\n */\nclass CancelRegistry {\n private readonly controllers = new Map<string, AbortController>()\n\n register(taskId: string): AbortController {\n const c = new AbortController()\n this.controllers.set(taskId, c)\n return c\n }\n\n clear(taskId: string): void {\n this.controllers.delete(taskId)\n }\n\n cancel(taskId: string): boolean {\n const c = this.controllers.get(taskId)\n if (!c) return false\n c.abort()\n this.controllers.delete(taskId)\n return true\n }\n}\n\nexport function createA2AHandlers(deps: A2AHandlerDeps) {\n const cancels = new CancelRegistry()\n\n // GET /:slug/.well-known/agent.json\n const handleAgentCard = async (c: Context): Promise<Response> => {\n const slug = c.req.param('slug')\n if (!slug) return c.json({ error: 'slug required' }, 400)\n const agent = await deps.config.resolveAgent(slug)\n if (!agent) {\n return c.json({ error: 'Agent not found or not published' }, 404)\n }\n const url = new URL(c.req.url)\n const agentUrl = `${url.origin}${url.pathname.replace(/\\/\\.well-known\\/agent\\.json$/, '')}`\n return c.json(buildAgentCard(agent, deps.config, agentUrl))\n }\n\n // POST /:slug — JSON-RPC dispatcher\n const handleJsonRpc = async (c: Context): Promise<Response> => {\n const slug = c.req.param('slug')\n if (!slug) {\n return c.json(fail(null, A2A_ERROR_CODES.INVALID_REQUEST, 'slug required'), 400)\n }\n\n // Body size limit (DoS prevention) — mirrors the OpenAI-compat handler.\n const contentLength = Number.parseInt(c.req.header('Content-Length') ?? '0', 10)\n if (contentLength > 65536) {\n return c.json(fail(null, A2A_ERROR_CODES.INVALID_REQUEST, 'request body too large (max 64KB)'), 413)\n }\n\n let raw: unknown\n try {\n raw = await c.req.json()\n } catch {\n return c.json(fail(null, A2A_ERROR_CODES.PARSE_ERROR, 'invalid JSON'), 400)\n }\n const parsed = parseEnvelope(raw)\n if ('code' in parsed) {\n return c.json(fail(parsed.id, parsed.code, parsed.message), 400)\n }\n\n switch (parsed.method) {\n case 'message/send':\n return handleMessageSend(c, slug, parsed, deps)\n case 'message/stream':\n return handleMessageStream(c, slug, parsed, deps, cancels)\n case 'tasks/get':\n return handleTasksGet(c, parsed, deps)\n case 'tasks/cancel':\n return handleTasksCancel(c, parsed, deps, cancels)\n case 'tasks/resubscribe':\n return handleTasksResubscribe(c, parsed, deps)\n case 'tasks/pushNotificationConfig/set':\n return handlePushSet(c, parsed, deps)\n case 'tasks/pushNotificationConfig/get':\n return handlePushGet(c, parsed, deps)\n case 'tasks/pushNotificationConfig/list':\n return handlePushList(c, parsed, deps)\n case 'tasks/pushNotificationConfig/delete':\n return handlePushDelete(c, parsed, deps)\n default:\n return c.json(\n fail(parsed.id, A2A_ERROR_CODES.METHOD_NOT_FOUND, `unknown method '${parsed.method}'`),\n )\n }\n }\n\n return { handleAgentCard, handleJsonRpc }\n}\n\n// ── message/send (synchronous) ────────────────────────────────────────────\n\nasync function handleMessageSend(\n c: Context,\n slug: string,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n const guard = await guardMessageRequest(c, slug, req, deps)\n if (guard instanceof Response) return guard\n const { authz, task } = guard\n\n let responseText = ''\n let outputTokens = 0\n let inputRequiredPrompt: string | undefined\n let inputRequiredSeen = false\n try {\n for await (const event of dispatchSandboxStreamRich(\n authz.agent,\n authz.userMessage,\n authz.consumerId,\n deps.config,\n undefined,\n task.id,\n )) {\n if (event.kind === 'text') {\n responseText += event.delta\n outputTokens += estimateTokens(event.delta)\n } else {\n inputRequiredSeen = true\n inputRequiredPrompt = event.prompt\n }\n }\n } catch (err) {\n const failed = withStatus(task, 'failed')\n await deps.taskStore.put(failed)\n await maybeDeliverPush(failed, deps)\n return c.json(\n fail(\n req.id,\n A2A_ERROR_CODES.INTERNAL_ERROR,\n err instanceof Error ? err.message : String(err),\n ),\n )\n }\n\n // Settle for the work done so far before short-circuiting on input-required.\n // The user has been charged for the partial response, which is the right\n // commercial behavior — the sandbox produced tokens.\n await settleAndRecord(\n authz.agent,\n authz,\n estimateTokens(authz.userMessage),\n outputTokens,\n deps.config,\n deps.state.obs,\n )\n\n if (inputRequiredSeen) {\n const paused = withStatus(\n task,\n 'input-required',\n inputRequiredPrompt ? agentMessage(task, inputRequiredPrompt) : undefined,\n responseText\n ? [responseTextToArtifact(responseText, `${task.id}-artifact-0`)]\n : task.artifacts,\n )\n await deps.taskStore.put(paused)\n // input-required is non-terminal — do NOT deliver push notifications.\n return c.json(ok(req.id, paused))\n }\n\n const completed = withStatus(task, 'completed', undefined, [\n responseTextToArtifact(responseText, `${task.id}-artifact-0`),\n ])\n await deps.taskStore.put(completed)\n await maybeDeliverPush(completed, deps)\n return c.json(ok(req.id, completed))\n}\n\n// ── message/stream (SSE) ──────────────────────────────────────────────────\n\nasync function handleMessageStream(\n c: Context,\n slug: string,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n cancels: CancelRegistry,\n): Promise<Response> {\n const guard = await guardMessageRequest(c, slug, req, deps)\n if (guard instanceof Response) return guard\n const { authz, task } = guard\n\n const controller = cancels.register(task.id)\n const inputTokens = estimateTokens(authz.userMessage)\n let outputTokens = 0\n let responseText = ''\n\n const stream = new ReadableStream({\n async start(ctrl) {\n const encoder = new TextEncoder()\n const send = (event: StreamingEvent) => {\n ctrl.enqueue(encoder.encode(`data: ${JSON.stringify(ok(req.id, event))}\\n\\n`))\n }\n\n // Status: working\n const workingStatus: TaskStatusUpdateEvent = {\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: { state: 'working', timestamp: nowIso() },\n final: false,\n }\n await deps.taskStore.put({ ...task, status: workingStatus.status })\n send(workingStatus)\n\n let inputRequiredPrompt: string | undefined\n let inputRequiredSeen = false\n try {\n for await (const event of dispatchSandboxStreamRich(\n authz.agent,\n authz.userMessage,\n authz.consumerId,\n deps.config,\n controller.signal,\n task.id,\n )) {\n if (event.kind === 'text') {\n responseText += event.delta\n outputTokens += estimateTokens(event.delta)\n const artifactEvent: TaskArtifactUpdateEvent = {\n kind: 'artifact-update',\n taskId: task.id,\n contextId: task.contextId,\n artifact: {\n artifactId: `${task.id}-artifact-0`,\n name: 'response',\n parts: [{ kind: 'text', text: event.delta }],\n },\n append: true,\n }\n send(artifactEvent)\n } else {\n inputRequiredSeen = true\n inputRequiredPrompt = event.prompt\n }\n }\n\n // Caller aborted via tasks/cancel — emit canceled, do not settle.\n if (controller.signal.aborted) {\n const canceled = withStatus(task, 'canceled', undefined, [\n responseTextToArtifact(responseText, `${task.id}-artifact-0`),\n ])\n await deps.taskStore.put(canceled)\n send({\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: canceled.status,\n final: true,\n })\n await maybeDeliverPush(canceled, deps)\n return\n }\n\n // Settle once for whatever the sandbox produced (full or partial).\n await settleAndRecord(\n authz.agent,\n authz,\n inputTokens,\n outputTokens,\n deps.config,\n deps.state.obs,\n )\n\n if (inputRequiredSeen) {\n const paused = withStatus(\n task,\n 'input-required',\n inputRequiredPrompt ? agentMessage(task, inputRequiredPrompt) : undefined,\n responseText\n ? [responseTextToArtifact(responseText, `${task.id}-artifact-0`)]\n : task.artifacts,\n )\n await deps.taskStore.put(paused)\n send({\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: paused.status,\n final: true,\n })\n // input-required is non-terminal — do NOT deliver push notifications.\n return\n }\n\n // Final: artifact lastChunk + completed status.\n send({\n kind: 'artifact-update',\n taskId: task.id,\n contextId: task.contextId,\n artifact: {\n artifactId: `${task.id}-artifact-0`,\n name: 'response',\n parts: [{ kind: 'text', text: '' }],\n },\n append: true,\n lastChunk: true,\n })\n const completed = withStatus(task, 'completed', undefined, [\n responseTextToArtifact(responseText, `${task.id}-artifact-0`),\n ])\n await deps.taskStore.put(completed)\n send({\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: completed.status,\n final: true,\n })\n await maybeDeliverPush(completed, deps)\n } catch (err) {\n const failed = withStatus(task, 'failed')\n await deps.taskStore.put(failed)\n send({\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: failed.status,\n final: true,\n })\n await maybeDeliverPush(failed, deps)\n await deps.state.obs?.onStreamError?.(\n {\n requestId: authz.requestId,\n agentSlug: authz.agent.slug,\n startMs: authz.startMs,\n },\n {\n consumerId: authz.consumerId,\n errorMessage: err instanceof Error ? err.message : String(err),\n },\n )\n } finally {\n cancels.clear(task.id)\n ctrl.close()\n }\n },\n })\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'X-Request-Id': authz.requestId,\n 'X-Agent-Slug': authz.agent.slug,\n 'X-Task-Id': task.id,\n },\n })\n}\n\n// ── tasks/get + tasks/cancel ──────────────────────────────────────────────\n\nasync function handleTasksGet(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n const params = req.params as TaskIdParams | undefined\n if (!params || typeof params.id !== 'string') {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id required'))\n }\n const task = await deps.taskStore.get(params.id)\n if (!task) {\n return c.json(\n fail(req.id, A2A_ERROR_CODES.TASK_NOT_FOUND, `task '${params.id}' not found`),\n )\n }\n return c.json(ok(req.id, task))\n}\n\nasync function handleTasksCancel(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n cancels: CancelRegistry,\n): Promise<Response> {\n const params = req.params as TaskIdParams | undefined\n if (!params || typeof params.id !== 'string') {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id required'))\n }\n const task = await deps.taskStore.get(params.id)\n if (!task) {\n return c.json(\n fail(req.id, A2A_ERROR_CODES.TASK_NOT_FOUND, `task '${params.id}' not found`),\n )\n }\n if (isTerminal(task.status.state)) {\n return c.json(\n fail(\n req.id,\n A2A_ERROR_CODES.TASK_NOT_CANCELABLE,\n `task '${params.id}' is in terminal state '${task.status.state}'`,\n ),\n )\n }\n\n const stillActive = cancels.cancel(task.id)\n const canceled: Task = {\n ...task,\n status: { state: 'canceled', timestamp: nowIso() },\n }\n await deps.taskStore.put(canceled)\n\n // If a stream was active, it'll observe the abort and emit its own final\n // status-update AND fire its own push delivery; the dispatcher only fires\n // push when the cancel races to terminal state with no active streamer.\n if (!stillActive) {\n await maybeDeliverPush(canceled, deps)\n }\n return c.json(ok(req.id, canceled))\n}\n\n// ── tasks/resubscribe ─────────────────────────────────────────────────────\n\n/**\n * Re-attach to a known task via SSE. The minimum-viable shape (and the one\n * the spec actually requires): emit the task's current status as one\n * status-update event with the right `final` flag, then close. Callers that\n * lost their original stream connection can re-subscribe to find out where\n * the task ended up; in-flight tasks return their last-known state and the\n * client polls (or re-subscribes) for further updates.\n *\n * Out of scope: live-rebroadcasting deltas from an in-flight stream to a new\n * subscriber. That requires per-task pub/sub which we haven't needed yet —\n * the typical recovery path is \"task already finished, fetch the result.\"\n */\nasync function handleTasksResubscribe(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n const params = req.params as TaskIdParams | undefined\n if (!params || typeof params.id !== 'string') {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id required'))\n }\n const task = await deps.taskStore.get(params.id)\n if (!task) {\n return c.json(\n fail(req.id, A2A_ERROR_CODES.TASK_NOT_FOUND, `task '${params.id}' not found`),\n )\n }\n const final = isTerminal(task.status.state) || task.status.state === 'input-required'\n const event: TaskStatusUpdateEvent = {\n kind: 'status-update',\n taskId: task.id,\n contextId: task.contextId,\n status: task.status,\n final,\n }\n const encoder = new TextEncoder()\n const stream = new ReadableStream({\n start(ctrl) {\n ctrl.enqueue(encoder.encode(`data: ${JSON.stringify(ok(req.id, event))}\\n\\n`))\n ctrl.close()\n },\n })\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'X-Task-Id': task.id,\n },\n })\n}\n\n// ── tasks/pushNotificationConfig/* ────────────────────────────────────────\n\nasync function handlePushSet(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n if (!deps.pushStore) {\n return c.json(fail(req.id, A2A_ERROR_CODES.PUSH_NOT_SUPPORTED, 'push notifications not configured'))\n }\n const params = req.params as TaskPushNotificationConfig | undefined\n if (!params || typeof params.taskId !== 'string' || !params.pushNotificationConfig?.id) {\n return c.json(\n fail(\n req.id,\n A2A_ERROR_CODES.INVALID_PARAMS,\n 'params.taskId and params.pushNotificationConfig.id required',\n ),\n )\n }\n if (typeof params.pushNotificationConfig.url !== 'string') {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'pushNotificationConfig.url required'))\n }\n const task = await deps.taskStore.get(params.taskId)\n if (!task) {\n return c.json(fail(req.id, A2A_ERROR_CODES.TASK_NOT_FOUND, `task '${params.taskId}' not found`))\n }\n await deps.pushStore.set(params.taskId, params.pushNotificationConfig)\n const stored = await deps.pushStore.get(params.taskId, params.pushNotificationConfig.id)\n return c.json(ok(req.id, { taskId: params.taskId, pushNotificationConfig: stored }))\n}\n\nasync function handlePushGet(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n if (!deps.pushStore) {\n return c.json(fail(req.id, A2A_ERROR_CODES.PUSH_NOT_SUPPORTED, 'push notifications not configured'))\n }\n const params = req.params as TaskPushNotificationConfigGetParams | undefined\n if (!params || typeof params.id !== 'string' || typeof params.pushNotificationConfigId !== 'string') {\n return c.json(\n fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id and params.pushNotificationConfigId required'),\n )\n }\n const cfg = await deps.pushStore.get(params.id, params.pushNotificationConfigId)\n if (!cfg) {\n return c.json(\n fail(\n req.id,\n A2A_ERROR_CODES.TASK_NOT_FOUND,\n `push config '${params.pushNotificationConfigId}' not found for task '${params.id}'`,\n ),\n )\n }\n return c.json(ok(req.id, { taskId: params.id, pushNotificationConfig: cfg }))\n}\n\nasync function handlePushList(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n if (!deps.pushStore) {\n return c.json(fail(req.id, A2A_ERROR_CODES.PUSH_NOT_SUPPORTED, 'push notifications not configured'))\n }\n const params = req.params as TaskIdParams | undefined\n if (!params || typeof params.id !== 'string') {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id required'))\n }\n const configs = await deps.pushStore.list(params.id)\n return c.json(ok(req.id, configs.map((cfg) => ({ taskId: params.id, pushNotificationConfig: cfg }))))\n}\n\nasync function handlePushDelete(\n c: Context,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<Response> {\n if (!deps.pushStore) {\n return c.json(fail(req.id, A2A_ERROR_CODES.PUSH_NOT_SUPPORTED, 'push notifications not configured'))\n }\n const params = req.params as TaskPushNotificationConfigGetParams | undefined\n if (!params || typeof params.id !== 'string' || typeof params.pushNotificationConfigId !== 'string') {\n return c.json(\n fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.id and params.pushNotificationConfigId required'),\n )\n }\n await deps.pushStore.delete(params.id, params.pushNotificationConfigId)\n return c.json(ok(req.id, null))\n}\n\n// ── Shared message-send setup (auth + task allocation) ────────────────────\n\ninterface GuardSuccess {\n authz: AuthorizedRequest\n task: Task\n}\n\nasync function guardMessageRequest(\n c: Context,\n slug: string,\n req: JSONRPCRequest,\n deps: A2AHandlerDeps,\n): Promise<GuardSuccess | Response> {\n const params = req.params as MessageSendParams | undefined\n if (!params || !params.message) {\n return c.json(fail(req.id, A2A_ERROR_CODES.INVALID_PARAMS, 'params.message required'))\n }\n const extracted = extractTextFromMessage(params.message)\n if ('error' in extracted) {\n return c.json(fail(req.id, extracted.error.code, extracted.error.message))\n }\n\n const guard = await authenticateAndGuard(\n c,\n slug,\n [{ role: 'user', content: extracted.text }],\n deps.config,\n deps.state,\n )\n if (guard instanceof Response) return guard\n const authz = guard\n\n // Multi-turn continuation: if the caller addressed an existing task that is\n // currently in `input-required`, append the new message and transition to\n // `working`. Any other taskId (unknown OR pointing at a terminal/working\n // task) means the caller is starting a fresh task and we mint a new id.\n if (typeof params.message.taskId === 'string') {\n const existing = await deps.taskStore.get(params.message.taskId)\n if (existing) {\n if (existing.status.state !== 'input-required') {\n return c.json(\n fail(\n req.id,\n A2A_ERROR_CODES.INVALID_PARAMS,\n `task '${existing.id}' is in state '${existing.status.state}'; only 'input-required' tasks accept follow-up messages`,\n ),\n )\n }\n const appendedMessage: Message = {\n ...params.message,\n taskId: existing.id,\n contextId: existing.contextId,\n }\n const continued: Task = {\n ...existing,\n status: { state: 'working', timestamp: nowIso() },\n history: [...(existing.history ?? []), appendedMessage],\n }\n await deps.taskStore.put(continued)\n return { authz, task: continued }\n }\n // Unknown taskId in params: fall through and mint a fresh task with that\n // exact id so callers that pre-allocate ids (idempotency) get them.\n }\n\n const taskId = params.message.taskId ?? `task_${cryptoRandomId()}`\n const contextId = params.message.contextId ?? `ctx_${cryptoRandomId()}`\n const initialMessage = {\n ...params.message,\n taskId,\n contextId,\n }\n const task: Task = {\n kind: 'task',\n id: taskId,\n contextId,\n status: { state: 'submitted', timestamp: nowIso() },\n history: [initialMessage],\n }\n await deps.taskStore.put(task)\n return { authz, task }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────\n\nfunction isTerminal(state: Task['status']['state']): boolean {\n return (\n state === 'completed' ||\n state === 'canceled' ||\n state === 'failed' ||\n state === 'rejected'\n )\n}\n\nfunction nowIso(): string {\n return new Date().toISOString()\n}\n\nfunction cryptoRandomId(): string {\n return crypto.randomUUID().replace(/-/g, '')\n}\n\n/**\n * Build a new Task with an updated status (and optional artifacts). Centralises\n * the timestamp + status structure so terminal transitions are written\n * identically across every code path.\n */\nfunction withStatus(\n task: Task,\n state: Task['status']['state'],\n message?: Message,\n artifacts?: Task['artifacts'],\n): Task {\n return {\n ...task,\n status: { state, timestamp: nowIso(), ...(message ? { message } : {}) },\n ...(artifacts !== undefined ? { artifacts } : {}),\n }\n}\n\n/**\n * Synthesize an agent-role message attached to a status (e.g. the\n * input-required prompt text). messageId is deterministic-by-task so callers\n * can dedupe on retry.\n */\nfunction agentMessage(task: Task, text: string): Message {\n return {\n kind: 'message',\n role: 'agent',\n parts: [{ kind: 'text', text }],\n messageId: `${task.id}-status-${task.status.state}-${nowIso()}`,\n taskId: task.id,\n contextId: task.contextId,\n }\n}\n\n/**\n * Fire-and-forget push delivery. Idempotent w.r.t. push: if the task hasn't\n * reached a terminal state, this is a no-op. The dispatch logs failures via\n * the observer rather than failing the request — webhook receivers re-fetch\n * via `tasks/get` to confirm state.\n */\nasync function maybeDeliverPush(task: Task, deps: A2AHandlerDeps): Promise<void> {\n if (!deps.pushStore || !TERMINAL_STATES.has(task.status.state)) return\n try {\n await deliverPushNotifications({\n task,\n store: deps.pushStore,\n webhookSecret: deps.config.a2a?.webhookSecret,\n fetcher: deps.config.a2a?.pushFetcher,\n onDelivery: (result) => {\n if (!result.ok) {\n deps.state.obs?.onStreamError?.(\n { requestId: result.taskId, agentSlug: task.id, startMs: Date.now() },\n {\n consumerId: result.configId,\n errorMessage: `push delivery failed (${result.status ?? 'no-status'}): ${result.error ?? 'non-2xx'}`,\n },\n )\n }\n },\n })\n } catch (err) {\n // Catastrophic failure of the push pipeline itself (e.g. the store threw).\n // Logged but never escalated — a busted webhook MUST NOT fail the agent.\n console.error(\n `[agent-gateway] push delivery threw for task ${task.id}: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\n","/**\n * Task persistence behind the JSON-RPC dispatcher. Default adapter is in\n * memory with a 1-hour TTL — adequate for tests, scratch, and Workers with\n * a short-lived process. Production deployments wire their own\n * `TaskStore` (D1, postgres, Durable Object) via `GatewayConfig.a2a`.\n */\n\nimport type { Task } from './types'\n\nexport interface TaskStore {\n get(id: string): Promise<Task | undefined>\n put(task: Task): Promise<void>\n delete(id: string): Promise<void>\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000\n\nexport class InMemoryTaskStore implements TaskStore {\n private readonly entries = new Map<string, { task: Task; expiresAt: number }>()\n\n constructor(private readonly ttlMs: number = DEFAULT_TTL_MS) {}\n\n async get(id: string): Promise<Task | undefined> {\n this.gc()\n const entry = this.entries.get(id)\n if (!entry) return undefined\n return clone(entry.task)\n }\n\n async put(task: Task): Promise<void> {\n this.gc()\n this.entries.set(task.id, { task: clone(task), expiresAt: Date.now() + this.ttlMs })\n }\n\n async delete(id: string): Promise<void> {\n this.entries.delete(id)\n }\n\n /**\n * Sweep expired tasks. Called inline on every read/write — cheap for the\n * Map sizes this is designed for (10s–1000s of concurrent tasks).\n */\n private gc(): void {\n const now = Date.now()\n for (const [id, entry] of this.entries) {\n if (entry.expiresAt <= now) this.entries.delete(id)\n }\n }\n}\n\nfunction clone<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-M7ZJAK4K.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// src/nonce-store.ts
|
|
2
|
-
var MemoryNonceStore = class {
|
|
3
|
-
seen = /* @__PURE__ */ new Map();
|
|
4
|
-
// nonce → expiresAt
|
|
5
|
-
lastEviction = Date.now();
|
|
6
|
-
async hasSeen(nonce) {
|
|
7
|
-
this.evictExpired();
|
|
8
|
-
const expiresAt = this.seen.get(nonce);
|
|
9
|
-
if (!expiresAt) return false;
|
|
10
|
-
if (expiresAt < Date.now()) {
|
|
11
|
-
this.seen.delete(nonce);
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
async markSeen(nonce, ttlSeconds) {
|
|
17
|
-
this.seen.set(nonce, Date.now() + ttlSeconds * 1e3);
|
|
18
|
-
this.evictExpired();
|
|
19
|
-
}
|
|
20
|
-
evictExpired() {
|
|
21
|
-
const now = Date.now();
|
|
22
|
-
if (now - this.lastEviction < 6e4) return;
|
|
23
|
-
this.lastEviction = now;
|
|
24
|
-
for (const [nonce, expiresAt] of this.seen) {
|
|
25
|
-
if (expiresAt < now) this.seen.delete(nonce);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var KvNonceStore = class {
|
|
30
|
-
constructor(kv, prefix = "nonce") {
|
|
31
|
-
this.kv = kv;
|
|
32
|
-
this.prefix = prefix;
|
|
33
|
-
}
|
|
34
|
-
kv;
|
|
35
|
-
prefix;
|
|
36
|
-
async hasSeen(nonce) {
|
|
37
|
-
const value = await this.kv.get(this.key(nonce));
|
|
38
|
-
return value !== null;
|
|
39
|
-
}
|
|
40
|
-
async markSeen(nonce, ttlSeconds) {
|
|
41
|
-
const ttl = Math.max(ttlSeconds, 60);
|
|
42
|
-
await this.kv.put(this.key(nonce), "1", { expirationTtl: ttl });
|
|
43
|
-
}
|
|
44
|
-
key(nonce) {
|
|
45
|
-
return `${this.prefix}:${nonce}`;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export {
|
|
50
|
-
MemoryNonceStore,
|
|
51
|
-
KvNonceStore
|
|
52
|
-
};
|
|
53
|
-
//# sourceMappingURL=chunk-M7ZJAK4K.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/nonce-store.ts"],"sourcesContent":["/**\n * Nonce replay protection for x402/MPP payments.\n * Tracks seen nonces to prevent the same payment from being used twice.\n */\n\nexport interface NonceStore {\n /** Check if nonce has been seen. Returns true if already used (reject). */\n hasSeen(nonce: string): Promise<boolean>\n /** Mark nonce as used. TTL = how long to remember it (seconds). */\n markSeen(nonce: string, ttlSeconds: number): Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// In-memory implementation — single-worker, ephemeral\n// ---------------------------------------------------------------------------\n\n/** In-memory nonce store with automatic eviction. Use in tests or single-worker deploys. */\nexport class MemoryNonceStore implements NonceStore {\n private seen = new Map<string, number>() // nonce → expiresAt\n private lastEviction = Date.now()\n\n async hasSeen(nonce: string): Promise<boolean> {\n this.evictExpired()\n const expiresAt = this.seen.get(nonce)\n if (!expiresAt) return false\n if (expiresAt < Date.now()) {\n this.seen.delete(nonce)\n return false\n }\n return true\n }\n\n async markSeen(nonce: string, ttlSeconds: number): Promise<void> {\n this.seen.set(nonce, Date.now() + ttlSeconds * 1000)\n this.evictExpired()\n }\n\n private evictExpired() {\n const now = Date.now()\n // Evict at most every 60 seconds to avoid O(n) on every request\n if (now - this.lastEviction < 60_000) return\n this.lastEviction = now\n for (const [nonce, expiresAt] of this.seen) {\n if (expiresAt < now) this.seen.delete(nonce)\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cloudflare KV implementation — multi-worker, distributed\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal KVNamespace shape — matches Cloudflare Workers' @cloudflare/workers-types\n * without pulling that package as a dep. Production consumers cast their KV\n * binding to this interface at the construction site.\n */\nexport interface KVNamespace {\n get(key: string, options?: { type?: 'text' | 'json' }): Promise<string | null>\n put(key: string, value: string, options?: { expirationTtl?: number }): Promise<void>\n delete(key: string): Promise<void>\n}\n\n/**\n * KV-backed NonceStore for distributed Cloudflare Workers deployments.\n *\n * Why this exists: MemoryNonceStore works on a single worker instance, but\n * Cloudflare routes requests across multiple isolates. Without shared state,\n * an attacker could retry a replayed nonce against a different isolate and\n * have it accepted. This implementation uses Workers KV with native TTL so\n * the nonce automatically expires at payment-expiry time.\n *\n * TTL precision: KV is eventually consistent (propagation ~60s). For x402\n * with 10-minute expiry windows this is fine — by the time KV propagates,\n * the payment itself would be expired anyway.\n *\n * Usage:\n * const nonceStore = new KvNonceStore(env.NONCE_KV, 'x402')\n * createAgentGateway({ ...config, nonceStore })\n */\nexport class KvNonceStore implements NonceStore {\n constructor(\n private readonly kv: KVNamespace,\n /** Key prefix to namespace within a shared KV (default: \"nonce\"). */\n private readonly prefix: string = 'nonce',\n ) {}\n\n async hasSeen(nonce: string): Promise<boolean> {\n const value = await this.kv.get(this.key(nonce))\n return value !== null\n }\n\n async markSeen(nonce: string, ttlSeconds: number): Promise<void> {\n // KV minimum TTL is 60 seconds\n const ttl = Math.max(ttlSeconds, 60)\n await this.kv.put(this.key(nonce), '1', { expirationTtl: ttl })\n }\n\n private key(nonce: string): string {\n return `${this.prefix}:${nonce}`\n }\n}\n"],"mappings":";AAiBO,IAAM,mBAAN,MAA6C;AAAA,EAC1C,OAAO,oBAAI,IAAoB;AAAA;AAAA,EAC/B,eAAe,KAAK,IAAI;AAAA,EAEhC,MAAM,QAAQ,OAAiC;AAC7C,SAAK,aAAa;AAClB,UAAM,YAAY,KAAK,KAAK,IAAI,KAAK;AACrC,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,WAAK,KAAK,OAAO,KAAK;AACtB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,OAAe,YAAmC;AAC/D,SAAK,KAAK,IAAI,OAAO,KAAK,IAAI,IAAI,aAAa,GAAI;AACnD,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,eAAe;AACrB,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,MAAM,KAAK,eAAe,IAAQ;AACtC,SAAK,eAAe;AACpB,eAAW,CAAC,OAAO,SAAS,KAAK,KAAK,MAAM;AAC1C,UAAI,YAAY,IAAK,MAAK,KAAK,OAAO,KAAK;AAAA,IAC7C;AAAA,EACF;AACF;AAkCO,IAAM,eAAN,MAAyC;AAAA,EAC9C,YACmB,IAEA,SAAiB,SAClC;AAHiB;AAEA;AAAA,EAChB;AAAA,EAHgB;AAAA,EAEA;AAAA,EAGnB,MAAM,QAAQ,OAAiC;AAC7C,UAAM,QAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC;AAC/C,WAAO,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,SAAS,OAAe,YAAmC;AAE/D,UAAM,MAAM,KAAK,IAAI,YAAY,EAAE;AACnC,UAAM,KAAK,GAAG,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,eAAe,IAAI,CAAC;AAAA,EAChE;AAAA,EAEQ,IAAI,OAAuB;AACjC,WAAO,GAAG,KAAK,MAAM,IAAI,KAAK;AAAA,EAChC;AACF;","names":[]}
|