@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-core.js","sourceRoot":"","sources":["../../src/deploy/workspace-core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workspace-core discovery.\n *\n * An enterprise can sit many agent-native apps in one monorepo alongside a\n * private \"workspace core\" package that provides shared plugins, skills,\n * actions, AGENTS.md, and shared Tailwind v4 design tokens. Apps inherit everything from\n * the workspace core without writing any boilerplate — this is the\n * middle layer of the three-layer inheritance model:\n *\n * 1. app local (highest priority — app's own server/plugins/, actions/, etc.)\n * 2. workspace core (middle — packages/core-module/ in the enterprise monorepo)\n * 3. @agent-native/core (lowest — framework defaults)\n *\n * Discovery works by walking up from the build cwd looking for a package.json\n * that declares `\"agent-native\": { \"workspaceCore\": \"@company/core-module\" }`.\n * The declared package is then resolved through the monorepo's node_modules,\n * and its directory structure is probed for the standard layout:\n *\n * packages/core-module/\n * package.json\n * src/server/index.ts (exports <slot>Plugin for any slot it wants to provide)\n * actions/ (shared agent-callable actions)\n * skills/ (shared .agents/skills/<name>/SKILL.md)\n * AGENTS.md (enterprise-wide agent instructions)\n * styles/tokens.css (brand tokens — `@import \"@agent-native/core/styles/agent-native.css\"` then your `@theme` overrides)\n */\nimport path from \"path\";\n\nlet _fs: typeof import(\"fs\") | undefined;\nasync function getFs(): Promise<typeof import(\"fs\")> {\n if (!_fs) _fs = await import(\"node:fs\");\n return _fs;\n}\n\n/** Mirrors DEFAULT_PLUGIN_REGISTRY's slot names. */\nexport type PluginSlot =\n | \"agent-chat\"\n | \"auth\"\n | \"core-routes\"\n | \"integrations\"\n | \"org\"\n | \"resources\"\n | \"terminal\";\n\nexport interface WorkspaceCoreExports {\n /** Absolute path of the monorepo root (the dir containing the root package.json). */\n workspaceRoot: string;\n /** Resolved package name — e.g. \"@my-company/core-module\". */\n packageName: string;\n /** Absolute path to the workspace core package's root directory. */\n packageDir: string;\n /** Plugin slot → export name (if the workspace core declares an override for that slot). */\n plugins: Partial<Record<PluginSlot, string>>;\n /** Absolute path to the workspace core's actions/ directory, or null if it doesn't have one. */\n actionsDir: string | null;\n /** Absolute path to the workspace core's skills/ directory, or null. */\n skillsDir: string | null;\n /** Absolute path to the workspace core's AGENTS.md, or null. */\n agentsMdPath: string | null;\n}\n\nlet cache: { cwd: string; result: WorkspaceCoreExports | null } | undefined;\n\n/**\n * Walk up from startDir looking for a directory whose package.json has an\n * `agent-native.workspaceCore` field. Returns both the root dir and the\n * declared package name, or null if there's no workspace core in the tree.\n */\nasync function findWorkspaceRoot(\n startDir: string,\n): Promise<{ workspaceRoot: string; packageName: string } | null> {\n const fs = await getFs();\n let dir = path.resolve(startDir);\n // Hard stop at filesystem root to avoid infinite loops.\n for (let i = 0; i < 20; i++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const declared = pkg?.[\"agent-native\"]?.workspaceCore;\n if (typeof declared === \"string\" && declared.length > 0) {\n return { workspaceRoot: dir, packageName: declared };\n }\n } catch {\n // Malformed package.json — keep walking up.\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve a workspace package name to its directory inside the monorepo.\n * Tries in order:\n * 1. <workspaceRoot>/node_modules/<packageName>/package.json (pnpm symlink)\n * 2. For each dir under <workspaceRoot>/packages/*, read its package.json\n * and match on `name`.\n * 3. For each dir under <workspaceRoot>/packages/*\\/*, same match.\n *\n * The pnpm symlink approach is fastest when deps are installed; the direct\n * scan is a fallback for pre-install scenarios (e.g. running tests before\n * the first `pnpm install` in a scaffolded workspace).\n */\nasync function resolvePackageDir(\n workspaceRoot: string,\n packageName: string,\n): Promise<string | null> {\n const fs = await getFs();\n\n // 1) pnpm / npm install symlink\n const nmCandidate = path.join(workspaceRoot, \"node_modules\", packageName);\n if (fs.existsSync(path.join(nmCandidate, \"package.json\"))) {\n return nmCandidate;\n }\n\n // 2) scan packages/*\n const packagesDir = path.join(workspaceRoot, \"packages\");\n const candidates: string[] = [];\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n candidates.push(path.join(packagesDir, entry.name));\n }\n }\n\n // 3) scan packages/*/* (for scoped layouts like packages/@company/core-module)\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || !entry.name.startsWith(\"@\")) continue;\n const scopeDir = path.join(packagesDir, entry.name);\n for (const sub of fs.readdirSync(scopeDir, { withFileTypes: true })) {\n if (!sub.isDirectory()) continue;\n candidates.push(path.join(scopeDir, sub.name));\n }\n }\n }\n\n for (const candidate of candidates) {\n const pkgPath = path.join(candidate, \"package.json\");\n if (!fs.existsSync(pkgPath)) continue;\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n if (pkg?.name === packageName) return candidate;\n } catch {\n // ignore\n }\n }\n return null;\n}\n\n/**\n * Probe a workspace core package directory to discover which plugin slots it\n * exports. We read its package.json `exports` field + peek at\n * `src/server/index.ts` (or dist/server/index.js) looking for exports of the\n * form `<slot>Plugin` — the same convention the core server index uses.\n */\nasync function discoverPluginExports(\n packageDir: string,\n): Promise<Partial<Record<PluginSlot, string>>> {\n const fs = await getFs();\n const out: Partial<Record<PluginSlot, string>> = {};\n\n const candidates = [\n path.join(packageDir, \"src\", \"server\", \"index.ts\"),\n path.join(packageDir, \"dist\", \"server\", \"index.js\"),\n path.join(packageDir, \"src\", \"server.ts\"),\n path.join(packageDir, \"dist\", \"server.js\"),\n ];\n\n let source = \"\";\n for (const c of candidates) {\n if (fs.existsSync(c)) {\n try {\n source = fs.readFileSync(c, \"utf-8\");\n break;\n } catch {\n // keep trying\n }\n }\n }\n if (!source) return out;\n\n // Map slot name → export name we're looking for. \"agent-chat\" has a hyphen,\n // so we probe both the camelCase and dash-free variants.\n const slotExportNames: Record<PluginSlot, string[]> = {\n \"agent-chat\": [\"agentChatPlugin\"],\n auth: [\"authPlugin\"],\n \"core-routes\": [\"coreRoutesPlugin\"],\n integrations: [\"integrationsPlugin\"],\n org: [\"orgPlugin\"],\n resources: [\"resourcesPlugin\"],\n terminal: [\"terminalPlugin\"],\n };\n\n for (const [slot, names] of Object.entries(slotExportNames) as [\n PluginSlot,\n string[],\n ][]) {\n for (const name of names) {\n // Match any of:\n // export const <name>\n // export async function <name>\n // export function <name>\n // export { <name>\n // export { foo as <name>\n const patterns = [\n new RegExp(`export\\\\s+const\\\\s+${name}\\\\b`, \"m\"),\n new RegExp(`export\\\\s+(?:async\\\\s+)?function\\\\s+${name}\\\\b`, \"m\"),\n new RegExp(`export\\\\s*\\\\{[^}]*?\\\\b${name}\\\\b[^}]*?\\\\}`, \"m\"),\n ];\n if (patterns.some((re) => re.test(source))) {\n out[slot] = name;\n break;\n }\n }\n }\n return out;\n}\n\n/**\n * Main entry point. Discovers the workspace core for the given cwd (defaults\n * to process.cwd()) and returns its layout. Returns null if there's no\n * workspace core in the ancestor chain. Result is cached per-cwd so repeated\n * calls during a single build are cheap.\n */\nexport async function getWorkspaceCoreExports(\n cwd: string = process.cwd(),\n): Promise<WorkspaceCoreExports | null> {\n if (cache && cache.cwd === cwd) return cache.result;\n\n const fs = await getFs();\n\n const rootInfo = await findWorkspaceRoot(cwd);\n if (!rootInfo) {\n cache = { cwd, result: null };\n return null;\n }\n\n const packageDir = await resolvePackageDir(\n rootInfo.workspaceRoot,\n rootInfo.packageName,\n );\n if (!packageDir) {\n cache = { cwd, result: null };\n return null;\n }\n\n const plugins = await discoverPluginExports(packageDir);\n\n const actionsDir = path.join(packageDir, \"actions\");\n const skillsDir = path.join(packageDir, \"skills\");\n const agentsMdPath = path.join(packageDir, \"AGENTS.md\");\n\n const result: WorkspaceCoreExports = {\n workspaceRoot: rootInfo.workspaceRoot,\n packageName: rootInfo.packageName,\n packageDir,\n plugins,\n actionsDir: fs.existsSync(actionsDir) ? actionsDir : null,\n skillsDir: fs.existsSync(skillsDir) ? skillsDir : null,\n agentsMdPath: fs.existsSync(agentsMdPath) ? agentsMdPath : null,\n };\n\n cache = { cwd, result };\n return result;\n}\n\n/** Reset the internal cache. Exposed only for tests. */\nexport function _resetWorkspaceCoreCache(): void {\n cache = undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-core.js","sourceRoot":"","sources":["../../src/deploy/workspace-core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workspace-core discovery.\n *\n * An enterprise can sit many agent-native apps in one monorepo alongside a\n * private workspace shared package that can provide shared plugins, skills,\n * actions, and AGENTS.md. Apps inherit everything from\n * the shared package without writing any boilerplate — this is the\n * middle layer of the three-layer inheritance model:\n *\n * 1. app local (highest priority — app's own server/plugins/, actions/, etc.)\n * 2. workspace core (middle — packages/shared/ in the enterprise monorepo)\n * 3. @agent-native/core (lowest — framework defaults)\n *\n * Discovery works by walking up from the build cwd looking for a package.json\n * that declares `\"agent-native\": { \"workspaceCore\": \"@company/shared\" }`.\n * The declared package is then resolved through the monorepo's node_modules,\n * and its directory structure is probed for the standard layout:\n *\n * packages/shared/\n * package.json\n * src/server/index.ts (exports <slot>Plugin for any slot it wants to provide)\n * actions/ (shared agent-callable actions)\n * .agents/skills/ (shared skills)\n * AGENTS.md (enterprise-wide agent instructions)\n * src/client/ (optional shared React code)\n */\nimport path from \"path\";\n\nlet _fs: typeof import(\"fs\") | undefined;\nasync function getFs(): Promise<typeof import(\"fs\")> {\n if (!_fs) _fs = await import(\"node:fs\");\n return _fs;\n}\n\n/** Mirrors DEFAULT_PLUGIN_REGISTRY's slot names. */\nexport type PluginSlot =\n | \"agent-chat\"\n | \"auth\"\n | \"core-routes\"\n | \"integrations\"\n | \"org\"\n | \"resources\"\n | \"terminal\";\n\nexport interface WorkspaceCoreExports {\n /** Absolute path of the monorepo root (the dir containing the root package.json). */\n workspaceRoot: string;\n /** Resolved package name — e.g. \"@my-company/shared\". */\n packageName: string;\n /** Absolute path to the workspace core package's root directory. */\n packageDir: string;\n /** Plugin slot → export name (if the workspace core declares an override for that slot). */\n plugins: Partial<Record<PluginSlot, string>>;\n /** Absolute path to the workspace core's actions/ directory, or null if it doesn't have one. */\n actionsDir: string | null;\n /** Absolute path to the workspace core's skills/ directory, or null. */\n skillsDir: string | null;\n /** Absolute path to the workspace core's AGENTS.md, or null. */\n agentsMdPath: string | null;\n}\n\nlet cache: { cwd: string; result: WorkspaceCoreExports | null } | undefined;\n\n/**\n * Walk up from startDir looking for a directory whose package.json has an\n * `agent-native.workspaceCore` field. Returns both the root dir and the\n * declared package name, or null if there's no workspace core in the tree.\n */\nasync function findWorkspaceRoot(\n startDir: string,\n): Promise<{ workspaceRoot: string; packageName: string } | null> {\n const fs = await getFs();\n let dir = path.resolve(startDir);\n // Hard stop at filesystem root to avoid infinite loops.\n for (let i = 0; i < 20; i++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const declared = pkg?.[\"agent-native\"]?.workspaceCore;\n if (typeof declared === \"string\" && declared.length > 0) {\n return { workspaceRoot: dir, packageName: declared };\n }\n } catch {\n // Malformed package.json — keep walking up.\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve a workspace package name to its directory inside the monorepo.\n * Tries in order:\n * 1. <workspaceRoot>/node_modules/<packageName>/package.json (pnpm symlink)\n * 2. For each dir under <workspaceRoot>/packages/*, read its package.json\n * and match on `name`.\n * 3. For each dir under <workspaceRoot>/packages/*\\/*, same match.\n *\n * The pnpm symlink approach is fastest when deps are installed; the direct\n * scan is a fallback for pre-install scenarios (e.g. running tests before\n * the first `pnpm install` in a scaffolded workspace).\n */\nasync function resolvePackageDir(\n workspaceRoot: string,\n packageName: string,\n): Promise<string | null> {\n const fs = await getFs();\n\n // 1) pnpm / npm install symlink\n const nmCandidate = path.join(workspaceRoot, \"node_modules\", packageName);\n if (fs.existsSync(path.join(nmCandidate, \"package.json\"))) {\n return nmCandidate;\n }\n\n // 2) scan packages/*\n const packagesDir = path.join(workspaceRoot, \"packages\");\n const candidates: string[] = [];\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n candidates.push(path.join(packagesDir, entry.name));\n }\n }\n\n // 3) scan packages/*/* (for scoped layouts like packages/@company/shared)\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || !entry.name.startsWith(\"@\")) continue;\n const scopeDir = path.join(packagesDir, entry.name);\n for (const sub of fs.readdirSync(scopeDir, { withFileTypes: true })) {\n if (!sub.isDirectory()) continue;\n candidates.push(path.join(scopeDir, sub.name));\n }\n }\n }\n\n for (const candidate of candidates) {\n const pkgPath = path.join(candidate, \"package.json\");\n if (!fs.existsSync(pkgPath)) continue;\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n if (pkg?.name === packageName) return candidate;\n } catch {\n // ignore\n }\n }\n return null;\n}\n\n/**\n * Probe a workspace core package directory to discover which plugin slots it\n * exports. We read its package.json `exports` field + peek at\n * `src/server/index.ts` (or dist/server/index.js) looking for exports of the\n * form `<slot>Plugin` — the same convention the core server index uses.\n */\nasync function discoverPluginExports(\n packageDir: string,\n): Promise<Partial<Record<PluginSlot, string>>> {\n const fs = await getFs();\n const out: Partial<Record<PluginSlot, string>> = {};\n\n const candidates = [\n path.join(packageDir, \"src\", \"server\", \"index.ts\"),\n path.join(packageDir, \"dist\", \"server\", \"index.js\"),\n path.join(packageDir, \"src\", \"server.ts\"),\n path.join(packageDir, \"dist\", \"server.js\"),\n ];\n\n let source = \"\";\n for (const c of candidates) {\n if (fs.existsSync(c)) {\n try {\n source = fs.readFileSync(c, \"utf-8\");\n break;\n } catch {\n // keep trying\n }\n }\n }\n if (!source) return out;\n\n // Map slot name → export name we're looking for. \"agent-chat\" has a hyphen,\n // so we probe both the camelCase and dash-free variants.\n const slotExportNames: Record<PluginSlot, string[]> = {\n \"agent-chat\": [\"agentChatPlugin\"],\n auth: [\"authPlugin\"],\n \"core-routes\": [\"coreRoutesPlugin\"],\n integrations: [\"integrationsPlugin\"],\n org: [\"orgPlugin\"],\n resources: [\"resourcesPlugin\"],\n terminal: [\"terminalPlugin\"],\n };\n\n for (const [slot, names] of Object.entries(slotExportNames) as [\n PluginSlot,\n string[],\n ][]) {\n for (const name of names) {\n // Match any of:\n // export const <name>\n // export async function <name>\n // export function <name>\n // export { <name>\n // export { foo as <name>\n const patterns = [\n new RegExp(`export\\\\s+const\\\\s+${name}\\\\b`, \"m\"),\n new RegExp(`export\\\\s+(?:async\\\\s+)?function\\\\s+${name}\\\\b`, \"m\"),\n new RegExp(`export\\\\s*\\\\{[^}]*?\\\\b${name}\\\\b[^}]*?\\\\}`, \"m\"),\n ];\n if (patterns.some((re) => re.test(source))) {\n out[slot] = name;\n break;\n }\n }\n }\n return out;\n}\n\n/**\n * Main entry point. Discovers the workspace core for the given cwd (defaults\n * to process.cwd()) and returns its layout. Returns null if there's no\n * workspace core in the ancestor chain. Result is cached per-cwd so repeated\n * calls during a single build are cheap.\n */\nexport async function getWorkspaceCoreExports(\n cwd: string = process.cwd(),\n): Promise<WorkspaceCoreExports | null> {\n if (cache && cache.cwd === cwd) return cache.result;\n\n const fs = await getFs();\n\n const rootInfo = await findWorkspaceRoot(cwd);\n if (!rootInfo) {\n cache = { cwd, result: null };\n return null;\n }\n\n const packageDir = await resolvePackageDir(\n rootInfo.workspaceRoot,\n rootInfo.packageName,\n );\n if (!packageDir) {\n cache = { cwd, result: null };\n return null;\n }\n\n const plugins = await discoverPluginExports(packageDir);\n\n const actionsDir = path.join(packageDir, \"actions\");\n const skillsDir =\n [\n path.join(packageDir, \".agents\", \"skills\"),\n path.join(packageDir, \"skills\"),\n ].find((candidate) => fs.existsSync(candidate)) ?? null;\n const agentsMdPath = path.join(packageDir, \"AGENTS.md\");\n\n const result: WorkspaceCoreExports = {\n workspaceRoot: rootInfo.workspaceRoot,\n packageName: rootInfo.packageName,\n packageDir,\n plugins,\n actionsDir: fs.existsSync(actionsDir) ? actionsDir : null,\n skillsDir,\n agentsMdPath: fs.existsSync(agentsMdPath) ? agentsMdPath : null,\n };\n\n cache = { cwd, result };\n return result;\n}\n\n/** Reset the internal cache. Exposed only for tests. */\nexport function _resetWorkspaceCoreCache(): void {\n cache = undefined;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlatformAdapter } from "./types.js";
|
|
2
|
+
export declare function dispatchA2AContinuation(continuationId: string, webhookBaseUrl?: string): Promise<void>;
|
|
3
|
+
export declare function processA2AContinuationById(continuationId: string, options: {
|
|
4
|
+
adapters: Map<string, PlatformAdapter>;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function processDueA2AContinuations(options: {
|
|
7
|
+
adapters: Map<string, PlatformAdapter>;
|
|
8
|
+
limit?: number;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=a2a-continuation-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-continuation-processor.d.ts","sourceRoot":"","sources":["../../src/integrations/a2a-continuation-processor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgBlD,wBAAsB,uBAAuB,CAC3C,cAAc,EAAE,MAAM,EACtB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CA0Cf;AAED,wBAAsB,0BAA0B,CAC9C,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE;IAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CAAE,GAClD,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { A2AClient, signA2AToken } from "../a2a/client.js";
|
|
2
|
+
import { withConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
3
|
+
import { FRAMEWORK_ROUTE_PREFIX } from "../server/core-routes-plugin.js";
|
|
4
|
+
import { signInternalToken } from "./internal-token.js";
|
|
5
|
+
import { claimA2AContinuation, claimDueA2AContinuations, completeA2AContinuation, failA2AContinuation, rescheduleA2AContinuation, } from "./a2a-continuations-store.js";
|
|
6
|
+
const PROCESSOR_PATH = `${FRAMEWORK_ROUTE_PREFIX}/integrations/process-a2a-continuation`;
|
|
7
|
+
const TERMINAL_STATES = new Set(["completed", "failed", "canceled"]);
|
|
8
|
+
const MAX_ATTEMPTS = 6;
|
|
9
|
+
const POLL_INTERVAL_MS = 2_000;
|
|
10
|
+
const PROCESSOR_WAIT_MS = 20_000;
|
|
11
|
+
export async function dispatchA2AContinuation(continuationId, webhookBaseUrl) {
|
|
12
|
+
const baseUrl = webhookBaseUrl ||
|
|
13
|
+
process.env.WEBHOOK_BASE_URL ||
|
|
14
|
+
process.env.APP_URL ||
|
|
15
|
+
process.env.URL ||
|
|
16
|
+
process.env.DEPLOY_URL ||
|
|
17
|
+
`http://localhost:${process.env.PORT || 3000}`;
|
|
18
|
+
const url = `${withConfiguredAppBasePath(baseUrl)}${PROCESSOR_PATH}`;
|
|
19
|
+
const headers = {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
};
|
|
22
|
+
try {
|
|
23
|
+
headers["Authorization"] = `Bearer ${signInternalToken(continuationId)}`;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (process.env.NODE_ENV === "production") {
|
|
27
|
+
console.error(`[integrations] Refusing to dispatch A2A continuation ${continuationId} — A2A_SECRET not configured.`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {
|
|
31
|
+
console.error(`[integrations] signInternalToken failed unexpectedly for ${continuationId}:`, err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const controller = new AbortController();
|
|
35
|
+
const timer = setTimeout(() => controller.abort(), 5_000);
|
|
36
|
+
try {
|
|
37
|
+
await fetch(url, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers,
|
|
40
|
+
body: JSON.stringify({ continuationId }),
|
|
41
|
+
signal: controller.signal,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function processA2AContinuationById(continuationId, options) {
|
|
49
|
+
const continuation = await claimA2AContinuation(continuationId);
|
|
50
|
+
if (!continuation)
|
|
51
|
+
return;
|
|
52
|
+
await processClaimedContinuation(continuation, options);
|
|
53
|
+
}
|
|
54
|
+
export async function processDueA2AContinuations(options) {
|
|
55
|
+
const continuations = await claimDueA2AContinuations(options.limit ?? 5);
|
|
56
|
+
for (const continuation of continuations) {
|
|
57
|
+
await processClaimedContinuation(continuation, options).catch((err) => console.error(`[integrations] A2A continuation ${continuation.id} failed:`, err));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function processClaimedContinuation(continuation, options) {
|
|
61
|
+
const adapter = options.adapters.get(continuation.platform);
|
|
62
|
+
if (!adapter) {
|
|
63
|
+
await failA2AContinuation(continuation.id, `Unknown platform: ${continuation.platform}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const client = new A2AClient(continuation.agentUrl, await signContinuationToken(continuation));
|
|
67
|
+
const deadline = Date.now() + PROCESSOR_WAIT_MS;
|
|
68
|
+
let task = null;
|
|
69
|
+
try {
|
|
70
|
+
while (Date.now() < deadline) {
|
|
71
|
+
task = await client.getTask(continuation.a2aTaskId);
|
|
72
|
+
if (TERMINAL_STATES.has(task.status.state))
|
|
73
|
+
break;
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
if (continuation.attempts >= MAX_ATTEMPTS) {
|
|
79
|
+
await failA2AContinuation(continuation.id, err instanceof Error ? err.message : String(err));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
await rescheduleA2AContinuation(continuation.id, 30_000);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (!task || !TERMINAL_STATES.has(task.status.state)) {
|
|
86
|
+
if (continuation.attempts >= MAX_ATTEMPTS) {
|
|
87
|
+
await failA2AContinuation(continuation.id, `Remote A2A task ${continuation.a2aTaskId} did not complete after ${MAX_ATTEMPTS} attempts`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
await rescheduleA2AContinuation(continuation.id, 30_000);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (task.status.state !== "completed") {
|
|
94
|
+
await failA2AContinuation(continuation.id, `Remote A2A task ${continuation.a2aTaskId} ended with state ${task.status.state}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const text = expandRelativeUrls(extractTaskText(task), continuation.agentUrl);
|
|
98
|
+
if (!text.trim()) {
|
|
99
|
+
await failA2AContinuation(continuation.id, `Remote A2A task ${continuation.a2aTaskId} completed without text`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await adapter.sendResponse(adapter.formatAgentResponse(text), continuation.incoming, { placeholderRef: continuation.placeholderRef ?? undefined });
|
|
104
|
+
await completeA2AContinuation(continuation.id);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
if (continuation.attempts >= MAX_ATTEMPTS) {
|
|
108
|
+
await failA2AContinuation(continuation.id, err instanceof Error ? err.message : String(err));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await rescheduleA2AContinuation(continuation.id, 30_000);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function signContinuationToken(continuation) {
|
|
115
|
+
let orgDomain;
|
|
116
|
+
let orgSecret;
|
|
117
|
+
if (continuation.orgId) {
|
|
118
|
+
try {
|
|
119
|
+
const { getOrgDomain, getOrgA2ASecret } = await import("../org/context.js");
|
|
120
|
+
orgDomain = (await getOrgDomain(continuation.orgId)) ?? undefined;
|
|
121
|
+
orgSecret = (await getOrgA2ASecret(continuation.orgId)) ?? undefined;
|
|
122
|
+
}
|
|
123
|
+
catch { }
|
|
124
|
+
}
|
|
125
|
+
if (!continuation.ownerEmail || !(orgSecret || process.env.A2A_SECRET)) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
return await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function extractTaskText(task) {
|
|
136
|
+
const parts = task.status.message?.parts ?? [];
|
|
137
|
+
return parts
|
|
138
|
+
.filter((part) => {
|
|
139
|
+
return part.type === "text" && typeof part.text === "string";
|
|
140
|
+
})
|
|
141
|
+
.map((part) => part.text)
|
|
142
|
+
.join("\n");
|
|
143
|
+
}
|
|
144
|
+
function expandRelativeUrls(text, agentUrl) {
|
|
145
|
+
if (!text || !agentUrl)
|
|
146
|
+
return text;
|
|
147
|
+
const base = agentUrl.replace(/\/$/, "");
|
|
148
|
+
return text.replace(/(^|[\s(\[<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi, (_match, lead, path) => `${lead}${base}${path}`);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=a2a-continuation-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-continuation-processor.js","sourceRoot":"","sources":["../../src/integrations/a2a-continuation-processor.ts"],"names":[],"mappings":"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","sourcesContent":["import { A2AClient, signA2AToken } from \"../a2a/client.js\";\nimport type { Task } from \"../a2a/types.js\";\nimport { withConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { FRAMEWORK_ROUTE_PREFIX } from \"../server/core-routes-plugin.js\";\nimport { signInternalToken } from \"./internal-token.js\";\nimport type { PlatformAdapter } from \"./types.js\";\nimport {\n claimA2AContinuation,\n claimDueA2AContinuations,\n completeA2AContinuation,\n failA2AContinuation,\n rescheduleA2AContinuation,\n type A2AContinuation,\n} from \"./a2a-continuations-store.js\";\n\nconst PROCESSOR_PATH = `${FRAMEWORK_ROUTE_PREFIX}/integrations/process-a2a-continuation`;\nconst TERMINAL_STATES = new Set([\"completed\", \"failed\", \"canceled\"]);\nconst MAX_ATTEMPTS = 6;\nconst POLL_INTERVAL_MS = 2_000;\nconst PROCESSOR_WAIT_MS = 20_000;\n\nexport async function dispatchA2AContinuation(\n continuationId: string,\n webhookBaseUrl?: string,\n): Promise<void> {\n const baseUrl =\n webhookBaseUrl ||\n process.env.WEBHOOK_BASE_URL ||\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n `http://localhost:${process.env.PORT || 3000}`;\n\n const url = `${withConfiguredAppBasePath(baseUrl)}${PROCESSOR_PATH}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(continuationId)}`;\n } catch (err) {\n if (process.env.NODE_ENV === \"production\") {\n console.error(\n `[integrations] Refusing to dispatch A2A continuation ${continuationId} — A2A_SECRET not configured.`,\n );\n return;\n }\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[integrations] signInternalToken failed unexpectedly for ${continuationId}:`,\n err,\n );\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n try {\n await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ continuationId }),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function processA2AContinuationById(\n continuationId: string,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const continuation = await claimA2AContinuation(continuationId);\n if (!continuation) return;\n await processClaimedContinuation(continuation, options);\n}\n\nexport async function processDueA2AContinuations(options: {\n adapters: Map<string, PlatformAdapter>;\n limit?: number;\n}): Promise<void> {\n const continuations = await claimDueA2AContinuations(options.limit ?? 5);\n for (const continuation of continuations) {\n await processClaimedContinuation(continuation, options).catch((err) =>\n console.error(\n `[integrations] A2A continuation ${continuation.id} failed:`,\n err,\n ),\n );\n }\n}\n\nasync function processClaimedContinuation(\n continuation: A2AContinuation,\n options: { adapters: Map<string, PlatformAdapter> },\n): Promise<void> {\n const adapter = options.adapters.get(continuation.platform);\n if (!adapter) {\n await failA2AContinuation(\n continuation.id,\n `Unknown platform: ${continuation.platform}`,\n );\n return;\n }\n\n const client = new A2AClient(\n continuation.agentUrl,\n await signContinuationToken(continuation),\n );\n const deadline = Date.now() + PROCESSOR_WAIT_MS;\n let task: Task | null = null;\n\n try {\n while (Date.now() < deadline) {\n task = await client.getTask(continuation.a2aTaskId);\n if (TERMINAL_STATES.has(task.status.state)) break;\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n } catch (err) {\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await failA2AContinuation(\n continuation.id,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, 30_000);\n return;\n }\n\n if (!task || !TERMINAL_STATES.has(task.status.state)) {\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await failA2AContinuation(\n continuation.id,\n `Remote A2A task ${continuation.a2aTaskId} did not complete after ${MAX_ATTEMPTS} attempts`,\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, 30_000);\n return;\n }\n\n if (task.status.state !== \"completed\") {\n await failA2AContinuation(\n continuation.id,\n `Remote A2A task ${continuation.a2aTaskId} ended with state ${task.status.state}`,\n );\n return;\n }\n\n const text = expandRelativeUrls(extractTaskText(task), continuation.agentUrl);\n if (!text.trim()) {\n await failA2AContinuation(\n continuation.id,\n `Remote A2A task ${continuation.a2aTaskId} completed without text`,\n );\n return;\n }\n\n try {\n await adapter.sendResponse(\n adapter.formatAgentResponse(text),\n continuation.incoming,\n { placeholderRef: continuation.placeholderRef ?? undefined },\n );\n await completeA2AContinuation(continuation.id);\n } catch (err) {\n if (continuation.attempts >= MAX_ATTEMPTS) {\n await failA2AContinuation(\n continuation.id,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n await rescheduleA2AContinuation(continuation.id, 30_000);\n }\n}\n\nasync function signContinuationToken(\n continuation: A2AContinuation,\n): Promise<string | undefined> {\n let orgDomain: string | undefined;\n let orgSecret: string | undefined;\n if (continuation.orgId) {\n try {\n const { getOrgDomain, getOrgA2ASecret } =\n await import(\"../org/context.js\");\n orgDomain = (await getOrgDomain(continuation.orgId)) ?? undefined;\n orgSecret = (await getOrgA2ASecret(continuation.orgId)) ?? undefined;\n } catch {}\n }\n\n if (!continuation.ownerEmail || !(orgSecret || process.env.A2A_SECRET)) {\n return undefined;\n }\n\n try {\n return await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret);\n } catch {\n return undefined;\n }\n}\n\nfunction extractTaskText(task: Task): string {\n const parts = task.status.message?.parts ?? [];\n return parts\n .filter((part): part is { type: \"text\"; text: string } => {\n return part.type === \"text\" && typeof part.text === \"string\";\n })\n .map((part) => part.text)\n .join(\"\\n\");\n}\n\nfunction expandRelativeUrls(text: string, agentUrl: string): string {\n if (!text || !agentUrl) return text;\n const base = agentUrl.replace(/\\/$/, \"\");\n return text.replace(\n /(^|[\\s(\\[<\"'`])(\\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,\n (_match, lead, path) => `${lead}${base}${path}`,\n );\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { IncomingMessage } from "./types.js";
|
|
2
|
+
export type A2AContinuationStatus = "pending" | "processing" | "completed" | "failed";
|
|
3
|
+
export interface A2AContinuation {
|
|
4
|
+
id: string;
|
|
5
|
+
integrationTaskId: string;
|
|
6
|
+
platform: string;
|
|
7
|
+
externalThreadId: string;
|
|
8
|
+
incoming: IncomingMessage;
|
|
9
|
+
placeholderRef: string | null;
|
|
10
|
+
ownerEmail: string;
|
|
11
|
+
orgId: string | null;
|
|
12
|
+
agentName: string;
|
|
13
|
+
agentUrl: string;
|
|
14
|
+
a2aTaskId: string;
|
|
15
|
+
status: A2AContinuationStatus;
|
|
16
|
+
attempts: number;
|
|
17
|
+
nextCheckAt: number;
|
|
18
|
+
errorMessage: string | null;
|
|
19
|
+
createdAt: number;
|
|
20
|
+
updatedAt: number;
|
|
21
|
+
completedAt: number | null;
|
|
22
|
+
}
|
|
23
|
+
export declare function insertA2AContinuation(input: {
|
|
24
|
+
integrationTaskId: string;
|
|
25
|
+
platform: string;
|
|
26
|
+
externalThreadId: string;
|
|
27
|
+
incoming: IncomingMessage;
|
|
28
|
+
placeholderRef?: string | null;
|
|
29
|
+
ownerEmail: string;
|
|
30
|
+
orgId?: string | null;
|
|
31
|
+
agentName: string;
|
|
32
|
+
agentUrl: string;
|
|
33
|
+
a2aTaskId: string;
|
|
34
|
+
}): Promise<A2AContinuation>;
|
|
35
|
+
export declare function getA2AContinuation(id: string): Promise<A2AContinuation | null>;
|
|
36
|
+
export declare function claimA2AContinuation(id: string): Promise<A2AContinuation | null>;
|
|
37
|
+
export declare function claimDueA2AContinuations(limit?: number): Promise<A2AContinuation[]>;
|
|
38
|
+
export declare function rescheduleA2AContinuation(id: string, delayMs: number): Promise<void>;
|
|
39
|
+
export declare function completeA2AContinuation(id: string): Promise<void>;
|
|
40
|
+
export declare function failA2AContinuation(id: string, errorMessage: string): Promise<void>;
|
|
41
|
+
//# sourceMappingURL=a2a-continuations-store.d.ts.map
|
|
@@ -0,0 +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;AAyClD,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,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,CAAC;IAClB,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;AA0BD,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,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,eAAe,CAAC,CA4C3B;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,CAuBjC;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,SAAI,GACR,OAAO,CAAC,eAAe,EAAE,CAAC,CAuB5B;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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { getDbExec, isPostgres, intType } from "../db/client.js";
|
|
2
|
+
let _initPromise;
|
|
3
|
+
async function ensureTable() {
|
|
4
|
+
if (!_initPromise) {
|
|
5
|
+
_initPromise = (async () => {
|
|
6
|
+
const client = getDbExec();
|
|
7
|
+
await client.execute(`
|
|
8
|
+
CREATE TABLE IF NOT EXISTS integration_a2a_continuations (
|
|
9
|
+
id TEXT PRIMARY KEY,
|
|
10
|
+
integration_task_id TEXT NOT NULL,
|
|
11
|
+
platform TEXT NOT NULL,
|
|
12
|
+
external_thread_id TEXT NOT NULL,
|
|
13
|
+
incoming_payload TEXT NOT NULL,
|
|
14
|
+
placeholder_ref TEXT,
|
|
15
|
+
owner_email TEXT NOT NULL,
|
|
16
|
+
org_id TEXT,
|
|
17
|
+
agent_name TEXT NOT NULL,
|
|
18
|
+
agent_url TEXT NOT NULL,
|
|
19
|
+
a2a_task_id TEXT NOT NULL,
|
|
20
|
+
status TEXT NOT NULL,
|
|
21
|
+
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
22
|
+
next_check_at ${intType()} NOT NULL,
|
|
23
|
+
error_message TEXT,
|
|
24
|
+
created_at ${intType()} NOT NULL,
|
|
25
|
+
updated_at ${intType()} NOT NULL,
|
|
26
|
+
completed_at ${intType()}
|
|
27
|
+
)
|
|
28
|
+
`);
|
|
29
|
+
await client.execute(`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`);
|
|
30
|
+
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)`);
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
return _initPromise;
|
|
34
|
+
}
|
|
35
|
+
function rowToContinuation(row) {
|
|
36
|
+
return {
|
|
37
|
+
id: row.id,
|
|
38
|
+
integrationTaskId: row.integration_task_id,
|
|
39
|
+
platform: row.platform,
|
|
40
|
+
externalThreadId: row.external_thread_id,
|
|
41
|
+
incoming: JSON.parse(row.incoming_payload),
|
|
42
|
+
placeholderRef: row.placeholder_ref ?? null,
|
|
43
|
+
ownerEmail: row.owner_email,
|
|
44
|
+
orgId: row.org_id ?? null,
|
|
45
|
+
agentName: row.agent_name,
|
|
46
|
+
agentUrl: row.agent_url,
|
|
47
|
+
a2aTaskId: row.a2a_task_id,
|
|
48
|
+
status: row.status,
|
|
49
|
+
attempts: Number(row.attempts ?? 0),
|
|
50
|
+
nextCheckAt: Number(row.next_check_at ?? 0),
|
|
51
|
+
errorMessage: row.error_message ?? null,
|
|
52
|
+
createdAt: Number(row.created_at ?? 0),
|
|
53
|
+
updatedAt: Number(row.updated_at ?? 0),
|
|
54
|
+
completedAt: row.completed_at == null ? null : Number(row.completed_at),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export async function insertA2AContinuation(input) {
|
|
58
|
+
await ensureTable();
|
|
59
|
+
const client = getDbExec();
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const id = `a2a-cont-${now}-${Math.random().toString(36).slice(2, 8)}`;
|
|
62
|
+
const payload = JSON.stringify(input.incoming);
|
|
63
|
+
try {
|
|
64
|
+
await client.execute({
|
|
65
|
+
sql: `INSERT INTO integration_a2a_continuations
|
|
66
|
+
(id, integration_task_id, platform, external_thread_id, incoming_payload,
|
|
67
|
+
placeholder_ref, owner_email, org_id, agent_name, agent_url, a2a_task_id,
|
|
68
|
+
status, attempts, next_check_at, created_at, updated_at)
|
|
69
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
70
|
+
args: [
|
|
71
|
+
id,
|
|
72
|
+
input.integrationTaskId,
|
|
73
|
+
input.platform,
|
|
74
|
+
input.externalThreadId,
|
|
75
|
+
payload,
|
|
76
|
+
input.placeholderRef ?? null,
|
|
77
|
+
input.ownerEmail,
|
|
78
|
+
input.orgId ?? null,
|
|
79
|
+
input.agentName,
|
|
80
|
+
input.agentUrl,
|
|
81
|
+
input.a2aTaskId,
|
|
82
|
+
"pending",
|
|
83
|
+
0,
|
|
84
|
+
now,
|
|
85
|
+
now,
|
|
86
|
+
now,
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
return (await getA2AContinuation(id));
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
if (!isDuplicateContinuationError(err))
|
|
93
|
+
throw err;
|
|
94
|
+
const existing = await findA2AContinuation(input.integrationTaskId, input.agentUrl, input.a2aTaskId);
|
|
95
|
+
if (existing)
|
|
96
|
+
return existing;
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function isDuplicateContinuationError(err) {
|
|
101
|
+
const e = err;
|
|
102
|
+
if (!e)
|
|
103
|
+
return false;
|
|
104
|
+
if (e.code === "23505")
|
|
105
|
+
return true;
|
|
106
|
+
const msg = String(e.message ?? "").toLowerCase();
|
|
107
|
+
return (msg.includes("unique") ||
|
|
108
|
+
msg.includes("duplicate entry") ||
|
|
109
|
+
msg.includes("duplicate key"));
|
|
110
|
+
}
|
|
111
|
+
async function findA2AContinuation(integrationTaskId, agentUrl, a2aTaskId) {
|
|
112
|
+
await ensureTable();
|
|
113
|
+
const client = getDbExec();
|
|
114
|
+
const { rows } = await client.execute({
|
|
115
|
+
sql: `SELECT * FROM integration_a2a_continuations
|
|
116
|
+
WHERE integration_task_id = ? AND agent_url = ? AND a2a_task_id = ?
|
|
117
|
+
LIMIT 1`,
|
|
118
|
+
args: [integrationTaskId, agentUrl, a2aTaskId],
|
|
119
|
+
});
|
|
120
|
+
return rows[0] ? rowToContinuation(rows[0]) : null;
|
|
121
|
+
}
|
|
122
|
+
export async function getA2AContinuation(id) {
|
|
123
|
+
await ensureTable();
|
|
124
|
+
const client = getDbExec();
|
|
125
|
+
const { rows } = await client.execute({
|
|
126
|
+
sql: `SELECT * FROM integration_a2a_continuations WHERE id = ? LIMIT 1`,
|
|
127
|
+
args: [id],
|
|
128
|
+
});
|
|
129
|
+
return rows[0] ? rowToContinuation(rows[0]) : null;
|
|
130
|
+
}
|
|
131
|
+
export async function claimA2AContinuation(id) {
|
|
132
|
+
await ensureTable();
|
|
133
|
+
const client = getDbExec();
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
const { rows } = await client.execute({
|
|
136
|
+
sql: isPostgres()
|
|
137
|
+
? `UPDATE integration_a2a_continuations
|
|
138
|
+
SET status = ?, attempts = attempts + 1, updated_at = ?
|
|
139
|
+
WHERE id = ? AND status = 'pending'
|
|
140
|
+
RETURNING *`
|
|
141
|
+
: `UPDATE integration_a2a_continuations
|
|
142
|
+
SET status = ?, attempts = attempts + 1, updated_at = ?
|
|
143
|
+
WHERE id = ? AND status = 'pending'`,
|
|
144
|
+
args: ["processing", now, id],
|
|
145
|
+
});
|
|
146
|
+
if (isPostgres()) {
|
|
147
|
+
return rows[0]
|
|
148
|
+
? rowToContinuation(rows[0])
|
|
149
|
+
: null;
|
|
150
|
+
}
|
|
151
|
+
const fetched = await getA2AContinuation(id);
|
|
152
|
+
if (!fetched || fetched.status !== "processing")
|
|
153
|
+
return null;
|
|
154
|
+
return fetched;
|
|
155
|
+
}
|
|
156
|
+
export async function claimDueA2AContinuations(limit = 5) {
|
|
157
|
+
await ensureTable();
|
|
158
|
+
const client = getDbExec();
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
await client.execute({
|
|
161
|
+
sql: `UPDATE integration_a2a_continuations
|
|
162
|
+
SET status = ?, next_check_at = ?, updated_at = ?
|
|
163
|
+
WHERE status = 'processing' AND updated_at <= ?`,
|
|
164
|
+
args: ["pending", now, now, now - 5 * 60 * 1000],
|
|
165
|
+
});
|
|
166
|
+
const { rows } = await client.execute({
|
|
167
|
+
sql: `SELECT id FROM integration_a2a_continuations
|
|
168
|
+
WHERE status = 'pending' AND next_check_at <= ?
|
|
169
|
+
ORDER BY next_check_at ASC
|
|
170
|
+
LIMIT ?`,
|
|
171
|
+
args: [now, limit],
|
|
172
|
+
});
|
|
173
|
+
const claimed = [];
|
|
174
|
+
for (const row of rows) {
|
|
175
|
+
const continuation = await claimA2AContinuation(row.id);
|
|
176
|
+
if (continuation)
|
|
177
|
+
claimed.push(continuation);
|
|
178
|
+
}
|
|
179
|
+
return claimed;
|
|
180
|
+
}
|
|
181
|
+
export async function rescheduleA2AContinuation(id, delayMs) {
|
|
182
|
+
await ensureTable();
|
|
183
|
+
const client = getDbExec();
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
await client.execute({
|
|
186
|
+
sql: `UPDATE integration_a2a_continuations
|
|
187
|
+
SET status = ?, next_check_at = ?, updated_at = ?
|
|
188
|
+
WHERE id = ? AND status = 'processing'`,
|
|
189
|
+
args: ["pending", now + delayMs, now, id],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
export async function completeA2AContinuation(id) {
|
|
193
|
+
await ensureTable();
|
|
194
|
+
const client = getDbExec();
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
await client.execute({
|
|
197
|
+
sql: `UPDATE integration_a2a_continuations
|
|
198
|
+
SET status = ?, updated_at = ?, completed_at = ?
|
|
199
|
+
WHERE id = ?`,
|
|
200
|
+
args: ["completed", now, now, id],
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
export async function failA2AContinuation(id, errorMessage) {
|
|
204
|
+
await ensureTable();
|
|
205
|
+
const client = getDbExec();
|
|
206
|
+
const now = Date.now();
|
|
207
|
+
await client.execute({
|
|
208
|
+
sql: `UPDATE integration_a2a_continuations
|
|
209
|
+
SET status = ?, updated_at = ?, error_message = ?
|
|
210
|
+
WHERE id = ?`,
|
|
211
|
+
args: ["failed", now, errorMessage.slice(0, 2000), id],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=a2a-continuations-store.js.map
|
|
@@ -0,0 +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;\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 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 UNIQUE INDEX IF NOT EXISTS idx_a2a_continuations_remote_task ON integration_a2a_continuations(integration_task_id, agent_url, a2a_task_id)`,\n );\n })();\n }\n return _initPromise;\n}\n\nexport type A2AContinuationStatus =\n | \"pending\"\n | \"processing\"\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 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 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}): 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,\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 \"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\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 { rows } = await client.execute({\n sql: isPostgres()\n ? `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ? AND status = 'pending'\n RETURNING *`\n : `UPDATE integration_a2a_continuations\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ? AND status = 'pending'`,\n args: [\"processing\", now, id],\n });\n if (isPostgres()) {\n return rows[0]\n ? rowToContinuation(rows[0] as Record<string, unknown>)\n : null;\n }\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 await client.execute({\n sql: `UPDATE integration_a2a_continuations\n SET status = ?, next_check_at = ?, updated_at = ?\n WHERE status = 'processing' AND updated_at <= ?`,\n args: [\"pending\", now, now, now - 5 * 60 * 1000],\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 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 = 'processing'`,\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 = ?`,\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 = ?`,\n args: [\"failed\", now, errorMessage.slice(0, 2000), id],\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,aAAa,CAAC;AAOrB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,aAAa,CAAC;AAOrB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,IAAI,eAAe,CAgU9C"}
|
|
@@ -50,7 +50,10 @@ export function slackAdapter() {
|
|
|
50
50
|
try {
|
|
51
51
|
const parsed = JSON.parse(body);
|
|
52
52
|
if (parsed.type === "url_verification") {
|
|
53
|
-
|
|
53
|
+
// Slack's URL verifier expects the raw challenge value in the
|
|
54
|
+
// response body. Returning JSON works for some clients but the app
|
|
55
|
+
// settings verifier rejects it as not matching the challenge.
|
|
56
|
+
return { handled: true, response: parsed.challenge };
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
catch { }
|