@axiom-lattice/gateway 4.2.0 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{A2AAuthService-DK5X6VIL.mjs → A2AAuthService-7UGQ7GMW.mjs} +3 -2
- package/dist/{WechatChannelAdapter-WSDKR4OA.mjs → WechatChannelAdapter-7WHE5UGY.mjs} +2 -1
- package/dist/{WechatChannelAdapter-WSDKR4OA.mjs.map → WechatChannelAdapter-7WHE5UGY.mjs.map} +1 -1
- package/dist/{a2a-7N3WDAOP.mjs → a2a-FGYX2HH3.mjs} +71 -32
- package/dist/a2a-FGYX2HH3.mjs.map +1 -0
- package/dist/{a2a-standard-WC2BSOFV.mjs → a2a-standard-VEQBXBMM.mjs} +93 -115
- package/dist/a2a-standard-VEQBXBMM.mjs.map +1 -0
- package/dist/agentProvider-X4FVQPKW.mjs +88 -0
- package/dist/agentProvider-X4FVQPKW.mjs.map +1 -0
- package/dist/chunk-2POW27EI.mjs +27 -0
- package/dist/chunk-2POW27EI.mjs.map +1 -0
- package/dist/chunk-52SUWMOX.mjs +121 -0
- package/dist/chunk-52SUWMOX.mjs.map +1 -0
- package/dist/chunk-GF4GGTWJ.mjs +164 -0
- package/dist/chunk-GF4GGTWJ.mjs.map +1 -0
- package/dist/{chunk-2HOCF46L.mjs → chunk-GPHOYR3X.mjs} +33 -11
- package/dist/chunk-GPHOYR3X.mjs.map +1 -0
- package/dist/chunk-NFEGQTCC.mjs +27 -0
- package/dist/chunk-PWHUWFXL.mjs +173 -0
- package/dist/chunk-PWHUWFXL.mjs.map +1 -0
- package/dist/chunk-QUT2DS4R.mjs +50 -0
- package/dist/chunk-QUT2DS4R.mjs.map +1 -0
- package/dist/chunk-TJAUXMYJ.mjs +109 -0
- package/dist/chunk-TJAUXMYJ.mjs.map +1 -0
- package/dist/chunk-WKNZ7GBC.mjs +56 -0
- package/dist/chunk-WKNZ7GBC.mjs.map +1 -0
- package/dist/collection_service-RTRJEQFL.mjs +8 -0
- package/dist/embed/agent-chat-loader.js +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-6CVXM3P3.js → embed-page-AgentDetailSideApp-KGYKTMZR.js} +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-DRGKJ6C5.css → embed-page-AgentDetailSideApp-O6G4NJ7I.css} +1 -1
- package/dist/embed/{embed-page-AgentGovernanceWorkbench-4B3NJPCY.js → embed-page-AgentGovernanceWorkbench-F42AJH77.js} +1 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-SFZNVMUH.css +1 -0
- package/dist/embed/embed-page-MessageGraph-ACHQORG7.js +6 -0
- package/dist/embed/{embed-page-ReactChart-OG5Z43H7.js → embed-page-ReactChart-FGUHXBED.js} +1 -1
- package/dist/embed/{embed-page-SkillFlow-GS4OUCJJ.js → embed-page-SkillFlow-SFZ5HLMK.js} +1 -1
- package/dist/embed/{embed-page-TasksSideApp-I6Z7BOT2.js → embed-page-TasksSideApp-4GY5YBTN.js} +1 -1
- package/dist/embed/{embed-page-TeamWorkspace-LSCUIJDA.js → embed-page-TeamWorkspace-YWE6ZTLB.js} +4 -4
- package/dist/embed/{embed-page-TopologyRuntimeView-RY7NOUB7.js → embed-page-TopologyRuntimeView-MKFPCHT3.js} +1 -1
- package/dist/embed/{embed-page-WorkflowAutomationView-RNKIKDUX.js → embed-page-WorkflowAutomationView-WT6VH5HD.js} +1 -1
- package/dist/embed/{embed-page-chunk-7CFGO35V.js → embed-page-chunk-3PY2YGBU.js} +1 -1
- package/dist/embed/embed-page-chunk-3WXEO6CG.js +245 -0
- package/dist/embed/embed-page-chunk-42S7N5Y5.js +4084 -0
- package/dist/embed/{embed-page-chunk-SU5GXLKX.js → embed-page-chunk-67U2KZFL.js} +4 -4
- package/dist/embed/{embed-page-chunk-4X5XHAMX.js → embed-page-chunk-74BPRLSV.js} +4 -4
- package/dist/embed/{embed-page-chunk-DVHOG6AY.js → embed-page-chunk-AC6X2XRH.js} +1 -1
- package/dist/embed/{embed-page-chunk-4BIOW547.js → embed-page-chunk-FDID7LZP.js} +1 -1
- package/dist/embed/{embed-page-chunk-JLWIJ4BP.js → embed-page-chunk-FU2KMTSK.js} +1 -1
- package/dist/embed/{embed-page-chunk-EPEKIAZP.js → embed-page-chunk-HS5VQFWH.js} +1 -1
- package/dist/embed/{embed-page-chunk-Q32Y7CP2.js → embed-page-chunk-IV5C4DYL.js} +1 -1
- package/dist/embed/{embed-page-chunk-KGX7G7XQ.js → embed-page-chunk-KEL6XU6R.js} +1 -1
- package/dist/embed/{embed-page-chunk-AYOVLRHX.js → embed-page-chunk-MGZK7ELC.js} +94 -69
- package/dist/embed/{embed-page-chunk-BZI3YCE7.js → embed-page-chunk-N46WJ2FS.js} +1 -1
- package/dist/embed/{embed-page-chunk-KG5A66WX.js → embed-page-chunk-O4QK5LWZ.js} +83 -83
- package/dist/embed/{embed-page-chunk-ESLOGPBN.js → embed-page-chunk-Z7USDLHI.js} +1 -1
- package/dist/embed/{embed-page-code-highlighter-TBT4ICNZ.js → embed-page-code-highlighter-Y6CQA4CN.js} +1 -1
- package/dist/embed/{embed-page-mermaid-TBO3M7GX.js → embed-page-mermaid-CW4QCAH3.js} +1 -1
- package/dist/embed/embed-page.css +1 -1
- package/dist/embed/embed-page.js +1 -1
- package/dist/index.js +2074 -619
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +345 -346
- package/dist/index.mjs.map +1 -1
- package/dist/kbProvider-2D6DZ34N.mjs +50 -0
- package/dist/kbProvider-2D6DZ34N.mjs.map +1 -0
- package/dist/{mcp-configs-IIKQM5GM.mjs → mcp-configs-WCY5EXCW.mjs} +2 -1
- package/dist/mcp-configs-WCY5EXCW.mjs.map +1 -0
- package/dist/{mcpTransportRegistry-XMJ5Y2RG.mjs → mcpTransportRegistry-VXUVJKBC.mjs} +2 -1
- package/dist/mcpTransportRegistry-VXUVJKBC.mjs.map +1 -0
- package/dist/open-HH7RKGML.mjs +260 -0
- package/dist/open-HH7RKGML.mjs.map +1 -0
- package/dist/open-audit-UJ3NXCGW.mjs +32 -0
- package/dist/open-audit-UJ3NXCGW.mjs.map +1 -0
- package/dist/open-catalog-WYS2AENM.mjs +59 -0
- package/dist/open-catalog-WYS2AENM.mjs.map +1 -0
- package/dist/open-exposure-FK4G6O6L.mjs +67 -0
- package/dist/open-exposure-FK4G6O6L.mjs.map +1 -0
- package/dist/open-files-GVRMK5PL.mjs +146 -0
- package/dist/open-files-GVRMK5PL.mjs.map +1 -0
- package/dist/open-session-3VN65PRR.mjs +53 -0
- package/dist/open-session-3VN65PRR.mjs.map +1 -0
- package/dist/openLattice-GAAGQJST.mjs +16 -0
- package/dist/openLattice-GAAGQJST.mjs.map +1 -0
- package/dist/registerExposedPlugins-63EUF4VS.mjs +99 -0
- package/dist/registerExposedPlugins-63EUF4VS.mjs.map +1 -0
- package/dist/{resources-VA7LSDKN.mjs → resources-SRQRKW5G.mjs} +47 -4
- package/dist/resources-SRQRKW5G.mjs.map +1 -0
- package/dist/sandboxProvider-I3P66VXT.mjs +10 -0
- package/dist/sandboxProvider-I3P66VXT.mjs.map +1 -0
- package/dist/{sender-PX32VSHB.mjs → sender-PLDU5EZ3.mjs} +3 -1
- package/dist/{sender-PX32VSHB.mjs.map → sender-PLDU5EZ3.mjs.map} +1 -1
- package/package.json +7 -7
- package/dist/a2a-7N3WDAOP.mjs.map +0 -1
- package/dist/a2a-standard-WC2BSOFV.mjs.map +0 -1
- package/dist/chunk-2HOCF46L.mjs.map +0 -1
- package/dist/embed/embed-page-chunk-A2LQIHX4.js +0 -261
- package/dist/embed/embed-page-chunk-OWGBADV6.js +0 -3880
- package/dist/open-DCAOL5CG.mjs +0 -176
- package/dist/open-DCAOL5CG.mjs.map +0 -1
- package/dist/resources-VA7LSDKN.mjs.map +0 -1
- /package/dist/{A2AAuthService-DK5X6VIL.mjs.map → A2AAuthService-7UGQ7GMW.mjs.map} +0 -0
- /package/dist/{mcp-configs-IIKQM5GM.mjs.map → chunk-NFEGQTCC.mjs.map} +0 -0
- /package/dist/{mcpTransportRegistry-XMJ5Y2RG.mjs.map → collection_service-RTRJEQFL.mjs.map} +0 -0
- /package/dist/embed/{embed-page-AgentGovernanceWorkbench-SDS3GBCC.css → embed-page-MessageGraph-TYOOATYV.css} +0 -0
|
@@ -2,10 +2,11 @@ import {
|
|
|
2
2
|
A2AAuthError,
|
|
3
3
|
A2AAuthService,
|
|
4
4
|
parseEnvKeys
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GPHOYR3X.mjs";
|
|
6
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
6
7
|
export {
|
|
7
8
|
A2AAuthError,
|
|
8
9
|
A2AAuthService,
|
|
9
10
|
parseEnvKeys
|
|
10
11
|
};
|
|
11
|
-
//# sourceMappingURL=A2AAuthService-
|
|
12
|
+
//# sourceMappingURL=A2AAuthService-7UGQ7GMW.mjs.map
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
getUpdates,
|
|
4
4
|
sendMessage
|
|
5
5
|
} from "./chunk-6CUQGDJI.mjs";
|
|
6
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
6
7
|
|
|
7
8
|
// src/channels/wechat/WechatChannelAdapter.ts
|
|
8
9
|
import { z } from "zod";
|
|
@@ -252,4 +253,4 @@ var wechatChannelAdapter = {
|
|
|
252
253
|
export {
|
|
253
254
|
wechatChannelAdapter
|
|
254
255
|
};
|
|
255
|
-
//# sourceMappingURL=WechatChannelAdapter-
|
|
256
|
+
//# sourceMappingURL=WechatChannelAdapter-7WHE5UGY.mjs.map
|
package/dist/{WechatChannelAdapter-WSDKR4OA.mjs.map → WechatChannelAdapter-7WHE5UGY.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/channels/wechat/WechatChannelAdapter.ts","../src/channels/wechat/context-store.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type {\n ChannelAdapter,\n InboundMessage,\n OutboundMessage,\n ReplyTarget,\n ChannelInstallation,\n} from \"@axiom-lattice/protocols\";\nimport type { WechatChannelInstallationConfig } from \"@axiom-lattice/protocols\";\nimport { getUpdates, sendMessage } from \"./wechat-client\";\nimport { setContextToken, getContextToken, deleteContextToken } from \"./context-store\";\nimport { Logger } from \"../../logger/Logger\";\n\nconst logger = new Logger({ serviceName: \"lattice/gateway/wechat\" });\n\nconst wechatConfigSchema = z.object({\n botToken: z.string(),\n uin: z.string().optional(),\n});\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst BASE_RECONNECT_DELAY_MS = 1_000;\nconst HEARTBEAT_INTERVAL_MS = 60_000;\nconst CHANNEL_VERSION = \"1.0.2\";\n\n// ─── Message type constants ───────────────────────────────────────────────\n\nconst MSG_TYPE_USER = 1;\nconst MSG_ITEM_TEXT = 1;\n\n// ─── Polling connection state ─────────────────────────────────────────────\n\ninterface PollingState {\n installationId: string;\n abortController: AbortController;\n lastActivity: number;\n heartbeatTimer: NodeJS.Timeout;\n}\n\nconst activeConnections = new Map<string, PollingState>();\n\n// ─── Message dedup ────────────────────────────────────────────────────────\n\nconst seenClientIds = new Set<string>();\n\nfunction addToDedup(clientId: string): boolean {\n if (!clientId || seenClientIds.has(clientId)) return false;\n seenClientIds.add(clientId);\n if (seenClientIds.size > 1000) {\n const first = seenClientIds.values().next().value;\n if (first !== undefined) seenClientIds.delete(first);\n }\n return true;\n}\n\n// ─── Text extraction from iLink message ───────────────────────────────────\n\nfunction extractText(msg: { item_list?: Array<{ type?: number; text_item?: { text?: string } }> }): string | null {\n if (!msg.item_list?.length) return null;\n for (const item of msg.item_list) {\n if (item.type === MSG_ITEM_TEXT && item.text_item?.text) {\n return item.text_item.text;\n }\n }\n return null;\n}\n\n// ─── Adapter ──────────────────────────────────────────────────────────────\n\nexport const wechatChannelAdapter: ChannelAdapter<WechatChannelInstallationConfig> = {\n channel: \"wechat\",\n\n configSchema: wechatConfigSchema,\n\n async receive(\n rawPayload: unknown,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<InboundMessage | null> {\n const msg = rawPayload as {\n from_user_id?: string;\n client_id?: string;\n message_type?: number;\n item_list?: Array<{ type?: number; text_item?: { text?: string } }>;\n context_token?: string;\n };\n\n // Only process user messages (type 1), skip bot echoes (type 2)\n if (msg.message_type !== MSG_TYPE_USER) return null;\n\n const senderId = msg.from_user_id;\n if (!senderId) return null;\n\n const text = extractText(msg);\n if (!text) return null;\n\n // Cache context token for reply\n if (msg.context_token) {\n setContextToken(installation.id, senderId, msg.context_token);\n }\n\n return {\n channel: \"wechat\",\n channelInstallationId: installation.id,\n tenantId: installation.tenantId,\n sender: {\n id: senderId,\n displayName: senderId.split(\"@\")[0],\n },\n content: {\n text,\n },\n conversation: {\n id: senderId,\n type: \"direct\",\n },\n replyTarget: {\n adapterChannel: \"wechat\",\n channelInstallationId: installation.id,\n rawTarget: { senderId },\n },\n };\n },\n\n async sendReply(\n replyTarget: ReplyTarget,\n message: OutboundMessage,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<void> {\n const senderId = replyTarget.rawTarget.senderId as string;\n const contextToken = getContextToken(installation.id, senderId);\n\n if (!contextToken) {\n logger.warn(\"WeChat context token expired, cannot send reply\", {\n installationId: installation.id,\n senderId,\n });\n deleteContextToken(installation.id, senderId);\n return;\n }\n\n const { botToken } = installation.config;\n await sendMessage(botToken, senderId, message.text, contextToken);\n },\n\n resolveThreadId(message: InboundMessage, binding: unknown): string {\n const date = new Date().toISOString().split(\"T\")[0];\n const agentId = (binding as { agentId: string }).agentId;\n return `wechat:dm:${message.sender.id}:${agentId}:${date}`;\n },\n\n async connect(\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n deps?: unknown,\n ): Promise<void> {\n const { id: installationId, tenantId, config } = installation;\n\n if (!config.botToken) {\n logger.warn(\"WeChat installation missing botToken, skipping\", { installationId });\n return;\n }\n\n if (activeConnections.has(installationId)) {\n logger.warn(\"WeChat polling already running for installation, skipping\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling starting\", { installationId, tenantId });\n\n const abortController = new AbortController();\n\n const heartbeatTimer = setInterval(() => {\n const state2 = activeConnections.get(installationId);\n if (!state2) {\n clearInterval(heartbeatTimer);\n return;\n }\n const elapsed = Date.now() - state2.lastActivity;\n if (elapsed > HEARTBEAT_INTERVAL_MS * 2) {\n logger.error(\"WeChat polling heartbeat lost — no activity\", {\n installationId,\n elapsedMs: elapsed,\n });\n state2.abortController.abort();\n }\n }, HEARTBEAT_INTERVAL_MS);\n\n const state: PollingState = {\n installationId,\n abortController,\n lastActivity: Date.now(),\n heartbeatTimer,\n };\n activeConnections.set(installationId, state);\n\n const router = (deps as { router?: { dispatch(msg: InboundMessage): Promise<unknown> } })?.router;\n\n let syncBuffer = \"\";\n let reconnectDelay = BASE_RECONNECT_DELAY_MS;\n\n const scheduleNextPoll = (): void => {\n poll().catch((err) => {\n logger.error(\"WeChat poll iteration crashed\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n const currentState = activeConnections.get(installationId);\n if (currentState && !currentState.abortController.signal.aborted) {\n setTimeout(scheduleNextPoll, reconnectDelay);\n }\n });\n };\n\n const poll = async (): Promise<void> => {\n const currentState = activeConnections.get(installationId);\n if (!currentState || currentState.abortController.signal.aborted) {\n logger.info(\"WeChat polling aborted\", { installationId });\n return;\n }\n\n try {\n const result = await getUpdates(\n config.botToken,\n syncBuffer,\n currentState.abortController.signal,\n );\n syncBuffer = result.syncBuffer;\n reconnectDelay = BASE_RECONNECT_DELAY_MS;\n currentState.lastActivity = Date.now();\n\n if (result.msgs.length > 0) {\n logger.info(\"WeChat poll received messages\", {\n installationId,\n count: result.msgs.length,\n });\n }\n\n for (const rawMsg of result.msgs) {\n // Only user messages, skip bot echoes and non-text\n if (rawMsg.message_type !== MSG_TYPE_USER) continue;\n\n const text = extractText(rawMsg);\n if (!text) continue;\n\n if (!addToDedup((rawMsg as { client_id?: string }).client_id ?? \"\")) continue;\n\n const inbound = await wechatChannelAdapter.receive(\n rawMsg,\n installation as ChannelInstallation<WechatChannelInstallationConfig>,\n );\n if (inbound && router) {\n const dispatchResult = await router.dispatch(inbound);\n if (!(dispatchResult as { success?: boolean }).success) {\n logger.warn(\"WeChat dispatch failed\", {\n installationId,\n error: (dispatchResult as { error?: { message?: string } }).error?.message,\n });\n }\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.info(\"WeChat poll aborted by signal\", { installationId });\n return;\n }\n\n logger.error(\"WeChat poll error\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((resolve) => setTimeout(resolve, reconnectDelay));\n reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);\n }\n\n scheduleNextPoll();\n };\n\n scheduleNextPoll();\n logger.info(\"WeChat polling started\", { installationId });\n },\n\n async disconnect(installationId: string): Promise<void> {\n const state = activeConnections.get(installationId);\n if (!state) {\n logger.warn(\"WeChat polling not running, nothing to disconnect\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling disconnecting\", { installationId });\n state.abortController.abort();\n clearInterval(state.heartbeatTimer);\n activeConnections.delete(installationId);\n logger.info(\"WeChat polling disconnected\", { installationId });\n },\n};\n","interface ContextTokenEntry {\n token: string;\n installationId: string;\n senderId: string;\n updatedAt: number;\n}\n\nconst TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst store = new Map<string, ContextTokenEntry>();\nconst timers = new Map<string, NodeJS.Timeout>();\n\nfunction makeKey(installationId: string, senderId: string): string {\n return `${installationId}::${senderId}`;\n}\n\nexport function getContextToken(installationId: string, senderId: string): string | undefined {\n const key = makeKey(installationId, senderId);\n const entry = store.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {\n deleteContextToken(installationId, senderId);\n return undefined;\n }\n return entry.token;\n}\n\nexport function setContextToken(installationId: string, senderId: string, token: string): void {\n const key = makeKey(installationId, senderId);\n\n const existingTimer = timers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n\n store.set(key, { token, installationId, senderId, updatedAt: Date.now() });\n\n const timer = setTimeout(() => {\n store.delete(key);\n timers.delete(key);\n }, TOKEN_TTL_MS);\n timers.set(key, timer);\n}\n\nexport function deleteContextToken(installationId: string, senderId: string): void {\n const key = makeKey(installationId, senderId);\n store.delete(key);\n const timer = timers.get(key);\n if (timer) {\n clearTimeout(timer);\n timers.delete(key);\n }\n}\n\nexport function getContextTokenStoreSize(): number {\n return store.size;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/channels/wechat/WechatChannelAdapter.ts","../src/channels/wechat/context-store.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type {\n ChannelAdapter,\n InboundMessage,\n OutboundMessage,\n ReplyTarget,\n ChannelInstallation,\n} from \"@axiom-lattice/protocols\";\nimport type { WechatChannelInstallationConfig } from \"@axiom-lattice/protocols\";\nimport { getUpdates, sendMessage } from \"./wechat-client\";\nimport { setContextToken, getContextToken, deleteContextToken } from \"./context-store\";\nimport { Logger } from \"../../logger/Logger\";\n\nconst logger = new Logger({ serviceName: \"lattice/gateway/wechat\" });\n\nconst wechatConfigSchema = z.object({\n botToken: z.string(),\n uin: z.string().optional(),\n});\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst BASE_RECONNECT_DELAY_MS = 1_000;\nconst HEARTBEAT_INTERVAL_MS = 60_000;\nconst CHANNEL_VERSION = \"1.0.2\";\n\n// ─── Message type constants ───────────────────────────────────────────────\n\nconst MSG_TYPE_USER = 1;\nconst MSG_ITEM_TEXT = 1;\n\n// ─── Polling connection state ─────────────────────────────────────────────\n\ninterface PollingState {\n installationId: string;\n abortController: AbortController;\n lastActivity: number;\n heartbeatTimer: NodeJS.Timeout;\n}\n\nconst activeConnections = new Map<string, PollingState>();\n\n// ─── Message dedup ────────────────────────────────────────────────────────\n\nconst seenClientIds = new Set<string>();\n\nfunction addToDedup(clientId: string): boolean {\n if (!clientId || seenClientIds.has(clientId)) return false;\n seenClientIds.add(clientId);\n if (seenClientIds.size > 1000) {\n const first = seenClientIds.values().next().value;\n if (first !== undefined) seenClientIds.delete(first);\n }\n return true;\n}\n\n// ─── Text extraction from iLink message ───────────────────────────────────\n\nfunction extractText(msg: { item_list?: Array<{ type?: number; text_item?: { text?: string } }> }): string | null {\n if (!msg.item_list?.length) return null;\n for (const item of msg.item_list) {\n if (item.type === MSG_ITEM_TEXT && item.text_item?.text) {\n return item.text_item.text;\n }\n }\n return null;\n}\n\n// ─── Adapter ──────────────────────────────────────────────────────────────\n\nexport const wechatChannelAdapter: ChannelAdapter<WechatChannelInstallationConfig> = {\n channel: \"wechat\",\n\n configSchema: wechatConfigSchema,\n\n async receive(\n rawPayload: unknown,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<InboundMessage | null> {\n const msg = rawPayload as {\n from_user_id?: string;\n client_id?: string;\n message_type?: number;\n item_list?: Array<{ type?: number; text_item?: { text?: string } }>;\n context_token?: string;\n };\n\n // Only process user messages (type 1), skip bot echoes (type 2)\n if (msg.message_type !== MSG_TYPE_USER) return null;\n\n const senderId = msg.from_user_id;\n if (!senderId) return null;\n\n const text = extractText(msg);\n if (!text) return null;\n\n // Cache context token for reply\n if (msg.context_token) {\n setContextToken(installation.id, senderId, msg.context_token);\n }\n\n return {\n channel: \"wechat\",\n channelInstallationId: installation.id,\n tenantId: installation.tenantId,\n sender: {\n id: senderId,\n displayName: senderId.split(\"@\")[0],\n },\n content: {\n text,\n },\n conversation: {\n id: senderId,\n type: \"direct\",\n },\n replyTarget: {\n adapterChannel: \"wechat\",\n channelInstallationId: installation.id,\n rawTarget: { senderId },\n },\n };\n },\n\n async sendReply(\n replyTarget: ReplyTarget,\n message: OutboundMessage,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<void> {\n const senderId = replyTarget.rawTarget.senderId as string;\n const contextToken = getContextToken(installation.id, senderId);\n\n if (!contextToken) {\n logger.warn(\"WeChat context token expired, cannot send reply\", {\n installationId: installation.id,\n senderId,\n });\n deleteContextToken(installation.id, senderId);\n return;\n }\n\n const { botToken } = installation.config;\n await sendMessage(botToken, senderId, message.text, contextToken);\n },\n\n resolveThreadId(message: InboundMessage, binding: unknown): string {\n const date = new Date().toISOString().split(\"T\")[0];\n const agentId = (binding as { agentId: string }).agentId;\n return `wechat:dm:${message.sender.id}:${agentId}:${date}`;\n },\n\n async connect(\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n deps?: unknown,\n ): Promise<void> {\n const { id: installationId, tenantId, config } = installation;\n\n if (!config.botToken) {\n logger.warn(\"WeChat installation missing botToken, skipping\", { installationId });\n return;\n }\n\n if (activeConnections.has(installationId)) {\n logger.warn(\"WeChat polling already running for installation, skipping\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling starting\", { installationId, tenantId });\n\n const abortController = new AbortController();\n\n const heartbeatTimer = setInterval(() => {\n const state2 = activeConnections.get(installationId);\n if (!state2) {\n clearInterval(heartbeatTimer);\n return;\n }\n const elapsed = Date.now() - state2.lastActivity;\n if (elapsed > HEARTBEAT_INTERVAL_MS * 2) {\n logger.error(\"WeChat polling heartbeat lost — no activity\", {\n installationId,\n elapsedMs: elapsed,\n });\n state2.abortController.abort();\n }\n }, HEARTBEAT_INTERVAL_MS);\n\n const state: PollingState = {\n installationId,\n abortController,\n lastActivity: Date.now(),\n heartbeatTimer,\n };\n activeConnections.set(installationId, state);\n\n const router = (deps as { router?: { dispatch(msg: InboundMessage): Promise<unknown> } })?.router;\n\n let syncBuffer = \"\";\n let reconnectDelay = BASE_RECONNECT_DELAY_MS;\n\n const scheduleNextPoll = (): void => {\n poll().catch((err) => {\n logger.error(\"WeChat poll iteration crashed\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n const currentState = activeConnections.get(installationId);\n if (currentState && !currentState.abortController.signal.aborted) {\n setTimeout(scheduleNextPoll, reconnectDelay);\n }\n });\n };\n\n const poll = async (): Promise<void> => {\n const currentState = activeConnections.get(installationId);\n if (!currentState || currentState.abortController.signal.aborted) {\n logger.info(\"WeChat polling aborted\", { installationId });\n return;\n }\n\n try {\n const result = await getUpdates(\n config.botToken,\n syncBuffer,\n currentState.abortController.signal,\n );\n syncBuffer = result.syncBuffer;\n reconnectDelay = BASE_RECONNECT_DELAY_MS;\n currentState.lastActivity = Date.now();\n\n if (result.msgs.length > 0) {\n logger.info(\"WeChat poll received messages\", {\n installationId,\n count: result.msgs.length,\n });\n }\n\n for (const rawMsg of result.msgs) {\n // Only user messages, skip bot echoes and non-text\n if (rawMsg.message_type !== MSG_TYPE_USER) continue;\n\n const text = extractText(rawMsg);\n if (!text) continue;\n\n if (!addToDedup((rawMsg as { client_id?: string }).client_id ?? \"\")) continue;\n\n const inbound = await wechatChannelAdapter.receive(\n rawMsg,\n installation as ChannelInstallation<WechatChannelInstallationConfig>,\n );\n if (inbound && router) {\n const dispatchResult = await router.dispatch(inbound);\n if (!(dispatchResult as { success?: boolean }).success) {\n logger.warn(\"WeChat dispatch failed\", {\n installationId,\n error: (dispatchResult as { error?: { message?: string } }).error?.message,\n });\n }\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.info(\"WeChat poll aborted by signal\", { installationId });\n return;\n }\n\n logger.error(\"WeChat poll error\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((resolve) => setTimeout(resolve, reconnectDelay));\n reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);\n }\n\n scheduleNextPoll();\n };\n\n scheduleNextPoll();\n logger.info(\"WeChat polling started\", { installationId });\n },\n\n async disconnect(installationId: string): Promise<void> {\n const state = activeConnections.get(installationId);\n if (!state) {\n logger.warn(\"WeChat polling not running, nothing to disconnect\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling disconnecting\", { installationId });\n state.abortController.abort();\n clearInterval(state.heartbeatTimer);\n activeConnections.delete(installationId);\n logger.info(\"WeChat polling disconnected\", { installationId });\n },\n};\n","interface ContextTokenEntry {\n token: string;\n installationId: string;\n senderId: string;\n updatedAt: number;\n}\n\nconst TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst store = new Map<string, ContextTokenEntry>();\nconst timers = new Map<string, NodeJS.Timeout>();\n\nfunction makeKey(installationId: string, senderId: string): string {\n return `${installationId}::${senderId}`;\n}\n\nexport function getContextToken(installationId: string, senderId: string): string | undefined {\n const key = makeKey(installationId, senderId);\n const entry = store.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {\n deleteContextToken(installationId, senderId);\n return undefined;\n }\n return entry.token;\n}\n\nexport function setContextToken(installationId: string, senderId: string, token: string): void {\n const key = makeKey(installationId, senderId);\n\n const existingTimer = timers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n\n store.set(key, { token, installationId, senderId, updatedAt: Date.now() });\n\n const timer = setTimeout(() => {\n store.delete(key);\n timers.delete(key);\n }, TOKEN_TTL_MS);\n timers.set(key, timer);\n}\n\nexport function deleteContextToken(installationId: string, senderId: string): void {\n const key = makeKey(installationId, senderId);\n store.delete(key);\n const timer = timers.get(key);\n if (timer) {\n clearTimeout(timer);\n timers.delete(key);\n }\n}\n\nexport function getContextTokenStoreSize(): number {\n return store.size;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
A2AAuthError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GPHOYR3X.mjs";
|
|
4
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
4
5
|
|
|
5
6
|
// src/routes/a2a.ts
|
|
6
7
|
var _a2aKeyStore = null;
|
|
@@ -68,6 +69,7 @@ async function handleApiKeyCreate(request, reply) {
|
|
|
68
69
|
tenantId,
|
|
69
70
|
projectId: body.projectId,
|
|
70
71
|
assistantIds: body.assistantIds,
|
|
72
|
+
grants: body.grants,
|
|
71
73
|
label: body.label
|
|
72
74
|
});
|
|
73
75
|
await refreshStoreKeyMap();
|
|
@@ -81,6 +83,36 @@ async function handleApiKeyCreate(request, reply) {
|
|
|
81
83
|
reply.status(500).send({ success: false, error: "Failed to create key" });
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
async function handleApiKeyUpdate(request, reply) {
|
|
87
|
+
if (!_a2aKeyStore || !_a2aAuthService) {
|
|
88
|
+
reply.status(501).send({ error: "Key store not configured" });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!await authorizeKeyMutation(request, reply)) return;
|
|
92
|
+
const body = request.body;
|
|
93
|
+
const tenantId = getUserTenantId(request);
|
|
94
|
+
try {
|
|
95
|
+
const record = await _a2aAuthService.updateKeyScoped(
|
|
96
|
+
request.params.id,
|
|
97
|
+
tenantId,
|
|
98
|
+
{
|
|
99
|
+
label: body.label,
|
|
100
|
+
projectId: body.projectId,
|
|
101
|
+
assistantIds: body.assistantIds,
|
|
102
|
+
grants: body.grants
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
await refreshStoreKeyMap();
|
|
106
|
+
reply.status(200).send({ success: true, data: record });
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if (err instanceof A2AAuthError) {
|
|
109
|
+
reply.status(err.statusCode).send({ success: false, error: err.message });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
request.log.error({ err }, "a2a:keys:update");
|
|
113
|
+
reply.status(500).send({ success: false, error: "Failed to update key" });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
84
116
|
async function handleApiKeyDelete(request, reply) {
|
|
85
117
|
if (!await authorizeKeyMutation(request, reply)) return;
|
|
86
118
|
await _a2aKeyStore.delete(request.params.id);
|
|
@@ -107,36 +139,43 @@ async function handleApiKeyRotate(request, reply) {
|
|
|
107
139
|
}
|
|
108
140
|
function registerA2ARoutes(app) {
|
|
109
141
|
const options = { preHandler: requireTenantSession };
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
for (const base of ["/api/keys", "/api/a2a/keys"]) {
|
|
143
|
+
app.get(
|
|
144
|
+
base,
|
|
145
|
+
options,
|
|
146
|
+
handleApiKeyList
|
|
147
|
+
);
|
|
148
|
+
app.post(
|
|
149
|
+
base,
|
|
150
|
+
options,
|
|
151
|
+
handleApiKeyCreate
|
|
152
|
+
);
|
|
153
|
+
app.delete(
|
|
154
|
+
`${base}/:id`,
|
|
155
|
+
options,
|
|
156
|
+
handleApiKeyDelete
|
|
157
|
+
);
|
|
158
|
+
app.post(
|
|
159
|
+
`${base}/:id/disable`,
|
|
160
|
+
options,
|
|
161
|
+
handleApiKeyDisable
|
|
162
|
+
);
|
|
163
|
+
app.post(
|
|
164
|
+
`${base}/:id/enable`,
|
|
165
|
+
options,
|
|
166
|
+
handleApiKeyEnable
|
|
167
|
+
);
|
|
168
|
+
app.post(
|
|
169
|
+
`${base}/:id/rotate`,
|
|
170
|
+
options,
|
|
171
|
+
handleApiKeyRotate
|
|
172
|
+
);
|
|
173
|
+
app.patch(
|
|
174
|
+
`${base}/:id`,
|
|
175
|
+
options,
|
|
176
|
+
handleApiKeyUpdate
|
|
177
|
+
);
|
|
178
|
+
}
|
|
140
179
|
}
|
|
141
180
|
export {
|
|
142
181
|
refreshStoreKeyMap,
|
|
@@ -144,4 +183,4 @@ export {
|
|
|
144
183
|
setA2AAuthService,
|
|
145
184
|
setA2AKeyStore
|
|
146
185
|
};
|
|
147
|
-
//# sourceMappingURL=a2a-
|
|
186
|
+
//# sourceMappingURL=a2a-FGYX2HH3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/routes/a2a.ts"],"sourcesContent":["import type { FastifyInstance, FastifyRequest, FastifyReply } from \"fastify\";\nimport type {\n A2AApiKeyStore,\n CreateA2AApiKeyInput,\n} from \"@axiom-lattice/protocols\";\nimport { A2AAuthError } from \"../services/a2a/A2AAuthService\";\nimport type { A2AAuthService } from \"../services/a2a/A2AAuthService\";\n\n// ─── Key Store ────────────────────────────────────────────────────────────\n\nlet _a2aKeyStore: A2AApiKeyStore | null = null;\nlet _a2aAuthService: A2AAuthService | null = null;\n\n/** Inject the A2A key store used by the keys management routes. */\nexport function setA2AKeyStore(store: A2AApiKeyStore): void {\n _a2aKeyStore = store;\n}\n\n/** Inject the A2A auth service used to create keys and refresh the key cache. */\nexport function setA2AAuthService(service: A2AAuthService): void {\n _a2aAuthService = service;\n}\n\n/**\n * Reload cached key maps after a keys CRUD mutation. Delegates to the auth\n * service's key-map cache so authentication reflects the latest keys without\n * hitting the store on every request.\n */\nexport async function refreshStoreKeyMap(): Promise<void> {\n if (_a2aAuthService) await _a2aAuthService.refresh();\n}\n\ninterface RequestWithUser extends FastifyRequest {\n user?: { id: string; tenantId?: string };\n}\n\nasync function requireTenantSession(\n request: FastifyRequest,\n reply: FastifyReply,\n): Promise<void> {\n if (!getUserTenantId(request)) {\n await reply.status(401).send({ success: false, error: \"Unauthorized\" });\n }\n}\n\nasync function authorizeKeyMutation(\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n): Promise<boolean> {\n if (!_a2aKeyStore) {\n await reply.status(501).send({ error: \"Key store not configured\" });\n return false;\n }\n const record = await _a2aKeyStore.findById(request.params.id);\n if (!record) {\n await reply.status(404).send({ success: false, error: \"A2A API key not found\" });\n return false;\n }\n if (record.tenantId !== getUserTenantId(request)) {\n await reply.status(403).send({ success: false, error: \"Forbidden\" });\n return false;\n }\n return true;\n}\n\nfunction getUserTenantId(request: FastifyRequest): string | undefined {\n return (request as RequestWithUser).user?.tenantId;\n}\n\n// ─── API Key Management Handlers ─────────────────────────────────────────\n\nasync function handleApiKeyList(\n request: FastifyRequest<{ Querystring: { tenantId?: string; limit?: string; offset?: string } }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!_a2aKeyStore) {\n reply.status(501).send({ error: \"Key store not configured\" });\n return;\n }\n\n const records = await _a2aKeyStore.list({\n tenantId: getUserTenantId(request),\n limit: request.query.limit ? parseInt(request.query.limit, 10) : undefined,\n offset: request.query.offset ? parseInt(request.query.offset, 10) : undefined,\n });\n\n reply.status(200).send({\n success: true,\n data: {\n records: records.map((r) => ({ ...r, key: r.key.slice(0, 8) + \"...\" })),\n total: records.length,\n },\n });\n}\n\nasync function handleApiKeyCreate(\n request: FastifyRequest<{ Body: Partial<CreateA2AApiKeyInput> }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!_a2aKeyStore || !_a2aAuthService) {\n reply.status(501).send({ error: \"Key store not configured\" });\n return;\n }\n\n const body = request.body as Partial<CreateA2AApiKeyInput>;\n const tenantId = getUserTenantId(request)!;\n\n try {\n const record = await _a2aAuthService.createKeyScoped({\n tenantId,\n projectId: body.projectId,\n assistantIds: body.assistantIds,\n grants: body.grants,\n label: body.label,\n });\n await refreshStoreKeyMap();\n reply.status(201).send({ success: true, data: record });\n } catch (err) {\n if (err instanceof A2AAuthError) {\n reply.status(err.statusCode).send({ success: false, error: err.message });\n return;\n }\n request.log.error({ err }, \"a2a:keys:create\");\n reply.status(500).send({ success: false, error: \"Failed to create key\" });\n }\n}\n\nasync function handleApiKeyUpdate(\n request: FastifyRequest<{ Params: { id: string }; Body: Partial<CreateA2AApiKeyInput> }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!_a2aKeyStore || !_a2aAuthService) {\n reply.status(501).send({ error: \"Key store not configured\" });\n return;\n }\n if (!(await authorizeKeyMutation(request, reply))) return;\n\n const body = request.body as Partial<CreateA2AApiKeyInput>;\n const tenantId = getUserTenantId(request)!;\n try {\n const record = await _a2aAuthService.updateKeyScoped(\n request.params.id,\n tenantId,\n {\n label: body.label,\n projectId: body.projectId,\n assistantIds: body.assistantIds,\n grants: body.grants,\n },\n );\n await refreshStoreKeyMap();\n reply.status(200).send({ success: true, data: record });\n } catch (err) {\n if (err instanceof A2AAuthError) {\n reply.status(err.statusCode).send({ success: false, error: err.message });\n return;\n }\n request.log.error({ err }, \"a2a:keys:update\");\n reply.status(500).send({ success: false, error: \"Failed to update key\" });\n }\n}\n\nasync function handleApiKeyDelete(\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!(await authorizeKeyMutation(request, reply))) return;\n\n await _a2aKeyStore!.delete(request.params.id);\n await refreshStoreKeyMap();\n\n reply.status(200).send({ success: true });\n}\n\nasync function handleApiKeyDisable(\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!(await authorizeKeyMutation(request, reply))) return;\n\n await _a2aKeyStore!.disable(request.params.id);\n await refreshStoreKeyMap();\n\n reply.status(200).send({ success: true });\n}\n\nasync function handleApiKeyEnable(\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!(await authorizeKeyMutation(request, reply))) return;\n\n await _a2aKeyStore!.enable(request.params.id);\n await refreshStoreKeyMap();\n\n reply.status(200).send({ success: true });\n}\n\nasync function handleApiKeyRotate(\n request: FastifyRequest<{ Params: { id: string } }>,\n reply: FastifyReply,\n): Promise<void> {\n if (!(await authorizeKeyMutation(request, reply))) return;\n\n const record = await _a2aKeyStore!.rotate(request.params.id);\n await refreshStoreKeyMap();\n\n reply.status(200).send({ success: true, data: record });\n}\n\n// ─── Route Registration ───────────────────────────────────────────────────\n\n/**\n * Register the API key management routes.\n *\n * `/api/keys` is the canonical unified surface; `/api/a2a/keys` remains as a\n * backward-compatible alias for existing clients.\n */\nexport function registerA2ARoutes(app: FastifyInstance): void {\n const options = { preHandler: requireTenantSession };\n for (const base of [\"/api/keys\", \"/api/a2a/keys\"]) {\n app.get<{ Querystring: { tenantId?: string; limit?: string; offset?: string } }>(\n base,\n options,\n handleApiKeyList,\n );\n\n app.post<{ Body: Partial<CreateA2AApiKeyInput> }>(\n base,\n options,\n handleApiKeyCreate,\n );\n\n app.delete<{ Params: { id: string } }>(\n `${base}/:id`,\n options,\n handleApiKeyDelete,\n );\n\n app.post<{ Params: { id: string } }>(\n `${base}/:id/disable`,\n options,\n handleApiKeyDisable,\n );\n\n app.post<{ Params: { id: string } }>(\n `${base}/:id/enable`,\n options,\n handleApiKeyEnable,\n );\n\n app.post<{ Params: { id: string } }>(\n `${base}/:id/rotate`,\n options,\n handleApiKeyRotate,\n );\n app.patch<{ Params: { id: string }; Body: Partial<CreateA2AApiKeyInput> }>(\n `${base}/:id`,\n options,\n handleApiKeyUpdate,\n );\n }\n}\n"],"mappings":";;;;;;AAUA,IAAI,eAAsC;AAC1C,IAAI,kBAAyC;AAGtC,SAAS,eAAe,OAA6B;AAC1D,iBAAe;AACjB;AAGO,SAAS,kBAAkB,SAA+B;AAC/D,oBAAkB;AACpB;AAOA,eAAsB,qBAAoC;AACxD,MAAI,gBAAiB,OAAM,gBAAgB,QAAQ;AACrD;AAMA,eAAe,qBACb,SACA,OACe;AACf,MAAI,CAAC,gBAAgB,OAAO,GAAG;AAC7B,UAAM,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,eAAe,CAAC;AAAA,EACxE;AACF;AAEA,eAAe,qBACb,SACA,OACkB;AAClB,MAAI,CAAC,cAAc;AACjB,UAAM,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAClE,WAAO;AAAA,EACT;AACA,QAAM,SAAS,MAAM,aAAa,SAAS,QAAQ,OAAO,EAAE;AAC5D,MAAI,CAAC,QAAQ;AACX,UAAM,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,wBAAwB,CAAC;AAC/E,WAAO;AAAA,EACT;AACA,MAAI,OAAO,aAAa,gBAAgB,OAAO,GAAG;AAChD,UAAM,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC;AACnE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,SAA6C;AACpE,SAAQ,QAA4B,MAAM;AAC5C;AAIA,eAAe,iBACb,SACA,OACe;AACf,MAAI,CAAC,cAAc;AACjB,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAC5D;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,aAAa,KAAK;AAAA,IACtC,UAAU,gBAAgB,OAAO;AAAA,IACjC,OAAO,QAAQ,MAAM,QAAQ,SAAS,QAAQ,MAAM,OAAO,EAAE,IAAI;AAAA,IACjE,QAAQ,QAAQ,MAAM,SAAS,SAAS,QAAQ,MAAM,QAAQ,EAAE,IAAI;AAAA,EACtE,CAAC;AAED,QAAM,OAAO,GAAG,EAAE,KAAK;AAAA,IACrB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,SAAS,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,EAAE,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,EAAE;AAAA,MACtE,OAAO,QAAQ;AAAA,IACjB;AAAA,EACF,CAAC;AACH;AAEA,eAAe,mBACb,SACA,OACe;AACf,MAAI,CAAC,gBAAgB,CAAC,iBAAiB;AACrC,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAC5D;AAAA,EACF;AAEA,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,gBAAgB,OAAO;AAExC,MAAI;AACF,UAAM,SAAS,MAAM,gBAAgB,gBAAgB;AAAA,MACnD;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,IACd,CAAC;AACD,UAAM,mBAAmB;AACzB,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,EACxD,SAAS,KAAK;AACZ,QAAI,eAAe,cAAc;AAC/B,YAAM,OAAO,IAAI,UAAU,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,IAAI,QAAQ,CAAC;AACxE;AAAA,IACF;AACA,YAAQ,IAAI,MAAM,EAAE,IAAI,GAAG,iBAAiB;AAC5C,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,uBAAuB,CAAC;AAAA,EAC1E;AACF;AAEA,eAAe,mBACb,SACA,OACe;AACf,MAAI,CAAC,gBAAgB,CAAC,iBAAiB;AACrC,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAC5D;AAAA,EACF;AACA,MAAI,CAAE,MAAM,qBAAqB,SAAS,KAAK,EAAI;AAEnD,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,gBAAgB,OAAO;AACxC,MAAI;AACF,UAAM,SAAS,MAAM,gBAAgB;AAAA,MACnC,QAAQ,OAAO;AAAA,MACf;AAAA,MACA;AAAA,QACE,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK;AAAA,QACnB,QAAQ,KAAK;AAAA,MACf;AAAA,IACF;AACA,UAAM,mBAAmB;AACzB,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,EACxD,SAAS,KAAK;AACZ,QAAI,eAAe,cAAc;AAC/B,YAAM,OAAO,IAAI,UAAU,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,IAAI,QAAQ,CAAC;AACxE;AAAA,IACF;AACA,YAAQ,IAAI,MAAM,EAAE,IAAI,GAAG,iBAAiB;AAC5C,UAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,uBAAuB,CAAC;AAAA,EAC1E;AACF;AAEA,eAAe,mBACb,SACA,OACe;AACf,MAAI,CAAE,MAAM,qBAAqB,SAAS,KAAK,EAAI;AAEnD,QAAM,aAAc,OAAO,QAAQ,OAAO,EAAE;AAC5C,QAAM,mBAAmB;AAEzB,QAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;AAC1C;AAEA,eAAe,oBACb,SACA,OACe;AACf,MAAI,CAAE,MAAM,qBAAqB,SAAS,KAAK,EAAI;AAEnD,QAAM,aAAc,QAAQ,QAAQ,OAAO,EAAE;AAC7C,QAAM,mBAAmB;AAEzB,QAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;AAC1C;AAEA,eAAe,mBACb,SACA,OACe;AACf,MAAI,CAAE,MAAM,qBAAqB,SAAS,KAAK,EAAI;AAEnD,QAAM,aAAc,OAAO,QAAQ,OAAO,EAAE;AAC5C,QAAM,mBAAmB;AAEzB,QAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;AAC1C;AAEA,eAAe,mBACb,SACA,OACe;AACf,MAAI,CAAE,MAAM,qBAAqB,SAAS,KAAK,EAAI;AAEnD,QAAM,SAAS,MAAM,aAAc,OAAO,QAAQ,OAAO,EAAE;AAC3D,QAAM,mBAAmB;AAEzB,QAAM,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AACxD;AAUO,SAAS,kBAAkB,KAA4B;AAC5D,QAAM,UAAU,EAAE,YAAY,qBAAqB;AACnD,aAAW,QAAQ,CAAC,aAAa,eAAe,GAAG;AACjD,QAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AAAA,MACF,GAAG,IAAI;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AAAA,MACF,GAAG,IAAI;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AAAA,MACF,GAAG,IAAI;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AAAA,MACF,GAAG,IAAI;AAAA,MACP;AAAA,MACA;AAAA,IACF;AACA,QAAI;AAAA,MACF,GAAG,IAAI;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildAgentCardForAssistant
|
|
3
|
+
} from "./chunk-QUT2DS4R.mjs";
|
|
1
4
|
import {
|
|
2
5
|
formatFileRefsSection,
|
|
3
6
|
saveProjectFile
|
|
4
7
|
} from "./chunk-J4BK77PA.mjs";
|
|
5
8
|
import {
|
|
6
9
|
A2AAuthError
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GPHOYR3X.mjs";
|
|
11
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
8
12
|
|
|
9
13
|
// src/routes/a2a-standard.ts
|
|
10
14
|
import { v4 as uuidv42 } from "uuid";
|
|
@@ -12,54 +16,12 @@ import {
|
|
|
12
16
|
A2AError,
|
|
13
17
|
DefaultExecutionEventBus as DefaultExecutionEventBus2,
|
|
14
18
|
DefaultRequestHandler,
|
|
19
|
+
InMemoryTaskStore,
|
|
15
20
|
JsonRpcTransportHandler,
|
|
16
21
|
RequestContext
|
|
17
22
|
} from "@a2a-js/sdk/server";
|
|
18
23
|
import { createTaskLifecycleService, getStoreLattice } from "@axiom-lattice/core";
|
|
19
24
|
|
|
20
|
-
// src/services/a2a/A2AAgentCardBuilder.ts
|
|
21
|
-
function buildAgentCardForAssistant(params) {
|
|
22
|
-
const { assistant, exposure, baseUrl } = params;
|
|
23
|
-
const jsonRpcUrl = `${baseUrl}/api/a2a/agents/${assistant.id}/jsonrpc`;
|
|
24
|
-
const skills = (exposure?.skills ?? []).map((s) => ({
|
|
25
|
-
id: s.id,
|
|
26
|
-
name: s.name,
|
|
27
|
-
description: s.description,
|
|
28
|
-
tags: s.tags ?? [],
|
|
29
|
-
examples: s.examples ?? []
|
|
30
|
-
}));
|
|
31
|
-
return {
|
|
32
|
-
name: assistant.name,
|
|
33
|
-
description: assistant.description ?? "",
|
|
34
|
-
url: jsonRpcUrl,
|
|
35
|
-
protocolVersion: "0.3.0",
|
|
36
|
-
version: "1.0.0",
|
|
37
|
-
defaultInputModes: exposure?.inputModes ?? ["text"],
|
|
38
|
-
defaultOutputModes: exposure?.outputModes ?? ["text"],
|
|
39
|
-
capabilities: {
|
|
40
|
-
streaming: true,
|
|
41
|
-
pushNotifications: false,
|
|
42
|
-
stateTransitionHistory: true
|
|
43
|
-
},
|
|
44
|
-
skills,
|
|
45
|
-
additionalInterfaces: [{ transport: "JSONRPC", url: jsonRpcUrl }],
|
|
46
|
-
securitySchemes: {
|
|
47
|
-
bearer: {
|
|
48
|
-
type: "http",
|
|
49
|
-
scheme: "Bearer",
|
|
50
|
-
description: "A2A API key sent as an Authorization Bearer token"
|
|
51
|
-
},
|
|
52
|
-
apiKeyHeader: {
|
|
53
|
-
type: "apiKey",
|
|
54
|
-
in: "header",
|
|
55
|
-
name: "x-api-key",
|
|
56
|
-
description: "A2A API key sent via the x-api-key header"
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
security: [{ bearer: [] }, { apiKeyHeader: [] }]
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
25
|
// src/services/a2a/A2ATaskStoreAdapter.ts
|
|
64
26
|
import { createHash } from "crypto";
|
|
65
27
|
import { isDeepStrictEqual } from "util";
|
|
@@ -515,6 +477,13 @@ function agentMessage(text) {
|
|
|
515
477
|
parts: [{ kind: "text", text }]
|
|
516
478
|
};
|
|
517
479
|
}
|
|
480
|
+
function assistantHasGovernedTask(assistant) {
|
|
481
|
+
const graph = assistant.graphDefinition;
|
|
482
|
+
const middleware = graph && typeof graph === "object" ? graph.middleware : void 0;
|
|
483
|
+
const taskMiddleware = Array.isArray(middleware) ? middleware.find((entry) => !!entry && typeof entry === "object" && entry.type === "task" && entry.enabled === true) : void 0;
|
|
484
|
+
const allowedTools = taskMiddleware?.allowedTools;
|
|
485
|
+
return !!taskMiddleware && (allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task")));
|
|
486
|
+
}
|
|
518
487
|
var _AxiomAgentExecutor = class _AxiomAgentExecutor {
|
|
519
488
|
constructor(options) {
|
|
520
489
|
this.scope = options.scope;
|
|
@@ -559,18 +528,13 @@ var _AxiomAgentExecutor = class _AxiomAgentExecutor {
|
|
|
559
528
|
});
|
|
560
529
|
};
|
|
561
530
|
try {
|
|
562
|
-
|
|
563
|
-
if (!this.taskStore) {
|
|
564
|
-
throw new Error("A2A governed execution requires a canonical task store");
|
|
565
|
-
}
|
|
566
|
-
this.assertGovernedTaskCapability();
|
|
567
|
-
} catch (err) {
|
|
531
|
+
if (!this.taskStore) {
|
|
568
532
|
const initialTask2 = createTask([]);
|
|
569
|
-
if (this.taskStore) await this.taskStore.save(initialTask2);
|
|
570
533
|
bus.publish(initialTask2);
|
|
571
|
-
publishFailed(
|
|
534
|
+
publishFailed(new Error("A2A execution requires a canonical task store"));
|
|
572
535
|
return;
|
|
573
536
|
}
|
|
537
|
+
const governed = this.hasGovernedTaskCapability();
|
|
574
538
|
const interruption = existing?.metadata?.interruption;
|
|
575
539
|
const reviewInterruption = interruption && typeof interruption === "object" && interruption.type === "review_required";
|
|
576
540
|
const reviewCommand = reviewInterruption ? this.reviewCommand(text) : void 0;
|
|
@@ -607,13 +571,13 @@ var _AxiomAgentExecutor = class _AxiomAgentExecutor {
|
|
|
607
571
|
const requestText = inputFiles.length > 0 ? `${text}
|
|
608
572
|
|
|
609
573
|
${formatFileRefsSection(inputFiles)}` : text;
|
|
610
|
-
const messageText = [
|
|
574
|
+
const messageText = governed ? [
|
|
611
575
|
`A2A governed task instruction: get and update the existing TaskItem ${ctx.taskId}; do not create a replacement task.`,
|
|
612
576
|
"Before doing the requested work, initialize its canonical description through manage_task with ## Objective, ## Acceptance Criteria, and ## Belief State sections.",
|
|
613
577
|
"Keep lifecycle status truthful. Change status only through manage_task set_status; complete with a nonblank result and structured beliefImpact, and use interrupted, failed, or cancelled when appropriate. Use manage_task update for content fields only.",
|
|
614
578
|
"",
|
|
615
579
|
requestText
|
|
616
|
-
].join("\n");
|
|
580
|
+
].join("\n") : requestText;
|
|
617
581
|
const continuationCommand = interruption && typeof interruption === "object" ? { resume: text } : void 0;
|
|
618
582
|
const { messageId } = await agent.addMessage({
|
|
619
583
|
input: { message: messageText },
|
|
@@ -623,13 +587,19 @@ ${formatFileRefsSection(inputFiles)}` : text;
|
|
|
623
587
|
const stream = agent.chunkStream(messageId, [
|
|
624
588
|
MessageChunkTypes.MESSAGE_COMPLETED
|
|
625
589
|
]);
|
|
590
|
+
let outputText = "";
|
|
591
|
+
let interrupted = false;
|
|
626
592
|
for await (const chunk of stream) {
|
|
627
593
|
if (execution.canceled) return;
|
|
628
594
|
const chunkType = chunk.type;
|
|
629
595
|
const chunkText = chunk.data?.content ?? "";
|
|
630
596
|
if (chunkType === MessageChunkTypes.INTERRUPT) {
|
|
597
|
+
interrupted = true;
|
|
631
598
|
break;
|
|
632
599
|
}
|
|
600
|
+
if (chunkType === MessageChunkTypes.AI && chunkText) {
|
|
601
|
+
outputText += chunkText;
|
|
602
|
+
}
|
|
633
603
|
if (chunkType === MessageChunkTypes.AI || chunkType === MessageChunkTypes.TOOL) {
|
|
634
604
|
if (chunkText) {
|
|
635
605
|
bus.publish({
|
|
@@ -647,6 +617,48 @@ ${formatFileRefsSection(inputFiles)}` : text;
|
|
|
647
617
|
}
|
|
648
618
|
}
|
|
649
619
|
if (execution.canceled) return;
|
|
620
|
+
if (!governed) {
|
|
621
|
+
if (interrupted) {
|
|
622
|
+
const paused = {
|
|
623
|
+
...createTask(inputFiles),
|
|
624
|
+
status: { state: "input-required", timestamp: isoNow() }
|
|
625
|
+
};
|
|
626
|
+
await this.taskStore.save(paused);
|
|
627
|
+
bus.publish({
|
|
628
|
+
kind: "status-update",
|
|
629
|
+
taskId: ctx.taskId,
|
|
630
|
+
contextId: ctx.contextId,
|
|
631
|
+
status: { state: "input-required", timestamp: isoNow() },
|
|
632
|
+
final: true
|
|
633
|
+
});
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const resultArtifact = {
|
|
637
|
+
artifactId: uuidv4(),
|
|
638
|
+
name: "result",
|
|
639
|
+
parts: [{ kind: "text", text: outputText }]
|
|
640
|
+
};
|
|
641
|
+
const completed = {
|
|
642
|
+
...createTask(inputFiles),
|
|
643
|
+
artifacts: [...existing?.artifacts ?? [], resultArtifact],
|
|
644
|
+
status: { state: "completed", timestamp: isoNow() }
|
|
645
|
+
};
|
|
646
|
+
await this.taskStore.save(completed);
|
|
647
|
+
bus.publish({
|
|
648
|
+
kind: "artifact-update",
|
|
649
|
+
taskId: ctx.taskId,
|
|
650
|
+
contextId: ctx.contextId,
|
|
651
|
+
artifact: resultArtifact
|
|
652
|
+
});
|
|
653
|
+
bus.publish({
|
|
654
|
+
kind: "status-update",
|
|
655
|
+
taskId: ctx.taskId,
|
|
656
|
+
contextId: ctx.contextId,
|
|
657
|
+
status: { state: "completed", timestamp: isoNow() },
|
|
658
|
+
final: true
|
|
659
|
+
});
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
650
662
|
const canonical = await this.taskStore.load(ctx.taskId);
|
|
651
663
|
const canonicalState = canonical?.status.state;
|
|
652
664
|
if (canonicalState === "completed") {
|
|
@@ -726,15 +738,8 @@ ${formatFileRefsSection(inputFiles)}` : text;
|
|
|
726
738
|
taskKey(taskId) {
|
|
727
739
|
return `${this.scope.tenantId}:${this.scope.projectId}:${this.scope.assistantId}:${taskId}`;
|
|
728
740
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const middleware = graph && typeof graph === "object" ? graph.middleware : void 0;
|
|
732
|
-
const taskMiddleware = Array.isArray(middleware) ? middleware.find((entry) => !!entry && typeof entry === "object" && entry.type === "task" && entry.enabled === true) : void 0;
|
|
733
|
-
const allowedTools = taskMiddleware?.allowedTools;
|
|
734
|
-
const exposesManageTask = taskMiddleware && (allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task")));
|
|
735
|
-
if (!exposesManageTask) {
|
|
736
|
-
throw new Error("A2A execution requires enabled TaskMiddleware exposing manage_task");
|
|
737
|
-
}
|
|
741
|
+
hasGovernedTaskCapability() {
|
|
742
|
+
return assistantHasGovernedTask(this.assistant);
|
|
738
743
|
}
|
|
739
744
|
/**
|
|
740
745
|
* Cancel a running task: resolve its thread id from the task store, abort the
|
|
@@ -1038,27 +1043,15 @@ function getHeader(value) {
|
|
|
1038
1043
|
if (Array.isArray(value)) return value[0];
|
|
1039
1044
|
return value;
|
|
1040
1045
|
}
|
|
1041
|
-
function getTenantHeader(request) {
|
|
1042
|
-
return getHeader(request.headers["x-tenant-id"]) ?? "default";
|
|
1043
|
-
}
|
|
1044
1046
|
function getSessionUser(request) {
|
|
1045
1047
|
return request.user;
|
|
1046
1048
|
}
|
|
1047
|
-
function getSessionTenantId(request) {
|
|
1048
|
-
const userTenantId = getSessionUser(request)?.tenantId;
|
|
1049
|
-
if (userTenantId) return userTenantId;
|
|
1050
|
-
return getTenantHeader(request);
|
|
1051
|
-
}
|
|
1052
1049
|
function buildBaseUrl(request) {
|
|
1053
1050
|
const protocol = getHeader(request.headers["x-forwarded-proto"]) ?? request.protocol;
|
|
1054
1051
|
const forwardedHost = getHeader(request.headers["x-forwarded-host"]);
|
|
1055
1052
|
const host = forwardedHost ? forwardedHost.split(",")[0].trim() : request.host;
|
|
1056
1053
|
return `${protocol}://${host}`;
|
|
1057
1054
|
}
|
|
1058
|
-
function getExposure(assistant) {
|
|
1059
|
-
const graphDefinition = assistant.graphDefinition;
|
|
1060
|
-
return graphDefinition?.a2aExposure;
|
|
1061
|
-
}
|
|
1062
1055
|
function makeFileIngestor(tenantId, maxFileBytes) {
|
|
1063
1056
|
return new A2AFileIngestor({
|
|
1064
1057
|
saveProjectFile: (params) => saveProjectFile({ tenantId, ...params }),
|
|
@@ -1105,33 +1098,6 @@ function registerA2AStandardRoutes(app, deps) {
|
|
|
1105
1098
|
const resolveTaskWorkItems = deps.getTaskWorkItemStore ?? (() => getStoreLattice("default", "taskWorkItem").store);
|
|
1106
1099
|
const getAssistantStore = deps.getAssistantStore ?? (() => getStoreLattice("default", "assistant").store);
|
|
1107
1100
|
const getProjectStore = deps.getProjectStore ?? (() => getStoreLattice("default", "project").store);
|
|
1108
|
-
const getTenantStore = deps.getTenantStore ?? (() => {
|
|
1109
|
-
try {
|
|
1110
|
-
return getStoreLattice("default", "tenant").store;
|
|
1111
|
-
} catch {
|
|
1112
|
-
return void 0;
|
|
1113
|
-
}
|
|
1114
|
-
});
|
|
1115
|
-
async function findExposedAssistant(request, assistantId) {
|
|
1116
|
-
const tenantId = getSessionTenantId(request);
|
|
1117
|
-
const direct = await getAssistantStore().getAssistantById(
|
|
1118
|
-
tenantId,
|
|
1119
|
-
assistantId
|
|
1120
|
-
);
|
|
1121
|
-
if (direct) return direct;
|
|
1122
|
-
const tenantStore = getTenantStore();
|
|
1123
|
-
if (!tenantStore) return null;
|
|
1124
|
-
const tenants = await tenantStore.getAllTenants();
|
|
1125
|
-
for (const tenant of tenants) {
|
|
1126
|
-
if (tenant.id === tenantId) continue;
|
|
1127
|
-
const found = await getAssistantStore().getAssistantById(
|
|
1128
|
-
tenant.id,
|
|
1129
|
-
assistantId
|
|
1130
|
-
);
|
|
1131
|
-
if (found) return found;
|
|
1132
|
-
}
|
|
1133
|
-
return null;
|
|
1134
|
-
}
|
|
1135
1101
|
const runtimeRegistry = deps.runtimeRegistry ?? new A2ARuntimeRegistry();
|
|
1136
1102
|
app.addHook("onClose", async () => {
|
|
1137
1103
|
runtimeRegistry.close();
|
|
@@ -1139,19 +1105,32 @@ function registerA2AStandardRoutes(app, deps) {
|
|
|
1139
1105
|
app.get(
|
|
1140
1106
|
"/api/a2a/agents/:assistantId/.well-known/agent-card.json",
|
|
1141
1107
|
async (request, reply) => {
|
|
1142
|
-
const
|
|
1143
|
-
request
|
|
1144
|
-
request.params.assistantId
|
|
1108
|
+
const auth = await authService.authenticate(
|
|
1109
|
+
getHeader(request.headers.authorization) ?? getHeader(request.headers["x-api-key"])
|
|
1145
1110
|
);
|
|
1146
|
-
if (!
|
|
1147
|
-
reply.status(
|
|
1111
|
+
if (!auth.authenticated) {
|
|
1112
|
+
reply.status(401).send({ error: "Unauthorized" });
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
let assistant;
|
|
1116
|
+
try {
|
|
1117
|
+
assistant = await authService.assertAgentAccess(
|
|
1118
|
+
auth,
|
|
1119
|
+
request.params.assistantId
|
|
1120
|
+
);
|
|
1121
|
+
} catch (err) {
|
|
1122
|
+
if (err instanceof A2AAuthError) {
|
|
1123
|
+
reply.status(err.statusCode).send({ error: err.message });
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
request.log.error({ err }, "a2a:agent-card:auth");
|
|
1127
|
+
reply.status(500).send({ error: "Internal error" });
|
|
1148
1128
|
return;
|
|
1149
1129
|
}
|
|
1150
1130
|
reply.header("A2A-Version", "0.3");
|
|
1151
1131
|
reply.status(200).send(
|
|
1152
1132
|
buildAgentCardForAssistant({
|
|
1153
1133
|
assistant,
|
|
1154
|
-
exposure: getExposure(assistant),
|
|
1155
1134
|
baseUrl: buildBaseUrl(request)
|
|
1156
1135
|
})
|
|
1157
1136
|
);
|
|
@@ -1170,7 +1149,7 @@ function registerA2AStandardRoutes(app, deps) {
|
|
|
1170
1149
|
}
|
|
1171
1150
|
let assistant;
|
|
1172
1151
|
try {
|
|
1173
|
-
assistant = await authService.
|
|
1152
|
+
assistant = await authService.assertAgentAccess(
|
|
1174
1153
|
auth,
|
|
1175
1154
|
request.params.assistantId
|
|
1176
1155
|
);
|
|
@@ -1196,7 +1175,7 @@ function registerA2AStandardRoutes(app, deps) {
|
|
|
1196
1175
|
};
|
|
1197
1176
|
const internalTasks = resolveTasks();
|
|
1198
1177
|
const workItems = resolveTaskWorkItems();
|
|
1199
|
-
const taskStore = new A2ATaskStoreAdapter({
|
|
1178
|
+
const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
|
|
1200
1179
|
taskStore: internalTasks,
|
|
1201
1180
|
workItemStore: workItems,
|
|
1202
1181
|
lifecycle: createTaskLifecycleService({
|
|
@@ -1204,12 +1183,11 @@ function registerA2AStandardRoutes(app, deps) {
|
|
|
1204
1183
|
workItemStore: workItems
|
|
1205
1184
|
}),
|
|
1206
1185
|
scope
|
|
1207
|
-
});
|
|
1186
|
+
}) : new InMemoryTaskStore();
|
|
1208
1187
|
const ingestor = makeFileIngestor(scope.tenantId, deps.maxFileBytes);
|
|
1209
1188
|
const executor = new AxiomAgentExecutor({ scope, assistant, taskStore, ingestor });
|
|
1210
1189
|
const card = buildAgentCardForAssistant({
|
|
1211
1190
|
assistant,
|
|
1212
|
-
exposure: getExposure(assistant),
|
|
1213
1191
|
baseUrl: buildBaseUrl(request)
|
|
1214
1192
|
});
|
|
1215
1193
|
let runtimeLease;
|
|
@@ -1315,7 +1293,7 @@ data: ${JSON.stringify(errorResponse)}
|
|
|
1315
1293
|
const ingestor = makeFileIngestor(scope.tenantId, deps.maxFileBytes);
|
|
1316
1294
|
const internalTasks = resolveTasks();
|
|
1317
1295
|
const workItems = resolveTaskWorkItems();
|
|
1318
|
-
const taskStore = new A2ATaskStoreAdapter({
|
|
1296
|
+
const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
|
|
1319
1297
|
taskStore: internalTasks,
|
|
1320
1298
|
workItemStore: workItems,
|
|
1321
1299
|
lifecycle: createTaskLifecycleService({
|
|
@@ -1323,7 +1301,7 @@ data: ${JSON.stringify(errorResponse)}
|
|
|
1323
1301
|
workItemStore: workItems
|
|
1324
1302
|
}),
|
|
1325
1303
|
scope
|
|
1326
|
-
});
|
|
1304
|
+
}) : new InMemoryTaskStore();
|
|
1327
1305
|
const executor = new AxiomAgentExecutor({ scope, assistant, taskStore, ingestor });
|
|
1328
1306
|
const taskId = uuidv42();
|
|
1329
1307
|
const contextId = uuidv42();
|
|
@@ -1366,4 +1344,4 @@ data: ${JSON.stringify(data)}
|
|
|
1366
1344
|
export {
|
|
1367
1345
|
registerA2AStandardRoutes
|
|
1368
1346
|
};
|
|
1369
|
-
//# sourceMappingURL=a2a-standard-
|
|
1347
|
+
//# sourceMappingURL=a2a-standard-VEQBXBMM.mjs.map
|