@agent-native/core 0.7.22 → 0.7.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/a2a/client.d.ts +10 -4
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +16 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +20 -17
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/cli/create.d.ts +3 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +33 -32
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +23 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts +3 -0
- package/dist/cli/workspace-dev.d.ts.map +1 -0
- package/dist/cli/workspace-dev.js +323 -0
- package/dist/cli/workspace-dev.js.map +1 -0
- package/dist/cli/workspacify.d.ts +3 -3
- package/dist/cli/workspacify.js +4 -4
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +10 -9
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/components/ui/tooltip.d.ts +8 -0
- package/dist/client/components/ui/tooltip.d.ts.map +1 -0
- package/dist/client/components/ui/tooltip.js +11 -0
- package/dist/client/components/ui/tooltip.js.map +1 -0
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +21 -17
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +13 -11
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/deploy/workspace-core.d.ts +1 -1
- package/dist/deploy/workspace-core.d.ts.map +1 -1
- package/dist/deploy/workspace-core.js +14 -11
- package/dist/deploy/workspace-core.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts +10 -0
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -0
- package/dist/integrations/a2a-continuation-processor.js +150 -0
- package/dist/integrations/a2a-continuation-processor.js.map +1 -0
- package/dist/integrations/a2a-continuations-store.d.ts +41 -0
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -0
- package/dist/integrations/a2a-continuations-store.js +214 -0
- package/dist/integrations/a2a-continuations-store.js.map +1 -0
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +4 -1
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +52 -0
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/types.d.ts +5 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +6 -0
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +69 -15
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +22 -16
- package/dist/org/handlers.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +91 -30
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +17 -105
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agents-bundle.js +1 -1
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +29 -120
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +1 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +7 -5
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/framework-request-handler.js +1 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +1 -8
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +321 -152
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/request-context.d.ts +14 -3
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +3 -0
- package/dist/server/request-context.js.map +1 -1
- package/dist/templates/default/_gitignore +2 -0
- package/dist/templates/workspace-core/AGENTS.md +18 -71
- package/dist/templates/workspace-core/package.json +2 -20
- package/dist/templates/workspace-core/src/client/index.ts +2 -26
- package/dist/templates/workspace-core/src/index.ts +1 -21
- package/dist/templates/workspace-core/src/server/index.ts +3 -22
- package/dist/templates/workspace-root/.prettierignore +19 -0
- package/dist/templates/workspace-root/README.md +17 -20
- package/dist/templates/workspace-root/_gitignore +8 -0
- package/dist/templates/workspace-root/package.json +8 -4
- package/dist/templates/workspace-root/pnpm-workspace.yaml +5 -2
- package/dist/vite/agents-bundle-plugin.js +2 -2
- package/dist/vite/agents-bundle-plugin.js.map +1 -1
- package/docs/content/authentication.md +3 -5
- package/docs/content/multi-app-workspace.md +38 -50
- package/package.json +1 -1
- package/src/templates/default/_gitignore +2 -0
- package/src/templates/workspace-core/AGENTS.md +18 -71
- package/src/templates/workspace-core/package.json +2 -20
- package/src/templates/workspace-core/src/client/index.ts +2 -26
- package/src/templates/workspace-core/src/index.ts +1 -21
- package/src/templates/workspace-core/src/server/index.ts +3 -22
- package/src/templates/workspace-root/.prettierignore +19 -0
- package/src/templates/workspace-root/README.md +17 -20
- package/src/templates/workspace-root/_gitignore +8 -0
- package/src/templates/workspace-root/package.json +8 -4
- package/src/templates/workspace-root/pnpm-workspace.yaml +5 -2
- package/dist/templates/default/.claude/settings.json +0 -100
- package/dist/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
- package/dist/templates/workspace-core/actions/company-directory.ts +0 -38
- package/dist/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
- package/dist/templates/workspace-core/src/credentials.ts +0 -67
- package/dist/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
- package/dist/templates/workspace-core/src/server/auth-plugin.ts +0 -35
- package/dist/templates/workspace-core/styles/tokens.css +0 -22
- package/dist/templates/workspace-root/scripts/workspace-dev.ts +0 -377
- package/src/templates/default/.claude/settings.json +0 -100
- package/src/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
- package/src/templates/workspace-core/actions/company-directory.ts +0 -38
- package/src/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
- package/src/templates/workspace-core/src/credentials.ts +0 -67
- package/src/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
- package/src/templates/workspace-core/src/server/auth-plugin.ts +0 -35
- package/src/templates/workspace-core/styles/tokens.css +0 -22
- package/src/templates/workspace-root/scripts/workspace-dev.ts +0 -377
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from "h3";
|
|
2
2
|
import type { PlatformAdapter, IncomingMessage } from "./types.js";
|
|
3
3
|
import { type ActionEntry } from "../agent/production-agent.js";
|
|
4
|
+
import type { AgentEngine } from "../agent/engine/types.js";
|
|
4
5
|
import { type PendingTask } from "./pending-tasks-store.js";
|
|
5
6
|
export interface WebhookHandlerOptions {
|
|
6
7
|
adapter: PlatformAdapter;
|
|
@@ -12,6 +13,11 @@ export interface WebhookHandlerOptions {
|
|
|
12
13
|
model: string;
|
|
13
14
|
/** Anthropic API key */
|
|
14
15
|
apiKey: string;
|
|
16
|
+
/** Agent engine to use. Defaults to the same resolver as web chat. */
|
|
17
|
+
engine?: AgentEngine | string | {
|
|
18
|
+
name: string;
|
|
19
|
+
config: Record<string, unknown>;
|
|
20
|
+
};
|
|
15
21
|
/** Thread owner for personal/shared resource loading */
|
|
16
22
|
ownerEmail: string;
|
|
17
23
|
/**
|
|
@@ -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,
|
|
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;AAQtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAU5D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AAoBlC,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;AA0CD;;;;;;;;;;;;;;;;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;AA6GD;;;;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,CASf"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { getThreadMapping, saveThreadMapping } from "./thread-mapping-store.js";
|
|
2
2
|
import { createThread, getThread } from "../chat-threads/store.js";
|
|
3
|
-
import { runAgentLoop, actionsToEngineTools, } from "../agent/production-agent.js";
|
|
4
|
-
import {
|
|
3
|
+
import { runAgentLoop, actionsToEngineTools, getOwnerActiveApiKey, getOwnerApiKey, engineToProvider, } from "../agent/production-agent.js";
|
|
4
|
+
import { PROVIDER_TO_ENV } from "../agent/engine/provider-env-vars.js";
|
|
5
|
+
import { isLocalDatabase } from "../db/client.js";
|
|
6
|
+
import { readDeployCredentialEnv } from "../server/credential-provider.js";
|
|
7
|
+
import { getStoredModelForEngine, resolveEngine, } from "../agent/engine/index.js";
|
|
5
8
|
import { startRun } from "../agent/run-manager.js";
|
|
6
9
|
import { buildAssistantMessage, extractThreadMeta, } from "../agent/thread-data-builder.js";
|
|
7
10
|
import { updateThreadData } from "../chat-threads/store.js";
|
|
@@ -25,6 +28,39 @@ import { withConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
|
25
28
|
function buildEventDedupKey(incoming) {
|
|
26
29
|
return `${incoming.platform}:${incoming.externalThreadId}:${incoming.timestamp}`;
|
|
27
30
|
}
|
|
31
|
+
function explicitEngineName(engineOption) {
|
|
32
|
+
if (!engineOption)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (typeof engineOption === "string")
|
|
35
|
+
return engineOption;
|
|
36
|
+
if (typeof engineOption === "object" &&
|
|
37
|
+
!("stream" in engineOption) &&
|
|
38
|
+
typeof engineOption.name === "string") {
|
|
39
|
+
return engineOption.name;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
function isMultiTenantDeploy() {
|
|
44
|
+
if (process.env.NODE_ENV !== "production")
|
|
45
|
+
return false;
|
|
46
|
+
return !isLocalDatabase();
|
|
47
|
+
}
|
|
48
|
+
async function resolveIntegrationApiKey(engineOption, ownerEmail, fallbackApiKey) {
|
|
49
|
+
const engineName = explicitEngineName(engineOption);
|
|
50
|
+
if (engineName) {
|
|
51
|
+
const provider = engineToProvider(engineName);
|
|
52
|
+
const userApiKey = await getOwnerApiKey(provider, ownerEmail);
|
|
53
|
+
if (userApiKey || isMultiTenantDeploy())
|
|
54
|
+
return userApiKey;
|
|
55
|
+
const envVar = PROVIDER_TO_ENV[provider];
|
|
56
|
+
const providerEnvKey = envVar ? readDeployCredentialEnv(envVar) : undefined;
|
|
57
|
+
return providerEnvKey || fallbackApiKey.trim() || undefined;
|
|
58
|
+
}
|
|
59
|
+
const userApiKey = await getOwnerActiveApiKey(ownerEmail);
|
|
60
|
+
if (userApiKey || isMultiTenantDeploy())
|
|
61
|
+
return userApiKey;
|
|
62
|
+
return fallbackApiKey.trim() || undefined;
|
|
63
|
+
}
|
|
28
64
|
/**
|
|
29
65
|
* Process an incoming webhook from a messaging platform.
|
|
30
66
|
*
|
|
@@ -110,7 +146,7 @@ export async function handleWebhook(event, options) {
|
|
|
110
146
|
*
|
|
111
147
|
* This pattern works on every supported host:
|
|
112
148
|
* - Netlify Lambda: function returns; the dispatched request hits a fresh
|
|
113
|
-
* Lambda with its own
|
|
149
|
+
* Lambda with its own function budget.
|
|
114
150
|
* - Vercel Functions: same.
|
|
115
151
|
* - Cloudflare Workers: same (no waitUntil dependency).
|
|
116
152
|
* - Self-hosted Node: a separate request comes back through the same
|
|
@@ -237,6 +273,7 @@ export function resolveBaseUrl(event) {
|
|
|
237
273
|
export async function processIntegrationTask(task, options) {
|
|
238
274
|
const parsed = JSON.parse(task.payload);
|
|
239
275
|
await processIncomingMessage(parsed.incoming, options, {
|
|
276
|
+
taskId: task.id,
|
|
240
277
|
placeholderRef: parsed.placeholderRef,
|
|
241
278
|
});
|
|
242
279
|
}
|
|
@@ -245,7 +282,7 @@ export async function processIntegrationTask(task, options) {
|
|
|
245
282
|
* Shared between the new processor endpoint and any direct callers.
|
|
246
283
|
*/
|
|
247
284
|
async function processIncomingMessage(incoming, options, opts = {}) {
|
|
248
|
-
const { adapter, systemPrompt, actions, model, apiKey, ownerEmail } = options;
|
|
285
|
+
const { adapter, systemPrompt, actions, model, apiKey, ownerEmail, engine: engineOption, } = options;
|
|
249
286
|
// Resolve or create internal thread
|
|
250
287
|
let mapping = await getThreadMapping(incoming.platform, incoming.externalThreadId);
|
|
251
288
|
if (!mapping) {
|
|
@@ -317,7 +354,6 @@ async function processIncomingMessage(incoming, options, opts = {}) {
|
|
|
317
354
|
// A2A delegation. Without this, getRequestOrgId() returns undefined and
|
|
318
355
|
// call-agent can't look up the org's a2a_secret or org_domain.
|
|
319
356
|
const orgId = await resolveOrgIdForEmail(ownerEmail);
|
|
320
|
-
const engine = createAnthropicEngine({ apiKey });
|
|
321
357
|
const tools = actionsToEngineTools(actions);
|
|
322
358
|
const runId = `integration-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
323
359
|
// Wait for the run to complete inside this fresh function execution.
|
|
@@ -331,16 +367,34 @@ async function processIncomingMessage(incoming, options, opts = {}) {
|
|
|
331
367
|
// budgets on integration paths without affecting normal
|
|
332
368
|
// agent-chat. See `isIntegrationCallerRequest()`.
|
|
333
369
|
isIntegrationCaller: true,
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
370
|
+
integration: opts.taskId
|
|
371
|
+
? {
|
|
372
|
+
taskId: opts.taskId,
|
|
373
|
+
incoming,
|
|
374
|
+
placeholderRef: opts.placeholderRef,
|
|
375
|
+
}
|
|
376
|
+
: undefined,
|
|
377
|
+
}, async () => {
|
|
378
|
+
const effectiveApiKey = await resolveIntegrationApiKey(engineOption, ownerEmail, apiKey);
|
|
379
|
+
const engine = await resolveEngine({
|
|
380
|
+
engineOption,
|
|
381
|
+
apiKey: effectiveApiKey,
|
|
382
|
+
model,
|
|
383
|
+
});
|
|
384
|
+
const resolvedModel = (await getStoredModelForEngine(engine)) ??
|
|
385
|
+
model ??
|
|
386
|
+
engine.defaultModel;
|
|
387
|
+
return runAgentLoop({
|
|
388
|
+
engine,
|
|
389
|
+
model: resolvedModel,
|
|
390
|
+
systemPrompt,
|
|
391
|
+
tools,
|
|
392
|
+
messages,
|
|
393
|
+
actions,
|
|
394
|
+
send,
|
|
395
|
+
signal,
|
|
396
|
+
});
|
|
397
|
+
});
|
|
344
398
|
}, async (completedRun) => {
|
|
345
399
|
try {
|
|
346
400
|
// Collect text events from the run, but drop any pre-tool-call
|
|
@@ -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 type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport { createAnthropicEngine } from \"../agent/engine/index.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\";\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 /** 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\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 26s 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 at least ~250ms to leave the\n // box; the trade-off is at most ~250ms of added webhook latency.\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) => setTimeout(resolve, 250)),\n ]);\n}\n\n/**\n * Resolve the base URL we should dispatch the processor request to.\n * Prefers explicit env vars (most reliable on serverless), falls back to the\n * inbound request's headers.\n */\nexport function resolveBaseUrl(event: H3Event): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(fromEnv);\n\n try {\n const headers = (event as any).node?.req?.headers ?? (event as any).headers;\n const get = (name: string): string | undefined => {\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const lower = String(name).toLowerCase();\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[lower];\n };\n const proto = get(\"x-forwarded-proto\") || \"http\";\n const host = get(\"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\n `http://localhost:${process.env.PORT || 3000}`,\n );\n }\n}\n\n/**\n * Run the actual agent loop for a previously-enqueued task. Called by the\n * processor endpoint in `plugin.ts`. This is a fresh function execution, so\n * it gets its own timeout budget independent of the inbound webhook handler.\n */\nexport async function processIntegrationTask(\n task: PendingTask,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const parsed = JSON.parse(task.payload) as {\n incoming: IncomingMessage;\n placeholderRef?: string;\n };\n await processIncomingMessage(parsed.incoming, options, {\n 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: { placeholderRef?: string } = {},\n): Promise<void> {\n const { adapter, systemPrompt, actions, model, apiKey, ownerEmail } = options;\n\n // Resolve or create internal thread\n let mapping = await getThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n );\n\n if (!mapping) {\n const thread = await createThread(ownerEmail, {\n title: `${adapter.label}: ${incoming.senderName || incoming.senderId || \"User\"}`,\n });\n await saveThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n thread.id,\n incoming.platformContext,\n );\n mapping = {\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n internalThreadId: thread.id,\n platformContext: incoming.platformContext,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n }\n\n const threadId = mapping.internalThreadId;\n\n // Load existing thread history for context\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n // Add the new user message. Include verified platform identity as lightweight\n // context so app-specific agents can attribute requests without guessing.\n const identityLines = [\n `Platform: ${incoming.platform}`,\n incoming.senderName ? `Sender name: ${incoming.senderName}` : null,\n incoming.senderEmail ? `Sender email: ${incoming.senderEmail}` : null,\n incoming.senderId ? `Sender ID: ${incoming.senderId}` : null,\n ].filter(Boolean);\n const userText =\n identityLines.length > 1\n ? `<integration-context>\\n${identityLines.join(\"\\n\")}\\n</integration-context>\\n\\n${incoming.text}`\n : incoming.text;\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text: userText }] },\n ];\n\n // Run agent loop via startRun, wrapped in a request context so that\n // tools (especially call-agent) can resolve the caller's org for org-scoped\n // A2A delegation. Without this, getRequestOrgId() returns undefined and\n // call-agent can't look up the org's a2a_secret or org_domain.\n const orgId = await resolveOrgIdForEmail(ownerEmail);\n const engine = createAnthropicEngine({ apiKey });\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 },\n () =>\n runAgentLoop({\n engine,\n model,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal,\n }),\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n // Collect text events from the run, but drop any pre-tool-call\n // preamble so the user sees just the final answer instead of\n // \"I need to delegate this...\" run-on into the raw tool result.\n //\n // Heuristic: when the agent fired any tool, only keep text events\n // that come AFTER the last tool. The preamble (\"Let me check…\")\n // and the final answer (\"630\") are emitted as two separate text\n // events, and concatenating them with no separator was producing\n // \"...signup data.630\" in Slack.\n let lastToolIdx = -1;\n for (let i = completedRun.events.length - 1; i >= 0; i--) {\n const t = completedRun.events[i].event.type;\n if (t === \"tool_start\" || t === \"tool_done\") {\n lastToolIdx = i;\n break;\n }\n }\n const startIdx = lastToolIdx >= 0 ? lastToolIdx + 1 : 0;\n let responseText = \"\";\n for (let i = startIdx; i < completedRun.events.length; i++) {\n const ev = completedRun.events[i].event;\n if (ev.type === \"text\") responseText += ev.text;\n }\n // If the post-tool window had no text (tool spoke for itself),\n // fall back to all text events so we never leave the user with\n // an empty reply.\n if (!responseText.trim() && lastToolIdx >= 0) {\n for (const runEvent of completedRun.events) {\n if (runEvent.event.type === \"text\") {\n responseText += runEvent.event.text;\n }\n }\n }\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 if (!responseText.trim() || runErrored) {\n if (runErrored) {\n responseText =\n (responseText.trim() ? responseText + \"\\n\\n\" : \"\") +\n \"I ran into a problem before I could finish that one. \" +\n \"If it was a complex analytics question, opening the analytics app \" +\n \"directly is the most reliable way to get an answer right now.\";\n } else {\n responseText = \"(No response)\";\n }\n }\n\n // Compute the deep-link to the dispatch UI for this thread, then\n // hand it to the adapter as a structured `threadDeepLinkUrl` so\n // platforms with rich blocks (Slack) can render a button instead\n // of inlining a `<url|text>` link that auto-unfurls into a giant\n // preview card.\n const baseUrl = process.env.APP_URL || process.env.URL || \"\";\n const appBaseUrl = baseUrl ? withConfiguredAppBasePath(baseUrl) : \"\";\n const threadDeepLinkUrl =\n appBaseUrl && threadId\n ? `${appBaseUrl}/?thread=${threadId}`\n : undefined;\n\n // Format and send back to platform — update the \"thinking…\"\n // placeholder in place if the adapter supplied one.\n const outgoing = adapter.formatAgentResponse(responseText, {\n threadDeepLinkUrl,\n });\n await adapter.sendResponse(outgoing, incoming, {\n placeholderRef: opts.placeholderRef,\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\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 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\";\n\n/**\n * Build a stable per-event dedup key from the incoming message. The same\n * key is computed for every retry of the same event from the platform —\n * Slack/Telegram retry on timeout (3s for Slack), so we MUST treat the\n * second delivery as a duplicate and return 200 silently.\n *\n * The `(platform, external_event_key)` UNIQUE index in\n * `integration_pending_tasks` enforces this at the SQL layer, replacing\n * the previous in-memory Map (H3 in the webhook security audit) which\n * couldn't survive serverless cold starts.\n */\nfunction buildEventDedupKey(incoming: IncomingMessage): string {\n return `${incoming.platform}:${incoming.externalThreadId}:${incoming.timestamp}`;\n}\n\nexport interface WebhookHandlerOptions {\n adapter: PlatformAdapter;\n /** Resolved system prompt string */\n systemPrompt: string;\n /** Action entries for the agent */\n actions: Record<string, ActionEntry>;\n /** Model to use */\n model: string;\n /** Anthropic API key */\n apiKey: string;\n /** Agent engine to use. Defaults to the same resolver as web chat. */\n engine?:\n | AgentEngine\n | string\n | { name: string; config: Record<string, unknown> };\n /** Thread owner for personal/shared resource loading */\n ownerEmail: string;\n /**\n * Pre-parsed incoming message. When provided, handleWebhook skips its own\n * verification + parsing steps. Required when the caller has already read\n * the request body (h3 doesn't reliably cache parsed bodies, so re-parsing\n * the same event hangs on streaming providers).\n */\n incoming?: IncomingMessage;\n /** Optional hook to intercept inbound commands before agent execution */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n\nfunction explicitEngineName(\n engineOption: WebhookHandlerOptions[\"engine\"],\n): string | undefined {\n if (!engineOption) return undefined;\n if (typeof engineOption === \"string\") return engineOption;\n if (\n typeof engineOption === \"object\" &&\n !(\"stream\" in engineOption) &&\n typeof engineOption.name === \"string\"\n ) {\n return engineOption.name;\n }\n return undefined;\n}\n\nfunction isMultiTenantDeploy(): boolean {\n if (process.env.NODE_ENV !== \"production\") return false;\n return !isLocalDatabase();\n}\n\nasync function resolveIntegrationApiKey(\n engineOption: WebhookHandlerOptions[\"engine\"],\n ownerEmail: string,\n fallbackApiKey: string,\n): Promise<string | undefined> {\n const engineName = explicitEngineName(engineOption);\n if (engineName) {\n const provider = engineToProvider(engineName);\n const userApiKey = await getOwnerApiKey(provider, ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n const envVar = PROVIDER_TO_ENV[provider];\n const providerEnvKey = envVar ? readDeployCredentialEnv(envVar) : undefined;\n return providerEnvKey || fallbackApiKey.trim() || undefined;\n }\n\n const userApiKey = await getOwnerActiveApiKey(ownerEmail);\n if (userApiKey || isMultiTenantDeploy()) return userApiKey;\n return fallbackApiKey.trim() || undefined;\n}\n\n/**\n * Process an incoming webhook from a messaging platform.\n *\n * Flow:\n * 1. Handle verification challenges (Slack url_verification, etc.)\n * 2. Verify webhook signature\n * 3. Parse incoming message (null = ignored event)\n * 4. Persist task to SQL\n * 5. Fire-and-forget POST to /_agent-native/integrations/process-task\n * (a fresh function execution with its own timeout budget)\n * 6. Return HTTP 200 immediately (within Slack's 3s SLA)\n *\n * The processor endpoint runs the actual agent loop. This split is essential\n * for serverless platforms (Netlify Lambda, Vercel, Cloudflare Workers) which\n * freeze the function as soon as the response is returned, killing any\n * lingering background promises.\n */\nexport async function handleWebhook(\n event: H3Event,\n options: WebhookHandlerOptions,\n): Promise<{ status: number; body: unknown }> {\n const { adapter, beforeProcess } = options;\n\n let incoming: IncomingMessage | null = options.incoming ?? null;\n\n // When the caller didn't pre-parse, run the full verify + parse pipeline.\n // Otherwise skip it — h3's body stream has already been consumed and a\n // second readBody call hangs on streaming providers.\n if (!incoming) {\n // Step 1: Handle platform-specific verification challenges\n const verification = await adapter.handleVerification(event);\n if (verification.handled) {\n return { status: 200, body: verification.response ?? \"ok\" };\n }\n\n // Step 2: Verify webhook signature\n const isValid = await adapter.verifyWebhook(event);\n if (!isValid) {\n return { status: 401, body: { error: \"Invalid webhook signature\" } };\n }\n\n // Step 3: Parse the incoming message\n incoming = await adapter.parseIncomingMessage(event);\n if (!incoming) {\n // Not a user message (bot message, edit, reaction, etc.) — acknowledge silently\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Dedup is enforced inside enqueueAndDispatch — the unique index on\n // `(platform, external_event_key)` raises a constraint violation we treat\n // as \"already enqueued\" and respond 200. We can't dedup BEFORE the\n // beforeProcess hook because some templates use beforeProcess for\n // command-style intercepts that are stateless and idempotent (e.g. a\n // Slack `/help` command that doesn't enqueue a task).\n\n if (beforeProcess) {\n const result = await beforeProcess(incoming, adapter);\n if (result.handled) {\n if (result.responseText?.trim()) {\n const outgoing = adapter.formatAgentResponse(result.responseText);\n await adapter.sendResponse(outgoing, incoming);\n }\n return { status: 200, body: \"ok\" };\n }\n }\n\n // Step 4 + 5: Enqueue to SQL and dispatch to processor in a fresh request.\n try {\n await enqueueAndDispatch(event, incoming, options);\n } catch (err) {\n // Duplicate event delivery: the SQL UNIQUE constraint on\n // (platform, external_event_key) rejected the second insert. This is\n // the expected path when a platform retries an event that already\n // landed (e.g. Slack 3-second timeout) — return 200 so the platform\n // stops retrying. See H3 in the webhook security audit.\n if (isDuplicateEventError(err)) {\n return { status: 200, body: \"ok\" };\n }\n console.error(\n `[integrations] Failed to enqueue/dispatch ${incoming.platform} message:`,\n err,\n );\n // Return 500 so the platform retries. If the SQL insert failed for a\n // non-dup reason, the message is genuinely lost — better to let Slack\n // retry (it will re-fire the same event_callback) than silently drop it.\n return { status: 500, body: { error: \"enqueue failed\" } };\n }\n\n return { status: 200, body: \"ok\" };\n}\n\n/**\n * Persist the task to SQL and dispatch a fresh HTTP request to the processor\n * endpoint. The dispatch is fire-and-forget — we deliberately do NOT await\n * the resulting fetch, so the current handler can return immediately.\n *\n * This pattern works on every supported host:\n * - Netlify Lambda: function returns; the dispatched request hits a fresh\n * Lambda with its own function budget.\n * - Vercel Functions: same.\n * - Cloudflare Workers: same (no waitUntil dependency).\n * - Self-hosted Node: a separate request comes back through the same\n * server, but each handler still runs to completion.\n */\nasync function enqueueAndDispatch(\n event: H3Event,\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Resolve the org id once at enqueue-time so the processor doesn't have to\n // re-derive it (and so we can drop it on the row for observability).\n let orgId: string | null = null;\n try {\n orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? null;\n } catch {\n orgId = null;\n }\n\n // Post a \"thinking…\" placeholder immediately if the adapter supports\n // in-place edits. The processor flow will update this same message with\n // the final answer, so users see one tidy thread reply instead of\n // \"[silence] → answer\". Adapters without edit support skip this and the\n // processor posts a fresh response.\n let placeholderRef: string | undefined;\n try {\n if (options.adapter.postProcessingPlaceholder) {\n const placeholder =\n await options.adapter.postProcessingPlaceholder(incoming);\n if (placeholder?.placeholderRef) {\n placeholderRef = placeholder.placeholderRef;\n }\n }\n } catch (err) {\n console.error(\"[integrations] postProcessingPlaceholder failed:\", err);\n }\n\n const payload = JSON.stringify({ incoming, placeholderRef });\n\n await insertPendingTask({\n id: taskId,\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n payload,\n ownerEmail: options.ownerEmail,\n orgId,\n // SQL-level dedup key — duplicate webhook deliveries from the same\n // platform produce the same key, so the unique index rejects the\n // second insert (H3 in the webhook security audit).\n externalEventKey: buildEventDedupKey(incoming),\n });\n\n const baseUrl = resolveBaseUrl(event);\n const processUrl = `${baseUrl}${FRAMEWORK_ROUTE_PREFIX}/integrations/process-task`;\n\n // Sign the dispatch with an HMAC token so the processor endpoint can\n // verify the request came from us and not the public internet. The\n // processor refuses unsigned requests in production (C3 in the webhook\n // security audit). In dev, dispatching unsigned is allowed and falls\n // through to the SQL atomic claim for double-processing protection.\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(taskId)}`;\n } catch (err) {\n // Distinguish \"secret not configured\" (the documented dev path) from\n // a real signing failure — silently swallowing both made malformed\n // secrets fail invisibly (L5 in the audit).\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${taskId}:`,\n err,\n );\n }\n }\n\n // Fire-and-forget: do NOT await the full response (the processor's run\n // takes minutes — we don't want to block the caller). BUT on Netlify\n // Lambda, when we return immediately, the runtime can freeze the function\n // before the outbound TCP handshake even starts, which leaves the dispatch\n // request stuck waiting for the 60s retry-sweep job. Race the fetch\n // against a short timer so the request gets at least ~250ms to leave the\n // box; the trade-off is at most ~250ms of added webhook latency.\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) => setTimeout(resolve, 250)),\n ]);\n}\n\n/**\n * Resolve the base URL we should dispatch the processor request to.\n * Prefers explicit env vars (most reliable on serverless), falls back to the\n * inbound request's headers.\n */\nexport function resolveBaseUrl(event: H3Event): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(fromEnv);\n\n try {\n const headers = (event as any).node?.req?.headers ?? (event as any).headers;\n const get = (name: string): string | undefined => {\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const lower = String(name).toLowerCase();\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[lower];\n };\n const proto = get(\"x-forwarded-proto\") || \"http\";\n const host = get(\"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {\n return withConfiguredAppBasePath(\n `http://localhost:${process.env.PORT || 3000}`,\n );\n }\n}\n\n/**\n * Run the actual agent loop for a previously-enqueued task. Called by the\n * processor endpoint in `plugin.ts`. This is a fresh function execution, so\n * it gets its own timeout budget independent of the inbound webhook handler.\n */\nexport async function processIntegrationTask(\n task: PendingTask,\n options: WebhookHandlerOptions,\n): Promise<void> {\n const parsed = JSON.parse(task.payload) as {\n incoming: IncomingMessage;\n placeholderRef?: string;\n };\n await processIncomingMessage(parsed.incoming, options, {\n taskId: task.id,\n placeholderRef: parsed.placeholderRef,\n });\n}\n\n/**\n * Resolve thread, run agent loop, post response, persist thread data.\n * Shared between the new processor endpoint and any direct callers.\n */\nasync function processIncomingMessage(\n incoming: IncomingMessage,\n options: WebhookHandlerOptions,\n opts: { taskId?: string; placeholderRef?: string } = {},\n): Promise<void> {\n const {\n adapter,\n systemPrompt,\n actions,\n model,\n apiKey,\n ownerEmail,\n engine: engineOption,\n } = options;\n\n // Resolve or create internal thread\n let mapping = await getThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n );\n\n if (!mapping) {\n const thread = await createThread(ownerEmail, {\n title: `${adapter.label}: ${incoming.senderName || incoming.senderId || \"User\"}`,\n });\n await saveThreadMapping(\n incoming.platform,\n incoming.externalThreadId,\n thread.id,\n incoming.platformContext,\n );\n mapping = {\n platform: incoming.platform,\n externalThreadId: incoming.externalThreadId,\n internalThreadId: thread.id,\n platformContext: incoming.platformContext,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n }\n\n const threadId = mapping.internalThreadId;\n\n // Load existing thread history for context\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n // Add the new user message. Include verified platform identity as lightweight\n // context so app-specific agents can attribute requests without guessing.\n const identityLines = [\n `Platform: ${incoming.platform}`,\n incoming.senderName ? `Sender name: ${incoming.senderName}` : null,\n incoming.senderEmail ? `Sender email: ${incoming.senderEmail}` : null,\n incoming.senderId ? `Sender ID: ${incoming.senderId}` : null,\n ].filter(Boolean);\n const userText =\n identityLines.length > 1\n ? `<integration-context>\\n${identityLines.join(\"\\n\")}\\n</integration-context>\\n\\n${incoming.text}`\n : incoming.text;\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text: userText }] },\n ];\n\n // Run agent loop via startRun, wrapped in a request context so that\n // tools (especially call-agent) can resolve the caller's org for org-scoped\n // A2A delegation. Without this, getRequestOrgId() returns undefined and\n // call-agent can't look up the org's a2a_secret or org_domain.\n const orgId = await resolveOrgIdForEmail(ownerEmail);\n const tools = actionsToEngineTools(actions);\n\n const runId = `integration-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n // Wait for the run to complete inside this fresh function execution.\n // We use a Promise so the processor endpoint can await the full lifecycle.\n await new Promise<void>((resolve) => {\n startRun(\n runId,\n threadId,\n async (send, signal) => {\n await runWithRequestContext(\n {\n userEmail: ownerEmail,\n orgId: orgId ?? undefined,\n // Lets downstream callers (call-agent script) apply tighter\n // budgets on integration paths without affecting normal\n // agent-chat. See `isIntegrationCallerRequest()`.\n isIntegrationCaller: true,\n integration: opts.taskId\n ? {\n taskId: opts.taskId,\n incoming,\n placeholderRef: opts.placeholderRef,\n }\n : undefined,\n },\n async () => {\n const effectiveApiKey = await resolveIntegrationApiKey(\n engineOption,\n ownerEmail,\n apiKey,\n );\n const engine = await resolveEngine({\n engineOption,\n apiKey: effectiveApiKey,\n model,\n });\n const resolvedModel =\n (await getStoredModelForEngine(engine)) ??\n model ??\n engine.defaultModel;\n\n return runAgentLoop({\n engine,\n model: resolvedModel,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal,\n });\n },\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n // Collect text events from the run, but drop any pre-tool-call\n // preamble so the user sees just the final answer instead of\n // \"I need to delegate this...\" run-on into the raw tool result.\n //\n // Heuristic: when the agent fired any tool, only keep text events\n // that come AFTER the last tool. The preamble (\"Let me check…\")\n // and the final answer (\"630\") are emitted as two separate text\n // events, and concatenating them with no separator was producing\n // \"...signup data.630\" in Slack.\n let lastToolIdx = -1;\n for (let i = completedRun.events.length - 1; i >= 0; i--) {\n const t = completedRun.events[i].event.type;\n if (t === \"tool_start\" || t === \"tool_done\") {\n lastToolIdx = i;\n break;\n }\n }\n const startIdx = lastToolIdx >= 0 ? lastToolIdx + 1 : 0;\n let responseText = \"\";\n for (let i = startIdx; i < completedRun.events.length; i++) {\n const ev = completedRun.events[i].event;\n if (ev.type === \"text\") responseText += ev.text;\n }\n // If the post-tool window had no text (tool spoke for itself),\n // fall back to all text events so we never leave the user with\n // an empty reply.\n if (!responseText.trim() && lastToolIdx >= 0) {\n for (const runEvent of completedRun.events) {\n if (runEvent.event.type === \"text\") {\n responseText += runEvent.event.text;\n }\n }\n }\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 if (!responseText.trim() || runErrored) {\n if (runErrored) {\n responseText =\n (responseText.trim() ? responseText + \"\\n\\n\" : \"\") +\n \"I ran into a problem before I could finish that one. \" +\n \"If it was a complex analytics question, opening the analytics app \" +\n \"directly is the most reliable way to get an answer right now.\";\n } else {\n responseText = \"(No response)\";\n }\n }\n\n // Compute the deep-link to the dispatch UI for this thread, then\n // hand it to the adapter as a structured `threadDeepLinkUrl` so\n // platforms with rich blocks (Slack) can render a button instead\n // of inlining a `<url|text>` link that auto-unfurls into a giant\n // preview card.\n const baseUrl = process.env.APP_URL || process.env.URL || \"\";\n const appBaseUrl = baseUrl ? withConfiguredAppBasePath(baseUrl) : \"\";\n const threadDeepLinkUrl =\n appBaseUrl && threadId\n ? `${appBaseUrl}/?thread=${threadId}`\n : undefined;\n\n // Format and send back to platform — update the \"thinking…\"\n // placeholder in place if the adapter supplied one.\n const outgoing = adapter.formatAgentResponse(responseText, {\n threadDeepLinkUrl,\n });\n await adapter.sendResponse(outgoing, incoming, {\n placeholderRef: opts.placeholderRef,\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\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":"handlers.d.ts","sourceRoot":"","sources":["../../src/org/handlers.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA2B1C,2FAA2F;AAC3F,eAAO,MAAM,eAAe;;;;;;;cAaA,OAAO;;;;;;;;;;eAIC,MAAM;iBAAW,MAAM;;;;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/org/handlers.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA2B1C,2FAA2F;AAC3F,eAAO,MAAM,eAAe;;;;;;;cAaA,OAAO;;;;;;;;;;eAIC,MAAM;iBAAW,MAAM;;;;GA0EzD,CAAC;AAEH,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB;;;;GAkC3B,CAAC;AAEH,wDAAwD;AACxD,eAAO,MAAM,kBAAkB;;;cAWH,OAAO;;;GAIjC,CAAC;AAEH,mEAAmE;AACnE,eAAO,MAAM,uBAAuB;;;;;;GA+EnC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,sBAAsB;;;;;;;;GAqBlC,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB;;;UAmD8B,OAAO;GAkBxE,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,mBAAmB;;GA2D/B,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,gBAAgB;;;GA4B3B,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB;;;UAkCC,OAAO;GAEnC,CAAC;AAEH,mGAAmG;AACnG,eAAO,MAAM,mBAAmB;;;UAqDR,OAAO;GAG9B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB;;GA2C3B,CAAC;AAEH,oGAAoG;AACpG,eAAO,MAAM,mBAAmB;;;GA0C/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB;;;;;YA2DvB,MAAM;cACJ,MAAM;aACP,MAAM;YACP,OAAO;iBACF,MAAM;gBACP,MAAM;;GAyDnB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB;;;GAgGnC,CAAC"}
|
package/dist/org/handlers.js
CHANGED
|
@@ -71,22 +71,28 @@ export const getMyOrgHandler = defineEventHandler(async (event) => {
|
|
|
71
71
|
orgName: String(r.orgName ?? r.org_name),
|
|
72
72
|
}));
|
|
73
73
|
let domainMatches = [];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
const domain = ctx.email.split("@")[1]?.toLowerCase();
|
|
75
|
+
if (domain) {
|
|
76
|
+
try {
|
|
77
|
+
const dmRes = await e.execute({
|
|
78
|
+
sql: `SELECT o.id, o.name
|
|
79
|
+
FROM organizations o
|
|
80
|
+
WHERE LOWER(o.allowed_domain) = ?
|
|
81
|
+
AND NOT EXISTS (
|
|
82
|
+
SELECT 1
|
|
83
|
+
FROM org_members m
|
|
84
|
+
WHERE m.org_id = o.id
|
|
85
|
+
AND LOWER(m.email) = ?
|
|
86
|
+
)`,
|
|
87
|
+
args: [domain, ctx.email.toLowerCase()],
|
|
88
|
+
});
|
|
89
|
+
domainMatches = dmRes.rows.map((r) => ({
|
|
90
|
+
orgId: String(r.id),
|
|
91
|
+
orgName: String(r.name),
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// allowed_domain column may not exist yet if migration hasn't run
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
let allowedDomain = null;
|