@agent-native/core 0.7.78 → 0.7.79
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/integrations/a2a-continuations-store.d.ts +3 -0
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +30 -2
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +2 -0
- 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 +32 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/request-context.d.ts +1 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ export interface A2AContinuation {
|
|
|
11
11
|
orgId: string | null;
|
|
12
12
|
agentName: string;
|
|
13
13
|
agentUrl: string;
|
|
14
|
+
dedupeKey: string | null;
|
|
14
15
|
a2aTaskId: string;
|
|
15
16
|
a2aAuthToken: string | null;
|
|
16
17
|
status: A2AContinuationStatus;
|
|
@@ -31,10 +32,12 @@ export declare function insertA2AContinuation(input: {
|
|
|
31
32
|
orgId?: string | null;
|
|
32
33
|
agentName: string;
|
|
33
34
|
agentUrl: string;
|
|
35
|
+
dedupeKey?: string | null;
|
|
34
36
|
a2aTaskId: string;
|
|
35
37
|
a2aAuthToken?: string | null;
|
|
36
38
|
}): Promise<A2AContinuation>;
|
|
37
39
|
export declare function getA2AContinuationForIntegrationTask(integrationTaskId: string): Promise<A2AContinuation | null>;
|
|
40
|
+
export declare function getA2AContinuationsForIntegrationTaskAgent(integrationTaskId: string, agentUrl: string, dedupeKey?: string | null): Promise<A2AContinuation[]>;
|
|
38
41
|
export declare function getA2AContinuation(id: string): Promise<A2AContinuation | null>;
|
|
39
42
|
export declare function claimA2AContinuation(id: string): Promise<A2AContinuation | null>;
|
|
40
43
|
export declare function claimDueA2AContinuations(limit?: number): Promise<A2AContinuation[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a2a-continuations-store.d.ts","sourceRoot":"","sources":["../../src/integrations/a2a-continuations-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"a2a-continuations-store.d.ts","sourceRoot":"","sources":["../../src/integrations/a2a-continuations-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAiElD,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,WAAW,GACX,QAAQ,CAAC;AAEb,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA4BD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,eAAe,CAAC,CA8C3B;AAED,wBAAsB,oCAAoC,CACxD,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAWjC;AAED,wBAAsB,0CAA0C,CAC9D,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,eAAe,EAAE,CAAC,CAmB5B;AA8BD,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAQjC;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA0CjC;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,SAAI,GACR,OAAO,CAAC,eAAe,EAAE,CAAC,CAmC5B;AAED,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA0BjC;AAED,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
|
@@ -18,6 +18,7 @@ async function ensureTable() {
|
|
|
18
18
|
org_id TEXT,
|
|
19
19
|
agent_name TEXT NOT NULL,
|
|
20
20
|
agent_url TEXT NOT NULL,
|
|
21
|
+
dedupe_key TEXT,
|
|
21
22
|
a2a_task_id TEXT NOT NULL,
|
|
22
23
|
a2a_auth_token TEXT,
|
|
23
24
|
status TEXT NOT NULL,
|
|
@@ -32,12 +33,19 @@ async function ensureTable() {
|
|
|
32
33
|
await client.execute(`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`);
|
|
33
34
|
await client.execute(`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_integration_task ON integration_a2a_continuations(integration_task_id)`);
|
|
34
35
|
await client.execute(`CREATE UNIQUE INDEX IF NOT EXISTS idx_a2a_continuations_remote_task ON integration_a2a_continuations(integration_task_id, agent_url, a2a_task_id)`);
|
|
36
|
+
await client.execute(`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_dedupe_key ON integration_a2a_continuations(integration_task_id, agent_url, dedupe_key)`);
|
|
35
37
|
try {
|
|
36
38
|
await client.execute(`ALTER TABLE integration_a2a_continuations ADD COLUMN a2a_auth_token TEXT`);
|
|
37
39
|
}
|
|
38
40
|
catch {
|
|
39
41
|
// Column already exists.
|
|
40
42
|
}
|
|
43
|
+
try {
|
|
44
|
+
await client.execute(`ALTER TABLE integration_a2a_continuations ADD COLUMN dedupe_key TEXT`);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Column already exists.
|
|
48
|
+
}
|
|
41
49
|
})();
|
|
42
50
|
}
|
|
43
51
|
return _initPromise;
|
|
@@ -54,6 +62,7 @@ function rowToContinuation(row) {
|
|
|
54
62
|
orgId: row.org_id ?? null,
|
|
55
63
|
agentName: row.agent_name,
|
|
56
64
|
agentUrl: row.agent_url,
|
|
65
|
+
dedupeKey: row.dedupe_key ?? null,
|
|
57
66
|
a2aTaskId: row.a2a_task_id,
|
|
58
67
|
a2aAuthToken: row.a2a_auth_token ?? null,
|
|
59
68
|
status: row.status,
|
|
@@ -75,9 +84,9 @@ export async function insertA2AContinuation(input) {
|
|
|
75
84
|
await client.execute({
|
|
76
85
|
sql: `INSERT INTO integration_a2a_continuations
|
|
77
86
|
(id, integration_task_id, platform, external_thread_id, incoming_payload,
|
|
78
|
-
placeholder_ref, owner_email, org_id, agent_name, agent_url, a2a_task_id, a2a_auth_token,
|
|
87
|
+
placeholder_ref, owner_email, org_id, agent_name, agent_url, dedupe_key, a2a_task_id, a2a_auth_token,
|
|
79
88
|
status, attempts, next_check_at, created_at, updated_at)
|
|
80
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
89
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
81
90
|
args: [
|
|
82
91
|
id,
|
|
83
92
|
input.integrationTaskId,
|
|
@@ -89,6 +98,7 @@ export async function insertA2AContinuation(input) {
|
|
|
89
98
|
input.orgId ?? null,
|
|
90
99
|
input.agentName,
|
|
91
100
|
input.agentUrl,
|
|
101
|
+
input.dedupeKey ?? null,
|
|
92
102
|
input.a2aTaskId,
|
|
93
103
|
input.a2aAuthToken ?? null,
|
|
94
104
|
"pending",
|
|
@@ -121,6 +131,24 @@ export async function getA2AContinuationForIntegrationTask(integrationTaskId) {
|
|
|
121
131
|
});
|
|
122
132
|
return rows[0] ? rowToContinuation(rows[0]) : null;
|
|
123
133
|
}
|
|
134
|
+
export async function getA2AContinuationsForIntegrationTaskAgent(integrationTaskId, agentUrl, dedupeKey) {
|
|
135
|
+
await ensureTable();
|
|
136
|
+
const client = getDbExec();
|
|
137
|
+
const { rows } = await client.execute(dedupeKey
|
|
138
|
+
? {
|
|
139
|
+
sql: `SELECT * FROM integration_a2a_continuations
|
|
140
|
+
WHERE integration_task_id = ? AND agent_url = ? AND dedupe_key = ?
|
|
141
|
+
ORDER BY created_at ASC`,
|
|
142
|
+
args: [integrationTaskId, agentUrl, dedupeKey],
|
|
143
|
+
}
|
|
144
|
+
: {
|
|
145
|
+
sql: `SELECT * FROM integration_a2a_continuations
|
|
146
|
+
WHERE integration_task_id = ? AND agent_url = ?
|
|
147
|
+
ORDER BY created_at ASC`,
|
|
148
|
+
args: [integrationTaskId, agentUrl],
|
|
149
|
+
});
|
|
150
|
+
return rows.map((row) => rowToContinuation(row));
|
|
151
|
+
}
|
|
124
152
|
function isDuplicateContinuationError(err) {
|
|
125
153
|
const e = err;
|
|
126
154
|
if (!e)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a2a-continuations-store.js","sourceRoot":"","sources":["../../src/integrations/a2a-continuations-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec, isPostgres, intType } from \"../db/client.js\";\nimport type { IncomingMessage } from \"./types.js\";\n\nlet _initPromise: Promise<void> | undefined;\nconst PROCESSING_STUCK_AFTER_MS = 5 * 60 * 1000;\nconst PROCESSING_NEXT_CHECK_STALE_AFTER_MS = 60 * 1000;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n await client.execute(`\n CREATE TABLE IF NOT EXISTS integration_a2a_continuations (\n id TEXT PRIMARY KEY,\n integration_task_id TEXT NOT NULL,\n platform TEXT NOT NULL,\n external_thread_id TEXT NOT NULL,\n incoming_payload TEXT NOT NULL,\n placeholder_ref TEXT,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n agent_name TEXT NOT NULL,\n agent_url TEXT NOT NULL,\n a2a_task_id TEXT NOT NULL,\n a2a_auth_token TEXT,\n status TEXT NOT NULL,\n attempts ${intType()} NOT NULL DEFAULT 0,\n next_check_at ${intType()} NOT NULL,\n error_message TEXT,\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL,\n completed_at ${intType()}\n )\n `);\n await client.execute(\n `CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`,\n );\n await client.execute(\n `CREATE INDEX IF NOT EXISTS idx_a2a_continuations_integration_task ON integration_a2a_continuations(integration_task_id)`,\n );\n await client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_a2a_continuations_remote_task ON integration_a2a_continuations(integration_task_id, agent_url, a2a_task_id)`,\n );\n try {\n await client.execute(\n `ALTER TABLE integration_a2a_continuations ADD COLUMN a2a_auth_token TEXT`,\n );\n } catch {\n // Column already exists.\n }\n })();\n }\n return _initPromise;\n}\n\nexport type A2AContinuationStatus =\n | \"pending\"\n | \"processing\"\n | \"delivering\"\n | \"completed\"\n | \"failed\";\n\nexport interface A2AContinuation {\n id: string;\n integrationTaskId: string;\n platform: string;\n externalThreadId: string;\n incoming: IncomingMessage;\n placeholderRef: string | null;\n ownerEmail: string;\n orgId: string | null;\n agentName: string;\n agentUrl: string;\n a2aTaskId: string;\n a2aAuthToken: string | null;\n status: A2AContinuationStatus;\n attempts: number;\n nextCheckAt: number;\n errorMessage: string | null;\n createdAt: number;\n updatedAt: number;\n completedAt: number | null;\n}\n\nfunction rowToContinuation(row: Record<string, unknown>): A2AContinuation {\n return {\n id: row.id as string,\n integrationTaskId: row.integration_task_id as string,\n platform: row.platform as string,\n externalThreadId: row.external_thread_id as string,\n incoming: JSON.parse(row.incoming_payload as string) as IncomingMessage,\n placeholderRef: (row.placeholder_ref as string | null) ?? null,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n agentName: row.agent_name as string,\n agentUrl: row.agent_url as string,\n a2aTaskId: row.a2a_task_id as string,\n a2aAuthToken: (row.a2a_auth_token as string | null) ?? null,\n status: row.status as A2AContinuationStatus,\n attempts: Number(row.attempts ?? 0),\n nextCheckAt: Number(row.next_check_at ?? 0),\n errorMessage: (row.error_message as string | null) ?? null,\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n completedAt:\n row.completed_at == null ? null : Number(row.completed_at as number),\n };\n}\n\nexport async function insertA2AContinuation(input: {\n integrationTaskId: string;\n platform: string;\n externalThreadId: string;\n incoming: IncomingMessage;\n placeholderRef?: string | null;\n ownerEmail: string;\n orgId?: string | null;\n agentName: string;\n agentUrl: string;\n a2aTaskId: string;\n a2aAuthToken?: string | null;\n}): Promise<A2AContinuation> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const id = `a2a-cont-${now}-${Math.random().toString(36).slice(2, 8)}`;\n const payload = JSON.stringify(input.incoming);\n\n try {\n await client.execute({\n sql: `INSERT INTO integration_a2a_continuations\n (id, integration_task_id, platform, external_thread_id, incoming_payload,\n placeholder_ref, owner_email, org_id, agent_name, agent_url, a2a_task_id, a2a_auth_token,\n status, attempts, next_check_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.integrationTaskId,\n input.platform,\n input.externalThreadId,\n payload,\n input.placeholderRef ?? null,\n input.ownerEmail,\n input.orgId ?? null,\n input.agentName,\n input.agentUrl,\n input.a2aTaskId,\n input.a2aAuthToken ?? null,\n \"pending\",\n 0,\n now,\n now,\n now,\n ],\n });\n return (await getA2AContinuation(id))!;\n } catch (err: any) {\n if (!isDuplicateContinuationError(err)) throw err;\n const existing = await findA2AContinuation(\n input.integrationTaskId,\n input.agentUrl,\n input.a2aTaskId,\n );\n if (existing) return existing;\n throw err;\n }\n}\n\nexport async function getA2AContinuationForIntegrationTask(\n integrationTaskId: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ?\n ORDER BY created_at ASC\n LIMIT 1`,\n args: [integrationTaskId],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nfunction isDuplicateContinuationError(err: unknown): boolean {\n const e = err as { code?: string; message?: string } | null;\n if (!e) return false;\n if (e.code === \"23505\") return true;\n const msg = String(e.message ?? \"\").toLowerCase();\n return (\n msg.includes(\"unique\") ||\n msg.includes(\"duplicate entry\") ||\n msg.includes(\"duplicate key\")\n );\n}\n\nasync function findA2AContinuation(\n integrationTaskId: string,\n agentUrl: string,\n a2aTaskId: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ? AND agent_url = ? AND a2a_task_id = ?\n LIMIT 1`,\n args: [integrationTaskId, agentUrl, a2aTaskId],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function getA2AContinuation(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations WHERE id = ? LIMIT 1`,\n args: [id],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function claimA2AContinuation(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const processingCutoff = now - PROCESSING_STUCK_AFTER_MS;\n const staleNextCheckCutoff = now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS;\n const result = await client.execute({\n sql: isPostgres()\n ? `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ?\n AND (\n status = 'pending'\n OR (\n status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)\n )\n )\n RETURNING *`\n : `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ?\n AND (\n status = 'pending'\n OR (\n status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)\n )\n )`,\n args: [\"processing\", now, id, processingCutoff, staleNextCheckCutoff],\n });\n const rows = result.rows ?? [];\n if (isPostgres()) {\n return rows[0]\n ? rowToContinuation(rows[0] as Record<string, unknown>)\n : null;\n }\n const affected = (result as any)?.rowsAffected ?? (result as any)?.rowCount;\n if (affected === 0) return null;\n const fetched = await getA2AContinuation(id);\n if (!fetched || fetched.status !== \"processing\") return null;\n return fetched;\n}\n\nexport async function claimDueA2AContinuations(\n limit = 5,\n): Promise<A2AContinuation[]> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const processingCutoff = now - PROCESSING_STUCK_AFTER_MS;\n const staleNextCheckCutoff = now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS;\n // If a processor dies while holding a delivery claim, retry the final send.\n // The stale cutoff preserves the in-flight delivery guard while keeping\n // final integration replies at-least-once.\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE status = 'delivering' AND updated_at <= ?`,\n args: [\"pending\", now, now, now - 5 * 60 * 1000],\n });\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)`,\n args: [\"pending\", now, now, processingCutoff, staleNextCheckCutoff],\n });\n const { rows } = await client.execute({\n sql: `SELECT id FROM integration_a2a_continuations\n WHERE status = 'pending' AND next_check_at <= ?\n ORDER BY next_check_at ASC\n LIMIT ?`,\n args: [now, limit],\n });\n const claimed: A2AContinuation[] = [];\n for (const row of rows) {\n const continuation = await claimA2AContinuation(row.id as string);\n if (continuation) claimed.push(continuation);\n }\n return claimed;\n}\n\nexport async function claimA2AContinuationDelivery(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: isPostgres()\n ? `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?\n WHERE id = ? AND status = 'processing'\n RETURNING *`\n : `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?\n WHERE id = ? AND status = 'processing'`,\n args: [\"delivering\", now, id],\n });\n const rows = result.rows ?? [];\n if (isPostgres()) {\n return rows[0]\n ? rowToContinuation(rows[0] as Record<string, unknown>)\n : null;\n }\n const affected = (result as any)?.rowsAffected ?? (result as any)?.rowCount;\n if (affected === 0) return null;\n const fetched = await getA2AContinuation(id);\n if (!fetched || fetched.status !== \"delivering\") return null;\n return fetched;\n}\n\nexport async function rescheduleA2AContinuation(\n id: string,\n delayMs: number,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE id = ? AND status IN ('processing', 'delivering')`,\n args: [\"pending\", now + delayMs, now, id],\n });\n}\n\nexport async function completeA2AContinuation(id: string): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?, completed_at = ?\n WHERE id = ? AND status IN ('processing', 'delivering', 'completed')`,\n args: [\"completed\", now, now, id],\n });\n}\n\nexport async function failA2AContinuation(\n id: string,\n errorMessage: string,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?, error_message = ?\n WHERE id = ? AND status <> 'completed'`,\n args: [\"failed\", now, errorMessage.slice(0, 2000), id],\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"a2a-continuations-store.js","sourceRoot":"","sources":["../../src/integrations/a2a-continuations-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec, isPostgres, intType } from \"../db/client.js\";\nimport type { IncomingMessage } from \"./types.js\";\n\nlet _initPromise: Promise<void> | undefined;\nconst PROCESSING_STUCK_AFTER_MS = 5 * 60 * 1000;\nconst PROCESSING_NEXT_CHECK_STALE_AFTER_MS = 60 * 1000;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n await client.execute(`\n CREATE TABLE IF NOT EXISTS integration_a2a_continuations (\n id TEXT PRIMARY KEY,\n integration_task_id TEXT NOT NULL,\n platform TEXT NOT NULL,\n external_thread_id TEXT NOT NULL,\n incoming_payload TEXT NOT NULL,\n placeholder_ref TEXT,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n agent_name TEXT NOT NULL,\n agent_url TEXT NOT NULL,\n dedupe_key TEXT,\n a2a_task_id TEXT NOT NULL,\n a2a_auth_token TEXT,\n status TEXT NOT NULL,\n attempts ${intType()} NOT NULL DEFAULT 0,\n next_check_at ${intType()} NOT NULL,\n error_message TEXT,\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL,\n completed_at ${intType()}\n )\n `);\n await client.execute(\n `CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`,\n );\n await client.execute(\n `CREATE INDEX IF NOT EXISTS idx_a2a_continuations_integration_task ON integration_a2a_continuations(integration_task_id)`,\n );\n await client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_a2a_continuations_remote_task ON integration_a2a_continuations(integration_task_id, agent_url, a2a_task_id)`,\n );\n await client.execute(\n `CREATE INDEX IF NOT EXISTS idx_a2a_continuations_dedupe_key ON integration_a2a_continuations(integration_task_id, agent_url, dedupe_key)`,\n );\n try {\n await client.execute(\n `ALTER TABLE integration_a2a_continuations ADD COLUMN a2a_auth_token TEXT`,\n );\n } catch {\n // Column already exists.\n }\n try {\n await client.execute(\n `ALTER TABLE integration_a2a_continuations ADD COLUMN dedupe_key TEXT`,\n );\n } catch {\n // Column already exists.\n }\n })();\n }\n return _initPromise;\n}\n\nexport type A2AContinuationStatus =\n | \"pending\"\n | \"processing\"\n | \"delivering\"\n | \"completed\"\n | \"failed\";\n\nexport interface A2AContinuation {\n id: string;\n integrationTaskId: string;\n platform: string;\n externalThreadId: string;\n incoming: IncomingMessage;\n placeholderRef: string | null;\n ownerEmail: string;\n orgId: string | null;\n agentName: string;\n agentUrl: string;\n dedupeKey: string | null;\n a2aTaskId: string;\n a2aAuthToken: string | null;\n status: A2AContinuationStatus;\n attempts: number;\n nextCheckAt: number;\n errorMessage: string | null;\n createdAt: number;\n updatedAt: number;\n completedAt: number | null;\n}\n\nfunction rowToContinuation(row: Record<string, unknown>): A2AContinuation {\n return {\n id: row.id as string,\n integrationTaskId: row.integration_task_id as string,\n platform: row.platform as string,\n externalThreadId: row.external_thread_id as string,\n incoming: JSON.parse(row.incoming_payload as string) as IncomingMessage,\n placeholderRef: (row.placeholder_ref as string | null) ?? null,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n agentName: row.agent_name as string,\n agentUrl: row.agent_url as string,\n dedupeKey: (row.dedupe_key as string | null) ?? null,\n a2aTaskId: row.a2a_task_id as string,\n a2aAuthToken: (row.a2a_auth_token as string | null) ?? null,\n status: row.status as A2AContinuationStatus,\n attempts: Number(row.attempts ?? 0),\n nextCheckAt: Number(row.next_check_at ?? 0),\n errorMessage: (row.error_message as string | null) ?? null,\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n completedAt:\n row.completed_at == null ? null : Number(row.completed_at as number),\n };\n}\n\nexport async function insertA2AContinuation(input: {\n integrationTaskId: string;\n platform: string;\n externalThreadId: string;\n incoming: IncomingMessage;\n placeholderRef?: string | null;\n ownerEmail: string;\n orgId?: string | null;\n agentName: string;\n agentUrl: string;\n dedupeKey?: string | null;\n a2aTaskId: string;\n a2aAuthToken?: string | null;\n}): Promise<A2AContinuation> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const id = `a2a-cont-${now}-${Math.random().toString(36).slice(2, 8)}`;\n const payload = JSON.stringify(input.incoming);\n\n try {\n await client.execute({\n sql: `INSERT INTO integration_a2a_continuations\n (id, integration_task_id, platform, external_thread_id, incoming_payload,\n placeholder_ref, owner_email, org_id, agent_name, agent_url, dedupe_key, a2a_task_id, a2a_auth_token,\n status, attempts, next_check_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.integrationTaskId,\n input.platform,\n input.externalThreadId,\n payload,\n input.placeholderRef ?? null,\n input.ownerEmail,\n input.orgId ?? null,\n input.agentName,\n input.agentUrl,\n input.dedupeKey ?? null,\n input.a2aTaskId,\n input.a2aAuthToken ?? null,\n \"pending\",\n 0,\n now,\n now,\n now,\n ],\n });\n return (await getA2AContinuation(id))!;\n } catch (err: any) {\n if (!isDuplicateContinuationError(err)) throw err;\n const existing = await findA2AContinuation(\n input.integrationTaskId,\n input.agentUrl,\n input.a2aTaskId,\n );\n if (existing) return existing;\n throw err;\n }\n}\n\nexport async function getA2AContinuationForIntegrationTask(\n integrationTaskId: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ?\n ORDER BY created_at ASC\n LIMIT 1`,\n args: [integrationTaskId],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function getA2AContinuationsForIntegrationTaskAgent(\n integrationTaskId: string,\n agentUrl: string,\n dedupeKey?: string | null,\n): Promise<A2AContinuation[]> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute(\n dedupeKey\n ? {\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ? AND agent_url = ? AND dedupe_key = ?\n ORDER BY created_at ASC`,\n args: [integrationTaskId, agentUrl, dedupeKey],\n }\n : {\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ? AND agent_url = ?\n ORDER BY created_at ASC`,\n args: [integrationTaskId, agentUrl],\n },\n );\n return rows.map((row) => rowToContinuation(row as Record<string, unknown>));\n}\n\nfunction isDuplicateContinuationError(err: unknown): boolean {\n const e = err as { code?: string; message?: string } | null;\n if (!e) return false;\n if (e.code === \"23505\") return true;\n const msg = String(e.message ?? \"\").toLowerCase();\n return (\n msg.includes(\"unique\") ||\n msg.includes(\"duplicate entry\") ||\n msg.includes(\"duplicate key\")\n );\n}\n\nasync function findA2AContinuation(\n integrationTaskId: string,\n agentUrl: string,\n a2aTaskId: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations\n WHERE integration_task_id = ? AND agent_url = ? AND a2a_task_id = ?\n LIMIT 1`,\n args: [integrationTaskId, agentUrl, a2aTaskId],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function getA2AContinuation(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_a2a_continuations WHERE id = ? LIMIT 1`,\n args: [id],\n });\n return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function claimA2AContinuation(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const processingCutoff = now - PROCESSING_STUCK_AFTER_MS;\n const staleNextCheckCutoff = now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS;\n const result = await client.execute({\n sql: isPostgres()\n ? `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ?\n AND (\n status = 'pending'\n OR (\n status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)\n )\n )\n RETURNING *`\n : `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ?\n AND (\n status = 'pending'\n OR (\n status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)\n )\n )`,\n args: [\"processing\", now, id, processingCutoff, staleNextCheckCutoff],\n });\n const rows = result.rows ?? [];\n if (isPostgres()) {\n return rows[0]\n ? rowToContinuation(rows[0] as Record<string, unknown>)\n : null;\n }\n const affected = (result as any)?.rowsAffected ?? (result as any)?.rowCount;\n if (affected === 0) return null;\n const fetched = await getA2AContinuation(id);\n if (!fetched || fetched.status !== \"processing\") return null;\n return fetched;\n}\n\nexport async function claimDueA2AContinuations(\n limit = 5,\n): Promise<A2AContinuation[]> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const processingCutoff = now - PROCESSING_STUCK_AFTER_MS;\n const staleNextCheckCutoff = now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS;\n // If a processor dies while holding a delivery claim, retry the final send.\n // The stale cutoff preserves the in-flight delivery guard while keeping\n // final integration replies at-least-once.\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE status = 'delivering' AND updated_at <= ?`,\n args: [\"pending\", now, now, now - 5 * 60 * 1000],\n });\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE status = 'processing'\n AND (updated_at <= ? OR next_check_at <= ?)`,\n args: [\"pending\", now, now, processingCutoff, staleNextCheckCutoff],\n });\n const { rows } = await client.execute({\n sql: `SELECT id FROM integration_a2a_continuations\n WHERE status = 'pending' AND next_check_at <= ?\n ORDER BY next_check_at ASC\n LIMIT ?`,\n args: [now, limit],\n });\n const claimed: A2AContinuation[] = [];\n for (const row of rows) {\n const continuation = await claimA2AContinuation(row.id as string);\n if (continuation) claimed.push(continuation);\n }\n return claimed;\n}\n\nexport async function claimA2AContinuationDelivery(\n id: string,\n): Promise<A2AContinuation | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: isPostgres()\n ? `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?\n WHERE id = ? AND status = 'processing'\n RETURNING *`\n : `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?\n WHERE id = ? AND status = 'processing'`,\n args: [\"delivering\", now, id],\n });\n const rows = result.rows ?? [];\n if (isPostgres()) {\n return rows[0]\n ? rowToContinuation(rows[0] as Record<string, unknown>)\n : null;\n }\n const affected = (result as any)?.rowsAffected ?? (result as any)?.rowCount;\n if (affected === 0) return null;\n const fetched = await getA2AContinuation(id);\n if (!fetched || fetched.status !== \"delivering\") return null;\n return fetched;\n}\n\nexport async function rescheduleA2AContinuation(\n id: string,\n delayMs: number,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE id = ? AND status IN ('processing', 'delivering')`,\n args: [\"pending\", now + delayMs, now, id],\n });\n}\n\nexport async function completeA2AContinuation(id: string): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?, completed_at = ?\n WHERE id = ? AND status IN ('processing', 'delivering', 'completed')`,\n args: [\"completed\", now, now, id],\n });\n}\n\nexport async function failA2AContinuation(\n id: string,\n errorMessage: string,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, updated_at = ?, error_message = ?\n WHERE id = ? AND status <> 'completed'`,\n args: [\"failed\", now, errorMessage.slice(0, 2000), id],\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-handler.d.ts","sourceRoot":"","sources":["../../src/integrations/webhook-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGnE,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAU5D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AA+BlC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,CAAC,EACH,WAAW,GACX,MAAM,GACN;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IACtD,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,yEAAyE;IACzE,aAAa,CAAC,EAAE,CACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,eAAe,KACrB,OAAO,CACR;QACE,OAAO,EAAE,IAAI,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACD;QAAE,OAAO,EAAE,KAAK,CAAA;KAAE,CACrB,CAAC;CACH;AAmDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAsE5C;AAgHD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2BrD;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"webhook-handler.d.ts","sourceRoot":"","sources":["../../src/integrations/webhook-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGnE,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAU5D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AA+BlC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,CAAC,EACH,WAAW,GACX,MAAM,GACN;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IACtD,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,yEAAyE;IACzE,aAAa,CAAC,EAAE,CACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,eAAe,KACrB,OAAO,CACR;QACE,OAAO,EAAE,IAAI,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACD;QAAE,OAAO,EAAE,KAAK,CAAA;KAAE,CACrB,CAAC;CACH;AAmDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAsE5C;AAgHD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2BrD;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
|
@@ -287,6 +287,7 @@ export async function processIntegrationTask(task, options) {
|
|
|
287
287
|
const parsed = JSON.parse(task.payload);
|
|
288
288
|
await processIncomingMessage(parsed.incoming, options, {
|
|
289
289
|
taskId: task.id,
|
|
290
|
+
attempts: task.attempts,
|
|
290
291
|
placeholderRef: parsed.placeholderRef,
|
|
291
292
|
});
|
|
292
293
|
}
|
|
@@ -384,6 +385,7 @@ async function processIncomingMessage(incoming, options, opts = {}) {
|
|
|
384
385
|
integration: opts.taskId
|
|
385
386
|
? {
|
|
386
387
|
taskId: opts.taskId,
|
|
388
|
+
attempts: opts.attempts,
|
|
387
389
|
incoming,
|
|
388
390
|
placeholderRef: opts.placeholderRef,
|
|
389
391
|
}
|
|
@@ -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\";\nimport {\n appendA2AArtifactLinks,\n type A2AToolResultSummary,\n} from \"../a2a/artifact-response.js\";\nimport { buildRuntimeContextPrompt } from \"../agent/runtime-context.js\";\n\nconst PROCESSOR_DISPATCH_SETTLE_WAIT_MS = 1_500;\n\ntype ToolDoneEvent = { type: \"tool_done\"; tool: string; result: string };\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\nfunction collectToolResultSummaries(\n completedRun: ActiveRun,\n): A2AToolResultSummary[] {\n return completedRun.events\n .map((runEvent) => runEvent.event)\n .filter((event): event is ToolDoneEvent => event.type === \"tool_done\")\n .map((event) => ({ tool: event.tool, result: event.result }));\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\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 const effectiveSystemPrompt = systemPrompt + buildRuntimeContextPrompt();\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: effectiveSystemPrompt,\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 if (!queuedA2AContinuation && !responseText.trim()) {\n const recoverableA2AArtifactText =\n extractRecoverableA2AArtifactToolResult(completedRun);\n if (recoverableA2AArtifactText) {\n responseText = recoverableA2AArtifactText;\n }\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 if (!suppressPlatformReply) {\n responseText = appendA2AArtifactLinks(\n responseText,\n collectToolResultSummaries(completedRun),\n { baseUrl: appBaseUrl || undefined },\n );\n }\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 extractRecoverableA2AArtifactToolResult(\n completedRun: ActiveRun,\n): string | null {\n for (let i = completedRun.events.length - 1; i >= 0; i--) {\n const event = completedRun.events[i].event;\n if (event.type !== \"tool_done\" || event.tool !== \"call-agent\") continue;\n\n const result = String(event.result ?? \"\").trim();\n if (\n result.includes(\"verified artifacts already exist\") &&\n result.includes(\"\\nArtifacts:\\n\")\n ) {\n return result;\n }\n }\n return null;\n}\n\nfunction isQueuedA2AContinuationDeferral(text: string): boolean {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) return true;\n if (hasSubstantiveA2APartialAnswer(text)) return false;\n if (normalized.includes(A2A_CONTINUATION_QUEUED_MARKER)) return true;\n return /\\b(?:still (?:working|processing)|is working on|taking longer than expected|will (?:post|update|surface|show up)|(?:it'?ll|it will|the result will|the final result will) (?:post|be posted|update|be updated|surface|show up)|will be (?:posted|updated|sent|shared)|final result when it finishes|while you wait|as soon as (?:it|it'?s|it is|the result|the artifact) (?:comes back|is ready|ready)|hang tight|relay from the .* agent)\\b/i.test(\n normalized,\n );\n}\n\nfunction hasSubstantiveA2APartialAnswer(text: string): boolean {\n const withoutMarker = text\n .replaceAll(A2A_CONTINUATION_QUEUED_MARKER, \"\")\n .trim();\n if (!withoutMarker) return false;\n if (/https?:\\/\\//i.test(withoutMarker)) return true;\n if (/\\|\\s*[-:]+\\s*\\|/.test(withoutMarker)) return true;\n if (\n /\\b(?:page\\s*views?|unique\\s+visitors?|dashboard|artifact id|document id|deck id|source|query|bigquery|created successfully)\\b/i.test(\n withoutMarker,\n )\n ) {\n return true;\n }\n return false;\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\";\nimport {\n appendA2AArtifactLinks,\n type A2AToolResultSummary,\n} from \"../a2a/artifact-response.js\";\nimport { buildRuntimeContextPrompt } from \"../agent/runtime-context.js\";\n\nconst PROCESSOR_DISPATCH_SETTLE_WAIT_MS = 1_500;\n\ntype ToolDoneEvent = { type: \"tool_done\"; tool: string; result: string };\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\nfunction collectToolResultSummaries(\n completedRun: ActiveRun,\n): A2AToolResultSummary[] {\n return completedRun.events\n .map((runEvent) => runEvent.event)\n .filter((event): event is ToolDoneEvent => event.type === \"tool_done\")\n .map((event) => ({ tool: event.tool, result: event.result }));\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\n await processIncomingMessage(parsed.incoming, options, {\n taskId: task.id,\n attempts: task.attempts,\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; attempts?: number; 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 const effectiveSystemPrompt = systemPrompt + buildRuntimeContextPrompt();\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 attempts: opts.attempts,\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: effectiveSystemPrompt,\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 if (!queuedA2AContinuation && !responseText.trim()) {\n const recoverableA2AArtifactText =\n extractRecoverableA2AArtifactToolResult(completedRun);\n if (recoverableA2AArtifactText) {\n responseText = recoverableA2AArtifactText;\n }\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 if (!suppressPlatformReply) {\n responseText = appendA2AArtifactLinks(\n responseText,\n collectToolResultSummaries(completedRun),\n { baseUrl: appBaseUrl || undefined },\n );\n }\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 extractRecoverableA2AArtifactToolResult(\n completedRun: ActiveRun,\n): string | null {\n for (let i = completedRun.events.length - 1; i >= 0; i--) {\n const event = completedRun.events[i].event;\n if (event.type !== \"tool_done\" || event.tool !== \"call-agent\") continue;\n\n const result = String(event.result ?? \"\").trim();\n if (\n result.includes(\"verified artifacts already exist\") &&\n result.includes(\"\\nArtifacts:\\n\")\n ) {\n return result;\n }\n }\n return null;\n}\n\nfunction isQueuedA2AContinuationDeferral(text: string): boolean {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) return true;\n if (hasSubstantiveA2APartialAnswer(text)) return false;\n if (normalized.includes(A2A_CONTINUATION_QUEUED_MARKER)) return true;\n return /\\b(?:still (?:working|processing)|is working on|taking longer than expected|will (?:post|update|surface|show up)|(?:it'?ll|it will|the result will|the final result will) (?:post|be posted|update|be updated|surface|show up)|will be (?:posted|updated|sent|shared)|final result when it finishes|while you wait|as soon as (?:it|it'?s|it is|the result|the artifact) (?:comes back|is ready|ready)|hang tight|relay from the .* agent)\\b/i.test(\n normalized,\n );\n}\n\nfunction hasSubstantiveA2APartialAnswer(text: string): boolean {\n const withoutMarker = text\n .replaceAll(A2A_CONTINUATION_QUEUED_MARKER, \"\")\n .trim();\n if (!withoutMarker) return false;\n if (/https?:\\/\\//i.test(withoutMarker)) return true;\n if (/\\|\\s*[-:]+\\s*\\|/.test(withoutMarker)) return true;\n if (\n /\\b(?:page\\s*views?|unique\\s+visitors?|dashboard|artifact id|document id|deck id|source|query|bigquery|created successfully)\\b/i.test(\n withoutMarker,\n )\n ) {\n return true;\n }\n return false;\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;
|
|
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;AAuErE,eAAO,MAAM,IAAI,EAAE,UAsBlB,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,CA2NjB;AAgGD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASzE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { findAgent, discoverAgents } from "../server/agent-discovery.js";
|
|
2
3
|
import { A2AClient, A2ATaskTimeoutError, callAgent, signA2AToken, } from "../a2a/client.js";
|
|
3
4
|
import { A2A_CONTINUATION_QUEUED_MARKER } from "../integrations/a2a-continuation-marker.js";
|
|
@@ -143,6 +144,9 @@ export async function run(args, context, selfAppId) {
|
|
|
143
144
|
}
|
|
144
145
|
let responseText = "";
|
|
145
146
|
let lastSentLength = 0;
|
|
147
|
+
const existingContinuationText = await formatExistingIntegrationContinuationIfRetry(agent, message);
|
|
148
|
+
if (existingContinuationText)
|
|
149
|
+
return existingContinuationText;
|
|
146
150
|
context.send({
|
|
147
151
|
type: "agent_call",
|
|
148
152
|
agent: agent.name,
|
|
@@ -198,7 +202,7 @@ export async function run(args, context, selfAppId) {
|
|
|
198
202
|
}
|
|
199
203
|
catch (pollErr) {
|
|
200
204
|
if (pollErr instanceof A2ATaskTimeoutError) {
|
|
201
|
-
const queued = await enqueueIntegrationContinuationIfPossible(pollErr, agent, callerEmail);
|
|
205
|
+
const queued = await enqueueIntegrationContinuationIfPossible(pollErr, agent, message, callerEmail);
|
|
202
206
|
if (queued) {
|
|
203
207
|
responseText =
|
|
204
208
|
`${A2A_CONTINUATION_QUEUED_MARKER}\n` +
|
|
@@ -261,7 +265,7 @@ export async function run(args, context, selfAppId) {
|
|
|
261
265
|
return `Error calling ${agent.name}: ${msg}`;
|
|
262
266
|
}
|
|
263
267
|
}
|
|
264
|
-
async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail) {
|
|
268
|
+
async function enqueueIntegrationContinuationIfPossible(error, agent, message, ownerEmail) {
|
|
265
269
|
const integration = getIntegrationRequestContext();
|
|
266
270
|
if (!integration || !ownerEmail)
|
|
267
271
|
return false;
|
|
@@ -280,6 +284,7 @@ async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail
|
|
|
280
284
|
orgId: getRequestOrgId() ?? null,
|
|
281
285
|
agentName: agent.name,
|
|
282
286
|
agentUrl: agent.url,
|
|
287
|
+
dedupeKey: getIntegrationContinuationDedupeKey(message),
|
|
283
288
|
a2aTaskId: error.taskId,
|
|
284
289
|
// Do not persist the short-lived JWT used for the initial send. The
|
|
285
290
|
// continuation processor can mint a fresh token for each poll.
|
|
@@ -295,6 +300,31 @@ async function enqueueIntegrationContinuationIfPossible(error, agent, ownerEmail
|
|
|
295
300
|
return false;
|
|
296
301
|
}
|
|
297
302
|
}
|
|
303
|
+
async function formatExistingIntegrationContinuationIfRetry(agent, message) {
|
|
304
|
+
const integration = getIntegrationRequestContext();
|
|
305
|
+
if (!integration || (integration.attempts ?? 1) <= 1)
|
|
306
|
+
return null;
|
|
307
|
+
try {
|
|
308
|
+
const { getA2AContinuationsForIntegrationTaskAgent } = await import("../integrations/a2a-continuations-store.js");
|
|
309
|
+
const continuations = await getA2AContinuationsForIntegrationTaskAgent(integration.taskId, agent.url, getIntegrationContinuationDedupeKey(message));
|
|
310
|
+
const active = continuations.find((continuation) => ["pending", "processing", "delivering", "completed"].includes(continuation.status));
|
|
311
|
+
if (!active)
|
|
312
|
+
return null;
|
|
313
|
+
const state = active.status === "completed"
|
|
314
|
+
? "already completed this delegated subtask and posted its result to the originating integration thread"
|
|
315
|
+
: "already accepted this delegated subtask and is still working on it for the originating integration thread";
|
|
316
|
+
return (`${A2A_CONTINUATION_QUEUED_MARKER}\n` +
|
|
317
|
+
`The ${agent.name} agent ${state}. Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting or has posted its result separately.`);
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
console.error("[call-agent] Failed to inspect existing continuation:", err);
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function getIntegrationContinuationDedupeKey(message) {
|
|
325
|
+
const normalized = message.trim().replace(/\s+/g, " ");
|
|
326
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
327
|
+
}
|
|
298
328
|
// Expand bare leading-slash paths (e.g. "/deck/abc") into fully-qualified URLs
|
|
299
329
|
// rooted at the receiving agent's host. The receiver doesn't always know it's
|
|
300
330
|
// being called cross-app, so it may emit relative paths that resolve against
|
|
@@ -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 formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.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 = 2_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. Keep delegated\n // calls very short so multi-agent integration requests queue downstream\n // continuations quickly instead of spending the parent Slack/email processor\n // budget waiting on separately deployed apps one-by-one.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nfunction formatDownstreamLlmCredentialFailure(\n agentName: string,\n value: unknown,\n): string | null {\n return isLlmCredentialError(value)\n ? formatLlmCredentialErrorMessage({ agentName })\n : null;\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 \"(c) If the downstream response reports missing credentials, never repeat raw env var names, Vault key names, token names, secret names, or other credential identifiers. Tell the user the target app needs its LLM/provider connection configured.\",\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/design/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only artifact IDs and URL paths returned by successful actions — never invent slugs, IDs, 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: !callerOrgSecret,\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 responseText =\n formatDownstreamLlmCredentialFailure(agent.name, responseText) ??\n responseText;\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 =\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent accepted this delegated subtask and will post its own final result to the originating integration thread automatically. ` +\n `Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting its result separately.`;\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 =\n formatDownstreamLlmCredentialFailure(agent.name, pollErr) ??\n `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 const sanitized =\n formatDownstreamLlmCredentialFailure(agent.name, response) ?? response;\n return expandRelativeUrls(sanitized, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n const credentialMessage = formatDownstreamLlmCredentialFailure(\n agent.name,\n err,\n );\n if (credentialMessage) return credentialMessage;\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"]}
|
|
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 { createHash } from \"node:crypto\";\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 formatLlmCredentialErrorMessage,\n isLlmCredentialError,\n} from \"../agent/engine/credential-errors.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 = 2_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. Keep delegated\n // calls very short so multi-agent integration requests queue downstream\n // continuations quickly instead of spending the parent Slack/email processor\n // budget waiting on separately deployed apps one-by-one.\n if (process.env.NETLIFY) return NETLIFY_INTEGRATION_A2A_TIMEOUT_MS;\n\n return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;\n}\n\nfunction formatDownstreamLlmCredentialFailure(\n agentName: string,\n value: unknown,\n): string | null {\n return isLlmCredentialError(value)\n ? formatLlmCredentialErrorMessage({ agentName })\n : null;\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 \"(c) If the downstream response reports missing credentials, never repeat raw env var names, Vault key names, token names, secret names, or other credential identifiers. Tell the user the target app needs its LLM/provider connection configured.\",\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/design/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +\n `Use only artifact IDs and URL paths returned by successful actions — never invent slugs, IDs, 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: !callerOrgSecret,\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 const existingContinuationText =\n await formatExistingIntegrationContinuationIfRetry(agent, message);\n if (existingContinuationText) return existingContinuationText;\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 responseText =\n formatDownstreamLlmCredentialFailure(agent.name, responseText) ??\n responseText;\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 message,\n callerEmail,\n );\n if (queued) {\n responseText =\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent accepted this delegated subtask and will post its own final result to the originating integration thread automatically. ` +\n `Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting its result separately.`;\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 =\n formatDownstreamLlmCredentialFailure(agent.name, pollErr) ??\n `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 const sanitized =\n formatDownstreamLlmCredentialFailure(agent.name, response) ?? response;\n return expandRelativeUrls(sanitized, agent.url) || \"(empty response)\";\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n const credentialMessage = formatDownstreamLlmCredentialFailure(\n agent.name,\n err,\n );\n if (credentialMessage) return credentialMessage;\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 message: 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 dedupeKey: getIntegrationContinuationDedupeKey(message),\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\nasync function formatExistingIntegrationContinuationIfRetry(\n agent: {\n name: string;\n url: string;\n },\n message: string,\n): Promise<string | null> {\n const integration = getIntegrationRequestContext();\n if (!integration || (integration.attempts ?? 1) <= 1) return null;\n\n try {\n const { getA2AContinuationsForIntegrationTaskAgent } =\n await import(\"../integrations/a2a-continuations-store.js\");\n const continuations = await getA2AContinuationsForIntegrationTaskAgent(\n integration.taskId,\n agent.url,\n getIntegrationContinuationDedupeKey(message),\n );\n const active = continuations.find((continuation) =>\n [\"pending\", \"processing\", \"delivering\", \"completed\"].includes(\n continuation.status,\n ),\n );\n if (!active) return null;\n\n const state =\n active.status === \"completed\"\n ? \"already completed this delegated subtask and posted its result to the originating integration thread\"\n : \"already accepted this delegated subtask and is still working on it for the originating integration thread\";\n return (\n `${A2A_CONTINUATION_QUEUED_MARKER}\\n` +\n `The ${agent.name} agent ${state}. Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting or has posted its result separately.`\n );\n } catch (err) {\n console.error(\"[call-agent] Failed to inspect existing continuation:\", err);\n return null;\n }\n}\n\nfunction getIntegrationContinuationDedupeKey(message: string): string {\n const normalized = message.trim().replace(/\\s+/g, \" \");\n return createHash(\"sha256\").update(normalized).digest(\"hex\");\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,0BAA0B,EAAE,WAAW,CAAC;IACxD,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,OAAO,0BAA0B,EAAE,eAAe,CAAC;QAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;OAGG;IACH,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAYD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAIxD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAIpD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,wBAAgB,4BAA4B,IACxC,WAAW,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,GAC1C,SAAS,CAEZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,GAAG,IAAI,CAIP;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,SAAS,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,GAAG,SAAS,CAKvE"}
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,0BAA0B,EAAE,WAAW,CAAC;IACxD,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,OAAO,0BAA0B,EAAE,eAAe,CAAC;QAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;OAGG;IACH,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAYD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAIxD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAIpD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,wBAAgB,4BAA4B,IACxC,WAAW,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,GAC1C,SAAS,CAEZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,GAAG,IAAI,CAIP;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,SAAS,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,GAAG,SAAS,CAKvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA2DrD,MAAM,UAAU,GAAG,gCAAyC,CAAC;AAI7D,MAAM,SAAS,GAAG,UAAsC,CAAC;AACzD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3B,SAAS,CAAC,UAAU,CAAC,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAClE,CAAC;AACD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAE,CAAC;AAEnC;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAmB,EACnB,EAAwB;IAExB,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,QAAQ,EAAE,KAAK,SAAS,CAAC;AACtC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IAChD,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,QAAQ,CAAC;IAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B;IACxC,OAAO,GAAG,CAAC,QAAQ,EAAE,EAAE,mBAAmB,KAAK,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,4BAA4B;IAG1C,OAAO,GAAG,CAAC,QAAQ,EAAE,EAAE,WAAW,CAAC;AACrC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB;IAIlC,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,IAAI,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,GAAG;QAAE,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;IAC/B,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC","sourcesContent":["/**\n * Per-request context using AsyncLocalStorage.\n *\n * Replaces the unsafe pattern of mutating `process.env.AGENT_USER_EMAIL` /\n * `process.env.AGENT_ORG_ID` on every request. On Node.js (Netlify, self-hosted)\n * concurrent requests would overwrite each other's env vars. AsyncLocalStorage\n * gives each async call-chain its own isolated context.\n *\n * Supported on all deployment targets:\n * - Node.js (native)\n * - Cloudflare Workers (via nodejs_compat flag)\n * - Deno Deploy (via node:async_hooks compat)\n *\n * For CLI scripts that run outside a request context, the getters fall back to\n * process.env so existing `AGENT_USER_EMAIL=x pnpm action foo` invocations\n * continue to work.\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Per-request agent-run state. Lives on `RequestContext.run` so the\n * agent-chat plugin can populate fields as the run progresses (owner,\n * resolved API key, system prompt, engine, model, threadId) without\n * mutating module-scope `let` bindings — those leak across concurrent\n * requests on a single Node.js process.\n *\n * Mutated in-place by `prepareRun`, `onEngineResolved`, `onRunStart` so\n * tool factory closures (automation, fetch, team, builder-browser) read\n * the live per-request value via `getRequestRunContext()`.\n */\nexport interface RequestRunContext {\n /** Origin of the current request (used by the builder-browser tool). */\n requestOrigin?: string;\n /** Resolved owner email (set by prepareRun). */\n owner?: string;\n /** Owner's active Anthropic API key (set by prepareRun). */\n userApiKey?: string;\n /** Thread ID for the current run (set by onRunStart). */\n threadId?: string;\n /** System prompt actually sent to the model for this run. */\n systemPrompt?: string;\n /** Engine instance for this run (set by onEngineResolved). */\n engine?: import(\"../agent/engine/types.js\").AgentEngine;\n /** Model name for this run (set by onEngineResolved). */\n model?: string;\n}\n\nexport interface RequestContext {\n userEmail?: string;\n orgId?: string;\n timezone?: string;\n /**\n * True when this request is being processed by an integration-platform\n * webhook (Slack, Telegram, etc.) where the function timeout is the\n * binding constraint. Code that calls slow remote APIs can use this to apply\n * tighter budgets on this path while leaving normal agent-chat callers\n * (5+ min budget) unaffected.\n */\n isIntegrationCaller?: boolean;\n /**\n * Metadata for the currently-processing integration task. This lets tools\n * that start long-running remote work persist a continuation that can update\n * the originating platform thread after the current function budget ends.\n */\n integration?: {\n taskId: string;\n incoming: import(\"../integrations/types.js\").IncomingMessage;\n placeholderRef?: string;\n };\n /**\n * Mutable per-request agent-run state. Populated by the agent-chat plugin\n * during a run; tool closures dereference it on each invocation.\n */\n run?: RequestRunContext;\n}\n\nconst GLOBAL_KEY = \"__agentNativeRequestContextAls\" as const;\ntype GlobalWithRequestContext = typeof globalThis & {\n [GLOBAL_KEY]?: AsyncLocalStorage<RequestContext>;\n};\nconst globalRef = globalThis as GlobalWithRequestContext;\nif (!globalRef[GLOBAL_KEY]) {\n globalRef[GLOBAL_KEY] = new AsyncLocalStorage<RequestContext>();\n}\nconst als = globalRef[GLOBAL_KEY]!;\n\n/**\n * Run a callback within a per-request context. The context is available to all\n * async operations spawned from `fn` via `getRequestUserEmail()` / `getRequestOrgId()`.\n */\nexport function runWithRequestContext<T>(\n ctx: RequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return als.run(ctx, fn);\n}\n\n/**\n * Return the active request context, if this call chain is running under one.\n *\n * This is intentionally distinct from `getRequestUserEmail()`: callers that\n * have an active context with no authenticated user must not fall through to\n * process-wide CLI fallbacks such as `AGENT_USER_EMAIL` or \"latest session\".\n */\nexport function getRequestContext(): RequestContext | undefined {\n return als.getStore();\n}\n\n/**\n * True when AsyncLocalStorage has an active context for this call chain.\n * Useful for helpers that support both HTTP requests and standalone CLI runs.\n */\nexport function hasRequestContext(): boolean {\n return als.getStore() !== undefined;\n}\n\n/**\n * Get the current request's user email.\n *\n * - If a request context exists (HTTP/A2A path), returns its `userEmail` —\n * even when that value is `undefined`. The env fallback MUST NOT fire here:\n * a stale process-wide `AGENT_USER_EMAIL` from a CLI run or previous bug\n * would leak into an unauthenticated A2A/API call (e.g. unsigned or API-key\n * modes where `runWithRequestContext({ userEmail: undefined })` is used).\n * - Only when there is NO request context (CLI scripts) do we fall back to\n * `process.env.AGENT_USER_EMAIL`.\n */\nexport function getRequestUserEmail(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.userEmail;\n return process.env.AGENT_USER_EMAIL;\n}\n\n/**\n * Get the current request's org ID.\n *\n * Same store-aware semantics as `getRequestUserEmail()` — env fallback is\n * CLI-only, so a request that explicitly has no org doesn't inherit a stale\n * `process.env.AGENT_ORG_ID` from a prior request on the same Lambda instance.\n */\nexport function getRequestOrgId(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.orgId;\n return process.env.AGENT_ORG_ID;\n}\n\n/**\n * Get the current request's IANA timezone (e.g. \"America/Los_Angeles\").\n * The UI sends this via the `x-user-timezone` header on every action call, and\n * the agent chat plugin propagates it into the request context so that\n * agent-initiated tool calls also see the user's timezone. Falls back to\n * `process.env.AGENT_USER_TIMEZONE` only for CLI scripts (no request context).\n */\nexport function getRequestTimezone(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.timezone;\n return process.env.AGENT_USER_TIMEZONE;\n}\n\n/**\n * Returns true when this request is on an integration-platform path (Slack,\n * Telegram, etc.) — i.e. we're inside the integration plugin's processor\n * function and the platform's deliver-by deadline plus the host's function\n * timeout are the binding budget. Non-integration callers (CLI, normal\n * agent chat) should treat this as `false`.\n */\nexport function isIntegrationCallerRequest(): boolean {\n return als.getStore()?.isIntegrationCaller === true;\n}\n\nexport function getIntegrationRequestContext():\n | NonNullable<RequestContext[\"integration\"]>\n | undefined {\n return als.getStore()?.integration;\n}\n\n/**\n * Convenience: returns `{ userEmail, orgId }` from the active request context,\n * suitable for passing to `resolveCredential(key, ctx)`. Returns `null` when\n * no user is associated with the call (e.g. an unauthenticated public route).\n *\n * For framework actions auto-mounted at `/_agent-native/actions/...` this is\n * always populated because action-routes wraps every invocation in\n * `runWithRequestContext`. For hand-written `/api/*` routes the calling code\n * is responsible for setting up the context (see `runWithRequestContext`).\n */\nexport function getCredentialContext(): {\n userEmail: string;\n orgId: string | null;\n} | null {\n const userEmail = getRequestUserEmail();\n if (!userEmail) return null;\n return { userEmail, orgId: getRequestOrgId() ?? null };\n}\n\n/**\n * Get the active request's mutable agent-run state. Returns `undefined` when\n * called outside an agent run (e.g. before `prepareRun` or in a non-agent\n * code path). Callers must tolerate the field absence; use the helper\n * `requireRequestRunContext()` if missing context is a programming error.\n */\nexport function getRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n return store.run;\n}\n\n/**\n * Ensure a `RequestRunContext` exists on the active request store and\n * return it. Used by the agent-chat handler to attach run state once it\n * starts processing a chat request. Returns `undefined` if there is no\n * active request store (caller should not be invoking this outside ALS).\n */\nexport function ensureRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n if (!store.run) store.run = {};\n return store.run;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA4DrD,MAAM,UAAU,GAAG,gCAAyC,CAAC;AAI7D,MAAM,SAAS,GAAG,UAAsC,CAAC;AACzD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3B,SAAS,CAAC,UAAU,CAAC,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAClE,CAAC;AACD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAE,CAAC;AAEnC;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAmB,EACnB,EAAwB;IAExB,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,QAAQ,EAAE,KAAK,SAAS,CAAC;AACtC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IAChD,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,QAAQ,CAAC;IAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B;IACxC,OAAO,GAAG,CAAC,QAAQ,EAAE,EAAE,mBAAmB,KAAK,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,4BAA4B;IAG1C,OAAO,GAAG,CAAC,QAAQ,EAAE,EAAE,WAAW,CAAC;AACrC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB;IAIlC,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,IAAI,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,GAAG;QAAE,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;IAC/B,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC","sourcesContent":["/**\n * Per-request context using AsyncLocalStorage.\n *\n * Replaces the unsafe pattern of mutating `process.env.AGENT_USER_EMAIL` /\n * `process.env.AGENT_ORG_ID` on every request. On Node.js (Netlify, self-hosted)\n * concurrent requests would overwrite each other's env vars. AsyncLocalStorage\n * gives each async call-chain its own isolated context.\n *\n * Supported on all deployment targets:\n * - Node.js (native)\n * - Cloudflare Workers (via nodejs_compat flag)\n * - Deno Deploy (via node:async_hooks compat)\n *\n * For CLI scripts that run outside a request context, the getters fall back to\n * process.env so existing `AGENT_USER_EMAIL=x pnpm action foo` invocations\n * continue to work.\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Per-request agent-run state. Lives on `RequestContext.run` so the\n * agent-chat plugin can populate fields as the run progresses (owner,\n * resolved API key, system prompt, engine, model, threadId) without\n * mutating module-scope `let` bindings — those leak across concurrent\n * requests on a single Node.js process.\n *\n * Mutated in-place by `prepareRun`, `onEngineResolved`, `onRunStart` so\n * tool factory closures (automation, fetch, team, builder-browser) read\n * the live per-request value via `getRequestRunContext()`.\n */\nexport interface RequestRunContext {\n /** Origin of the current request (used by the builder-browser tool). */\n requestOrigin?: string;\n /** Resolved owner email (set by prepareRun). */\n owner?: string;\n /** Owner's active Anthropic API key (set by prepareRun). */\n userApiKey?: string;\n /** Thread ID for the current run (set by onRunStart). */\n threadId?: string;\n /** System prompt actually sent to the model for this run. */\n systemPrompt?: string;\n /** Engine instance for this run (set by onEngineResolved). */\n engine?: import(\"../agent/engine/types.js\").AgentEngine;\n /** Model name for this run (set by onEngineResolved). */\n model?: string;\n}\n\nexport interface RequestContext {\n userEmail?: string;\n orgId?: string;\n timezone?: string;\n /**\n * True when this request is being processed by an integration-platform\n * webhook (Slack, Telegram, etc.) where the function timeout is the\n * binding constraint. Code that calls slow remote APIs can use this to apply\n * tighter budgets on this path while leaving normal agent-chat callers\n * (5+ min budget) unaffected.\n */\n isIntegrationCaller?: boolean;\n /**\n * Metadata for the currently-processing integration task. This lets tools\n * that start long-running remote work persist a continuation that can update\n * the originating platform thread after the current function budget ends.\n */\n integration?: {\n taskId: string;\n attempts?: number;\n incoming: import(\"../integrations/types.js\").IncomingMessage;\n placeholderRef?: string;\n };\n /**\n * Mutable per-request agent-run state. Populated by the agent-chat plugin\n * during a run; tool closures dereference it on each invocation.\n */\n run?: RequestRunContext;\n}\n\nconst GLOBAL_KEY = \"__agentNativeRequestContextAls\" as const;\ntype GlobalWithRequestContext = typeof globalThis & {\n [GLOBAL_KEY]?: AsyncLocalStorage<RequestContext>;\n};\nconst globalRef = globalThis as GlobalWithRequestContext;\nif (!globalRef[GLOBAL_KEY]) {\n globalRef[GLOBAL_KEY] = new AsyncLocalStorage<RequestContext>();\n}\nconst als = globalRef[GLOBAL_KEY]!;\n\n/**\n * Run a callback within a per-request context. The context is available to all\n * async operations spawned from `fn` via `getRequestUserEmail()` / `getRequestOrgId()`.\n */\nexport function runWithRequestContext<T>(\n ctx: RequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return als.run(ctx, fn);\n}\n\n/**\n * Return the active request context, if this call chain is running under one.\n *\n * This is intentionally distinct from `getRequestUserEmail()`: callers that\n * have an active context with no authenticated user must not fall through to\n * process-wide CLI fallbacks such as `AGENT_USER_EMAIL` or \"latest session\".\n */\nexport function getRequestContext(): RequestContext | undefined {\n return als.getStore();\n}\n\n/**\n * True when AsyncLocalStorage has an active context for this call chain.\n * Useful for helpers that support both HTTP requests and standalone CLI runs.\n */\nexport function hasRequestContext(): boolean {\n return als.getStore() !== undefined;\n}\n\n/**\n * Get the current request's user email.\n *\n * - If a request context exists (HTTP/A2A path), returns its `userEmail` —\n * even when that value is `undefined`. The env fallback MUST NOT fire here:\n * a stale process-wide `AGENT_USER_EMAIL` from a CLI run or previous bug\n * would leak into an unauthenticated A2A/API call (e.g. unsigned or API-key\n * modes where `runWithRequestContext({ userEmail: undefined })` is used).\n * - Only when there is NO request context (CLI scripts) do we fall back to\n * `process.env.AGENT_USER_EMAIL`.\n */\nexport function getRequestUserEmail(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.userEmail;\n return process.env.AGENT_USER_EMAIL;\n}\n\n/**\n * Get the current request's org ID.\n *\n * Same store-aware semantics as `getRequestUserEmail()` — env fallback is\n * CLI-only, so a request that explicitly has no org doesn't inherit a stale\n * `process.env.AGENT_ORG_ID` from a prior request on the same Lambda instance.\n */\nexport function getRequestOrgId(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.orgId;\n return process.env.AGENT_ORG_ID;\n}\n\n/**\n * Get the current request's IANA timezone (e.g. \"America/Los_Angeles\").\n * The UI sends this via the `x-user-timezone` header on every action call, and\n * the agent chat plugin propagates it into the request context so that\n * agent-initiated tool calls also see the user's timezone. Falls back to\n * `process.env.AGENT_USER_TIMEZONE` only for CLI scripts (no request context).\n */\nexport function getRequestTimezone(): string | undefined {\n const store = als.getStore();\n if (store !== undefined) return store.timezone;\n return process.env.AGENT_USER_TIMEZONE;\n}\n\n/**\n * Returns true when this request is on an integration-platform path (Slack,\n * Telegram, etc.) — i.e. we're inside the integration plugin's processor\n * function and the platform's deliver-by deadline plus the host's function\n * timeout are the binding budget. Non-integration callers (CLI, normal\n * agent chat) should treat this as `false`.\n */\nexport function isIntegrationCallerRequest(): boolean {\n return als.getStore()?.isIntegrationCaller === true;\n}\n\nexport function getIntegrationRequestContext():\n | NonNullable<RequestContext[\"integration\"]>\n | undefined {\n return als.getStore()?.integration;\n}\n\n/**\n * Convenience: returns `{ userEmail, orgId }` from the active request context,\n * suitable for passing to `resolveCredential(key, ctx)`. Returns `null` when\n * no user is associated with the call (e.g. an unauthenticated public route).\n *\n * For framework actions auto-mounted at `/_agent-native/actions/...` this is\n * always populated because action-routes wraps every invocation in\n * `runWithRequestContext`. For hand-written `/api/*` routes the calling code\n * is responsible for setting up the context (see `runWithRequestContext`).\n */\nexport function getCredentialContext(): {\n userEmail: string;\n orgId: string | null;\n} | null {\n const userEmail = getRequestUserEmail();\n if (!userEmail) return null;\n return { userEmail, orgId: getRequestOrgId() ?? null };\n}\n\n/**\n * Get the active request's mutable agent-run state. Returns `undefined` when\n * called outside an agent run (e.g. before `prepareRun` or in a non-agent\n * code path). Callers must tolerate the field absence; use the helper\n * `requireRequestRunContext()` if missing context is a programming error.\n */\nexport function getRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n return store.run;\n}\n\n/**\n * Ensure a `RequestRunContext` exists on the active request store and\n * return it. Used by the agent-chat handler to attach run state once it\n * starts processing a chat request. Returns `undefined` if there is no\n * active request store (caller should not be invoking this outside ALS).\n */\nexport function ensureRequestRunContext(): RequestRunContext | undefined {\n const store = als.getStore();\n if (!store) return undefined;\n if (!store.run) store.run = {};\n return store.run;\n}\n"]}
|