@agent-native/core 0.7.49 → 0.7.50
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/dist/a2a/client.d.ts +6 -2
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +9 -4
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/response-text.d.ts +4 -1
- package/dist/a2a/response-text.d.ts.map +1 -1
- package/dist/a2a/response-text.js +3 -2
- package/dist/a2a/response-text.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +28 -15
- package/dist/a2a/server.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +22 -2
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/webhook-handler.js +3 -2
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +9 -4
- package/dist/scripts/call-agent.js.map +1 -1
- package/package.json +1 -1
package/dist/a2a/client.d.ts
CHANGED
|
@@ -9,11 +9,15 @@ export declare class A2ATaskTimeoutError extends Error {
|
|
|
9
9
|
/**
|
|
10
10
|
* Sign a JWT for A2A cross-app identity verification.
|
|
11
11
|
*
|
|
12
|
-
* Uses
|
|
13
|
-
*
|
|
12
|
+
* Uses an org-level secret by default for direct org-secret workflows. Callers
|
|
13
|
+
* that are doing ordinary hosted cross-app delegation can set
|
|
14
|
+
* `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on
|
|
15
|
+
* every app database having an identical org row. The token contains the
|
|
16
|
+
* caller's email as `sub`, so the receiving app can verify who's calling.
|
|
14
17
|
*/
|
|
15
18
|
export declare function signA2AToken(email: string, orgDomain?: string, orgSecret?: string, options?: {
|
|
16
19
|
expiresIn?: string | number;
|
|
20
|
+
preferGlobalSecret?: boolean;
|
|
17
21
|
}): Promise<string>;
|
|
18
22
|
export declare class A2AClient {
|
|
19
23
|
private baseUrl;
|
package/dist/a2a/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EAGT,OAAO,EACP,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM;CAW9D;AAED
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EAGT,OAAO,EACP,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM;CAW9D;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,GACtE,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAC,CAAS;gBAGhC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE;IAazC;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtC,OAAO,CAAC,OAAO;YAQD,GAAG;IAqCX,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAQlC,IAAI,CACR,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC;;;;;;;WAOG;QACH,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GACA,OAAO,CAAC,IAAI,CAAC;IAiBhB;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5C;;;;;;;;OAQG;IACG,WAAW,CACf,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,wDAAwD;QACxD,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,iCAAiC;QACjC,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,oEAAoE;QACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;KACjC,GACA,OAAO,CAAC,IAAI,CAAC;IA6BT,MAAM,CACX,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAChE,cAAc,CAAC,IAAI,CAAC;YA6DT,wBAAwB;YAyBxB,QAAQ;CAmBvB;AA2DD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IACL,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACA,OAAO,CAAC,MAAM,CAAC,CA6DjB"}
|
package/dist/a2a/client.js
CHANGED
|
@@ -17,11 +17,16 @@ export class A2ATaskTimeoutError extends Error {
|
|
|
17
17
|
/**
|
|
18
18
|
* Sign a JWT for A2A cross-app identity verification.
|
|
19
19
|
*
|
|
20
|
-
* Uses
|
|
21
|
-
*
|
|
20
|
+
* Uses an org-level secret by default for direct org-secret workflows. Callers
|
|
21
|
+
* that are doing ordinary hosted cross-app delegation can set
|
|
22
|
+
* `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on
|
|
23
|
+
* every app database having an identical org row. The token contains the
|
|
24
|
+
* caller's email as `sub`, so the receiving app can verify who's calling.
|
|
22
25
|
*/
|
|
23
26
|
export async function signA2AToken(email, orgDomain, orgSecret, options) {
|
|
24
|
-
const secret =
|
|
27
|
+
const secret = options?.preferGlobalSecret
|
|
28
|
+
? process.env.A2A_SECRET || orgSecret
|
|
29
|
+
: orgSecret || process.env.A2A_SECRET;
|
|
25
30
|
if (!secret) {
|
|
26
31
|
throw new Error("No A2A secret available. Set an org-level A2A secret in Team settings, " +
|
|
27
32
|
"or set A2A_SECRET as an environment variable on all apps that need to verify identity.");
|
|
@@ -345,7 +350,7 @@ export async function callAgent(url, text, opts) {
|
|
|
345
350
|
opts?.userEmail &&
|
|
346
351
|
(opts?.orgSecret || process.env.A2A_SECRET)) {
|
|
347
352
|
try {
|
|
348
|
-
apiKey = await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret);
|
|
353
|
+
apiKey = await signA2AToken(opts.userEmail, opts.orgDomain, opts.orgSecret, { preferGlobalSecret: true });
|
|
349
354
|
}
|
|
350
355
|
catch {
|
|
351
356
|
// Fall back to unsigned call
|
package/dist/a2a/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport type {\n AgentCard,\n JsonRpcRequest,\n JsonRpcResponse,\n Message,\n Task,\n} from \"./types.js\";\n\nexport class A2ATaskTimeoutError extends Error {\n readonly taskId: string;\n readonly lastTask: Task;\n readonly lastState: string;\n readonly timeoutMs: number;\n\n constructor(taskId: string, lastTask: Task, timeoutMs: number) {\n const lastState = lastTask.status.state;\n super(\n `A2A task ${taskId} did not complete within ${timeoutMs}ms (last state: ${lastState})`,\n );\n this.name = \"A2ATaskTimeoutError\";\n this.taskId = taskId;\n this.lastTask = lastTask;\n this.lastState = lastState;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Sign a JWT for A2A cross-app identity verification.\n *\n * Uses A2A_SECRET as an HMAC key. The token contains the caller's email\n * as `sub`, so the receiving app can verify who's calling.\n */\nexport async function signA2AToken(\n email: string,\n orgDomain?: string,\n orgSecret?: string,\n options?: { expiresIn?: string | number },\n): Promise<string> {\n const secret = orgSecret || process.env.A2A_SECRET;\n if (!secret) {\n throw new Error(\n \"No A2A secret available. Set an org-level A2A secret in Team settings, \" +\n \"or set A2A_SECRET as an environment variable on all apps that need to verify identity.\",\n );\n }\n\n const appUrl =\n process.env.APP_URL ||\n process.env.BETTER_AUTH_URL ||\n \"http://localhost:3000\";\n\n return new jose.SignJWT({\n sub: email,\n ...(orgDomain ? { org_domain: orgDomain } : {}),\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuer(appUrl)\n .setIssuedAt()\n .setExpirationTime(options?.expiresIn ?? \"15m\")\n .sign(new TextEncoder().encode(secret));\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private apiKey?: string;\n private endpointCandidates: string[] = [];\n private endpointResolved = false;\n private requestTimeoutMs?: number;\n\n constructor(\n baseUrl: string,\n apiKey?: string,\n options?: { requestTimeoutMs?: number },\n ) {\n const normalized = baseUrl.replace(/\\/$/, \"\");\n const explicitEndpoint = splitExplicitA2AEndpoint(normalized);\n this.baseUrl = explicitEndpoint?.baseUrl ?? normalized;\n if (explicitEndpoint) {\n this.endpointCandidates = [explicitEndpoint.endpointUrl];\n this.endpointResolved = true;\n }\n this.apiKey = apiKey;\n this.requestTimeoutMs = options?.requestTimeoutMs;\n }\n\n /**\n * Detect which A2A path the target agent uses.\n * Agent-native apps use /_agent-native/a2a, external agents may use /a2a.\n */\n async resolveEndpoint(): Promise<void> {\n await this.ensureEndpointCandidates();\n if (this.endpointCandidates.length <= 1) return;\n\n for (const endpoint of this.endpointCandidates) {\n try {\n const res = await fetch(endpoint, { method: \"OPTIONS\" });\n if (res.status !== 404 && res.status !== 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n if (res.status === 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n } catch {\n // Try the next candidate.\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) {\n h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async rpc(\n method: string,\n params: Record<string, unknown>,\n ): Promise<JsonRpcResponse> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n };\n\n await this.ensureEndpointCandidates();\n let lastError: Error | null = null;\n\n for (const url of this.endpointCandidates) {\n console.log(`[A2A Client] POST ${url} method=${method}`);\n const startTime = Date.now();\n const res = await this.postJson(url, body);\n console.log(\n `[A2A Client] Response: ${res.status} in ${Date.now() - startTime}ms`,\n );\n\n if (res.ok) {\n this.endpointCandidates = [url];\n return res.json() as Promise<JsonRpcResponse>;\n }\n\n const text = await res.text();\n lastError = new Error(`A2A request failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) {\n throw lastError;\n }\n }\n\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n async getAgentCard(): Promise<AgentCard> {\n const res = await fetch(`${this.baseUrl}/.well-known/agent-card.json`);\n if (!res.ok) {\n throw new Error(`Failed to fetch agent card (${res.status})`);\n }\n return res.json() as Promise<AgentCard>;\n }\n\n async send(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /**\n * If true, ask the server to return the task immediately in `working`\n * state and process the handler in the background. The caller should\n * then poll `getTask(taskId)` until `completed` / `failed` / `canceled`.\n *\n * Use this when you expect the handler may exceed a synchronous\n * serverless request budget.\n */\n async?: boolean;\n },\n ): Promise<Task> {\n const response = await this.rpc(\"message/send\", {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n ...(opts?.async ? { async: true } : {}),\n });\n\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n\n return response.result as Task;\n }\n\n /**\n * Poll for a task by id. Used in async mode after `send({ async: true })`.\n */\n async getTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/get\", { id: taskId });\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n return response.result as Task;\n }\n\n /**\n * Send a message in async mode and poll until the task reaches a terminal\n * state. This is the recommended path on serverless hosts with short\n * function timeouts (Netlify, Vercel) where a synchronous LLM-driven A2A\n * call can exceed the gateway limit.\n *\n * Each individual fetch returns quickly; long-running work happens on the\n * receiving side and is checked via `tasks/get`.\n */\n async sendAndWait(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /** Total time to wait for completion. Default 5 min. */\n timeoutMs?: number;\n /** Poll interval. Default 2s. */\n pollIntervalMs?: number;\n /** Called with each polled task — useful for surfacing progress. */\n onUpdate?: (task: Task) => void;\n },\n ): Promise<Task> {\n const submitted = await this.send(message, {\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n async: true,\n });\n\n const terminalStates = new Set([\"completed\", \"failed\", \"canceled\"]);\n if (terminalStates.has(submitted.status.state)) return submitted;\n\n const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n const pollMs = opts?.pollIntervalMs ?? 2_000;\n const deadline = Date.now() + timeoutMs;\n\n let current = submitted;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, pollMs));\n try {\n current = await this.getTask(submitted.id);\n opts?.onUpdate?.(current);\n } catch (err) {\n // Transient fetch failure — keep polling until the deadline.\n continue;\n }\n if (terminalStates.has(current.status.state)) return current;\n }\n throw new A2ATaskTimeoutError(submitted.id, current, timeoutMs);\n }\n\n async *stream(\n message: Message,\n opts?: { contextId?: string; metadata?: Record<string, unknown> },\n ): AsyncGenerator<Task> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"message/stream\",\n params: {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n },\n };\n\n await this.ensureEndpointCandidates();\n let res: Response | null = null;\n let lastError: Error | null = null;\n for (const candidate of this.endpointCandidates) {\n res = await this.postJson(candidate, body);\n if (res.ok) {\n this.endpointCandidates = [candidate];\n break;\n }\n const text = await res.text();\n lastError = new Error(`A2A stream failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) throw lastError;\n }\n if (!res?.ok) {\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const json = line.slice(6).trim();\n if (!json) continue;\n\n const response: JsonRpcResponse = JSON.parse(json);\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n if (response.result) {\n yield response.result as Task;\n }\n }\n }\n }\n\n private async ensureEndpointCandidates(): Promise<void> {\n if (this.endpointResolved) return;\n this.endpointResolved = true;\n\n const candidates: string[] = [];\n addDefaultEndpointCandidates(candidates, this.baseUrl);\n\n try {\n const card = await this.getAgentCard();\n const cardUrl = normalizeUrl(card.url, this.baseUrl);\n if (cardUrl) {\n const explicitEndpoint = splitExplicitA2AEndpoint(cardUrl);\n if (explicitEndpoint) {\n candidates.unshift(explicitEndpoint.endpointUrl);\n } else {\n addDefaultEndpointCandidates(candidates, cardUrl);\n }\n }\n } catch {\n // Agent cards are discovery hints. Fall back to conventional endpoints.\n }\n\n this.endpointCandidates = unique(candidates);\n }\n\n private async postJson(url: string, body: JsonRpcRequest): Promise<Response> {\n const controller = this.requestTimeoutMs\n ? new AbortController()\n : undefined;\n const timer =\n controller && this.requestTimeoutMs\n ? setTimeout(() => controller.abort(), this.requestTimeoutMs)\n : undefined;\n try {\n return await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(body),\n signal: controller?.signal,\n });\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n}\n\nfunction splitExplicitA2AEndpoint(\n url: string,\n): { baseUrl: string; endpointUrl: string } | null {\n try {\n const parsed = new URL(url);\n const pathname = parsed.pathname.replace(/\\/$/, \"\");\n if (pathname.endsWith(\"/_agent-native/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/_agent-native/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n if (pathname.endsWith(\"/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n } catch {\n // Relative or invalid URLs are handled by the caller's normal fetch path.\n }\n return null;\n}\n\nfunction addDefaultEndpointCandidates(candidates: string[], baseUrl: string) {\n const base = baseUrl.replace(/\\/$/, \"\");\n candidates.push(`${base}/_agent-native/a2a`, `${base}/a2a`);\n}\n\nfunction normalizeUrl(\n value: string | undefined,\n baseUrl: string,\n): string | null {\n if (!value) return null;\n try {\n return new URL(value, `${baseUrl.replace(/\\/$/, \"\")}/`)\n .toString()\n .replace(/\\/$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction shouldTryNextEndpoint(status: number): boolean {\n return status === 404 || status === 405;\n}\n\nfunction unique(values: string[]): string[] {\n return Array.from(new Set(values));\n}\n\n/**\n * One-shot convenience function: send a text message and get a text response.\n *\n * When A2A_SECRET is set and userEmail is provided, outbound calls are signed\n * with a JWT so the receiving app can cryptographically verify the caller's\n * identity (instead of blindly trusting metadata).\n */\nexport async function callAgent(\n url: string,\n text: string,\n opts?: {\n apiKey?: string;\n contextId?: string;\n userEmail?: string;\n orgDomain?: string;\n orgSecret?: string;\n /**\n * Use async/poll instead of a single blocking POST. Recommended for\n * cross-app calls that may exceed a synchronous serverless request budget.\n * Defaults to true so callers get safe behavior out of the box.\n */\n async?: boolean;\n /** Total time to wait for the polled task (default 5 min). */\n timeoutMs?: number;\n },\n): Promise<string> {\n let apiKey = opts?.apiKey;\n\n // Auto-sign with JWT when an A2A secret (org or global) is available and we have a user email\n if (\n !apiKey &&\n opts?.userEmail &&\n (opts?.orgSecret || process.env.A2A_SECRET)\n ) {\n try {\n apiKey = await signA2AToken(\n opts.userEmail,\n opts.orgDomain,\n opts.orgSecret,\n );\n } catch {\n // Fall back to unsigned call\n }\n }\n\n const client = new A2AClient(url, apiKey);\n const metadata: Record<string, unknown> = {};\n if (opts?.userEmail) metadata.userEmail = opts.userEmail;\n if (opts?.orgDomain) metadata.orgDomain = opts.orgDomain;\n\n // Default to async + poll. The receiving A2A server's `_process-task` route\n // runs the handler in a fresh function execution (cross-platform queue\n // pattern), so async mode now works on every host instead of relying on\n // detached promises that get killed on Netlify/Vercel. Callers that\n // explicitly want a single-shot blocking POST can pass `async: false`.\n const useAsync = opts?.async ?? true;\n const message: Message = {\n role: \"user\",\n parts: [{ type: \"text\", text }],\n };\n\n let task: Task;\n if (useAsync) {\n task = await client.sendAndWait(message, {\n contextId: opts?.contextId,\n metadata,\n timeoutMs: opts?.timeoutMs,\n });\n } else {\n task = await client.send(message, {\n contextId: opts?.contextId,\n metadata,\n });\n }\n\n // Extract text from the response\n const responseMessage = task.status.message;\n if (responseMessage) {\n const textParts = responseMessage.parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text);\n return textParts.join(\"\\n\");\n }\n\n return \"\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport type {\n AgentCard,\n JsonRpcRequest,\n JsonRpcResponse,\n Message,\n Task,\n} from \"./types.js\";\n\nexport class A2ATaskTimeoutError extends Error {\n readonly taskId: string;\n readonly lastTask: Task;\n readonly lastState: string;\n readonly timeoutMs: number;\n\n constructor(taskId: string, lastTask: Task, timeoutMs: number) {\n const lastState = lastTask.status.state;\n super(\n `A2A task ${taskId} did not complete within ${timeoutMs}ms (last state: ${lastState})`,\n );\n this.name = \"A2ATaskTimeoutError\";\n this.taskId = taskId;\n this.lastTask = lastTask;\n this.lastState = lastState;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Sign a JWT for A2A cross-app identity verification.\n *\n * Uses an org-level secret by default for direct org-secret workflows. Callers\n * that are doing ordinary hosted cross-app delegation can set\n * `preferGlobalSecret` so deployments with a shared A2A_SECRET don't depend on\n * every app database having an identical org row. The token contains the\n * caller's email as `sub`, so the receiving app can verify who's calling.\n */\nexport async function signA2AToken(\n email: string,\n orgDomain?: string,\n orgSecret?: string,\n options?: { expiresIn?: string | number; preferGlobalSecret?: boolean },\n): Promise<string> {\n const secret = options?.preferGlobalSecret\n ? process.env.A2A_SECRET || orgSecret\n : orgSecret || process.env.A2A_SECRET;\n if (!secret) {\n throw new Error(\n \"No A2A secret available. Set an org-level A2A secret in Team settings, \" +\n \"or set A2A_SECRET as an environment variable on all apps that need to verify identity.\",\n );\n }\n\n const appUrl =\n process.env.APP_URL ||\n process.env.BETTER_AUTH_URL ||\n \"http://localhost:3000\";\n\n return new jose.SignJWT({\n sub: email,\n ...(orgDomain ? { org_domain: orgDomain } : {}),\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuer(appUrl)\n .setIssuedAt()\n .setExpirationTime(options?.expiresIn ?? \"15m\")\n .sign(new TextEncoder().encode(secret));\n}\n\nexport class A2AClient {\n private baseUrl: string;\n private apiKey?: string;\n private endpointCandidates: string[] = [];\n private endpointResolved = false;\n private requestTimeoutMs?: number;\n\n constructor(\n baseUrl: string,\n apiKey?: string,\n options?: { requestTimeoutMs?: number },\n ) {\n const normalized = baseUrl.replace(/\\/$/, \"\");\n const explicitEndpoint = splitExplicitA2AEndpoint(normalized);\n this.baseUrl = explicitEndpoint?.baseUrl ?? normalized;\n if (explicitEndpoint) {\n this.endpointCandidates = [explicitEndpoint.endpointUrl];\n this.endpointResolved = true;\n }\n this.apiKey = apiKey;\n this.requestTimeoutMs = options?.requestTimeoutMs;\n }\n\n /**\n * Detect which A2A path the target agent uses.\n * Agent-native apps use /_agent-native/a2a, external agents may use /a2a.\n */\n async resolveEndpoint(): Promise<void> {\n await this.ensureEndpointCandidates();\n if (this.endpointCandidates.length <= 1) return;\n\n for (const endpoint of this.endpointCandidates) {\n try {\n const res = await fetch(endpoint, { method: \"OPTIONS\" });\n if (res.status !== 404 && res.status !== 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n if (res.status === 405) {\n this.endpointCandidates = [endpoint];\n return;\n }\n } catch {\n // Try the next candidate.\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.apiKey) {\n h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async rpc(\n method: string,\n params: Record<string, unknown>,\n ): Promise<JsonRpcResponse> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n };\n\n await this.ensureEndpointCandidates();\n let lastError: Error | null = null;\n\n for (const url of this.endpointCandidates) {\n console.log(`[A2A Client] POST ${url} method=${method}`);\n const startTime = Date.now();\n const res = await this.postJson(url, body);\n console.log(\n `[A2A Client] Response: ${res.status} in ${Date.now() - startTime}ms`,\n );\n\n if (res.ok) {\n this.endpointCandidates = [url];\n return res.json() as Promise<JsonRpcResponse>;\n }\n\n const text = await res.text();\n lastError = new Error(`A2A request failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) {\n throw lastError;\n }\n }\n\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n async getAgentCard(): Promise<AgentCard> {\n const res = await fetch(`${this.baseUrl}/.well-known/agent-card.json`);\n if (!res.ok) {\n throw new Error(`Failed to fetch agent card (${res.status})`);\n }\n return res.json() as Promise<AgentCard>;\n }\n\n async send(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /**\n * If true, ask the server to return the task immediately in `working`\n * state and process the handler in the background. The caller should\n * then poll `getTask(taskId)` until `completed` / `failed` / `canceled`.\n *\n * Use this when you expect the handler may exceed a synchronous\n * serverless request budget.\n */\n async?: boolean;\n },\n ): Promise<Task> {\n const response = await this.rpc(\"message/send\", {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n ...(opts?.async ? { async: true } : {}),\n });\n\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n\n return response.result as Task;\n }\n\n /**\n * Poll for a task by id. Used in async mode after `send({ async: true })`.\n */\n async getTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/get\", { id: taskId });\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n return response.result as Task;\n }\n\n /**\n * Send a message in async mode and poll until the task reaches a terminal\n * state. This is the recommended path on serverless hosts with short\n * function timeouts (Netlify, Vercel) where a synchronous LLM-driven A2A\n * call can exceed the gateway limit.\n *\n * Each individual fetch returns quickly; long-running work happens on the\n * receiving side and is checked via `tasks/get`.\n */\n async sendAndWait(\n message: Message,\n opts?: {\n contextId?: string;\n metadata?: Record<string, unknown>;\n /** Total time to wait for completion. Default 5 min. */\n timeoutMs?: number;\n /** Poll interval. Default 2s. */\n pollIntervalMs?: number;\n /** Called with each polled task — useful for surfacing progress. */\n onUpdate?: (task: Task) => void;\n },\n ): Promise<Task> {\n const submitted = await this.send(message, {\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n async: true,\n });\n\n const terminalStates = new Set([\"completed\", \"failed\", \"canceled\"]);\n if (terminalStates.has(submitted.status.state)) return submitted;\n\n const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n const pollMs = opts?.pollIntervalMs ?? 2_000;\n const deadline = Date.now() + timeoutMs;\n\n let current = submitted;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, pollMs));\n try {\n current = await this.getTask(submitted.id);\n opts?.onUpdate?.(current);\n } catch (err) {\n // Transient fetch failure — keep polling until the deadline.\n continue;\n }\n if (terminalStates.has(current.status.state)) return current;\n }\n throw new A2ATaskTimeoutError(submitted.id, current, timeoutMs);\n }\n\n async *stream(\n message: Message,\n opts?: { contextId?: string; metadata?: Record<string, unknown> },\n ): AsyncGenerator<Task> {\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"message/stream\",\n params: {\n message,\n contextId: opts?.contextId,\n metadata: opts?.metadata,\n },\n };\n\n await this.ensureEndpointCandidates();\n let res: Response | null = null;\n let lastError: Error | null = null;\n for (const candidate of this.endpointCandidates) {\n res = await this.postJson(candidate, body);\n if (res.ok) {\n this.endpointCandidates = [candidate];\n break;\n }\n const text = await res.text();\n lastError = new Error(`A2A stream failed (${res.status}): ${text}`);\n if (!shouldTryNextEndpoint(res.status)) throw lastError;\n }\n if (!res?.ok) {\n throw lastError ?? new Error(\"No A2A endpoint candidates available\");\n }\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const json = line.slice(6).trim();\n if (!json) continue;\n\n const response: JsonRpcResponse = JSON.parse(json);\n if (response.error) {\n throw new Error(\n `A2A error (${response.error.code}): ${response.error.message}`,\n );\n }\n if (response.result) {\n yield response.result as Task;\n }\n }\n }\n }\n\n private async ensureEndpointCandidates(): Promise<void> {\n if (this.endpointResolved) return;\n this.endpointResolved = true;\n\n const candidates: string[] = [];\n addDefaultEndpointCandidates(candidates, this.baseUrl);\n\n try {\n const card = await this.getAgentCard();\n const cardUrl = normalizeUrl(card.url, this.baseUrl);\n if (cardUrl) {\n const explicitEndpoint = splitExplicitA2AEndpoint(cardUrl);\n if (explicitEndpoint) {\n candidates.unshift(explicitEndpoint.endpointUrl);\n } else {\n addDefaultEndpointCandidates(candidates, cardUrl);\n }\n }\n } catch {\n // Agent cards are discovery hints. Fall back to conventional endpoints.\n }\n\n this.endpointCandidates = unique(candidates);\n }\n\n private async postJson(url: string, body: JsonRpcRequest): Promise<Response> {\n const controller = this.requestTimeoutMs\n ? new AbortController()\n : undefined;\n const timer =\n controller && this.requestTimeoutMs\n ? setTimeout(() => controller.abort(), this.requestTimeoutMs)\n : undefined;\n try {\n return await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(body),\n signal: controller?.signal,\n });\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n}\n\nfunction splitExplicitA2AEndpoint(\n url: string,\n): { baseUrl: string; endpointUrl: string } | null {\n try {\n const parsed = new URL(url);\n const pathname = parsed.pathname.replace(/\\/$/, \"\");\n if (pathname.endsWith(\"/_agent-native/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/_agent-native/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n if (pathname.endsWith(\"/a2a\")) {\n parsed.pathname = pathname.slice(0, -\"/a2a\".length) || \"/\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return {\n baseUrl: parsed.toString().replace(/\\/$/, \"\"),\n endpointUrl: url,\n };\n }\n } catch {\n // Relative or invalid URLs are handled by the caller's normal fetch path.\n }\n return null;\n}\n\nfunction addDefaultEndpointCandidates(candidates: string[], baseUrl: string) {\n const base = baseUrl.replace(/\\/$/, \"\");\n candidates.push(`${base}/_agent-native/a2a`, `${base}/a2a`);\n}\n\nfunction normalizeUrl(\n value: string | undefined,\n baseUrl: string,\n): string | null {\n if (!value) return null;\n try {\n return new URL(value, `${baseUrl.replace(/\\/$/, \"\")}/`)\n .toString()\n .replace(/\\/$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction shouldTryNextEndpoint(status: number): boolean {\n return status === 404 || status === 405;\n}\n\nfunction unique(values: string[]): string[] {\n return Array.from(new Set(values));\n}\n\n/**\n * One-shot convenience function: send a text message and get a text response.\n *\n * When A2A_SECRET is set and userEmail is provided, outbound calls are signed\n * with a JWT so the receiving app can cryptographically verify the caller's\n * identity (instead of blindly trusting metadata).\n */\nexport async function callAgent(\n url: string,\n text: string,\n opts?: {\n apiKey?: string;\n contextId?: string;\n userEmail?: string;\n orgDomain?: string;\n orgSecret?: string;\n /**\n * Use async/poll instead of a single blocking POST. Recommended for\n * cross-app calls that may exceed a synchronous serverless request budget.\n * Defaults to true so callers get safe behavior out of the box.\n */\n async?: boolean;\n /** Total time to wait for the polled task (default 5 min). */\n timeoutMs?: number;\n },\n): Promise<string> {\n let apiKey = opts?.apiKey;\n\n // Auto-sign with JWT when an A2A secret (org or global) is available and we have a user email\n if (\n !apiKey &&\n opts?.userEmail &&\n (opts?.orgSecret || process.env.A2A_SECRET)\n ) {\n try {\n apiKey = await signA2AToken(\n opts.userEmail,\n opts.orgDomain,\n opts.orgSecret,\n { preferGlobalSecret: true },\n );\n } catch {\n // Fall back to unsigned call\n }\n }\n\n const client = new A2AClient(url, apiKey);\n const metadata: Record<string, unknown> = {};\n if (opts?.userEmail) metadata.userEmail = opts.userEmail;\n if (opts?.orgDomain) metadata.orgDomain = opts.orgDomain;\n\n // Default to async + poll. The receiving A2A server's `_process-task` route\n // runs the handler in a fresh function execution (cross-platform queue\n // pattern), so async mode now works on every host instead of relying on\n // detached promises that get killed on Netlify/Vercel. Callers that\n // explicitly want a single-shot blocking POST can pass `async: false`.\n const useAsync = opts?.async ?? true;\n const message: Message = {\n role: \"user\",\n parts: [{ type: \"text\", text }],\n };\n\n let task: Task;\n if (useAsync) {\n task = await client.sendAndWait(message, {\n contextId: opts?.contextId,\n metadata,\n timeoutMs: opts?.timeoutMs,\n });\n } else {\n task = await client.send(message, {\n contextId: opts?.contextId,\n metadata,\n });\n }\n\n // Extract text from the response\n const responseMessage = task.status.message;\n if (responseMessage) {\n const textParts = responseMessage.parts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text);\n return textParts.join(\"\\n\");\n }\n\n return \"\";\n}\n"]}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { AgentChatEvent } from "../agent/types.js";
|
|
2
|
-
export
|
|
2
|
+
export interface CollectFinalResponseTextOptions {
|
|
3
|
+
fallbackToPreToolText?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function collectFinalResponseTextFromAgentEvents(events: readonly AgentChatEvent[], options?: CollectFinalResponseTextOptions): string;
|
|
3
6
|
//# sourceMappingURL=response-text.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-text.d.ts","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,SAAS,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"response-text.d.ts","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,WAAW,+BAA+B;IAC9C,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,OAAO,GAAE,+BAAoC,GAC5C,MAAM,CAsBR"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export function collectFinalResponseTextFromAgentEvents(events) {
|
|
1
|
+
export function collectFinalResponseTextFromAgentEvents(events, options = {}) {
|
|
2
|
+
const fallbackToPreToolText = options.fallbackToPreToolText ?? true;
|
|
2
3
|
let lastToolIdx = -1;
|
|
3
4
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
4
5
|
const type = events[i].type;
|
|
@@ -12,7 +13,7 @@ export function collectFinalResponseTextFromAgentEvents(events) {
|
|
|
12
13
|
// Some agents let the final tool output speak for itself. Fall back to all
|
|
13
14
|
// text so callers do not get an empty reply just because no post-tool text
|
|
14
15
|
// was emitted.
|
|
15
|
-
if (!responseText.trim() && lastToolIdx >= 0) {
|
|
16
|
+
if (!responseText.trim() && lastToolIdx >= 0 && fallbackToPreToolText) {
|
|
16
17
|
responseText = collectTextEvents(events, 0);
|
|
17
18
|
}
|
|
18
19
|
return responseText;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-text.js","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"response-text.js","sourceRoot":"","sources":["../../src/a2a/response-text.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,uCAAuC,CACrD,MAAiC,EACjC,UAA2C,EAAE;IAE7C,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,IAAI,IAAI,CAAC;IACpE,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5B,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAClD,WAAW,GAAG,CAAC,CAAC;YAChB,MAAM;QACR,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,YAAY,GAAG,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEvD,2EAA2E;IAC3E,2EAA2E;IAC3E,eAAe;IACf,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,WAAW,IAAI,CAAC,IAAI,qBAAqB,EAAE,CAAC;QACtE,YAAY,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAiC,EACjC,QAAgB;IAEhB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { AgentChatEvent } from \"../agent/types.js\";\n\nexport interface CollectFinalResponseTextOptions {\n fallbackToPreToolText?: boolean;\n}\n\nexport function collectFinalResponseTextFromAgentEvents(\n events: readonly AgentChatEvent[],\n options: CollectFinalResponseTextOptions = {},\n): string {\n const fallbackToPreToolText = options.fallbackToPreToolText ?? true;\n let lastToolIdx = -1;\n for (let i = events.length - 1; i >= 0; i--) {\n const type = events[i].type;\n if (type === \"tool_start\" || type === \"tool_done\") {\n lastToolIdx = i;\n break;\n }\n }\n\n const startIdx = lastToolIdx >= 0 ? lastToolIdx + 1 : 0;\n let responseText = collectTextEvents(events, startIdx);\n\n // Some agents let the final tool output speak for itself. Fall back to all\n // text so callers do not get an empty reply just because no post-tool text\n // was emitted.\n if (!responseText.trim() && lastToolIdx >= 0 && fallbackToPreToolText) {\n responseText = collectTextEvents(events, 0);\n }\n\n return responseText;\n}\n\nfunction collectTextEvents(\n events: readonly AgentChatEvent[],\n startIdx: number,\n): string {\n let text = \"\";\n for (let i = startIdx; i < events.length; i++) {\n const event = events[i];\n if (event.type === \"text\") text += event.text;\n }\n return text;\n}\n"]}
|
package/dist/a2a/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0J5C;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,GAAG,EACb,MAAM,EAAE,SAAS,EACjB,WAAW,SAAmB,GAC7B,IAAI,CAkNN"}
|
package/dist/a2a/server.js
CHANGED
|
@@ -20,6 +20,12 @@ function warnA2AUnauthOnce() {
|
|
|
20
20
|
console.warn("[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. " +
|
|
21
21
|
"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.");
|
|
22
22
|
}
|
|
23
|
+
function addSecretCandidate(candidates, secret) {
|
|
24
|
+
const trimmed = secret?.trim();
|
|
25
|
+
if (!trimmed || candidates.includes(trimmed))
|
|
26
|
+
return;
|
|
27
|
+
candidates.push(trimmed);
|
|
28
|
+
}
|
|
23
29
|
/**
|
|
24
30
|
* Resolve the audience (`aud`) value to expect in an inbound JWT. We use the
|
|
25
31
|
* receiver's app URL — it's the natural identifier of "who this token was
|
|
@@ -62,25 +68,24 @@ async function verifyA2AToken(authHeader, event) {
|
|
|
62
68
|
catch {
|
|
63
69
|
// Malformed token — fall through to global secret attempt
|
|
64
70
|
}
|
|
65
|
-
// Step 2:
|
|
66
|
-
|
|
71
|
+
// Step 2: Build a small, ordered set of candidate secrets. Tokens minted by
|
|
72
|
+
// current callers prefer the shared A2A_SECRET; older callers may still use
|
|
73
|
+
// an org-level secret. Try both without logging or reflecting secret details.
|
|
74
|
+
const candidateSecrets = [];
|
|
75
|
+
addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);
|
|
67
76
|
if (orgDomainHint) {
|
|
68
77
|
try {
|
|
69
78
|
const { getA2ASecretByDomain } = await import("../org/context.js");
|
|
70
79
|
const orgSecret = await getA2ASecretByDomain(orgDomainHint);
|
|
71
|
-
|
|
72
|
-
secret = orgSecret;
|
|
80
|
+
addSecretCandidate(candidateSecrets, orgSecret);
|
|
73
81
|
}
|
|
74
82
|
catch {
|
|
75
83
|
// DB not ready or column doesn't exist yet — fall through
|
|
76
84
|
}
|
|
77
85
|
}
|
|
78
|
-
|
|
79
|
-
if (!secret)
|
|
80
|
-
secret = process.env.A2A_SECRET;
|
|
81
|
-
if (!secret)
|
|
86
|
+
if (candidateSecrets.length === 0)
|
|
82
87
|
return { email: null, orgDomain: null };
|
|
83
|
-
// Step
|
|
88
|
+
// Step 3: Verify JWT with the candidate secrets.
|
|
84
89
|
//
|
|
85
90
|
// - `audience`: passed only when the token carries an `aud` claim
|
|
86
91
|
// (backward-compat: tokens minted by older `signA2AToken` versions
|
|
@@ -107,15 +112,23 @@ async function verifyA2AToken(authHeader, event) {
|
|
|
107
112
|
unverifiedPayload.iss.length > 0) {
|
|
108
113
|
verifyOptions.issuer = unverifiedPayload.iss;
|
|
109
114
|
}
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
for (const secret of candidateSecrets) {
|
|
116
|
+
try {
|
|
117
|
+
const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(secret), verifyOptions);
|
|
118
|
+
return {
|
|
119
|
+
email: payload.sub ?? null,
|
|
120
|
+
orgDomain: payload.org_domain ?? null,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Try the next candidate without leaking which secret failed.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
115
127
|
}
|
|
116
128
|
catch {
|
|
117
|
-
|
|
129
|
+
// Keep malformed option construction indistinguishable from auth failure.
|
|
118
130
|
}
|
|
131
|
+
return { email: null, orgDomain: null };
|
|
119
132
|
}
|
|
120
133
|
/**
|
|
121
134
|
* Mount A2A protocol endpoints on an H3/Nitro app.
|
package/dist/a2a/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport type { A2AConfig } from \"./types.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Verify an inbound A2A JWT signed with the shared A2A_SECRET.\n * Returns the caller's email (from `sub` claim) if valid, null otherwise.\n */\ninterface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Falls back to undefined when no app URL is configured, in\n * which case the audience check is skipped (backward-compat with tokens\n * minted before the audience claim shipped).\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv);\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\nasync function verifyA2AToken(\n authHeader: string,\n event: any | undefined,\n): Promise<A2ATokenPayload> {\n const token = authHeader.replace(\"Bearer \", \"\");\n\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Look up the org's A2A secret by domain\n let secret: string | undefined;\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n if (orgSecret) secret = orgSecret;\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n\n // Step 3: Fall back to global A2A_SECRET\n if (!secret) secret = process.env.A2A_SECRET;\n if (!secret) return { email: null, orgDomain: null };\n\n // Step 4: Verify JWT with the resolved secret.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n const aud = expectedJwtAudience(event);\n if (aud) verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n return { email: null, orgDomain: null };\n }\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n // Filter out per-user/per-org MCP tools to avoid tenant disclosure.\n // Note: stdio MCP tools loaded from a file-based mcp.config.json are\n // process-wide and don't carry a per-user/per-org prefix, so they\n // remain visible. That's intentional — they're an operator-controlled\n // capability list.\n const filteredSkills = (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id !== \"string\") return true;\n return !id.startsWith(\"mcp__user_\") && !id.startsWith(\"mcp__org_\");\n });\n\n return generateAgentCard({ ...config, skills: filteredSkills }, baseUrl);\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (process.env.A2A_SECRET) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = !!process.env.A2A_SECRET;\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (authHeader?.startsWith(\"Bearer \")) {\n const tokenPayload = await verifyA2AToken(authHeader, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n const token = authHeader.slice(7);\n if (token !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // If a global secret exists and JWT verification failed, reject after\n // giving the legacy exact-match apiKeyEnv path a chance to succeed.\n if (bearerTokenRejectedByJwt && process.env.A2A_SECRET) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as jose from \"jose\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport type { A2AConfig } from \"./types.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Verify an inbound A2A JWT signed with the shared A2A_SECRET.\n * Returns the caller's email (from `sub` claim) if valid, null otherwise.\n */\ninterface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\nfunction addSecretCandidate(\n candidates: string[],\n secret: string | undefined,\n): void {\n const trimmed = secret?.trim();\n if (!trimmed || candidates.includes(trimmed)) return;\n candidates.push(trimmed);\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Falls back to undefined when no app URL is configured, in\n * which case the audience check is skipped (backward-compat with tokens\n * minted before the audience claim shipped).\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv);\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\nasync function verifyA2AToken(\n authHeader: string,\n event: any | undefined,\n): Promise<A2ATokenPayload> {\n const token = authHeader.replace(\"Bearer \", \"\");\n\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Build a small, ordered set of candidate secrets. Tokens minted by\n // current callers prefer the shared A2A_SECRET; older callers may still use\n // an org-level secret. Try both without logging or reflecting secret details.\n const candidateSecrets: string[] = [];\n addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n addSecretCandidate(candidateSecrets, orgSecret);\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n if (candidateSecrets.length === 0) return { email: null, orgDomain: null };\n\n // Step 3: Verify JWT with the candidate secrets.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n const aud = expectedJwtAudience(event);\n if (aud) verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n for (const secret of candidateSecrets) {\n try {\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n // Try the next candidate without leaking which secret failed.\n }\n }\n } catch {\n // Keep malformed option construction indistinguishable from auth failure.\n }\n return { email: null, orgDomain: null };\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n // Filter out per-user/per-org MCP tools to avoid tenant disclosure.\n // Note: stdio MCP tools loaded from a file-based mcp.config.json are\n // process-wide and don't carry a per-user/per-org prefix, so they\n // remain visible. That's intentional — they're an operator-controlled\n // capability list.\n const filteredSkills = (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id !== \"string\") return true;\n return !id.startsWith(\"mcp__user_\") && !id.startsWith(\"mcp__org_\");\n });\n\n return generateAgentCard({ ...config, skills: filteredSkills }, baseUrl);\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (process.env.A2A_SECRET) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok)) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = !!process.env.A2A_SECRET;\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (authHeader?.startsWith(\"Bearer \")) {\n const tokenPayload = await verifyA2AToken(authHeader, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n const token = authHeader.slice(7);\n if (token !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // If a global secret exists and JWT verification failed, reject after\n // giving the legacy exact-match apiKeyEnv path a chance to succeed.\n if (bearerTokenRejectedByJwt && process.env.A2A_SECRET) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n"]}
|
|
@@ -226,9 +226,25 @@ async function redispatchContinuation(continuationId) {
|
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
async function signContinuationToken(continuation) {
|
|
229
|
-
if (continuation.a2aAuthToken
|
|
230
|
-
return
|
|
229
|
+
if (continuation.a2aAuthToken === "") {
|
|
230
|
+
return undefined;
|
|
231
231
|
}
|
|
232
|
+
const storedToken = continuation.a2aAuthToken;
|
|
233
|
+
if (storedToken && !isLikelyJwt(storedToken))
|
|
234
|
+
return storedToken;
|
|
235
|
+
const freshToken = await signFreshContinuationToken(continuation);
|
|
236
|
+
if (freshToken)
|
|
237
|
+
return freshToken;
|
|
238
|
+
if (!storedToken)
|
|
239
|
+
return undefined;
|
|
240
|
+
// Older continuations may have persisted the initial short-lived JWT. Avoid
|
|
241
|
+
// replaying it forever after expiry; opaque legacy bearer keys can still be
|
|
242
|
+
// reused because we cannot re-mint those.
|
|
243
|
+
if (isLikelyJwt(storedToken))
|
|
244
|
+
return undefined;
|
|
245
|
+
return storedToken;
|
|
246
|
+
}
|
|
247
|
+
async function signFreshContinuationToken(continuation) {
|
|
232
248
|
let orgDomain;
|
|
233
249
|
let orgSecret;
|
|
234
250
|
if (continuation.orgId) {
|
|
@@ -245,12 +261,16 @@ async function signContinuationToken(continuation) {
|
|
|
245
261
|
try {
|
|
246
262
|
return await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret, {
|
|
247
263
|
expiresIn: "30m",
|
|
264
|
+
preferGlobalSecret: true,
|
|
248
265
|
});
|
|
249
266
|
}
|
|
250
267
|
catch {
|
|
251
268
|
return undefined;
|
|
252
269
|
}
|
|
253
270
|
}
|
|
271
|
+
function isLikelyJwt(token) {
|
|
272
|
+
return token.split(".").length === 3;
|
|
273
|
+
}
|
|
254
274
|
function extractTaskText(task) {
|
|
255
275
|
const parts = task.status.message?.parts ?? [];
|
|
256
276
|
return parts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a2a-continuation-processor.js","sourceRoot":"","sources":["../../src/integrations/a2a-continuation-processor.ts"],"names":[],"mappings":"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","sourcesContent":["import { A2AClient, signA2AToken } from \"../a2a/client.js\";\nimport type { Task } from \"../a2a/types.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { signInternalToken } from \"./internal-token.js\";\nimport type { PlatformAdapter } from \"./types.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport {\n claimA2AContinuation,\n claimDueA2AContinuations,\n completeA2AContinuation,\n failA2AContinuation,\n getA2AContinuation,\n rescheduleA2AContinuation,\n type A2AContinuation,\n} from \"./a2a-continuations-store.js\";\n\nconst PROCESSOR_PATH = `${FRAMEWORK_ROUTE_PREFIX}/integrations/process-a2a-continuation`;\nconst TERMINAL_STATES = new Set([\"completed\", \"failed\", \"canceled\"]);\nconst MAX_ATTEMPTS = 6;\nconst MAX_REMOTE_WORK_MS = 10 * 60_000;\nconst RESCHEDULE_DELAY_MS = 5_000;\nconst MAX_PRE_CLAIM_WAIT_MS = RESCHEDULE_DELAY_MS + 5_000;\nconst POLL_INTERVAL_MS = 2_000;\nconst PROCESSOR_WAIT_MS = 20_000;\nconst POLL_REQUEST_TIMEOUT_MS = 25_000;\nconst PLATFORM_SEND_TIMEOUT_MS = 12_000;\nconst DISPATCH_SETTLE_WAIT_MS = 2_000;\n\nexport async function dispatchA2AContinuation(\n continuationId: string,\n webhookBaseUrl?: string,\n): Promise<void> {\n const baseUrl =\n webhookBaseUrl ||\n process.env.WEBHOOK_BASE_URL ||\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n `http://localhost:${process.env.PORT || 3000}`;\n\n const url = `${withConfiguredAppBasePath(baseUrl)}${PROCESSOR_PATH}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(continuationId)}`;\n } catch (err) {\n if (process.env.NODE_ENV === \"production\") {\n console.error(\n `[integrations] Refusing to dispatch A2A continuation ${continuationId} — A2A_SECRET not configured.`,\n );\n return;\n }\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${continuationId}:`,\n err,\n );\n }\n }\n\n const dispatchPromise = fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ continuationId }),\n })\n .then(async (response) => {\n if (!response.ok) {\n await logFailedDispatchResponse(continuationId, response);\n }\n })\n .catch((err) => {\n console.error(\n `[integrations] Failed to dispatch A2A continuation ${continuationId}:`,\n err,\n );\n });\n\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) =>\n setTimeout(resolve, DISPATCH_SETTLE_WAIT_MS),\n ),\n ]);\n}\n\nasync function logFailedDispatchResponse(\n continuationId: string,\n response: Response,\n): Promise<void> {\n let body = \"\";\n try {\n body = await response.text();\n } catch {}\n\n const trimmedBody = body.trim();\n console.error(\n `[integrations] A2A continuation ${continuationId} processor dispatch returned HTTP ` +\n `${response.status}${response.statusText ? ` ${response.statusText}` : \"\"}` +\n `${trimmedBody ? `: ${trimmedBody.slice(0, 500)}` : \"\"}`,\n );\n}\n\nexport async function processA2AContinuationById(\n continuationId: string,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const shouldClaim = await waitForContinuationDue(continuationId);\n if (!shouldClaim) return;\n const continuation = await claimA2AContinuation(continuationId);\n if (!continuation) return;\n await processClaimedContinuation(continuation, options);\n}\n\nexport async function processDueA2AContinuations(options: {\n adapters: Map<string, PlatformAdapter>;\n limit?: number;\n}): Promise<void> {\n const continuations = await claimDueA2AContinuations(options.limit ?? 5);\n for (const continuation of continuations) {\n await processClaimedContinuation(continuation, options).catch((err) =>\n console.error(\n `[integrations] A2A continuation ${continuation.id} failed:`,\n err,\n ),\n );\n }\n}\n\nasync function processClaimedContinuation(\n continuation: A2AContinuation,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const adapter = options.adapters.get(continuation.platform);\n if (!adapter) {\n await failA2AContinuation(\n continuation.id,\n `Unknown platform: ${continuation.platform}`,\n );\n return;\n }\n\n const client = new A2AClient(\n continuation.agentUrl,\n await signContinuationToken(continuation),\n { requestTimeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n const deadline = Date.now() + PROCESSOR_WAIT_MS;\n let task: Task | null = null;\n\n try {\n while (Date.now() < deadline) {\n task = await client.getTask(continuation.a2aTaskId);\n if (TERMINAL_STATES.has(task.status.state)) break;\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n } catch (err) {\n if (isTransientA2APollError(err)) {\n if (isRemoteWorkExpired(continuation)) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n remotePollTimeoutReason(continuation),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n\n if (!task || !TERMINAL_STATES.has(task.status.state)) {\n if (isRemoteWorkExpired(continuation)) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n `Remote A2A task ${continuation.a2aTaskId} did not complete within ${Math.round(\n MAX_REMOTE_WORK_MS / 60_000,\n )} minutes`,\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n\n if (task.status.state !== \"completed\") {\n const reason =\n extractTaskText(task) ||\n `Remote A2A task ${continuation.a2aTaskId} ended with state ${task.status.state}`;\n await notifyAndFailA2AContinuation(continuation, adapter, reason);\n return;\n }\n\n const text = expandRelativeUrls(extractTaskText(task), continuation.agentUrl);\n if (!text.trim()) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n `Remote A2A task ${continuation.a2aTaskId} completed without text`,\n );\n return;\n }\n\n try {\n await withTimeout(\n adapter.sendResponse(\n adapter.formatAgentResponse(text),\n continuation.incoming,\n { placeholderRef: continuation.placeholderRef ?? undefined },\n ),\n PLATFORM_SEND_TIMEOUT_MS,\n `${continuation.platform} response delivery timed out`,\n );\n await completeA2AContinuation(continuation.id);\n } catch (err) {\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await failA2AContinuation(\n continuation.id,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n }\n}\n\nasync function waitForContinuationDue(\n continuationId: string,\n): Promise<boolean> {\n const continuation = await getA2AContinuation(continuationId);\n if (!continuation) return false;\n if (continuation.status === \"completed\" || continuation.status === \"failed\") {\n return false;\n }\n if (continuation.status !== \"pending\") return true;\n\n const waitMs = continuation.nextCheckAt - Date.now();\n if (waitMs <= 0) return true;\n\n await sleep(Math.min(waitMs, MAX_PRE_CLAIM_WAIT_MS));\n return true;\n}\n\nasync function notifyAndFailA2AContinuation(\n continuation: A2AContinuation,\n adapter: PlatformAdapter,\n reason: string,\n): Promise<void> {\n const message = formatContinuationFailureMessage(continuation, reason);\n try {\n await withTimeout(\n adapter.sendResponse(\n adapter.formatAgentResponse(message),\n continuation.incoming,\n { placeholderRef: continuation.placeholderRef ?? undefined },\n ),\n PLATFORM_SEND_TIMEOUT_MS,\n `${continuation.platform} failure notification timed out`,\n );\n } catch (err) {\n console.error(\n `[integrations] Failed to notify ${continuation.platform} about failed A2A continuation ${continuation.id}:`,\n err,\n );\n }\n\n await failA2AContinuation(continuation.id, reason);\n}\n\nfunction formatContinuationFailureMessage(\n continuation: A2AContinuation,\n reason: string,\n): string {\n if (isLlmCredentialError(reason)) {\n return formatLlmCredentialErrorMessage({\n agentName: continuation.agentName,\n });\n }\n\n return `The ${continuation.agentName} agent could not finish this request: ${sanitizeFailureReason(\n reason,\n )}`;\n}\n\nfunction isRemoteWorkExpired(continuation: A2AContinuation): boolean {\n return Date.now() - continuation.createdAt >= MAX_REMOTE_WORK_MS;\n}\n\nfunction isTransientA2APollError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n return /operation was aborted|aborted|timed out|timeout|Invalid or expired A2A token|A2A request failed \\(401\\)/i.test(\n err.message,\n );\n}\n\nfunction remotePollTimeoutReason(continuation: A2AContinuation): string {\n return `Timed out polling the ${continuation.agentName} A2A task ${continuation.a2aTaskId} after ${Math.round(\n MAX_REMOTE_WORK_MS / 60_000,\n )} minutes. The downstream agent did not return a final result.`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), timeoutMs);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nfunction sanitizeFailureReason(reason: string): string {\n const oneLine = reason.replace(/\\s+/g, \" \").trim();\n const withoutEnvNames = oneLine.replace(\n /\\b[A-Z][A-Z0-9_]*(?:API_KEY|PRIVATE_KEY|SECRET|TOKEN)\\b/g,\n \"a required credential\",\n );\n return (\n withoutEnvNames.slice(0, 500) ||\n \"the downstream agent returned an empty error\"\n );\n}\n\nasync function redispatchContinuation(continuationId: string): Promise<void> {\n await dispatchA2AContinuation(continuationId).catch((err) => {\n console.error(\n `[integrations] Failed to redispatch A2A continuation ${continuationId}:`,\n err,\n );\n });\n}\n\nasync function signContinuationToken(\n continuation: A2AContinuation,\n): Promise<string | undefined> {\n if (continuation.a2aAuthToken !== null) {\n return continuation.a2aAuthToken || undefined;\n }\n\n let orgDomain: string | undefined;\n let orgSecret: string | undefined;\n if (continuation.orgId) {\n try {\n const { getOrgDomain, getOrgA2ASecret } =\n await import(\"../org/context.js\");\n orgDomain = (await getOrgDomain(continuation.orgId)) ?? undefined;\n orgSecret = (await getOrgA2ASecret(continuation.orgId)) ?? undefined;\n } catch {}\n }\n\n if (!continuation.ownerEmail || !(orgSecret || process.env.A2A_SECRET)) {\n return undefined;\n }\n\n try {\n return await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret, {\n expiresIn: \"30m\",\n });\n } catch {\n return undefined;\n }\n}\n\nfunction extractTaskText(task: Task): string {\n const parts = task.status.message?.parts ?? [];\n return parts\n .filter((part): part is { type: \"text\"; text: string } => {\n return part.type === \"text\" && typeof part.text === \"string\";\n })\n .map((part) => part.text)\n .join(\"\\n\");\n}\n\nfunction expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n return text.replace(\n /(^|[\\s(\\[<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"a2a-continuation-processor.js","sourceRoot":"","sources":["../../src/integrations/a2a-continuation-processor.ts"],"names":[],"mappings":"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","sourcesContent":["import { A2AClient, signA2AToken } from \"../a2a/client.js\";\nimport type { Task } from \"../a2a/types.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { signInternalToken } from \"./internal-token.js\";\nimport type { PlatformAdapter } from \"./types.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport {\n claimA2AContinuation,\n claimDueA2AContinuations,\n completeA2AContinuation,\n failA2AContinuation,\n getA2AContinuation,\n rescheduleA2AContinuation,\n type A2AContinuation,\n} from \"./a2a-continuations-store.js\";\n\nconst PROCESSOR_PATH = `${FRAMEWORK_ROUTE_PREFIX}/integrations/process-a2a-continuation`;\nconst TERMINAL_STATES = new Set([\"completed\", \"failed\", \"canceled\"]);\nconst MAX_ATTEMPTS = 6;\nconst MAX_REMOTE_WORK_MS = 10 * 60_000;\nconst RESCHEDULE_DELAY_MS = 5_000;\nconst MAX_PRE_CLAIM_WAIT_MS = RESCHEDULE_DELAY_MS + 5_000;\nconst POLL_INTERVAL_MS = 2_000;\nconst PROCESSOR_WAIT_MS = 20_000;\nconst POLL_REQUEST_TIMEOUT_MS = 25_000;\nconst PLATFORM_SEND_TIMEOUT_MS = 12_000;\nconst DISPATCH_SETTLE_WAIT_MS = 2_000;\n\nexport async function dispatchA2AContinuation(\n continuationId: string,\n webhookBaseUrl?: string,\n): Promise<void> {\n const baseUrl =\n webhookBaseUrl ||\n process.env.WEBHOOK_BASE_URL ||\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n `http://localhost:${process.env.PORT || 3000}`;\n\n const url = `${withConfiguredAppBasePath(baseUrl)}${PROCESSOR_PATH}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(continuationId)}`;\n } catch (err) {\n if (process.env.NODE_ENV === \"production\") {\n console.error(\n `[integrations] Refusing to dispatch A2A continuation ${continuationId} — A2A_SECRET not configured.`,\n );\n return;\n }\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${continuationId}:`,\n err,\n );\n }\n }\n\n const dispatchPromise = fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ continuationId }),\n })\n .then(async (response) => {\n if (!response.ok) {\n await logFailedDispatchResponse(continuationId, response);\n }\n })\n .catch((err) => {\n console.error(\n `[integrations] Failed to dispatch A2A continuation ${continuationId}:`,\n err,\n );\n });\n\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) =>\n setTimeout(resolve, DISPATCH_SETTLE_WAIT_MS),\n ),\n ]);\n}\n\nasync function logFailedDispatchResponse(\n continuationId: string,\n response: Response,\n): Promise<void> {\n let body = \"\";\n try {\n body = await response.text();\n } catch {}\n\n const trimmedBody = body.trim();\n console.error(\n `[integrations] A2A continuation ${continuationId} processor dispatch returned HTTP ` +\n `${response.status}${response.statusText ? ` ${response.statusText}` : \"\"}` +\n `${trimmedBody ? `: ${trimmedBody.slice(0, 500)}` : \"\"}`,\n );\n}\n\nexport async function processA2AContinuationById(\n continuationId: string,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const shouldClaim = await waitForContinuationDue(continuationId);\n if (!shouldClaim) return;\n const continuation = await claimA2AContinuation(continuationId);\n if (!continuation) return;\n await processClaimedContinuation(continuation, options);\n}\n\nexport async function processDueA2AContinuations(options: {\n adapters: Map<string, PlatformAdapter>;\n limit?: number;\n}): Promise<void> {\n const continuations = await claimDueA2AContinuations(options.limit ?? 5);\n for (const continuation of continuations) {\n await processClaimedContinuation(continuation, options).catch((err) =>\n console.error(\n `[integrations] A2A continuation ${continuation.id} failed:`,\n err,\n ),\n );\n }\n}\n\nasync function processClaimedContinuation(\n continuation: A2AContinuation,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const adapter = options.adapters.get(continuation.platform);\n if (!adapter) {\n await failA2AContinuation(\n continuation.id,\n `Unknown platform: ${continuation.platform}`,\n );\n return;\n }\n\n const client = new A2AClient(\n continuation.agentUrl,\n await signContinuationToken(continuation),\n { requestTimeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n const deadline = Date.now() + PROCESSOR_WAIT_MS;\n let task: Task | null = null;\n\n try {\n while (Date.now() < deadline) {\n task = await client.getTask(continuation.a2aTaskId);\n if (TERMINAL_STATES.has(task.status.state)) break;\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n } catch (err) {\n if (isTransientA2APollError(err)) {\n if (isRemoteWorkExpired(continuation)) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n remotePollTimeoutReason(continuation),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n\n if (!task || !TERMINAL_STATES.has(task.status.state)) {\n if (isRemoteWorkExpired(continuation)) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n `Remote A2A task ${continuation.a2aTaskId} did not complete within ${Math.round(\n MAX_REMOTE_WORK_MS / 60_000,\n )} minutes`,\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n return;\n }\n\n if (task.status.state !== \"completed\") {\n const reason =\n extractTaskText(task) ||\n `Remote A2A task ${continuation.a2aTaskId} ended with state ${task.status.state}`;\n await notifyAndFailA2AContinuation(continuation, adapter, reason);\n return;\n }\n\n const text = expandRelativeUrls(extractTaskText(task), continuation.agentUrl);\n if (!text.trim()) {\n await notifyAndFailA2AContinuation(\n continuation,\n adapter,\n `Remote A2A task ${continuation.a2aTaskId} completed without text`,\n );\n return;\n }\n\n try {\n await withTimeout(\n adapter.sendResponse(\n adapter.formatAgentResponse(text),\n continuation.incoming,\n { placeholderRef: continuation.placeholderRef ?? undefined },\n ),\n PLATFORM_SEND_TIMEOUT_MS,\n `${continuation.platform} response delivery timed out`,\n );\n await completeA2AContinuation(continuation.id);\n } catch (err) {\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await failA2AContinuation(\n continuation.id,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, RESCHEDULE_DELAY_MS);\n await redispatchContinuation(continuation.id);\n }\n}\n\nasync function waitForContinuationDue(\n continuationId: string,\n): Promise<boolean> {\n const continuation = await getA2AContinuation(continuationId);\n if (!continuation) return false;\n if (continuation.status === \"completed\" || continuation.status === \"failed\") {\n return false;\n }\n if (continuation.status !== \"pending\") return true;\n\n const waitMs = continuation.nextCheckAt - Date.now();\n if (waitMs <= 0) return true;\n\n await sleep(Math.min(waitMs, MAX_PRE_CLAIM_WAIT_MS));\n return true;\n}\n\nasync function notifyAndFailA2AContinuation(\n continuation: A2AContinuation,\n adapter: PlatformAdapter,\n reason: string,\n): Promise<void> {\n const message = formatContinuationFailureMessage(continuation, reason);\n try {\n await withTimeout(\n adapter.sendResponse(\n adapter.formatAgentResponse(message),\n continuation.incoming,\n { placeholderRef: continuation.placeholderRef ?? undefined },\n ),\n PLATFORM_SEND_TIMEOUT_MS,\n `${continuation.platform} failure notification timed out`,\n );\n } catch (err) {\n console.error(\n `[integrations] Failed to notify ${continuation.platform} about failed A2A continuation ${continuation.id}:`,\n err,\n );\n }\n\n await failA2AContinuation(continuation.id, reason);\n}\n\nfunction formatContinuationFailureMessage(\n continuation: A2AContinuation,\n reason: string,\n): string {\n if (isLlmCredentialError(reason)) {\n return formatLlmCredentialErrorMessage({\n agentName: continuation.agentName,\n });\n }\n\n return `The ${continuation.agentName} agent could not finish this request: ${sanitizeFailureReason(\n reason,\n )}`;\n}\n\nfunction isRemoteWorkExpired(continuation: A2AContinuation): boolean {\n return Date.now() - continuation.createdAt >= MAX_REMOTE_WORK_MS;\n}\n\nfunction isTransientA2APollError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n return /operation was aborted|aborted|timed out|timeout|Invalid or expired A2A token|A2A request failed \\(401\\)/i.test(\n err.message,\n );\n}\n\nfunction remotePollTimeoutReason(continuation: A2AContinuation): string {\n return `Timed out polling the ${continuation.agentName} A2A task ${continuation.a2aTaskId} after ${Math.round(\n MAX_REMOTE_WORK_MS / 60_000,\n )} minutes. The downstream agent did not return a final result.`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), timeoutMs);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nfunction sanitizeFailureReason(reason: string): string {\n const oneLine = reason.replace(/\\s+/g, \" \").trim();\n const withoutEnvNames = oneLine.replace(\n /\\b[A-Z][A-Z0-9_]*(?:API_KEY|PRIVATE_KEY|SECRET|TOKEN)\\b/g,\n \"a required credential\",\n );\n return (\n withoutEnvNames.slice(0, 500) ||\n \"the downstream agent returned an empty error\"\n );\n}\n\nasync function redispatchContinuation(continuationId: string): Promise<void> {\n await dispatchA2AContinuation(continuationId).catch((err) => {\n console.error(\n `[integrations] Failed to redispatch A2A continuation ${continuationId}:`,\n err,\n );\n });\n}\n\nasync function signContinuationToken(\n continuation: A2AContinuation,\n): Promise<string | undefined> {\n if (continuation.a2aAuthToken === \"\") {\n return undefined;\n }\n\n const storedToken = continuation.a2aAuthToken;\n if (storedToken && !isLikelyJwt(storedToken)) return storedToken;\n\n const freshToken = await signFreshContinuationToken(continuation);\n if (freshToken) return freshToken;\n if (!storedToken) return undefined;\n\n // Older continuations may have persisted the initial short-lived JWT. Avoid\n // replaying it forever after expiry; opaque legacy bearer keys can still be\n // reused because we cannot re-mint those.\n if (isLikelyJwt(storedToken)) return undefined;\n return storedToken;\n}\n\nasync function signFreshContinuationToken(\n continuation: A2AContinuation,\n): Promise<string | undefined> {\n let orgDomain: string | undefined;\n let orgSecret: string | undefined;\n if (continuation.orgId) {\n try {\n const { getOrgDomain, getOrgA2ASecret } =\n await import(\"../org/context.js\");\n orgDomain = (await getOrgDomain(continuation.orgId)) ?? undefined;\n orgSecret = (await getOrgA2ASecret(continuation.orgId)) ?? undefined;\n } catch {}\n }\n\n if (!continuation.ownerEmail || !(orgSecret || process.env.A2A_SECRET)) {\n return undefined;\n }\n\n try {\n return await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret, {\n expiresIn: \"30m\",\n preferGlobalSecret: true,\n });\n } catch {\n return undefined;\n }\n}\n\nfunction isLikelyJwt(token: string): boolean {\n return token.split(\".\").length === 3;\n}\n\nfunction extractTaskText(task: Task): string {\n const parts = task.status.message?.parts ?? [];\n return parts\n .filter((part): part is { type: \"text\"; text: string } => {\n return part.type === \"text\" && typeof part.text === \"string\";\n })\n .map((part) => part.text)\n .join(\"\\n\");\n}\n\nfunction expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n return text.replace(\n /(^|[\\s(\\[<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
|
|
@@ -402,8 +402,9 @@ async function processIncomingMessage(incoming, options, opts = {}) {
|
|
|
402
402
|
});
|
|
403
403
|
}, async (completedRun) => {
|
|
404
404
|
try {
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
const queuedA2AContinuation = hasQueuedA2AContinuation(completedRun);
|
|
406
|
+
let responseText = collectFinalResponseTextFromAgentEvents(completedRun.events.map((runEvent) => runEvent.event), { fallbackToPreToolText: !queuedA2AContinuation });
|
|
407
|
+
const suppressPlatformReply = queuedA2AContinuation &&
|
|
407
408
|
isQueuedA2AContinuationDeferral(responseText);
|
|
408
409
|
// If the run errored OR produced no text, post a graceful fallback so
|
|
409
410
|
// the user isn't left wondering whether the bot saw their message.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-handler.js","sourceRoot":"","sources":["../../src/integrations/webhook-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { PlatformAdapter, IncomingMessage } from \"./types.js\";\nimport { getThreadMapping, saveThreadMapping } from \"./thread-mapping-store.js\";\nimport { createThread, getThread } from \"../chat-threads/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n getOwnerActiveApiKey,\n getOwnerApiKey,\n engineToProvider,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport { PROVIDER_TO_ENV } from \"../agent/engine/provider-env-vars.js\";\nimport { isLocalDatabase } from \"../db/client.js\";\nimport { readDeployCredentialEnv } from \"../server/credential-provider.js\";\nimport {\n getStoredModelForEngine,\n resolveEngine,\n} from \"../agent/engine/index.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport type { AgentEngine } from \"../agent/engine/types.js\";\nimport type { EngineMessage } from \"../agent/engine/types.js\";\nimport { startRun, type ActiveRun } from \"../agent/run-manager.js\";\nimport {\n buildAssistantMessage,\n extractThreadMeta,\n} from \"../agent/thread-data-builder.js\";\nimport { updateThreadData } from \"../chat-threads/store.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport { resolveOrgIdForEmail } from \"../org/context.js\";\nimport {\n insertPendingTask,\n isDuplicateEventError,\n type PendingTask,\n} from \"./pending-tasks-store.js\";\nimport { signInternalToken } from \"./internal-token.js\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"./a2a-continuation-marker.js\";\nimport { collectFinalResponseTextFromAgentEvents } from \"../a2a/response-text.js\";\n\nconst PROCESSOR_DISPATCH_SETTLE_WAIT_MS = 1_500;\n\n/**\n * Build a stable per-event dedup key from the incoming message. The same\n * key is computed for every retry of the same event from the platform —\n * Slack/Telegram retry on timeout (3s for Slack), so we MUST treat the\n * second delivery as a duplicate and return 200 silently.\n *\n * The `(platform, external_event_key)` UNIQUE index in\n * `integration_pending_tasks` enforces this at the SQL layer, replacing\n * the previous in-memory Map (H3 in the webhook security audit) which\n * couldn't survive serverless cold starts.\n */\nfunction buildEventDedupKey(incoming: IncomingMessage): string {\n return `${incoming.platform}:${incoming.externalThreadId}:${incoming.timestamp}`;\n}\n\nexport interface WebhookHandlerOptions {\n adapter: PlatformAdapter;\n /** Resolved system prompt string */\n systemPrompt: string;\n /** Action entries for the agent */\n actions: Record<string, ActionEntry>;\n /** Model to use */\n model: string;\n /** Anthropic API key */\n apiKey: string;\n /** Agent engine to use. Defaults to the same resolver as web chat. */\n engine?:\n | AgentEngine\n | string\n | { name: string; config: Record<string, unknown> };\n /** Thread owner for personal/shared resource loading */\n ownerEmail: string;\n /**\n * Pre-parsed incoming message. When provided, handleWebhook skips its own\n * verification + parsing steps. Required when the caller has already read\n * the request body (h3 doesn't reliably cache parsed bodies, so re-parsing\n * the same event hangs on streaming providers).\n */\n incoming?: IncomingMessage;\n /** Optional hook to intercept inbound commands before agent execution */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n\nfunction explicitEngineName(\n engineOption: WebhookHandlerOptions[\"engine\"],\n): string | undefined {\n if (!engineOption) return undefined;\n if (typeof engineOption === \"string\") return engineOption;\n if (\n typeof engineOption === \"object\" &&\n !(\"stream\" in engineOption) &&\n typeof engineOption.name === \"string\"\n ) {\n return engineOption.name;\n }\n return undefined;\n}\n\nfunction isMultiTenantDeploy(): boolean {\n if (process.env.NODE_ENV !== \"production\") return false;\n return !isLocalDatabase();\n}\n\nasync function resolveIntegrationApiKey(\n engineOption: WebhookHandlerOptions[\"engine\"],\n ownerEmail: string,\n fallbackApiKey: string,\n): Promise<string | undefined> {\n const engineName = explicitEngineName(engineOption);\n if (engineName) {\n const provider = engineToProvider(engineName);\n const userApiKey = await getOwnerApiKey(provider, ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n const envVar = PROVIDER_TO_ENV[provider];\n const providerEnvKey = envVar ? readDeployCredentialEnv(envVar) : undefined;\n return providerEnvKey || fallbackApiKey.trim() || undefined;\n }\n\n const userApiKey = await getOwnerActiveApiKey(ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n return fallbackApiKey.trim() || undefined;\n}\n\n/**\n * Process an incoming webhook from a messaging platform.\n *\n * Flow:\n * 1. Handle verification challenges (Slack url_verification, etc.)\n * 2. Verify webhook signature\n * 3. Parse incoming message (null = ignored event)\n * 4. Persist task to SQL\n * 5. Fire-and-forget POST to /_agent-native/integrations/process-task\n * (a fresh function execution with its own timeout budget)\n * 6. Return HTTP 200 immediately (within Slack's 3s SLA)\n *\n * The processor endpoint runs the actual agent loop. This split is essential\n * for serverless platforms (Netlify Lambda, Vercel, Cloudflare Workers) which\n * freeze the function as soon as the response is returned, killing any\n * lingering background promises.\n */\nexport async function handleWebhook(\n event: H3Event,\n options: WebhookHandlerOptions,\n): Promise<{ status: number; body: unknown }> {\n const { adapter, beforeProcess } = options;\n\n let incoming: IncomingMessage | null = options.incoming ?? null;\n\n // When the caller didn't pre-parse, run the full verify + parse pipeline.\n // Otherwise skip it — h3's body stream has already been consumed and a\n // second readBody call hangs on streaming providers.\n if (!incoming) {\n // Step 1: Handle platform-specific verification challenges\n const verification = await adapter.handleVerification(event);\n if (verification.handled) {\n return { status: 200, body: verification.response ?? \"ok\" };\n }\n\n // Step 2: Verify webhook signature\n const isValid = await adapter.verifyWebhook(event);\n if (!isValid) {\n return { status: 401, body: { error: \"Invalid webhook signature\" } };\n }\n\n // Step 3: Parse the incoming message\n incoming = await adapter.parseIncomingMessage(event);\n if (!incoming) {\n // Not a user message (bot message, edit, reaction, etc.) — acknowledge silently\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Dedup is enforced inside enqueueAndDispatch — the unique index on\n // `(platform, external_event_key)` raises a constraint violation we treat\n // as \"already enqueued\" and respond 200. We can't dedup BEFORE the\n // beforeProcess hook because some templates use beforeProcess for\n // command-style intercepts that are stateless and idempotent (e.g. a\n // Slack `/help` command that doesn't enqueue a task).\n\n if (beforeProcess) {\n const result = await beforeProcess(incoming, adapter);\n if (result.handled) {\n if (result.responseText?.trim()) {\n const outgoing = adapter.formatAgentResponse(result.responseText);\n await adapter.sendResponse(outgoing, incoming);\n }\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Step 4 + 5: Enqueue to SQL and dispatch to processor in a fresh request.\n try {\n await enqueueAndDispatch(event, incoming, options);\n } catch (err) {\n // Duplicate event delivery: the SQL UNIQUE constraint on\n // (platform, external_event_key) rejected the second insert. This is\n // the expected path when a platform retries an event that already\n // landed (e.g. Slack 3-second timeout) — return 200 so the platform\n // stops retrying. See H3 in the webhook security audit.\n if (isDuplicateEventError(err)) {\n return { status: 200, body: \"ok\" };\n }\n console.error(\n `[integrations] Failed to enqueue/dispatch ${incoming.platform} message:`,\n err,\n );\n // Return 500 so the platform retries. If the SQL insert failed for a\n // non-dup reason, the message is genuinely lost — better to let Slack\n // retry (it will re-fire the same event_callback) than silently drop it.\n return { status: 500, body: { error: \"enqueue failed\" } };\n }\n\n return { status: 200, body: \"ok\" };\n}\n\n/**\n * Persist the task to SQL and dispatch a fresh HTTP request to the processor\n * endpoint. The dispatch is fire-and-forget — we deliberately do NOT await\n * the resulting fetch, so the current handler can return immediately.\n *\n * This pattern works on every supported host:\n * - Netlify Lambda: function returns; the dispatched request hits a fresh\n * Lambda with its own function budget.\n * - Vercel Functions: same.\n * - Cloudflare Workers: same (no waitUntil dependency).\n * - Self-hosted Node: a separate request comes back through the same\n * server, but each handler still runs to completion.\n */\nasync function enqueueAndDispatch(\n event: H3Event,\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Resolve the org id once at enqueue-time so the processor doesn't have to\n // re-derive it (and so we can drop it on the row for observability).\n let orgId: string | null = null;\n try {\n orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? null;\n } catch {\n orgId = null;\n }\n\n // Post a \"thinking…\" placeholder immediately if the adapter supports\n // in-place edits. The processor flow will update this same message with\n // the final answer, so users see one tidy thread reply instead of\n // \"[silence] → answer\". Adapters without edit support skip this and the\n // processor posts a fresh response.\n let placeholderRef: string | undefined;\n try {\n if (options.adapter.postProcessingPlaceholder) {\n const placeholder =\n await options.adapter.postProcessingPlaceholder(incoming);\n if (placeholder?.placeholderRef) {\n placeholderRef = placeholder.placeholderRef;\n }\n }\n } catch (err) {\n console.error(\"[integrations] postProcessingPlaceholder failed:\", err);\n }\n\n const payload = JSON.stringify({ incoming, placeholderRef });\n\n await insertPendingTask({\n id: taskId,\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n payload,\n ownerEmail: options.ownerEmail,\n orgId,\n // SQL-level dedup key — duplicate webhook deliveries from the same\n // platform produce the same key, so the unique index rejects the\n // second insert (H3 in the webhook security audit).\n externalEventKey: buildEventDedupKey(incoming),\n });\n\n const baseUrl = resolveBaseUrl(event);\n const processUrl = `${baseUrl}${FRAMEWORK_ROUTE_PREFIX}/integrations/process-task`;\n\n // Sign the dispatch with an HMAC token so the processor endpoint can\n // verify the request came from us and not the public internet. The\n // processor refuses unsigned requests in production (C3 in the webhook\n // security audit). In dev, dispatching unsigned is allowed and falls\n // through to the SQL atomic claim for double-processing protection.\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(taskId)}`;\n } catch (err) {\n // Distinguish \"secret not configured\" (the documented dev path) from\n // a real signing failure — silently swallowing both made malformed\n // secrets fail invisibly (L5 in the audit).\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${taskId}:`,\n err,\n );\n }\n }\n\n // Fire-and-forget: do NOT await the full response (the processor's run\n // takes minutes — we don't want to block the caller). BUT on Netlify\n // Lambda, when we return immediately, the runtime can freeze the function\n // before the outbound TCP handshake even starts, which leaves the dispatch\n // request stuck waiting for the 60s retry-sweep job. Race the fetch\n // against a short timer so the request gets a reasonable chance to leave\n // the box; the trade-off is at most a couple seconds of added webhook\n // latency, still inside Slack's timeout window.\n const dispatchPromise = fetch(processUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ taskId }),\n }).catch((err) => {\n console.error(\"[integrations] Failed to dispatch processor request:\", err);\n });\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) =>\n setTimeout(resolve, PROCESSOR_DISPATCH_SETTLE_WAIT_MS),\n ),\n ]);\n}\n\n/**\n * Resolve the base URL we should dispatch the processor request to.\n * Prefers explicit env vars (most reliable on serverless), falls back to the\n * inbound request's headers.\n */\nexport function resolveBaseUrl(event: H3Event): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(fromEnv);\n\n try {\n const headers = (event as any).node?.req?.headers ?? (event as any).headers;\n const get = (name: string): string | undefined => {\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const lower = String(name).toLowerCase();\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[lower];\n };\n const proto = get(\"x-forwarded-proto\") || \"http\";\n const host = get(\"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\n `http://localhost:${process.env.PORT || 3000}`,\n );\n }\n}\n\n/**\n * Run the actual agent loop for a previously-enqueued task. Called by the\n * processor endpoint in `plugin.ts`. This is a fresh function execution, so\n * it gets its own timeout budget independent of the inbound webhook handler.\n */\nexport async function processIntegrationTask(\n task: PendingTask,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const parsed = JSON.parse(task.payload) as {\n incoming: IncomingMessage;\n placeholderRef?: string;\n };\n await processIncomingMessage(parsed.incoming, options, {\n taskId: task.id,\n placeholderRef: parsed.placeholderRef,\n });\n}\n\n/**\n * Resolve thread, run agent loop, post response, persist thread data.\n * Shared between the new processor endpoint and any direct callers.\n */\nasync function processIncomingMessage(\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n opts: { taskId?: string; placeholderRef?: string } = {},\n): Promise<void> {\n const {\n adapter,\n systemPrompt,\n actions,\n model,\n apiKey,\n ownerEmail,\n engine: engineOption,\n } = options;\n\n // Resolve or create internal thread\n let mapping = await getThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n );\n\n if (!mapping) {\n const thread = await createThread(ownerEmail, {\n title: `${adapter.label}: ${incoming.senderName || incoming.senderId || \"User\"}`,\n });\n await saveThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n thread.id,\n incoming.platformContext,\n );\n mapping = {\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n internalThreadId: thread.id,\n platformContext: incoming.platformContext,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n }\n\n const threadId = mapping.internalThreadId;\n\n // Load existing thread history for context\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n // Add the new user message. Include verified platform identity as lightweight\n // context so app-specific agents can attribute requests without guessing.\n const identityLines = [\n `Platform: ${incoming.platform}`,\n incoming.senderName ? `Sender name: ${incoming.senderName}` : null,\n incoming.senderEmail ? `Sender email: ${incoming.senderEmail}` : null,\n incoming.senderId ? `Sender ID: ${incoming.senderId}` : null,\n ].filter(Boolean);\n const userText =\n identityLines.length > 1\n ? `<integration-context>\\n${identityLines.join(\"\\n\")}\\n</integration-context>\\n\\n${incoming.text}`\n : incoming.text;\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text: userText }] },\n ];\n\n // Run agent loop via startRun, wrapped in a request context so that\n // tools (especially call-agent) can resolve the caller's org for org-scoped\n // A2A delegation. Without this, getRequestOrgId() returns undefined and\n // call-agent can't look up the org's a2a_secret or org_domain.\n const orgId = await resolveOrgIdForEmail(ownerEmail);\n const tools = actionsToEngineTools(actions);\n\n const runId = `integration-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Wait for the run to complete inside this fresh function execution.\n // We use a Promise so the processor endpoint can await the full lifecycle.\n await new Promise<void>((resolve) => {\n startRun(\n runId,\n threadId,\n async (send, signal) => {\n await runWithRequestContext(\n {\n userEmail: ownerEmail,\n orgId: orgId ?? undefined,\n // Lets downstream callers (call-agent script) apply tighter\n // budgets on integration paths without affecting normal\n // agent-chat. See `isIntegrationCallerRequest()`.\n isIntegrationCaller: true,\n integration: opts.taskId\n ? {\n taskId: opts.taskId,\n incoming,\n placeholderRef: opts.placeholderRef,\n }\n : undefined,\n },\n async () => {\n const effectiveApiKey = await resolveIntegrationApiKey(\n engineOption,\n ownerEmail,\n apiKey,\n );\n const engine = await resolveEngine({\n engineOption,\n apiKey: effectiveApiKey,\n model,\n });\n const resolvedModel =\n (await getStoredModelForEngine(engine)) ??\n model ??\n engine.defaultModel;\n\n return runAgentLoop({\n engine,\n model: resolvedModel,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal,\n });\n },\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n let responseText = collectFinalResponseTextFromAgentEvents(\n completedRun.events.map((runEvent) => runEvent.event),\n );\n\n const suppressPlatformReply =\n hasQueuedA2AContinuation(completedRun) &&\n isQueuedA2AContinuationDeferral(responseText);\n\n // If the run errored OR produced no text, post a graceful fallback so\n // the user isn't left wondering whether the bot saw their message.\n // Common case: an A2A delegation timed out and the agent loop bailed\n // before generating any user-facing text.\n const runErrored = completedRun.status === \"errored\";\n const runErrorText = completedRun.events\n .map((runEvent) =>\n runEvent.event.type === \"error\" ? runEvent.event.error : \"\",\n )\n .filter(Boolean)\n .join(\"\\n\");\n if (\n isLlmCredentialError(responseText) ||\n isLlmCredentialError(runErrorText)\n ) {\n responseText = formatLlmCredentialErrorMessage();\n } else if (\n !suppressPlatformReply &&\n (!responseText.trim() || runErrored)\n ) {\n if (runErrored) {\n responseText =\n (responseText.trim() ? responseText + \"\\n\\n\" : \"\") +\n \"I ran into a problem before I could finish that one. \" +\n \"If it was a complex analytics question, opening the analytics app \" +\n \"directly is the most reliable way to get an answer right now.\";\n } else {\n responseText = \"(No response)\";\n }\n }\n\n // Compute the deep-link to the dispatch UI for this thread, then\n // hand it to the adapter as a structured `threadDeepLinkUrl` so\n // platforms with rich blocks (Slack) can render a button instead\n // of inlining a `<url|text>` link that auto-unfurls into a giant\n // preview card.\n const baseUrl = process.env.APP_URL || process.env.URL || \"\";\n const appBaseUrl = baseUrl ? withConfiguredAppBasePath(baseUrl) : \"\";\n const threadDeepLinkUrl =\n appBaseUrl && threadId\n ? `${appBaseUrl}/?thread=${threadId}`\n : undefined;\n\n // Format and send back to platform — update the \"thinking…\"\n // placeholder in place if the adapter supplied one.\n if (!suppressPlatformReply) {\n const outgoing = adapter.formatAgentResponse(responseText, {\n threadDeepLinkUrl,\n });\n await adapter.sendResponse(outgoing, incoming, {\n placeholderRef: opts.placeholderRef,\n });\n }\n\n // Persist thread data\n await persistThreadData(\n threadId,\n incoming.text,\n completedRun,\n thread,\n );\n } catch (err) {\n console.error(\n `[integrations] Error sending response to ${incoming.platform}:`,\n err,\n );\n // Last-ditch: try to post a brief apology so the thread isn't silent.\n try {\n const fallback = adapter.formatAgentResponse(\n \"Something went wrong on my end while replying. Please try again.\",\n );\n await adapter.sendResponse(fallback, incoming);\n } catch {}\n } finally {\n resolve();\n }\n },\n );\n });\n}\n\nfunction hasQueuedA2AContinuation(completedRun: ActiveRun): boolean {\n return completedRun.events.some((runEvent) => {\n const event = runEvent.event;\n return (\n event.type === \"tool_done\" &&\n event.tool === \"call-agent\" &&\n String(event.result ?? \"\").includes(A2A_CONTINUATION_QUEUED_MARKER)\n );\n });\n}\n\nfunction isQueuedA2AContinuationDeferral(text: string): boolean {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) return true;\n if (normalized.includes(A2A_CONTINUATION_QUEUED_MARKER)) return true;\n return /\\b(?:still (?:working|processing)|taking longer than expected|will (?:post|update|surface|show up)|final result when it finishes|while you wait|as soon as (?:it|the result) (?:comes back|is ready)|relay from the .* agent)\\b/i.test(\n normalized,\n );\n}\n\n/**\n * Persist the user message and agent response to the thread data,\n * so the conversation history is available in the web UI too.\n */\nasync function persistThreadData(\n threadId: string,\n userText: string,\n completedRun: ActiveRun,\n thread: any,\n): Promise<void> {\n try {\n let repo: any;\n try {\n repo = JSON.parse(thread?.threadData || \"{}\");\n } catch {\n repo = {};\n }\n if (!Array.isArray(repo.messages)) repo.messages = [];\n\n // Add user message\n const userMsg = {\n id: `msg-${Date.now()}-user`,\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n createdAt: new Date().toISOString(),\n };\n\n // Build assistant message from run events\n const assistantMsg = buildAssistantMessage(\n completedRun.events ?? [],\n completedRun.runId,\n );\n\n repo.messages.push(userMsg);\n if (assistantMsg) {\n repo.messages.push(assistantMsg);\n }\n\n const meta = extractThreadMeta(repo);\n await updateThreadData(\n threadId,\n JSON.stringify(repo),\n meta.title || thread?.title || \"Integration Chat\",\n meta.preview || thread?.preview || \"\",\n repo.messages.length,\n );\n } catch {\n // Best-effort persistence\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"webhook-handler.js","sourceRoot":"","sources":["../../src/integrations/webhook-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { PlatformAdapter, IncomingMessage } from \"./types.js\";\nimport { getThreadMapping, saveThreadMapping } from \"./thread-mapping-store.js\";\nimport { createThread, getThread } from \"../chat-threads/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n getOwnerActiveApiKey,\n getOwnerApiKey,\n engineToProvider,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport { PROVIDER_TO_ENV } from \"../agent/engine/provider-env-vars.js\";\nimport { isLocalDatabase } from \"../db/client.js\";\nimport { readDeployCredentialEnv } from \"../server/credential-provider.js\";\nimport {\n getStoredModelForEngine,\n resolveEngine,\n} from \"../agent/engine/index.js\";\nimport {\n formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.js\";\nimport type { AgentEngine } from \"../agent/engine/types.js\";\nimport type { EngineMessage } from \"../agent/engine/types.js\";\nimport { startRun, type ActiveRun } from \"../agent/run-manager.js\";\nimport {\n buildAssistantMessage,\n extractThreadMeta,\n} from \"../agent/thread-data-builder.js\";\nimport { updateThreadData } from \"../chat-threads/store.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport { resolveOrgIdForEmail } from \"../org/context.js\";\nimport {\n insertPendingTask,\n isDuplicateEventError,\n type PendingTask,\n} from \"./pending-tasks-store.js\";\nimport { signInternalToken } from \"./internal-token.js\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"./a2a-continuation-marker.js\";\nimport { collectFinalResponseTextFromAgentEvents } from \"../a2a/response-text.js\";\n\nconst PROCESSOR_DISPATCH_SETTLE_WAIT_MS = 1_500;\n\n/**\n * Build a stable per-event dedup key from the incoming message. The same\n * key is computed for every retry of the same event from the platform —\n * Slack/Telegram retry on timeout (3s for Slack), so we MUST treat the\n * second delivery as a duplicate and return 200 silently.\n *\n * The `(platform, external_event_key)` UNIQUE index in\n * `integration_pending_tasks` enforces this at the SQL layer, replacing\n * the previous in-memory Map (H3 in the webhook security audit) which\n * couldn't survive serverless cold starts.\n */\nfunction buildEventDedupKey(incoming: IncomingMessage): string {\n return `${incoming.platform}:${incoming.externalThreadId}:${incoming.timestamp}`;\n}\n\nexport interface WebhookHandlerOptions {\n adapter: PlatformAdapter;\n /** Resolved system prompt string */\n systemPrompt: string;\n /** Action entries for the agent */\n actions: Record<string, ActionEntry>;\n /** Model to use */\n model: string;\n /** Anthropic API key */\n apiKey: string;\n /** Agent engine to use. Defaults to the same resolver as web chat. */\n engine?:\n | AgentEngine\n | string\n | { name: string; config: Record<string, unknown> };\n /** Thread owner for personal/shared resource loading */\n ownerEmail: string;\n /**\n * Pre-parsed incoming message. When provided, handleWebhook skips its own\n * verification + parsing steps. Required when the caller has already read\n * the request body (h3 doesn't reliably cache parsed bodies, so re-parsing\n * the same event hangs on streaming providers).\n */\n incoming?: IncomingMessage;\n /** Optional hook to intercept inbound commands before agent execution */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n\nfunction explicitEngineName(\n engineOption: WebhookHandlerOptions[\"engine\"],\n): string | undefined {\n if (!engineOption) return undefined;\n if (typeof engineOption === \"string\") return engineOption;\n if (\n typeof engineOption === \"object\" &&\n !(\"stream\" in engineOption) &&\n typeof engineOption.name === \"string\"\n ) {\n return engineOption.name;\n }\n return undefined;\n}\n\nfunction isMultiTenantDeploy(): boolean {\n if (process.env.NODE_ENV !== \"production\") return false;\n return !isLocalDatabase();\n}\n\nasync function resolveIntegrationApiKey(\n engineOption: WebhookHandlerOptions[\"engine\"],\n ownerEmail: string,\n fallbackApiKey: string,\n): Promise<string | undefined> {\n const engineName = explicitEngineName(engineOption);\n if (engineName) {\n const provider = engineToProvider(engineName);\n const userApiKey = await getOwnerApiKey(provider, ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n const envVar = PROVIDER_TO_ENV[provider];\n const providerEnvKey = envVar ? readDeployCredentialEnv(envVar) : undefined;\n return providerEnvKey || fallbackApiKey.trim() || undefined;\n }\n\n const userApiKey = await getOwnerActiveApiKey(ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n return fallbackApiKey.trim() || undefined;\n}\n\n/**\n * Process an incoming webhook from a messaging platform.\n *\n * Flow:\n * 1. Handle verification challenges (Slack url_verification, etc.)\n * 2. Verify webhook signature\n * 3. Parse incoming message (null = ignored event)\n * 4. Persist task to SQL\n * 5. Fire-and-forget POST to /_agent-native/integrations/process-task\n * (a fresh function execution with its own timeout budget)\n * 6. Return HTTP 200 immediately (within Slack's 3s SLA)\n *\n * The processor endpoint runs the actual agent loop. This split is essential\n * for serverless platforms (Netlify Lambda, Vercel, Cloudflare Workers) which\n * freeze the function as soon as the response is returned, killing any\n * lingering background promises.\n */\nexport async function handleWebhook(\n event: H3Event,\n options: WebhookHandlerOptions,\n): Promise<{ status: number; body: unknown }> {\n const { adapter, beforeProcess } = options;\n\n let incoming: IncomingMessage | null = options.incoming ?? null;\n\n // When the caller didn't pre-parse, run the full verify + parse pipeline.\n // Otherwise skip it — h3's body stream has already been consumed and a\n // second readBody call hangs on streaming providers.\n if (!incoming) {\n // Step 1: Handle platform-specific verification challenges\n const verification = await adapter.handleVerification(event);\n if (verification.handled) {\n return { status: 200, body: verification.response ?? \"ok\" };\n }\n\n // Step 2: Verify webhook signature\n const isValid = await adapter.verifyWebhook(event);\n if (!isValid) {\n return { status: 401, body: { error: \"Invalid webhook signature\" } };\n }\n\n // Step 3: Parse the incoming message\n incoming = await adapter.parseIncomingMessage(event);\n if (!incoming) {\n // Not a user message (bot message, edit, reaction, etc.) — acknowledge silently\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Dedup is enforced inside enqueueAndDispatch — the unique index on\n // `(platform, external_event_key)` raises a constraint violation we treat\n // as \"already enqueued\" and respond 200. We can't dedup BEFORE the\n // beforeProcess hook because some templates use beforeProcess for\n // command-style intercepts that are stateless and idempotent (e.g. a\n // Slack `/help` command that doesn't enqueue a task).\n\n if (beforeProcess) {\n const result = await beforeProcess(incoming, adapter);\n if (result.handled) {\n if (result.responseText?.trim()) {\n const outgoing = adapter.formatAgentResponse(result.responseText);\n await adapter.sendResponse(outgoing, incoming);\n }\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Step 4 + 5: Enqueue to SQL and dispatch to processor in a fresh request.\n try {\n await enqueueAndDispatch(event, incoming, options);\n } catch (err) {\n // Duplicate event delivery: the SQL UNIQUE constraint on\n // (platform, external_event_key) rejected the second insert. This is\n // the expected path when a platform retries an event that already\n // landed (e.g. Slack 3-second timeout) — return 200 so the platform\n // stops retrying. See H3 in the webhook security audit.\n if (isDuplicateEventError(err)) {\n return { status: 200, body: \"ok\" };\n }\n console.error(\n `[integrations] Failed to enqueue/dispatch ${incoming.platform} message:`,\n err,\n );\n // Return 500 so the platform retries. If the SQL insert failed for a\n // non-dup reason, the message is genuinely lost — better to let Slack\n // retry (it will re-fire the same event_callback) than silently drop it.\n return { status: 500, body: { error: \"enqueue failed\" } };\n }\n\n return { status: 200, body: \"ok\" };\n}\n\n/**\n * Persist the task to SQL and dispatch a fresh HTTP request to the processor\n * endpoint. The dispatch is fire-and-forget — we deliberately do NOT await\n * the resulting fetch, so the current handler can return immediately.\n *\n * This pattern works on every supported host:\n * - Netlify Lambda: function returns; the dispatched request hits a fresh\n * Lambda with its own function budget.\n * - Vercel Functions: same.\n * - Cloudflare Workers: same (no waitUntil dependency).\n * - Self-hosted Node: a separate request comes back through the same\n * server, but each handler still runs to completion.\n */\nasync function enqueueAndDispatch(\n event: H3Event,\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Resolve the org id once at enqueue-time so the processor doesn't have to\n // re-derive it (and so we can drop it on the row for observability).\n let orgId: string | null = null;\n try {\n orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? null;\n } catch {\n orgId = null;\n }\n\n // Post a \"thinking…\" placeholder immediately if the adapter supports\n // in-place edits. The processor flow will update this same message with\n // the final answer, so users see one tidy thread reply instead of\n // \"[silence] → answer\". Adapters without edit support skip this and the\n // processor posts a fresh response.\n let placeholderRef: string | undefined;\n try {\n if (options.adapter.postProcessingPlaceholder) {\n const placeholder =\n await options.adapter.postProcessingPlaceholder(incoming);\n if (placeholder?.placeholderRef) {\n placeholderRef = placeholder.placeholderRef;\n }\n }\n } catch (err) {\n console.error(\"[integrations] postProcessingPlaceholder failed:\", err);\n }\n\n const payload = JSON.stringify({ incoming, placeholderRef });\n\n await insertPendingTask({\n id: taskId,\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n payload,\n ownerEmail: options.ownerEmail,\n orgId,\n // SQL-level dedup key — duplicate webhook deliveries from the same\n // platform produce the same key, so the unique index rejects the\n // second insert (H3 in the webhook security audit).\n externalEventKey: buildEventDedupKey(incoming),\n });\n\n const baseUrl = resolveBaseUrl(event);\n const processUrl = `${baseUrl}${FRAMEWORK_ROUTE_PREFIX}/integrations/process-task`;\n\n // Sign the dispatch with an HMAC token so the processor endpoint can\n // verify the request came from us and not the public internet. The\n // processor refuses unsigned requests in production (C3 in the webhook\n // security audit). In dev, dispatching unsigned is allowed and falls\n // through to the SQL atomic claim for double-processing protection.\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(taskId)}`;\n } catch (err) {\n // Distinguish \"secret not configured\" (the documented dev path) from\n // a real signing failure — silently swallowing both made malformed\n // secrets fail invisibly (L5 in the audit).\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${taskId}:`,\n err,\n );\n }\n }\n\n // Fire-and-forget: do NOT await the full response (the processor's run\n // takes minutes — we don't want to block the caller). BUT on Netlify\n // Lambda, when we return immediately, the runtime can freeze the function\n // before the outbound TCP handshake even starts, which leaves the dispatch\n // request stuck waiting for the 60s retry-sweep job. Race the fetch\n // against a short timer so the request gets a reasonable chance to leave\n // the box; the trade-off is at most a couple seconds of added webhook\n // latency, still inside Slack's timeout window.\n const dispatchPromise = fetch(processUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ taskId }),\n }).catch((err) => {\n console.error(\"[integrations] Failed to dispatch processor request:\", err);\n });\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) =>\n setTimeout(resolve, PROCESSOR_DISPATCH_SETTLE_WAIT_MS),\n ),\n ]);\n}\n\n/**\n * Resolve the base URL we should dispatch the processor request to.\n * Prefers explicit env vars (most reliable on serverless), falls back to the\n * inbound request's headers.\n */\nexport function resolveBaseUrl(event: H3Event): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(fromEnv);\n\n try {\n const headers = (event as any).node?.req?.headers ?? (event as any).headers;\n const get = (name: string): string | undefined => {\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const lower = String(name).toLowerCase();\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[lower];\n };\n const proto = get(\"x-forwarded-proto\") || \"http\";\n const host = get(\"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\n `http://localhost:${process.env.PORT || 3000}`,\n );\n }\n}\n\n/**\n * Run the actual agent loop for a previously-enqueued task. Called by the\n * processor endpoint in `plugin.ts`. This is a fresh function execution, so\n * it gets its own timeout budget independent of the inbound webhook handler.\n */\nexport async function processIntegrationTask(\n task: PendingTask,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const parsed = JSON.parse(task.payload) as {\n incoming: IncomingMessage;\n placeholderRef?: string;\n };\n await processIncomingMessage(parsed.incoming, options, {\n taskId: task.id,\n placeholderRef: parsed.placeholderRef,\n });\n}\n\n/**\n * Resolve thread, run agent loop, post response, persist thread data.\n * Shared between the new processor endpoint and any direct callers.\n */\nasync function processIncomingMessage(\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n opts: { taskId?: string; placeholderRef?: string } = {},\n): Promise<void> {\n const {\n adapter,\n systemPrompt,\n actions,\n model,\n apiKey,\n ownerEmail,\n engine: engineOption,\n } = options;\n\n // Resolve or create internal thread\n let mapping = await getThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n );\n\n if (!mapping) {\n const thread = await createThread(ownerEmail, {\n title: `${adapter.label}: ${incoming.senderName || incoming.senderId || \"User\"}`,\n });\n await saveThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n thread.id,\n incoming.platformContext,\n );\n mapping = {\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n internalThreadId: thread.id,\n platformContext: incoming.platformContext,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n }\n\n const threadId = mapping.internalThreadId;\n\n // Load existing thread history for context\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n // Add the new user message. Include verified platform identity as lightweight\n // context so app-specific agents can attribute requests without guessing.\n const identityLines = [\n `Platform: ${incoming.platform}`,\n incoming.senderName ? `Sender name: ${incoming.senderName}` : null,\n incoming.senderEmail ? `Sender email: ${incoming.senderEmail}` : null,\n incoming.senderId ? `Sender ID: ${incoming.senderId}` : null,\n ].filter(Boolean);\n const userText =\n identityLines.length > 1\n ? `<integration-context>\\n${identityLines.join(\"\\n\")}\\n</integration-context>\\n\\n${incoming.text}`\n : incoming.text;\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text: userText }] },\n ];\n\n // Run agent loop via startRun, wrapped in a request context so that\n // tools (especially call-agent) can resolve the caller's org for org-scoped\n // A2A delegation. Without this, getRequestOrgId() returns undefined and\n // call-agent can't look up the org's a2a_secret or org_domain.\n const orgId = await resolveOrgIdForEmail(ownerEmail);\n const tools = actionsToEngineTools(actions);\n\n const runId = `integration-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Wait for the run to complete inside this fresh function execution.\n // We use a Promise so the processor endpoint can await the full lifecycle.\n await new Promise<void>((resolve) => {\n startRun(\n runId,\n threadId,\n async (send, signal) => {\n await runWithRequestContext(\n {\n userEmail: ownerEmail,\n orgId: orgId ?? undefined,\n // Lets downstream callers (call-agent script) apply tighter\n // budgets on integration paths without affecting normal\n // agent-chat. See `isIntegrationCallerRequest()`.\n isIntegrationCaller: true,\n integration: opts.taskId\n ? {\n taskId: opts.taskId,\n incoming,\n placeholderRef: opts.placeholderRef,\n }\n : undefined,\n },\n async () => {\n const effectiveApiKey = await resolveIntegrationApiKey(\n engineOption,\n ownerEmail,\n apiKey,\n );\n const engine = await resolveEngine({\n engineOption,\n apiKey: effectiveApiKey,\n model,\n });\n const resolvedModel =\n (await getStoredModelForEngine(engine)) ??\n model ??\n engine.defaultModel;\n\n return runAgentLoop({\n engine,\n model: resolvedModel,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal,\n });\n },\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n const queuedA2AContinuation = hasQueuedA2AContinuation(completedRun);\n let responseText = collectFinalResponseTextFromAgentEvents(\n completedRun.events.map((runEvent) => runEvent.event),\n { fallbackToPreToolText: !queuedA2AContinuation },\n );\n\n const suppressPlatformReply =\n queuedA2AContinuation &&\n isQueuedA2AContinuationDeferral(responseText);\n\n // If the run errored OR produced no text, post a graceful fallback so\n // the user isn't left wondering whether the bot saw their message.\n // Common case: an A2A delegation timed out and the agent loop bailed\n // before generating any user-facing text.\n const runErrored = completedRun.status === \"errored\";\n const runErrorText = completedRun.events\n .map((runEvent) =>\n runEvent.event.type === \"error\" ? runEvent.event.error : \"\",\n )\n .filter(Boolean)\n .join(\"\\n\");\n if (\n isLlmCredentialError(responseText) ||\n isLlmCredentialError(runErrorText)\n ) {\n responseText = formatLlmCredentialErrorMessage();\n } else if (\n !suppressPlatformReply &&\n (!responseText.trim() || runErrored)\n ) {\n if (runErrored) {\n responseText =\n (responseText.trim() ? responseText + \"\\n\\n\" : \"\") +\n \"I ran into a problem before I could finish that one. \" +\n \"If it was a complex analytics question, opening the analytics app \" +\n \"directly is the most reliable way to get an answer right now.\";\n } else {\n responseText = \"(No response)\";\n }\n }\n\n // Compute the deep-link to the dispatch UI for this thread, then\n // hand it to the adapter as a structured `threadDeepLinkUrl` so\n // platforms with rich blocks (Slack) can render a button instead\n // of inlining a `<url|text>` link that auto-unfurls into a giant\n // preview card.\n const baseUrl = process.env.APP_URL || process.env.URL || \"\";\n const appBaseUrl = baseUrl ? withConfiguredAppBasePath(baseUrl) : \"\";\n const threadDeepLinkUrl =\n appBaseUrl && threadId\n ? `${appBaseUrl}/?thread=${threadId}`\n : undefined;\n\n // Format and send back to platform — update the \"thinking…\"\n // placeholder in place if the adapter supplied one.\n if (!suppressPlatformReply) {\n const outgoing = adapter.formatAgentResponse(responseText, {\n threadDeepLinkUrl,\n });\n await adapter.sendResponse(outgoing, incoming, {\n placeholderRef: opts.placeholderRef,\n });\n }\n\n // Persist thread data\n await persistThreadData(\n threadId,\n incoming.text,\n completedRun,\n thread,\n );\n } catch (err) {\n console.error(\n `[integrations] Error sending response to ${incoming.platform}:`,\n err,\n );\n // Last-ditch: try to post a brief apology so the thread isn't silent.\n try {\n const fallback = adapter.formatAgentResponse(\n \"Something went wrong on my end while replying. Please try again.\",\n );\n await adapter.sendResponse(fallback, incoming);\n } catch {}\n } finally {\n resolve();\n }\n },\n );\n });\n}\n\nfunction hasQueuedA2AContinuation(completedRun: ActiveRun): boolean {\n return completedRun.events.some((runEvent) => {\n const event = runEvent.event;\n return (\n event.type === \"tool_done\" &&\n event.tool === \"call-agent\" &&\n String(event.result ?? \"\").includes(A2A_CONTINUATION_QUEUED_MARKER)\n );\n });\n}\n\nfunction isQueuedA2AContinuationDeferral(text: string): boolean {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) return true;\n if (normalized.includes(A2A_CONTINUATION_QUEUED_MARKER)) return true;\n return /\\b(?:still (?:working|processing)|taking longer than expected|will (?:post|update|surface|show up)|final result when it finishes|while you wait|as soon as (?:it|the result) (?:comes back|is ready)|relay from the .* agent)\\b/i.test(\n normalized,\n );\n}\n\n/**\n * Persist the user message and agent response to the thread data,\n * so the conversation history is available in the web UI too.\n */\nasync function persistThreadData(\n threadId: string,\n userText: string,\n completedRun: ActiveRun,\n thread: any,\n): Promise<void> {\n try {\n let repo: any;\n try {\n repo = JSON.parse(thread?.threadData || \"{}\");\n } catch {\n repo = {};\n }\n if (!Array.isArray(repo.messages)) repo.messages = [];\n\n // Add user message\n const userMsg = {\n id: `msg-${Date.now()}-user`,\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n createdAt: new Date().toISOString(),\n };\n\n // Build assistant message from run events\n const assistantMsg = buildAssistantMessage(\n completedRun.events ?? [],\n completedRun.runId,\n );\n\n repo.messages.push(userMsg);\n if (assistantMsg) {\n repo.messages.push(assistantMsg);\n }\n\n const meta = extractThreadMeta(repo);\n await updateThreadData(\n threadId,\n JSON.stringify(repo),\n meta.title || thread?.title || \"Integration Chat\",\n meta.preview || thread?.preview || \"\",\n repo.messages.length,\n );\n } catch {\n // Best-effort persistence\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-agent.d.ts","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAuDrE,eAAO,MAAM,IAAI,EAAE,UAqBlB,CAAC;AAEF,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"call-agent.d.ts","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAuDrE,eAAO,MAAM,IAAI,EAAE,UAqBlB,CAAC;AAEF,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAwMjB;AAkDD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASzE"}
|
|
@@ -113,7 +113,10 @@ export async function run(args, context, selfAppId) {
|
|
|
113
113
|
let apiKey;
|
|
114
114
|
if (callerEmail && (callerOrgSecret || process.env.A2A_SECRET)) {
|
|
115
115
|
try {
|
|
116
|
-
apiKey = await signA2AToken(callerEmail, callerOrgDomain, callerOrgSecret, {
|
|
116
|
+
apiKey = await signA2AToken(callerEmail, callerOrgDomain, callerOrgSecret, {
|
|
117
|
+
expiresIn: INTEGRATION_A2A_TOKEN_TTL,
|
|
118
|
+
preferGlobalSecret: true,
|
|
119
|
+
});
|
|
117
120
|
}
|
|
118
121
|
catch { }
|
|
119
122
|
}
|
|
@@ -183,7 +186,7 @@ export async function run(args, context, selfAppId) {
|
|
|
183
186
|
}
|
|
184
187
|
catch (pollErr) {
|
|
185
188
|
if (pollErr instanceof A2ATaskTimeoutError) {
|
|
186
|
-
const queued = await enqueueIntegrationContinuationIfPossible(pollErr, agent, callerEmail
|
|
189
|
+
const queued = await enqueueIntegrationContinuationIfPossible(pollErr, agent, callerEmail);
|
|
187
190
|
if (queued) {
|
|
188
191
|
responseText = `${A2A_CONTINUATION_QUEUED_MARKER}\nThe ${agent.name} agent is still working. Do not send an interim reply to the user; the final result will be posted to the originating integration thread automatically.`;
|
|
189
192
|
}
|
|
@@ -237,7 +240,7 @@ export async function run(args, context, selfAppId) {
|
|
|
237
240
|
return `Error calling ${agent.name}: ${msg}`;
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
|
-
async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail
|
|
243
|
+
async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail) {
|
|
241
244
|
const integration = getIntegrationRequestContext();
|
|
242
245
|
if (!integration || !ownerEmail)
|
|
243
246
|
return false;
|
|
@@ -257,7 +260,9 @@ async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail
|
|
|
257
260
|
agentName: agent.name,
|
|
258
261
|
agentUrl: agent.url,
|
|
259
262
|
a2aTaskId: error.taskId,
|
|
260
|
-
|
|
263
|
+
// Do not persist the short-lived JWT used for the initial send. The
|
|
264
|
+
// continuation processor can mint a fresh token for each poll.
|
|
265
|
+
a2aAuthToken: null,
|
|
261
266
|
});
|
|
262
267
|
await dispatchA2AContinuation(continuation.id).catch((err) => {
|
|
263
268
|
console.error(`[call-agent] Failed to dispatch A2A continuation ${continuation.id}:`, err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionTool } from \"../agent/types.js\";\nimport type { ActionRunContext } from \"../agent/production-agent.js\";\nimport { findAgent, discoverAgents } from \"../server/agent-discovery.js\";\nimport {\n A2AClient,\n A2ATaskTimeoutError,\n callAgent,\n signA2AToken,\n} from \"../a2a/client.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"../integrations/a2a-continuation-marker.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n isIntegrationCallerRequest,\n getIntegrationRequestContext,\n} from \"../server/request-context.js\";\nimport { getOrgDomain, getOrgA2ASecret } from \"../org/context.js\";\n\nconst DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS = 18_000;\nconst NETLIFY_INTEGRATION_A2A_TIMEOUT_MS = 50_000;\nconst INTEGRATION_A2A_TOKEN_TTL = \"30m\";\n\nfunction parseTimeoutMs(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed <= 0) return undefined;\n return Math.floor(parsed);\n}\n\nfunction isServerlessHost(): boolean {\n // Detection mirrors db/migrations.ts:297-301. On Cloudflare Workers/Pages,\n // `process.env` is shimmed and CF_PAGES isn't reliably populated at runtime —\n // the canonical signal is the `__cf_env` global injected by workerd.\n return (\n !!process.env.NETLIFY ||\n !!process.env.AWS_LAMBDA_FUNCTION_NAME ||\n !!process.env.VERCEL ||\n \"__cf_env\" in globalThis\n );\n}\n\nfunction getIntegrationCallTimeoutMs(): number | undefined {\n if (!isServerlessHost() || !isIntegrationCallerRequest()) return undefined;\n\n const configured = parseTimeoutMs(\n process.env.AGENT_NATIVE_INTEGRATION_A2A_TIMEOUT_MS,\n );\n if (configured !== undefined) return configured;\n\n // Netlify's current synchronous function budget is 60s, but leave room for\n // cold start, polling overhead, and the caller's final platform response.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nexport const tool: ActionTool = {\n description:\n \"Call a DIFFERENT, separately-deployed agent app to ask a question or delegate a task. This is strictly for cross-app A2A communication — for example, asking the mail agent to send an email while you are the calendar agent. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. \" +\n \"IMPORTANT — handling the response: \" +\n \"(a) If it contains a URL or ID, copy it VERBATIM into your reply. Do not 'correct' or pluralize the path (e.g. /deck/ → /decks/), normalize casing, or change the slug — any edit breaks the link. \" +\n '(b) If it does NOT contain a URL/ID and the user asked for one, say so explicitly (e.g. \"the agent created the deck but didn\\'t return a link — open the app directly to view it\"). NEVER invent a URL, slug, or path — guessing produces broken links that look real.',\n parameters: {\n type: \"object\",\n properties: {\n agent: {\n type: \"string\",\n description:\n \"Name or URL of a DIFFERENT deployed agent app (e.g. 'mail', 'calendar', 'analytics'). Must not be the current app's own name.\",\n },\n message: {\n type: \"string\",\n description: \"The message/question to send to the other agent\",\n },\n },\n required: [\"agent\", \"message\"],\n },\n};\n\nexport async function run(\n args: Record<string, string>,\n context?: ActionRunContext,\n selfAppId?: string,\n): Promise<string> {\n const { agent: agentIdOrName, message } = args;\n\n if (!agentIdOrName) return \"Error: --agent is required\";\n if (!message) return \"Error: --message is required\";\n\n // Prevent self-calls — the agent must use its own registered tools instead\n if (selfAppId && agentIdOrName.toLowerCase() === selfAppId.toLowerCase()) {\n return `Error: You cannot use call-agent to call yourself (${selfAppId}). Use your own registered actions/tools instead. call-agent is only for communicating with OTHER separately-deployed apps.`;\n }\n\n const agent = await findAgent(agentIdOrName, selfAppId);\n if (!agent) {\n const available = (await discoverAgents(selfAppId))\n .map((a) => a.name)\n .join(\", \");\n return `Error: Agent \"${agentIdOrName}\" not found. Available agents: ${available || \"(none)\"}`;\n }\n\n // Append a small cross-app hint to the outgoing message so the receiving\n // agent (which may be on an older deploy without the receiver-side hint\n // in handlers.ts) still emits fully-qualified URLs. This is belt-and-\n // suspenders with the receiver hint — but it works against any current\n // deployment, no redeploy required.\n const messageWithHint =\n `${message}\\n\\n` +\n `[Note: this request comes from another app via A2A. The caller cannot see your local UI, deck list, or navigation — only the literal text you put in your reply. ` +\n `If you create or reference a deck/document/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only IDs returned by your own actions — never invent slugs or hosts.]`;\n\n try {\n // If we have a send context, use streaming so the UI shows progressive text\n if (context?.send) {\n const callerEmail = getRequestUserEmail();\n\n // Build metadata with identity\n const a2aMetadata: Record<string, unknown> = {};\n if (callerEmail) a2aMetadata.userEmail = callerEmail;\n\n // Include org domain for cross-app org resolution\n let callerOrgDomain: string | undefined;\n let callerOrgSecret: string | undefined;\n const orgId = getRequestOrgId();\n if (orgId) {\n try {\n const domain = await getOrgDomain(orgId);\n if (domain) {\n callerOrgDomain = domain;\n a2aMetadata.orgDomain = domain;\n }\n } catch {}\n try {\n const secret = await getOrgA2ASecret(orgId);\n if (secret) callerOrgSecret = secret;\n } catch {}\n }\n\n // Sign JWT with identity + org domain for the streaming client\n let apiKey: string | undefined;\n if (callerEmail && (callerOrgSecret || process.env.A2A_SECRET)) {\n try {\n apiKey = await signA2AToken(\n callerEmail,\n callerOrgDomain,\n callerOrgSecret,\n { expiresIn: INTEGRATION_A2A_TOKEN_TTL },\n );\n } catch {}\n }\n\n const client = new A2AClient(agent.url, apiKey);\n\n if (process.env.NODE_ENV === \"production\" && callerEmail) {\n try {\n const { listOAuthAccountsByOwner } =\n await import(\"../oauth-tokens/store.js\");\n const accounts = await listOAuthAccountsByOwner(\n \"google\",\n callerEmail,\n );\n const tokens = accounts[0]?.tokens;\n if (tokens?.access_token) {\n a2aMetadata.googleToken = tokens.access_token;\n }\n } catch {}\n }\n\n let responseText = \"\";\n let lastSentLength = 0;\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"start\",\n });\n\n const emitNewText = (newText: string) => {\n if (newText.length > lastSentLength) {\n context.send!({\n type: \"agent_call_text\",\n agent: agent.name,\n text: newText.slice(lastSentLength),\n });\n lastSentLength = newText.length;\n }\n responseText = newText;\n };\n\n // Skip the SSE streaming attempt and go straight to async + poll.\n // Why: on Netlify (Lambda), the receiving server has no streaming\n // response support, so message/stream returns a single JSON-RPC error\n // body in a 200 response that our SSE parser silently consumes — the\n // `for await` loop yields nothing AND keeps the connection open until\n // the function timeout, eating the current serverless budget. By the\n // time we get to the sync fallback, Lambda is dead and the second fetch\n // errors out as \"fetch failed\". Async+poll has its own short fetches\n // with their own budgets, so it works reliably across hosts. The\n // trade-off is we lose progressive in-UI text streaming for cross-app\n // A2A calls, but the receiving agent's full response still surfaces via\n // the tool_result event below.\n try {\n // Apply a polling cap ONLY for integration-platform callers on\n // serverless hosts. Normal chat, local Node, self-hosted Node, and\n // Docker can wait for slow-but-valid answers; integration processors\n // still need to finish before their current function execution dies.\n const callTimeoutMs = getIntegrationCallTimeoutMs();\n responseText = await callAgent(agent.url, messageWithHint, {\n apiKey,\n userEmail: callerEmail,\n orgDomain: callerOrgDomain,\n orgSecret: callerOrgSecret,\n ...(callTimeoutMs ? { timeoutMs: callTimeoutMs } : {}),\n });\n // Some agents reply with relative paths (e.g. slides emits\n // \"/deck/abc\"). Those resolve against the caller's host, not the\n // receiver's, so they're broken for the user. Expand any leading-slash\n // URL into a fully-qualified one rooted at the receiving agent's host.\n responseText = expandRelativeUrls(responseText, agent.url);\n // Mirror the response into the streaming UI so the user sees it.\n if (responseText) emitNewText(responseText);\n } catch (pollErr: any) {\n if (pollErr instanceof A2ATaskTimeoutError) {\n const queued = await enqueueIntegrationContinuationIfPossible(\n pollErr,\n agent,\n callerEmail,\n apiKey,\n );\n if (queued) {\n responseText = `${A2A_CONTINUATION_QUEUED_MARKER}\\nThe ${agent.name} agent is still working. Do not send an interim reply to the user; the final result will be posted to the originating integration thread automatically.`;\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n }\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"done\",\n });\n\n return responseText || \"(empty response)\";\n }\n\n // No context — use the async + poll call so we don't get cut off at the\n // serverless gateway's ~30s timeout. callAgent defaults to async:true.\n const email = getRequestUserEmail();\n let domain: string | undefined;\n let orgSecret: string | undefined;\n const currentOrgId = getRequestOrgId();\n if (currentOrgId) {\n try {\n domain = (await getOrgDomain(currentOrgId)) ?? undefined;\n } catch {}\n try {\n orgSecret = (await getOrgA2ASecret(currentOrgId)) ?? undefined;\n } catch {}\n }\n const response = await callAgent(agent.url, messageWithHint, {\n userEmail: email,\n orgDomain: domain,\n orgSecret,\n });\n return expandRelativeUrls(response, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n // Friendlier message for the common timeout case so the calling agent can\n // decide whether to give up or retry.\n if (/timeout|did not complete|Inactivity|504/i.test(msg)) {\n return `The ${agent.name} agent is taking longer than expected. Please try again, ask a simpler question, or open the ${agent.name} app directly.`;\n }\n return `Error calling ${agent.name}: ${msg}`;\n }\n}\n\nasync function enqueueIntegrationContinuationIfPossible(\n error: A2ATaskTimeoutError,\n agent: { name: string; url: string },\n ownerEmail: string | undefined,\n a2aAuthToken: string | undefined,\n): Promise<boolean> {\n const integration = getIntegrationRequestContext();\n if (!integration || !ownerEmail) return false;\n\n try {\n const [{ insertA2AContinuation }, { dispatchA2AContinuation }] =\n await Promise.all([\n import(\"../integrations/a2a-continuations-store.js\"),\n import(\"../integrations/a2a-continuation-processor.js\"),\n ]);\n const continuation = await insertA2AContinuation({\n integrationTaskId: integration.taskId,\n platform: integration.incoming.platform,\n externalThreadId: integration.incoming.externalThreadId,\n incoming: integration.incoming,\n placeholderRef: integration.placeholderRef,\n ownerEmail,\n orgId: getRequestOrgId() ?? null,\n agentName: agent.name,\n agentUrl: agent.url,\n a2aTaskId: error.taskId,\n a2aAuthToken: a2aAuthToken ?? \"\",\n });\n await dispatchA2AContinuation(continuation.id).catch((err) => {\n console.error(\n `[call-agent] Failed to dispatch A2A continuation ${continuation.id}:`,\n err,\n );\n });\n return true;\n } catch (err) {\n console.error(\"[call-agent] Failed to enqueue A2A continuation:\", err);\n return false;\n }\n}\n\n// Expand bare leading-slash paths (e.g. \"/deck/abc\") into fully-qualified URLs\n// rooted at the receiving agent's host. The receiver doesn't always know it's\n// being called cross-app, so it may emit relative paths that resolve against\n// the caller's host (broken). Match a path that starts at a word boundary,\n// begins with `/`, and has at least one path segment after that. Skip if it\n// already looks like a fully-qualified URL.\nexport function expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n // Path must start at boundary (start, whitespace, or punctuation that isn't\n // ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).\n return text.replace(\n /(^|[\\s(\\[<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../src/scripts/call-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionTool } from \"../agent/types.js\";\nimport type { ActionRunContext } from \"../agent/production-agent.js\";\nimport { findAgent, discoverAgents } from \"../server/agent-discovery.js\";\nimport {\n A2AClient,\n A2ATaskTimeoutError,\n callAgent,\n signA2AToken,\n} from \"../a2a/client.js\";\nimport { A2A_CONTINUATION_QUEUED_MARKER } from \"../integrations/a2a-continuation-marker.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n isIntegrationCallerRequest,\n getIntegrationRequestContext,\n} from \"../server/request-context.js\";\nimport { getOrgDomain, getOrgA2ASecret } from \"../org/context.js\";\n\nconst DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS = 18_000;\nconst NETLIFY_INTEGRATION_A2A_TIMEOUT_MS = 50_000;\nconst INTEGRATION_A2A_TOKEN_TTL = \"30m\";\n\nfunction parseTimeoutMs(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed <= 0) return undefined;\n return Math.floor(parsed);\n}\n\nfunction isServerlessHost(): boolean {\n // Detection mirrors db/migrations.ts:297-301. On Cloudflare Workers/Pages,\n // `process.env` is shimmed and CF_PAGES isn't reliably populated at runtime —\n // the canonical signal is the `__cf_env` global injected by workerd.\n return (\n !!process.env.NETLIFY ||\n !!process.env.AWS_LAMBDA_FUNCTION_NAME ||\n !!process.env.VERCEL ||\n \"__cf_env\" in globalThis\n );\n}\n\nfunction getIntegrationCallTimeoutMs(): number | undefined {\n if (!isServerlessHost() || !isIntegrationCallerRequest()) return undefined;\n\n const configured = parseTimeoutMs(\n process.env.AGENT_NATIVE_INTEGRATION_A2A_TIMEOUT_MS,\n );\n if (configured !== undefined) return configured;\n\n // Netlify's current synchronous function budget is 60s, but leave room for\n // cold start, polling overhead, and the caller's final platform response.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nexport const tool: ActionTool = {\n description:\n \"Call a DIFFERENT, separately-deployed agent app to ask a question or delegate a task. This is strictly for cross-app A2A communication — for example, asking the mail agent to send an email while you are the calendar agent. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. \" +\n \"IMPORTANT — handling the response: \" +\n \"(a) If it contains a URL or ID, copy it VERBATIM into your reply. Do not 'correct' or pluralize the path (e.g. /deck/ → /decks/), normalize casing, or change the slug — any edit breaks the link. \" +\n '(b) If it does NOT contain a URL/ID and the user asked for one, say so explicitly (e.g. \"the agent created the deck but didn\\'t return a link — open the app directly to view it\"). NEVER invent a URL, slug, or path — guessing produces broken links that look real.',\n parameters: {\n type: \"object\",\n properties: {\n agent: {\n type: \"string\",\n description:\n \"Name or URL of a DIFFERENT deployed agent app (e.g. 'mail', 'calendar', 'analytics'). Must not be the current app's own name.\",\n },\n message: {\n type: \"string\",\n description: \"The message/question to send to the other agent\",\n },\n },\n required: [\"agent\", \"message\"],\n },\n};\n\nexport async function run(\n args: Record<string, string>,\n context?: ActionRunContext,\n selfAppId?: string,\n): Promise<string> {\n const { agent: agentIdOrName, message } = args;\n\n if (!agentIdOrName) return \"Error: --agent is required\";\n if (!message) return \"Error: --message is required\";\n\n // Prevent self-calls — the agent must use its own registered tools instead\n if (selfAppId && agentIdOrName.toLowerCase() === selfAppId.toLowerCase()) {\n return `Error: You cannot use call-agent to call yourself (${selfAppId}). Use your own registered actions/tools instead. call-agent is only for communicating with OTHER separately-deployed apps.`;\n }\n\n const agent = await findAgent(agentIdOrName, selfAppId);\n if (!agent) {\n const available = (await discoverAgents(selfAppId))\n .map((a) => a.name)\n .join(\", \");\n return `Error: Agent \"${agentIdOrName}\" not found. Available agents: ${available || \"(none)\"}`;\n }\n\n // Append a small cross-app hint to the outgoing message so the receiving\n // agent (which may be on an older deploy without the receiver-side hint\n // in handlers.ts) still emits fully-qualified URLs. This is belt-and-\n // suspenders with the receiver hint — but it works against any current\n // deployment, no redeploy required.\n const messageWithHint =\n `${message}\\n\\n` +\n `[Note: this request comes from another app via A2A. The caller cannot see your local UI, deck list, or navigation — only the literal text you put in your reply. ` +\n `If you create or reference a deck/document/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only IDs returned by your own actions — never invent slugs or hosts.]`;\n\n try {\n // If we have a send context, use streaming so the UI shows progressive text\n if (context?.send) {\n const callerEmail = getRequestUserEmail();\n\n // Build metadata with identity\n const a2aMetadata: Record<string, unknown> = {};\n if (callerEmail) a2aMetadata.userEmail = callerEmail;\n\n // Include org domain for cross-app org resolution\n let callerOrgDomain: string | undefined;\n let callerOrgSecret: string | undefined;\n const orgId = getRequestOrgId();\n if (orgId) {\n try {\n const domain = await getOrgDomain(orgId);\n if (domain) {\n callerOrgDomain = domain;\n a2aMetadata.orgDomain = domain;\n }\n } catch {}\n try {\n const secret = await getOrgA2ASecret(orgId);\n if (secret) callerOrgSecret = secret;\n } catch {}\n }\n\n // Sign JWT with identity + org domain for the streaming client\n let apiKey: string | undefined;\n if (callerEmail && (callerOrgSecret || process.env.A2A_SECRET)) {\n try {\n apiKey = await signA2AToken(\n callerEmail,\n callerOrgDomain,\n callerOrgSecret,\n {\n expiresIn: INTEGRATION_A2A_TOKEN_TTL,\n preferGlobalSecret: true,\n },\n );\n } catch {}\n }\n\n const client = new A2AClient(agent.url, apiKey);\n\n if (process.env.NODE_ENV === \"production\" && callerEmail) {\n try {\n const { listOAuthAccountsByOwner } =\n await import(\"../oauth-tokens/store.js\");\n const accounts = await listOAuthAccountsByOwner(\n \"google\",\n callerEmail,\n );\n const tokens = accounts[0]?.tokens;\n if (tokens?.access_token) {\n a2aMetadata.googleToken = tokens.access_token;\n }\n } catch {}\n }\n\n let responseText = \"\";\n let lastSentLength = 0;\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"start\",\n });\n\n const emitNewText = (newText: string) => {\n if (newText.length > lastSentLength) {\n context.send!({\n type: \"agent_call_text\",\n agent: agent.name,\n text: newText.slice(lastSentLength),\n });\n lastSentLength = newText.length;\n }\n responseText = newText;\n };\n\n // Skip the SSE streaming attempt and go straight to async + poll.\n // Why: on Netlify (Lambda), the receiving server has no streaming\n // response support, so message/stream returns a single JSON-RPC error\n // body in a 200 response that our SSE parser silently consumes — the\n // `for await` loop yields nothing AND keeps the connection open until\n // the function timeout, eating the current serverless budget. By the\n // time we get to the sync fallback, Lambda is dead and the second fetch\n // errors out as \"fetch failed\". Async+poll has its own short fetches\n // with their own budgets, so it works reliably across hosts. The\n // trade-off is we lose progressive in-UI text streaming for cross-app\n // A2A calls, but the receiving agent's full response still surfaces via\n // the tool_result event below.\n try {\n // Apply a polling cap ONLY for integration-platform callers on\n // serverless hosts. Normal chat, local Node, self-hosted Node, and\n // Docker can wait for slow-but-valid answers; integration processors\n // still need to finish before their current function execution dies.\n const callTimeoutMs = getIntegrationCallTimeoutMs();\n responseText = await callAgent(agent.url, messageWithHint, {\n apiKey,\n userEmail: callerEmail,\n orgDomain: callerOrgDomain,\n orgSecret: callerOrgSecret,\n ...(callTimeoutMs ? { timeoutMs: callTimeoutMs } : {}),\n });\n // Some agents reply with relative paths (e.g. slides emits\n // \"/deck/abc\"). Those resolve against the caller's host, not the\n // receiver's, so they're broken for the user. Expand any leading-slash\n // URL into a fully-qualified one rooted at the receiving agent's host.\n responseText = expandRelativeUrls(responseText, agent.url);\n // Mirror the response into the streaming UI so the user sees it.\n if (responseText) emitNewText(responseText);\n } catch (pollErr: any) {\n if (pollErr instanceof A2ATaskTimeoutError) {\n const queued = await enqueueIntegrationContinuationIfPossible(\n pollErr,\n agent,\n callerEmail,\n );\n if (queued) {\n responseText = `${A2A_CONTINUATION_QUEUED_MARKER}\\nThe ${agent.name} agent is still working. Do not send an interim reply to the user; the final result will be posted to the originating integration thread automatically.`;\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n } else {\n const reason = pollErr?.message ?? \"unknown error\";\n responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;\n }\n }\n\n context.send({\n type: \"agent_call\",\n agent: agent.name,\n status: \"done\",\n });\n\n return responseText || \"(empty response)\";\n }\n\n // No context — use the async + poll call so we don't get cut off at the\n // serverless gateway's ~30s timeout. callAgent defaults to async:true.\n const email = getRequestUserEmail();\n let domain: string | undefined;\n let orgSecret: string | undefined;\n const currentOrgId = getRequestOrgId();\n if (currentOrgId) {\n try {\n domain = (await getOrgDomain(currentOrgId)) ?? undefined;\n } catch {}\n try {\n orgSecret = (await getOrgA2ASecret(currentOrgId)) ?? undefined;\n } catch {}\n }\n const response = await callAgent(agent.url, messageWithHint, {\n userEmail: email,\n orgDomain: domain,\n orgSecret,\n });\n return expandRelativeUrls(response, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n // Friendlier message for the common timeout case so the calling agent can\n // decide whether to give up or retry.\n if (/timeout|did not complete|Inactivity|504/i.test(msg)) {\n return `The ${agent.name} agent is taking longer than expected. Please try again, ask a simpler question, or open the ${agent.name} app directly.`;\n }\n return `Error calling ${agent.name}: ${msg}`;\n }\n}\n\nasync function enqueueIntegrationContinuationIfPossible(\n error: A2ATaskTimeoutError,\n agent: { name: string; url: string },\n ownerEmail: string | undefined,\n): Promise<boolean> {\n const integration = getIntegrationRequestContext();\n if (!integration || !ownerEmail) return false;\n\n try {\n const [{ insertA2AContinuation }, { dispatchA2AContinuation }] =\n await Promise.all([\n import(\"../integrations/a2a-continuations-store.js\"),\n import(\"../integrations/a2a-continuation-processor.js\"),\n ]);\n const continuation = await insertA2AContinuation({\n integrationTaskId: integration.taskId,\n platform: integration.incoming.platform,\n externalThreadId: integration.incoming.externalThreadId,\n incoming: integration.incoming,\n placeholderRef: integration.placeholderRef,\n ownerEmail,\n orgId: getRequestOrgId() ?? null,\n agentName: agent.name,\n agentUrl: agent.url,\n a2aTaskId: error.taskId,\n // Do not persist the short-lived JWT used for the initial send. The\n // continuation processor can mint a fresh token for each poll.\n a2aAuthToken: null,\n });\n await dispatchA2AContinuation(continuation.id).catch((err) => {\n console.error(\n `[call-agent] Failed to dispatch A2A continuation ${continuation.id}:`,\n err,\n );\n });\n return true;\n } catch (err) {\n console.error(\"[call-agent] Failed to enqueue A2A continuation:\", err);\n return false;\n }\n}\n\n// Expand bare leading-slash paths (e.g. \"/deck/abc\") into fully-qualified URLs\n// rooted at the receiving agent's host. The receiver doesn't always know it's\n// being called cross-app, so it may emit relative paths that resolve against\n// the caller's host (broken). Match a path that starts at a word boundary,\n// begins with `/`, and has at least one path segment after that. Skip if it\n// already looks like a fully-qualified URL.\nexport function expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n // Path must start at boundary (start, whitespace, or punctuation that isn't\n // ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).\n return text.replace(\n /(^|[\\s(\\[<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
|