@axiom-lattice/gateway 4.3.2 → 4.4.0

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.
Files changed (73) hide show
  1. package/dist/{a2a-standard-ALXWP7V6.mjs → a2a-standard-P7JDL6ZA.mjs} +63 -35
  2. package/dist/a2a-standard-P7JDL6ZA.mjs.map +1 -0
  3. package/dist/{registerExposedPlugins-63EUF4VS.mjs → chunk-3XIIQ6EK.mjs} +62 -18
  4. package/dist/chunk-3XIIQ6EK.mjs.map +1 -0
  5. package/dist/chunk-526UYVNQ.mjs +157 -0
  6. package/dist/chunk-526UYVNQ.mjs.map +1 -0
  7. package/dist/chunk-73QZQQOT.mjs +43 -0
  8. package/dist/chunk-73QZQQOT.mjs.map +1 -0
  9. package/dist/{chunk-GF4GGTWJ.mjs → chunk-HVIKCUOF.mjs} +10 -7
  10. package/dist/chunk-HVIKCUOF.mjs.map +1 -0
  11. package/dist/embed/embed-page-AgentDetailSideApp-PSRQVFNR.js +1 -0
  12. package/dist/embed/{embed-page-AgentGovernanceWorkbench-ZNW72EEJ.js → embed-page-AgentGovernanceWorkbench-UPQHJZD7.js} +1 -1
  13. package/dist/embed/embed-page-MessageGraph-PDNQ67T4.js +6 -0
  14. package/dist/embed/{embed-page-TasksSideApp-F4XUHPTG.css → embed-page-MessageGraph-UT2TCPSO.css} +1 -1
  15. package/dist/embed/{embed-page-ReactChart-XS7D26VP.js → embed-page-ReactChart-25KAFLQ3.js} +1 -1
  16. package/dist/embed/embed-page-ReactChart-MXGF35OQ.css +1 -0
  17. package/dist/embed/embed-page-SkillFlow-TKBMB5VV.js +1 -0
  18. package/dist/embed/{embed-page-TasksSideApp-MQTUCJO4.js → embed-page-TasksSideApp-DLH5LRMS.js} +1 -1
  19. package/dist/embed/{embed-page-TopologyRuntimeView-2NQ3OOYI.css → embed-page-TasksSideApp-HV6DKQ26.css} +1 -1
  20. package/dist/embed/{embed-page-TeamWorkspace-7T2HRXLG.js → embed-page-TeamWorkspace-2WJJWF25.js} +1 -1
  21. package/dist/embed/{embed-page-TeamWorkspace-DXKGNQ3C.css → embed-page-TeamWorkspace-YQFWXDLI.css} +1 -1
  22. package/dist/embed/{embed-page-MessageGraph-TYOOATYV.css → embed-page-TopologyRuntimeView-CWOXLVFW.css} +1 -1
  23. package/dist/embed/{embed-page-TopologyRuntimeView-PU2D7VZ7.js → embed-page-TopologyRuntimeView-WDQRHDMO.js} +1 -1
  24. package/dist/embed/{embed-page-WorkflowAutomationView-ST76M33F.js → embed-page-WorkflowAutomationView-BAMJ2WVB.js} +1 -1
  25. package/dist/embed/embed-page-WorkflowAutomationView-YQFB3CTV.css +1 -0
  26. package/dist/embed/{embed-page-chunk-T25T2YE6.js → embed-page-chunk-HMTKPZ5B.js} +7 -5
  27. package/dist/embed/{embed-page-chunk-ZKJ7Z7P3.js → embed-page-chunk-LOXLXZNP.js} +1 -1
  28. package/dist/embed/{embed-page-chunk-Z4S4OYA4.js → embed-page-chunk-MQDYZS3S.js} +1 -1
  29. package/dist/embed/embed-page-chunk-OBM5EUWZ.js +6974 -0
  30. package/dist/embed/{embed-page-chunk-RLP3BC7G.js → embed-page-chunk-SSC7ANWV.js} +2 -2
  31. package/dist/embed/embed-page-chunk-TL2AYM76.js +2 -0
  32. package/dist/embed/{embed-page-chunk-LE6OFJ7R.js → embed-page-chunk-XVUA7UHE.js} +1 -1
  33. package/dist/embed/embed-page.js +1 -1
  34. package/dist/index.js +5103 -3988
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +1566 -411
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/{open-HH7RKGML.mjs → open-AMEMJOFJ.mjs} +99 -14
  39. package/dist/open-AMEMJOFJ.mjs.map +1 -0
  40. package/dist/{open-catalog-WYS2AENM.mjs → open-catalog-SZQ435AY.mjs} +34 -3
  41. package/dist/open-catalog-SZQ435AY.mjs.map +1 -0
  42. package/dist/{open-exposure-FK4G6O6L.mjs → open-exposure-I44Q4M3T.mjs} +37 -7
  43. package/dist/open-exposure-I44Q4M3T.mjs.map +1 -0
  44. package/dist/{open-files-GVRMK5PL.mjs → open-files-EJ6O2SGX.mjs} +4 -4
  45. package/dist/{open-session-3VN65PRR.mjs → open-session-LBTCU3AE.mjs} +4 -4
  46. package/dist/{openLattice-GAAGQJST.mjs → openLattice-Q6M5S6CY.mjs} +4 -2
  47. package/dist/registerExposedPlugins-6GCOE64C.mjs +11 -0
  48. package/dist/{resources-JFKAPS45.mjs → resources-DXPXAXEZ.mjs} +16 -9
  49. package/dist/{resources-JFKAPS45.mjs.map → resources-DXPXAXEZ.mjs.map} +1 -1
  50. package/package.json +11 -8
  51. package/dist/a2a-standard-ALXWP7V6.mjs.map +0 -1
  52. package/dist/chunk-GF4GGTWJ.mjs.map +0 -1
  53. package/dist/chunk-QKPZWWHH.mjs +0 -433
  54. package/dist/chunk-QKPZWWHH.mjs.map +0 -1
  55. package/dist/embed/embed-page-AgentDetailSideApp-7PQ2JKG6.js +0 -1
  56. package/dist/embed/embed-page-MessageGraph-P7DBTZCL.js +0 -6
  57. package/dist/embed/embed-page-ReactChart-VBM467ER.css +0 -1
  58. package/dist/embed/embed-page-SkillFlow-HPH37PZH.js +0 -1
  59. package/dist/embed/embed-page-WorkflowAutomationView-MAYS27YJ.css +0 -1
  60. package/dist/embed/embed-page-chunk-4ZSGPIBZ.js +0 -1
  61. package/dist/embed/embed-page-chunk-BRETUPSG.js +0 -4094
  62. package/dist/embed/embed-page-chunk-I42T7B7V.js +0 -2415
  63. package/dist/embed/embed-page-chunk-VRV57DFE.js +0 -466
  64. package/dist/embed/embed-page-chunk-ZXFZANZM.js +0 -1
  65. package/dist/mcp-configs-WCY5EXCW.mjs +0 -30
  66. package/dist/open-HH7RKGML.mjs.map +0 -1
  67. package/dist/open-catalog-WYS2AENM.mjs.map +0 -1
  68. package/dist/open-exposure-FK4G6O6L.mjs.map +0 -1
  69. package/dist/registerExposedPlugins-63EUF4VS.mjs.map +0 -1
  70. /package/dist/{open-files-GVRMK5PL.mjs.map → open-files-EJ6O2SGX.mjs.map} +0 -0
  71. /package/dist/{open-session-3VN65PRR.mjs.map → open-session-LBTCU3AE.mjs.map} +0 -0
  72. /package/dist/{mcp-configs-WCY5EXCW.mjs.map → openLattice-Q6M5S6CY.mjs.map} +0 -0
  73. /package/dist/{openLattice-GAAGQJST.mjs.map → registerExposedPlugins-6GCOE64C.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/open/registerExposedPlugins.ts","../src/services/open/pluginExposeAdapter.ts"],"sourcesContent":["import { PluginRegistry } from \"@axiom-lattice/core\";\nimport type { OpenGrant, Plugin, PluginToolUi } from \"@axiom-lattice/protocols\";\nimport { grantCovers, openLattice } from \"./openLattice\";\nimport { createPluginProvider } from \"./pluginExposeAdapter\";\nimport type { OpenUiResource } from \"./openMcpServer\";\n\n/** A single exposed-tool declaration (annotation hints optional). */\ninterface ExposedDeclaration {\n name: string;\n description: string;\n readOnly?: boolean;\n destructive?: boolean;\n}\n\n/**\n * Declaration source: meta.openExpose (preferred, standalone) or\n * meta.tools[].expose (per-tool flags).\n */\nfunction exposedDeclarations(plugin: Plugin): ExposedDeclaration[] {\n const openExpose = plugin.meta.openExpose;\n if (openExpose) {\n return openExpose.map((entry) =>\n typeof entry === \"string\"\n ? { name: entry, description: \"\" }\n : {\n name: entry.name,\n description: \"\",\n readOnly: entry.readOnly,\n destructive: entry.destructive,\n },\n );\n }\n return (plugin.meta.tools ?? []).filter((t) => t.expose);\n}\n\n/** Walk PluginRegistry and register every exposed tool as an Open provider. */\nexport async function registerExposedPluginTools(): Promise<void> {\n for (const key of PluginRegistry.list()) {\n const plugin = PluginRegistry.get(key);\n if (!plugin?.middleware) continue;\n const exposed = exposedDeclarations(plugin);\n if (exposed.length === 0) continue;\n // Tool-level UI declarations keyed by tool name (raw meta, unlike listMeta).\n const uiByTool = new Map<string, PluginToolUi>();\n for (const toolMeta of plugin.meta.tools ?? []) {\n if (toolMeta.ui) uiByTool.set(toolMeta.name, toolMeta.ui);\n }\n try {\n // Open-door semantics: resolve the tenant's connections at call time\n // (credential → tenant → tenant's own Connection Store entries).\n const middleware = await plugin.middleware({\n ...(plugin.meta.defaultConfig ?? {}),\n connectAll: true,\n });\n const toolObjects = (middleware as { tools?: Array<{ name: string; description: string; invoke: (input: unknown, config?: unknown) => Promise<string> }> }).tools ?? [];\n const matched = exposed\n .map((tm) => {\n const tool = toolObjects.find((t: { name: string }) => t.name === tm.name);\n if (!tool) return null;\n return {\n name: tm.name,\n description: tm.description,\n tool,\n readOnly: tm.readOnly,\n destructive: tm.destructive,\n ui: uiByTool.get(tm.name),\n };\n })\n .filter(Boolean) as Array<{\n name: string;\n description?: string;\n tool: { name: string; description: string; invoke: (input: unknown, config?: unknown) => Promise<string> };\n readOnly?: boolean;\n destructive?: boolean;\n ui?: PluginToolUi;\n }>;\n if (matched.length === 0) continue;\n const provider = createPluginProvider(key, matched, { label: plugin.meta.name });\n openLattice.register(provider);\n } catch {\n // skip plugins whose middleware fails to instantiate\n }\n }\n}\n\n/**\n * Inline `ui://` resources declared by GLOBAL plugins (raw meta, not listMeta).\n *\n * `serializePluginMeta` is a whitelist and drops `meta.uiResources`, so the raw\n * plugin is read back from `PluginRegistry.get(type)`. A resource is included\n * only when an **exposed** tool of that domain declares it (`meta.tools[].ui`)\n * **and** the credential's grant covers that exact tool (item-level) — a domain\n * grant alone must not leak another tool's UI document, and an unexposed or\n * unauthorized plugin must not leak any. `mimeType` defaults to\n * `text/html;profile=mcp-app` (the `PluginUiResource` contract).\n *\n * Synchronous: `PluginRegistry` is synchronous. The returned `read` callback\n * serves the plugin's inline HTML lazily per `resources/read`.\n *\n * @param grants - Credential grants; an item not granted (or unknown resource)\n * is skipped.\n * @returns Map of `ui://` URI → Open session UI resource.\n */\nexport function collectExposedPluginUiResources(grants: OpenGrant[]): Map<string, OpenUiResource> {\n const resources = new Map<string, OpenUiResource>();\n for (const type of PluginRegistry.list()) {\n const plugin = PluginRegistry.get(type);\n if (!plugin?.middleware) continue;\n const exposedNames = new Set(exposedDeclarations(plugin).map((d) => d.name));\n if (exposedNames.size === 0) continue;\n // Only resources owned by an exposed, item-level-granted tool are reachable.\n const allowedUris = new Set<string>();\n for (const toolMeta of plugin.meta.tools ?? []) {\n const uri = toolMeta.ui?.resource;\n if (!uri) continue;\n if (!exposedNames.has(toolMeta.name)) continue;\n if (!grantCovers(grants, type, toolMeta.name)) continue;\n allowedUris.add(uri);\n }\n if (allowedUris.size === 0) continue;\n for (const [uri, res] of Object.entries(plugin.meta.uiResources ?? {})) {\n if (!allowedUris.has(uri)) continue;\n resources.set(uri, {\n mimeType: res.mimeType ?? \"text/html;profile=mcp-app\",\n csp: res.csp,\n read: async () => ({ html: res.html, csp: res.csp }),\n });\n }\n }\n return resources;\n}\n","/**\n * Plugin expose adapter: converts a plugin's middleware-emitted tools into an\n * OpenProvider, so `expose: true` tools surface on the Open API catalog.\n *\n * The LangChain tool emits schema via .lc_kwargs.schema (ZodType) and runs via\n * .invoke(input, exeConfig). We synthesize the exeConfig the way the Agent\n * path would — injecting run identity (tenantId/workspaceId/projectId) into\n * runConfig. Plugin tools resolve their own connections from the\n * tenant-scoped Connection Store at invocation time.\n */\n\nimport { z } from \"zod\";\nimport type { OpenExecutionContext, PluginToolUi } from \"@axiom-lattice/protocols\";\nimport type { OpenProviderDeclaration, OpenActionDeclaration } from \"./openLattice\";\n\nexport interface PluginToolLike {\n name: string;\n description: string;\n invoke: (input: unknown, exeConfig?: unknown) => Promise<string>;\n lc_kwargs?: { schema?: z.ZodTypeAny };\n schema?: z.ZodTypeAny;\n}\n\nfunction schemaOf(tool: PluginToolLike): z.ZodTypeAny {\n return tool.lc_kwargs?.schema ?? tool.schema ?? z.object({}).passthrough();\n}\n\n/** Build an Open provider exposing the given plugin tools under a domain. */\nexport interface PluginExposedTool {\n name: string;\n description?: string;\n tool: PluginToolLike;\n /** MCP readOnlyHint (default false — conservative). */\n readOnly?: boolean;\n /** MCP destructiveHint (default false). */\n destructive?: boolean;\n /**\n * MCP App UI declaration from the plugin's tool meta. For global plugins\n * `resource` is already a `ui://` URI (unlike sandbox plugins, where it is a\n * file path relative to the plugin directory).\n */\n ui?: PluginToolUi;\n}\n\nexport function createPluginProvider(\n domain: string,\n tools: PluginExposedTool[],\n options: { label?: string } = {},\n): OpenProviderDeclaration {\n function toAction(info: PluginExposedTool): OpenActionDeclaration {\n return {\n name: info.name,\n description:\n info.description || info.tool.description || `Plugin tool ${info.name}`,\n schema: schemaOf(info.tool),\n annotations: {\n readOnlyHint: info.readOnly ?? false,\n destructiveHint: info.destructive ?? false,\n },\n ui: info.ui\n ? {\n resourceUri: info.ui.resource,\n csp: info.ui.csp,\n displayMode: info.ui.displayMode,\n }\n : undefined,\n };\n }\n\n const actions = tools.map(toAction);\n return {\n domain,\n label: options.label ?? domain,\n source: \"plugin\",\n scopeKind: \"tenant\",\n actions,\n execute: async (action: string, args: unknown, ctx: OpenExecutionContext) => {\n const info = tools.find((t) => t.name === action);\n if (!info) {\n return {\n content: [{ type: \"text\", text: `Unknown action: ${action}` }],\n isError: true,\n };\n }\n const exeConfig = {\n configurable: {\n runConfig: {\n tenantId: ctx.tenantId,\n workspaceId: ctx.workspaceId,\n projectId: ctx.projectId,\n },\n },\n };\n const output = await info.tool.invoke(args, exeConfig);\n return { content: [{ type: \"text\", text: output }] };\n },\n };\n}"],"mappings":"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","names":[]}
@@ -0,0 +1,157 @@
1
+ import {
2
+ PluginToolScopeError,
3
+ invokePluginTool
4
+ } from "./chunk-73QZQQOT.mjs";
5
+ import {
6
+ grantCovers
7
+ } from "./chunk-HVIKCUOF.mjs";
8
+
9
+ // src/services/open/tenantOpenPlugins.ts
10
+ import {
11
+ getSandboxPluginCatalog,
12
+ jsonSchemaToZod,
13
+ resolveSandboxPluginConnections
14
+ } from "@axiom-lattice/core";
15
+ function asArgs(value) {
16
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
17
+ }
18
+ function toText(result) {
19
+ return typeof result === "string" ? result : JSON.stringify(result ?? null);
20
+ }
21
+ function defaultCatalog() {
22
+ return {
23
+ getValidatedManifest: (tenantId, type) => getSandboxPluginCatalog().getValidatedManifest(tenantId, type),
24
+ getExecutor: () => getSandboxPluginCatalog().getExecutor(),
25
+ readPluginFile: (tenantId, type, relPath) => getSandboxPluginCatalog().readPluginFile(tenantId, type, relPath)
26
+ };
27
+ }
28
+ async function defaultResolveConnections(pluginType, ctx) {
29
+ try {
30
+ return await resolveSandboxPluginConnections(
31
+ pluginType,
32
+ { connectAll: true },
33
+ {
34
+ tenantId: ctx.tenantId,
35
+ workspaceId: ctx.workspaceId,
36
+ projectId: ctx.projectId
37
+ }
38
+ );
39
+ } catch (err) {
40
+ if (err instanceof Error && err.message === "ConnectionStore not configured") {
41
+ return {};
42
+ }
43
+ throw err;
44
+ }
45
+ }
46
+ function mergeOpenCatalog(globalCatalog, tenantTools) {
47
+ const seen = new Set(globalCatalog.map((t) => t.toolName));
48
+ const merged = [...globalCatalog];
49
+ for (const tool of tenantTools) {
50
+ if (seen.has(tool.toolName)) continue;
51
+ seen.add(tool.toolName);
52
+ merged.push(tool);
53
+ }
54
+ return merged;
55
+ }
56
+ async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
57
+ const catalog = deps.catalog ?? defaultCatalog();
58
+ const listPlugins = deps.listPlugins ?? (async (tenant) => {
59
+ const snapshot = await getSandboxPluginCatalog().ensureLoaded(tenant);
60
+ return { plugins: snapshot.plugins, diagnostics: snapshot.diagnostics };
61
+ });
62
+ const resolveConnections = deps.resolveConnections ?? defaultResolveConnections;
63
+ const listed = await listPlugins(tenantId);
64
+ const plugins = Array.isArray(listed) ? listed : listed.plugins;
65
+ const diagnostics = Array.isArray(listed) ? [] : listed.diagnostics ?? [];
66
+ const degraded = diagnostics.some((d) => d.level === "error");
67
+ const tools = [];
68
+ const uiResources = /* @__PURE__ */ new Map();
69
+ const toolIndex = /* @__PURE__ */ new Map();
70
+ for (const plugin of plugins) {
71
+ const domain = plugin.meta.type;
72
+ const manifest = await catalog.getValidatedManifest(tenantId, domain);
73
+ if (!manifest) continue;
74
+ for (const tool of manifest.tools ?? []) {
75
+ if (tool.expose !== true) continue;
76
+ if (!grantCovers(grants, domain, tool.name)) continue;
77
+ const toolName = `${domain}_${tool.name}`;
78
+ if (deps.reservedToolNames?.has(toolName)) continue;
79
+ const ui = tool.ui?.resource ? {
80
+ resourceUri: `ui://${domain}/${tool.ui.resource}`,
81
+ csp: tool.ui.csp,
82
+ displayMode: tool.ui.displayMode
83
+ } : void 0;
84
+ if (tool.ui?.resource) {
85
+ const resource = tool.ui.resource;
86
+ const csp = tool.ui.csp;
87
+ uiResources.set(ui.resourceUri, {
88
+ mimeType: "text/html;profile=mcp-app",
89
+ csp,
90
+ read: async () => ({
91
+ html: await catalog.readPluginFile(tenantId, domain, resource),
92
+ csp
93
+ })
94
+ });
95
+ }
96
+ tools.push({
97
+ toolName,
98
+ domain,
99
+ action: tool.name,
100
+ description: tool.description,
101
+ schema: jsonSchemaToZod(tool.schema),
102
+ annotations: {
103
+ readOnlyHint: tool.readOnly ?? false,
104
+ destructiveHint: tool.destructive ?? false
105
+ },
106
+ ui
107
+ });
108
+ toolIndex.set(toolName, { pluginType: domain, action: tool.name });
109
+ }
110
+ }
111
+ return {
112
+ tools,
113
+ uiResources,
114
+ hasTool: (toolName) => toolIndex.has(toolName),
115
+ degraded,
116
+ invoke: async (toolName, args, ctx) => {
117
+ const entry = toolIndex.get(toolName);
118
+ if (!entry) {
119
+ return {
120
+ content: [{ type: "text", text: `Unknown action: ${toolName}` }],
121
+ isError: true
122
+ };
123
+ }
124
+ try {
125
+ const { connection, connections } = await resolveConnections(entry.pluginType, ctx);
126
+ const result = await invokePluginTool(
127
+ { catalog },
128
+ ctx.tenantId,
129
+ entry.pluginType,
130
+ entry.action,
131
+ asArgs(args),
132
+ {
133
+ workspaceId: ctx.workspaceId,
134
+ projectId: ctx.projectId,
135
+ ...connection === void 0 ? {} : { connection },
136
+ ...connections === void 0 ? {} : { connections }
137
+ }
138
+ );
139
+ return { content: [{ type: "text", text: toText(result) }] };
140
+ } catch (error) {
141
+ if (error instanceof PluginToolScopeError) {
142
+ return {
143
+ content: [{ type: "text", text: error.message }],
144
+ isError: true
145
+ };
146
+ }
147
+ throw error;
148
+ }
149
+ }
150
+ };
151
+ }
152
+
153
+ export {
154
+ mergeOpenCatalog,
155
+ buildTenantOpenPlugins
156
+ };
157
+ //# sourceMappingURL=chunk-526UYVNQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/open/tenantOpenPlugins.ts"],"sourcesContent":["/**\n * Tenant sandbox plugin exposure for the Open MCP surface.\n *\n * Global plugins are registered into `openLattice` by `registerExposedPlugins`;\n * tenant sandbox plugins live in per-tenant volumes and are not part of that\n * registry. This module derives the credential's grant-filtered view of those\n * tenant plugins (tools + `ui://` resources) and routes execution back into the\n * tenant sandbox executor through the shared {@link invokePluginTool} seam.\n *\n * Scope is strictly the credential's `tenantId`; globals are merged by the\n * caller (`routes/open.ts`).\n */\n\nimport {\n getSandboxPluginCatalog,\n jsonSchemaToZod,\n resolveSandboxPluginConnections,\n} from \"@axiom-lattice/core\";\nimport type {\n OpenExecutionResult,\n OpenGrant,\n Plugin,\n SandboxPluginDiagnostic,\n} from \"@axiom-lattice/protocols\";\nimport { grantCovers, type OpenToolDescriptor } from \"./openLattice\";\nimport type { OpenUiResource } from \"./openMcpServer\";\nimport {\n invokePluginTool,\n PluginToolScopeError,\n type PluginToolCatalog,\n} from \"../plugins/pluginToolExecution\";\n\n/** Catalog surface needed to read tenant plugin files and execute tools. */\nexport interface TenantOpenPluginCatalog extends PluginToolCatalog {\n /** Read a file inside a tenant plugin directory (e.g. a `ui/*.html`). */\n readPluginFile(tenantId: string, pluginType: string, relPath: string): Promise<string>;\n}\n\n/**\n * Result of listing a tenant's sandbox plugins.\n *\n * The live catalog's `ensureLoaded` reports read failures as error-level\n * diagnostics instead of throwing, so the richer object shape is preferred.\n * A bare `Plugin[]` remains accepted for test/back-compat seams and is treated\n * as a healthy listing (`degraded: false`).\n */\nexport type TenantPluginListing =\n | Plugin[]\n | { plugins: Plugin[]; diagnostics?: SandboxPluginDiagnostic[] };\n\n/** Test seams for {@link buildTenantOpenPlugins}; both default to the live catalog. */\nexport interface TenantOpenPluginDeps {\n catalog?: TenantOpenPluginCatalog;\n listPlugins?: (tenantId: string) => Promise<TenantPluginListing>;\n /**\n * Resolve the invoked plugin's connection credentials.\n *\n * Defaults to core's {@link resolveSandboxPluginConnections} with\n * `connectAll: true`, scoped to the credential tenant. Injected by tests and\n * by callers that have already resolved connections.\n */\n resolveConnections?: (\n pluginType: string,\n ctx: TenantOpenPluginInvokeContext,\n ) => Promise<TenantConnectionResolution>;\n /**\n * Tool names already owned by the global/built-in Open catalog.\n *\n * Defense in depth for the `mergeOpenCatalog` guarantee: a tenant tool whose\n * name collides is skipped at build time, so the session never registers a\n * duplicate (the SDK throws on `registerTool`) **and** the bundle's\n * `hasTool` never claims a tool that must route to the global provider.\n */\n reservedToolNames?: ReadonlySet<string>;\n}\n\n/** Credentials resolved for one plugin domain, forwarded to the sandbox executor. */\nexport interface TenantConnectionResolution {\n connection?: Record<string, unknown>;\n connections?: Array<{ key: string; config: Record<string, unknown> }>;\n}\n\n/** Request-scoped identity forwarded when invoking a tenant plugin tool. */\nexport interface TenantOpenPluginInvokeContext {\n tenantId: string;\n workspaceId?: string;\n projectId?: string;\n /** Synthesized run identity forwarded alongside the invocation. */\n runConfig?: Record<string, unknown>;\n}\n\n/** The credential's grant-filtered tenant plugin bundle for one MCP session. */\nexport interface TenantOpenPlugins {\n tools: OpenToolDescriptor[];\n uiResources: Map<string, OpenUiResource>;\n hasTool(toolName: string): boolean;\n invoke(\n toolName: string,\n args: unknown,\n ctx: TenantOpenPluginInvokeContext,\n ): Promise<OpenExecutionResult>;\n /**\n * True when the tenant catalog could not be read reliably: it reported at\n * least one error-level diagnostic (e.g. `SANDBOX_UNAVAILABLE`,\n * `PLUGINS_LIST_FAILED`). Callers should log this and serve global tools only;\n * the bundle is still safe to use (empty tools, `hasTool` returns false).\n */\n degraded: boolean;\n}\n\n/** Narrow an unknown value to a plain data record, otherwise an empty record. */\nfunction asArgs(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** Serialize a handler result the way the Open surface renders tool output. */\nfunction toText(result: unknown): string {\n return typeof result === \"string\" ? result : JSON.stringify(result ?? null);\n}\n\n/** Adapter over the process-wide sandbox plugin catalog. */\nfunction defaultCatalog(): TenantOpenPluginCatalog {\n return {\n getValidatedManifest: (tenantId, type) =>\n getSandboxPluginCatalog().getValidatedManifest(tenantId, type),\n getExecutor: () => getSandboxPluginCatalog().getExecutor(),\n readPluginFile: (tenantId, type, relPath) =>\n getSandboxPluginCatalog().readPluginFile(tenantId, type, relPath),\n };\n}\n\n/**\n * Default connection resolution: every connection of the invoked plugin type,\n * scoped to the credential tenant.\n *\n * A missing connection store degrades to no credentials, matching the Agent\n * path's tolerance, so an unconfigured deployment fails at the plugin boundary\n * rather than throwing from the Open session.\n */\nasync function defaultResolveConnections(\n pluginType: string,\n ctx: TenantOpenPluginInvokeContext,\n): Promise<TenantConnectionResolution> {\n try {\n return await resolveSandboxPluginConnections(\n pluginType,\n { connectAll: true },\n {\n tenantId: ctx.tenantId,\n workspaceId: ctx.workspaceId,\n projectId: ctx.projectId,\n },\n );\n } catch (err) {\n if (err instanceof Error && err.message === \"ConnectionStore not configured\") {\n return {};\n }\n throw err;\n }\n}\n\n/**\n * Merge global/built-in Open tools with tenant sandbox plugin tools.\n *\n * The MCP SDK throws when `registerTool` sees a duplicate tool name, and the\n * built-in Open domains (`kb`/`sandbox`/`agent`) are not sandbox plugin types,\n * so a tenant plugin of the same type could otherwise shadow/crash the session.\n * **Global wins**: a tenant tool whose `toolName` already exists in the global\n * catalog is dropped. Tenant-internal duplicates are also collapsed\n * (first-wins) as a defensive measure.\n *\n * @param globalCatalog - Grant-filtered OpenLattice descriptors.\n * @param tenantTools - Tenant sandbox plugin descriptors.\n * @returns A duplicate-free catalog with global entries taking precedence.\n */\nexport function mergeOpenCatalog(\n globalCatalog: OpenToolDescriptor[],\n tenantTools: OpenToolDescriptor[],\n): OpenToolDescriptor[] {\n const seen = new Set(globalCatalog.map((t) => t.toolName));\n const merged = [...globalCatalog];\n for (const tool of tenantTools) {\n if (seen.has(tool.toolName)) continue;\n seen.add(tool.toolName);\n merged.push(tool);\n }\n return merged;\n}\n\n/**\n * Build the credential-scoped tenant plugin tool catalog and UI resources.\n *\n * Only tools whose manifest marks `expose: true` and whose `(domain, action)` is\n * covered by the credential's grants are included. A tool's declared\n * `ui.resource` becomes a deterministic `ui://${domain}/${resource}` URI whose\n * reader pulls the HTML from the tenant volume lazily.\n *\n * @param tenantId - Credential tenant; never caller-supplied.\n * @param grants - Credential grants (domain/action allow-list).\n * @param deps - Optional catalog/list seams for tests.\n * @returns The merged tool descriptors, UI resources, and invoke router.\n *\n * @remarks\n * Sandbox tools carry a restricted JSON Schema object, which is converted with\n * core's {@link jsonSchemaToZod} (the same conversion the manifest validator\n * used), so the registered MCP input schema matches the sandbox contract.\n */\nexport async function buildTenantOpenPlugins(\n tenantId: string,\n grants: OpenGrant[],\n deps: TenantOpenPluginDeps = {},\n): Promise<TenantOpenPlugins> {\n const catalog = deps.catalog ?? defaultCatalog();\n const listPlugins =\n deps.listPlugins ??\n (async (tenant: string) => {\n // `ensureLoaded` reports read failures as diagnostics (it does not throw),\n // so capture both halves of the snapshot to detect degradation.\n const snapshot = await getSandboxPluginCatalog().ensureLoaded(tenant);\n return { plugins: snapshot.plugins, diagnostics: snapshot.diagnostics };\n });\n const resolveConnections = deps.resolveConnections ?? defaultResolveConnections;\n const listed = await listPlugins(tenantId);\n const plugins = Array.isArray(listed) ? listed : listed.plugins;\n const diagnostics = Array.isArray(listed) ? [] : listed.diagnostics ?? [];\n // A throw from `listPlugins` still propagates: callers keep their own catch\n // (which degrades to an empty bundle). Any error-level diagnostic marks the\n // bundle degraded so callers can surface the real, non-throwing failure mode.\n const degraded = diagnostics.some((d) => d.level === \"error\");\n\n const tools: OpenToolDescriptor[] = [];\n const uiResources = new Map<string, OpenUiResource>();\n const toolIndex = new Map<string, { pluginType: string; action: string }>();\n\n for (const plugin of plugins) {\n const domain = plugin.meta.type;\n const manifest = await catalog.getValidatedManifest(tenantId, domain);\n if (!manifest) continue;\n for (const tool of manifest.tools ?? []) {\n if (tool.expose !== true) continue;\n if (!grantCovers(grants, domain, tool.name)) continue;\n const toolName = `${domain}_${tool.name}`;\n if (deps.reservedToolNames?.has(toolName)) continue;\n const ui = tool.ui?.resource\n ? {\n resourceUri: `ui://${domain}/${tool.ui.resource}`,\n csp: tool.ui.csp,\n displayMode: tool.ui.displayMode,\n }\n : undefined;\n if (tool.ui?.resource) {\n const resource = tool.ui.resource;\n const csp = tool.ui.csp;\n uiResources.set(ui!.resourceUri, {\n mimeType: \"text/html;profile=mcp-app\",\n csp,\n read: async () => ({\n html: await catalog.readPluginFile(tenantId, domain, resource),\n csp,\n }),\n });\n }\n tools.push({\n toolName,\n domain,\n action: tool.name,\n description: tool.description,\n schema: jsonSchemaToZod(tool.schema),\n annotations: {\n readOnlyHint: tool.readOnly ?? false,\n destructiveHint: tool.destructive ?? false,\n },\n ui,\n });\n toolIndex.set(toolName, { pluginType: domain, action: tool.name });\n }\n }\n\n return {\n tools,\n uiResources,\n hasTool: (toolName) => toolIndex.has(toolName),\n degraded,\n invoke: async (toolName, args, ctx) => {\n const entry = toolIndex.get(toolName);\n if (!entry) {\n return {\n content: [{ type: \"text\", text: `Unknown action: ${toolName}` }],\n isError: true,\n };\n }\n try {\n // Resolve the plugin's own connections from the credential tenant. The\n // Open surface has no agent run to select connection keys, so exposure\n // uses the Agent path's `connectAll` semantics (see\n // `registerExposedPluginTools` for global plugins).\n const { connection, connections } = await resolveConnections(entry.pluginType, ctx);\n const result = await invokePluginTool(\n { catalog },\n ctx.tenantId,\n entry.pluginType,\n entry.action,\n asArgs(args),\n {\n workspaceId: ctx.workspaceId,\n projectId: ctx.projectId,\n ...(connection === undefined ? {} : { connection }),\n ...(connections === undefined ? {} : { connections }),\n },\n );\n return { content: [{ type: \"text\", text: toText(result) }] };\n } catch (error) {\n if (error instanceof PluginToolScopeError) {\n return {\n content: [{ type: \"text\", text: error.message }],\n isError: true,\n };\n }\n throw error;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;AAaA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA8FP,SAAS,OAAO,OAAyC;AACvD,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD,CAAC;AACP;AAGA,SAAS,OAAO,QAAyB;AACvC,SAAO,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,UAAU,IAAI;AAC5E;AAGA,SAAS,iBAA0C;AACjD,SAAO;AAAA,IACL,sBAAsB,CAAC,UAAU,SAC/B,wBAAwB,EAAE,qBAAqB,UAAU,IAAI;AAAA,IAC/D,aAAa,MAAM,wBAAwB,EAAE,YAAY;AAAA,IACzD,gBAAgB,CAAC,UAAU,MAAM,YAC/B,wBAAwB,EAAE,eAAe,UAAU,MAAM,OAAO;AAAA,EACpE;AACF;AAUA,eAAe,0BACb,YACA,KACqC;AACrC,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,EAAE,YAAY,KAAK;AAAA,MACnB;AAAA,QACE,UAAU,IAAI;AAAA,QACd,aAAa,IAAI;AAAA,QACjB,WAAW,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,eAAe,SAAS,IAAI,YAAY,kCAAkC;AAC5E,aAAO,CAAC;AAAA,IACV;AACA,UAAM;AAAA,EACR;AACF;AAgBO,SAAS,iBACd,eACA,aACsB;AACtB,QAAM,OAAO,IAAI,IAAI,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AACzD,QAAM,SAAS,CAAC,GAAG,aAAa;AAChC,aAAW,QAAQ,aAAa;AAC9B,QAAI,KAAK,IAAI,KAAK,QAAQ,EAAG;AAC7B,SAAK,IAAI,KAAK,QAAQ;AACtB,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;AAoBA,eAAsB,uBACpB,UACA,QACA,OAA6B,CAAC,GACF;AAC5B,QAAM,UAAU,KAAK,WAAW,eAAe;AAC/C,QAAM,cACJ,KAAK,gBACJ,OAAO,WAAmB;AAGzB,UAAM,WAAW,MAAM,wBAAwB,EAAE,aAAa,MAAM;AACpE,WAAO,EAAE,SAAS,SAAS,SAAS,aAAa,SAAS,YAAY;AAAA,EACxE;AACF,QAAM,qBAAqB,KAAK,sBAAsB;AACtD,QAAM,SAAS,MAAM,YAAY,QAAQ;AACzC,QAAM,UAAU,MAAM,QAAQ,MAAM,IAAI,SAAS,OAAO;AACxD,QAAM,cAAc,MAAM,QAAQ,MAAM,IAAI,CAAC,IAAI,OAAO,eAAe,CAAC;AAIxE,QAAM,WAAW,YAAY,KAAK,CAAC,MAAM,EAAE,UAAU,OAAO;AAE5D,QAAM,QAA8B,CAAC;AACrC,QAAM,cAAc,oBAAI,IAA4B;AACpD,QAAM,YAAY,oBAAI,IAAoD;AAE1E,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAS,OAAO,KAAK;AAC3B,UAAM,WAAW,MAAM,QAAQ,qBAAqB,UAAU,MAAM;AACpE,QAAI,CAAC,SAAU;AACf,eAAW,QAAQ,SAAS,SAAS,CAAC,GAAG;AACvC,UAAI,KAAK,WAAW,KAAM;AAC1B,UAAI,CAAC,YAAY,QAAQ,QAAQ,KAAK,IAAI,EAAG;AAC7C,YAAM,WAAW,GAAG,MAAM,IAAI,KAAK,IAAI;AACvC,UAAI,KAAK,mBAAmB,IAAI,QAAQ,EAAG;AAC3C,YAAM,KAAK,KAAK,IAAI,WAChB;AAAA,QACE,aAAa,QAAQ,MAAM,IAAI,KAAK,GAAG,QAAQ;AAAA,QAC/C,KAAK,KAAK,GAAG;AAAA,QACb,aAAa,KAAK,GAAG;AAAA,MACvB,IACA;AACJ,UAAI,KAAK,IAAI,UAAU;AACrB,cAAM,WAAW,KAAK,GAAG;AACzB,cAAM,MAAM,KAAK,GAAG;AACpB,oBAAY,IAAI,GAAI,aAAa;AAAA,UAC/B,UAAU;AAAA,UACV;AAAA,UACA,MAAM,aAAa;AAAA,YACjB,MAAM,MAAM,QAAQ,eAAe,UAAU,QAAQ,QAAQ;AAAA,YAC7D;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,YAAM,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,aAAa,KAAK;AAAA,QAClB,QAAQ,gBAAgB,KAAK,MAAM;AAAA,QACnC,aAAa;AAAA,UACX,cAAc,KAAK,YAAY;AAAA,UAC/B,iBAAiB,KAAK,eAAe;AAAA,QACvC;AAAA,QACA;AAAA,MACF,CAAC;AACD,gBAAU,IAAI,UAAU,EAAE,YAAY,QAAQ,QAAQ,KAAK,KAAK,CAAC;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,CAAC,aAAa,UAAU,IAAI,QAAQ;AAAA,IAC7C;AAAA,IACA,QAAQ,OAAO,UAAU,MAAM,QAAQ;AACrC,YAAM,QAAQ,UAAU,IAAI,QAAQ;AACpC,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,mBAAmB,QAAQ,GAAG,CAAC;AAAA,UAC/D,SAAS;AAAA,QACX;AAAA,MACF;AACA,UAAI;AAKF,cAAM,EAAE,YAAY,YAAY,IAAI,MAAM,mBAAmB,MAAM,YAAY,GAAG;AAClF,cAAM,SAAS,MAAM;AAAA,UACnB,EAAE,QAAQ;AAAA,UACV,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO,IAAI;AAAA,UACX;AAAA,YACE,aAAa,IAAI;AAAA,YACjB,WAAW,IAAI;AAAA,YACf,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,YACjD,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;AAAA,UACrD;AAAA,QACF;AACA,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,EAAE,CAAC,EAAE;AAAA,MAC7D,SAAS,OAAO;AACd,YAAI,iBAAiB,sBAAsB;AACzC,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAAA,YAC/C,SAAS;AAAA,UACX;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,43 @@
1
+ // src/services/plugins/pluginToolExecution.ts
2
+ var PluginToolScopeError = class extends Error {
3
+ /**
4
+ * @param name - Rejected tool name.
5
+ * @param pluginType - Plugin the request addressed.
6
+ */
7
+ constructor(name, pluginType) {
8
+ super(`tool "${name}" is not owned by plugin "${pluginType}"`);
9
+ /** Stable machine-readable code for callers that translate the error. */
10
+ this.code = "PLUGIN_TOOL_SCOPE";
11
+ this.name = "PluginToolScopeError";
12
+ }
13
+ };
14
+ async function invokePluginTool(deps, tenantId, pluginType, name, args, runContext) {
15
+ const manifest = await deps.catalog.getValidatedManifest(tenantId, pluginType);
16
+ if (!manifest) throw new Error(`plugin "${pluginType}" has no validated manifest`);
17
+ const tool = (manifest.tools ?? []).find((t) => t.name === name);
18
+ if (!tool) throw new PluginToolScopeError(name, pluginType);
19
+ const runConfig = {
20
+ tenantId,
21
+ ...runContext?.workspaceId === void 0 ? {} : { workspaceId: runContext.workspaceId },
22
+ ...runContext?.projectId === void 0 ? {} : { projectId: runContext.projectId }
23
+ };
24
+ const result = await deps.catalog.getExecutor().invoke({
25
+ manifest,
26
+ handler: tool.handler,
27
+ input: args,
28
+ ...runContext?.connection === void 0 ? {} : { connection: runContext.connection },
29
+ ...runContext?.connections === void 0 ? {} : { connections: runContext.connections },
30
+ context: { tenantId, pluginType, tool: name },
31
+ runConfig,
32
+ timeoutMs: tool.timeoutMs,
33
+ maxResultBytes: tool.maxResultBytes
34
+ });
35
+ if (!result.ok) throw new Error(result.error ?? "sandbox plugin execution failed");
36
+ return result.result;
37
+ }
38
+
39
+ export {
40
+ PluginToolScopeError,
41
+ invokePluginTool
42
+ };
43
+ //# sourceMappingURL=chunk-73QZQQOT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/plugins/pluginToolExecution.ts"],"sourcesContent":["/**\n * Shared sandbox plugin tool execution helper.\n *\n * Membership resolution and executor invocation must have exactly one\n * constructor in the gateway: producing the `runConfig`/`context`/handler\n * envelope in two places would let the MCP App UI path and the Open MCP path\n * drift. Both `routes/mcp-apps.ts` (`callPluginTool`) and\n * `services/open/tenantOpenPlugins.ts` delegate here.\n *\n * `SandboxPluginInvokeArgs` is imported from core (the executor's own argument\n * contract) so this seam cannot silently diverge from {@link SandboxPluginExecutor}.\n */\n\nimport type { SandboxPluginManifest } from \"@axiom-lattice/protocols\";\nimport type { SandboxPluginInvokeArgs } from \"@axiom-lattice/core\";\n\n/**\n * Thrown when a requested tool is not owned by the addressed plugin's validated\n * manifest. Callers map it to a client error (the MCP App route maps it to 403).\n */\nexport class PluginToolScopeError extends Error {\n /** Stable machine-readable code for callers that translate the error. */\n readonly code = \"PLUGIN_TOOL_SCOPE\";\n\n /**\n * @param name - Rejected tool name.\n * @param pluginType - Plugin the request addressed.\n */\n constructor(name: string, pluginType: string) {\n super(`tool \"${name}\" is not owned by plugin \"${pluginType}\"`);\n this.name = \"PluginToolScopeError\";\n }\n}\n\n/** Minimal executor outcome the invocation seam depends on. */\nexport interface PluginToolInvokeResult {\n ok: boolean;\n result?: unknown;\n error?: string;\n}\n\n/** The catalog surface required to execute a plugin tool. */\nexport interface PluginToolCatalog {\n /**\n * Validated (normalized) manifest for the plugin.\n *\n * This is the authoritative source for handler paths and tool caps: it is the\n * output of the manifest validator, not a fresh parse of the raw\n * `plugin.json`, so execution cannot diverge from what validation accepted.\n */\n getValidatedManifest(tenantId: string, type: string): Promise<SandboxPluginManifest | undefined>;\n getExecutor(): {\n invoke(args: SandboxPluginInvokeArgs): Promise<PluginToolInvokeResult>;\n };\n}\n\n/** Dependencies injected into {@link invokePluginTool}. */\nexport interface PluginToolExecutionDeps {\n catalog: PluginToolCatalog;\n}\n\n/** Optional run identity and credential payload for a plugin tool invocation. */\nexport interface PluginToolRunContext {\n workspaceId?: string;\n projectId?: string;\n connection?: Record<string, unknown>;\n connections?: Array<{ key: string; config: Record<string, unknown> }>;\n}\n\n/**\n * Execute one of a plugin's own tools through the injected sandbox executor.\n *\n * A tool the plugin does not own is a scope violation\n * ({@link PluginToolScopeError}); a missing plugin, validated manifest, or\n * failed execution is a backend failure.\n *\n * @param deps - Catalog seam exposing the validated manifest and executor.\n * @param tenantId - Tenant scope.\n * @param pluginType - Plugin type addressed by the request.\n * @param name - Tool name requested by the caller.\n * @param args - Tool arguments.\n * @param runContext - Optional run identity (workspace/project) selecting the\n * project-isolated sandbox, plus any connection payload. Undefined identity\n * fields are omitted so the executor falls back to the tenant-level sandbox.\n * @returns The handler result.\n * @throws PluginToolScopeError when the validated manifest does not own the tool.\n * @throws Error when the manifest is missing or execution fails.\n */\nexport async function invokePluginTool(\n deps: PluginToolExecutionDeps,\n tenantId: string,\n pluginType: string,\n name: string,\n args: Record<string, unknown>,\n runContext?: PluginToolRunContext,\n): Promise<unknown> {\n const manifest = await deps.catalog.getValidatedManifest(tenantId, pluginType);\n if (!manifest) throw new Error(`plugin \"${pluginType}\" has no validated manifest`);\n const tool = (manifest.tools ?? []).find((t) => t.name === name);\n if (!tool) throw new PluginToolScopeError(name, pluginType);\n // Spread/omit undefined so the executor sees only the identity it was given:\n // a call with workspace/project resolves the project-isolated sandbox, while a\n // context-less call falls back to the tenant-level sandbox.\n const runConfig = {\n tenantId,\n ...(runContext?.workspaceId === undefined ? {} : { workspaceId: runContext.workspaceId }),\n ...(runContext?.projectId === undefined ? {} : { projectId: runContext.projectId }),\n };\n const result = await deps.catalog.getExecutor().invoke({\n manifest,\n handler: tool.handler,\n input: args,\n ...(runContext?.connection === undefined ? {} : { connection: runContext.connection }),\n ...(runContext?.connections === undefined ? {} : { connections: runContext.connections }),\n context: { tenantId, pluginType, tool: name },\n runConfig,\n timeoutMs: tool.timeoutMs,\n maxResultBytes: tool.maxResultBytes,\n });\n if (!result.ok) throw new Error(result.error ?? \"sandbox plugin execution failed\");\n return result.result;\n}\n"],"mappings":";AAoBO,IAAM,uBAAN,cAAmC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ9C,YAAY,MAAc,YAAoB;AAC5C,UAAM,SAAS,IAAI,6BAA6B,UAAU,GAAG;AAP/D;AAAA,SAAS,OAAO;AAQd,SAAK,OAAO;AAAA,EACd;AACF;AAwDA,eAAsB,iBACpB,MACA,UACA,YACA,MACA,MACA,YACkB;AAClB,QAAM,WAAW,MAAM,KAAK,QAAQ,qBAAqB,UAAU,UAAU;AAC7E,MAAI,CAAC,SAAU,OAAM,IAAI,MAAM,WAAW,UAAU,6BAA6B;AACjF,QAAM,QAAQ,SAAS,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC/D,MAAI,CAAC,KAAM,OAAM,IAAI,qBAAqB,MAAM,UAAU;AAI1D,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,GAAI,YAAY,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;AAAA,IACvF,GAAI,YAAY,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,WAAW,UAAU;AAAA,EACnF;AACA,QAAM,SAAS,MAAM,KAAK,QAAQ,YAAY,EAAE,OAAO;AAAA,IACrD;AAAA,IACA,SAAS,KAAK;AAAA,IACd,OAAO;AAAA,IACP,GAAI,YAAY,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,WAAW,WAAW;AAAA,IACpF,GAAI,YAAY,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;AAAA,IACvF,SAAS,EAAE,UAAU,YAAY,MAAM,KAAK;AAAA,IAC5C;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,gBAAgB,KAAK;AAAA,EACvB,CAAC;AACD,MAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,OAAO,SAAS,iCAAiC;AACjF,SAAO,OAAO;AAChB;","names":[]}
@@ -24,7 +24,7 @@ var ActionNotFoundError = class extends Error {
24
24
  function effectiveToolName(domain, action) {
25
25
  return action.toolName ?? `${domain}_${action.name}`;
26
26
  }
27
- function grantCoversAction(grants, domain, action) {
27
+ function grantCovers(grants, domain, action) {
28
28
  return grants.some(
29
29
  (g) => g.domain === domain && (!g.items || g.items.length === 0 || g.items.includes(action))
30
30
  );
@@ -52,14 +52,15 @@ var OpenLattice = class {
52
52
  const catalog = [];
53
53
  for (const [domain, entry] of this.providers) {
54
54
  for (const [actionName, action] of entry.actions) {
55
- if (!grantCoversAction(grants, domain, actionName)) continue;
55
+ if (!grantCovers(grants, domain, actionName)) continue;
56
56
  catalog.push({
57
57
  toolName: effectiveToolName(domain, action),
58
58
  domain,
59
59
  action: actionName,
60
60
  description: action.description,
61
61
  schema: action.schema,
62
- annotations: action.annotations
62
+ annotations: action.annotations,
63
+ ui: action.ui
63
64
  });
64
65
  }
65
66
  if (entry.declaration.instanceActions) {
@@ -71,7 +72,8 @@ var OpenLattice = class {
71
72
  action: action.name,
72
73
  description: action.description,
73
74
  schema: action.schema,
74
- annotations: action.annotations
75
+ annotations: action.annotations,
76
+ ui: action.ui
75
77
  });
76
78
  }
77
79
  }
@@ -133,7 +135,7 @@ var OpenLattice = class {
133
135
  const sep = toolName.indexOf("_");
134
136
  const domain = sep > 0 ? toolName.slice(0, sep) : toolName;
135
137
  const action = sep > 0 ? toolName.slice(sep + 1) : "";
136
- return grantCoversAction(grants, domain, action);
138
+ return grantCovers(grants, domain, action);
137
139
  }
138
140
  /** The single credential-driven execution path. */
139
141
  async invoke(grants, ctx, toolName, args) {
@@ -141,7 +143,7 @@ var OpenLattice = class {
141
143
  if (!resolved) {
142
144
  throw new ActionNotFoundError(toolName);
143
145
  }
144
- if (!grantCoversAction(grants, resolved.domain, resolved.actionName)) {
146
+ if (!grantCovers(grants, resolved.domain, resolved.actionName)) {
145
147
  throw new GrantDeniedError(toolName);
146
148
  }
147
149
  const resolvedSchema = resolved.action.schema;
@@ -158,7 +160,8 @@ export {
158
160
  GrantDeniedError,
159
161
  ValidationError,
160
162
  ActionNotFoundError,
163
+ grantCovers,
161
164
  OpenLattice,
162
165
  openLattice
163
166
  };
164
- //# sourceMappingURL=chunk-GF4GGTWJ.mjs.map
167
+ //# sourceMappingURL=chunk-HVIKCUOF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/open/openLattice.ts"],"sourcesContent":["/**\n * OpenLattice — the registry + invocation kernel for the Open API surface.\n *\n * Every credential-driven execution flows through exactly one path:\n * catalogFor(grants) → what the credential may see\n * invoke(grants, ...) → authorize → validate → execute → result\n *\n * Built-in providers (kb, sandbox, agent) and plugin-exposed tools all\n * register the same OpenProviderDeclaration contract.\n */\n\nimport { z } from \"zod\";\nimport type {\n McpUiCsp,\n McpUiDisplayMode,\n OpenCapabilitySource,\n OpenCatalogDomain,\n OpenCatalogItem,\n OpenExecutionContext,\n OpenExecutionResult,\n OpenGrant,\n} from \"@axiom-lattice/protocols\";\n\n/**\n * UI metadata exposed to MCP App hosts: `resourceUri` is advertised in a\n * tool's `_meta.ui`, while `csp`/`displayMode` are consumer hints.\n */\nexport type OpenUiMeta = {\n resourceUri: string;\n csp?: McpUiCsp;\n displayMode?: McpUiDisplayMode;\n};\n\nexport interface OpenActionDeclaration {\n name: string;\n /** Explicit MCP tool name override (defaults to `{domain}_{name}`). */\n toolName?: string;\n /** Friendly display label (falls back to the action name). */\n label?: string;\n description: string;\n schema: z.ZodRawShape | z.ZodTypeAny;\n annotations: { readOnlyHint: boolean; destructiveHint: boolean };\n /** MCP App UI metadata; advertised in the tool's `_meta.ui`. */\n ui?: OpenUiMeta;\n}\n\n/** Request-scoped context available while deriving the catalog. */\nexport interface OpenCatalogContext {\n tenantId?: string;\n}\n\nexport interface OpenProviderDeclaration {\n domain: string;\n /** Human label for the management catalog (defaults to domain). */\n label?: string;\n /** Catalog provenance (defaults to \"builtin\"). */\n source?: OpenCapabilitySource;\n /** \"action\" (kb/plugins) or \"instance\" (agent); defaults to \"action\". */\n itemKind?: \"action\" | \"instance\";\n /** Display-only scope hint (defaults to \"tenant\"). */\n scopeKind?: \"tenant\" | \"workspace\" | \"project\";\n actions: OpenActionDeclaration[];\n /**\n * Dynamic actions derived from the credential's grants — used by instance\n * domains (e.g. agent: one tool per granted assistant).\n */\n instanceActions?: (grants: OpenGrant[], ctx?: OpenCatalogContext) => OpenActionDeclaration[] | Promise<OpenActionDeclaration[]>;\n execute: (\n action: string,\n args: unknown,\n ctx: OpenExecutionContext,\n ) => Promise<OpenExecutionResult>;\n}\n\nexport interface OpenToolDescriptor {\n /** MCP tool name, \"{domain}_{action}\". */\n toolName: string;\n domain: string;\n action: string;\n description: string;\n schema: z.ZodRawShape | z.ZodTypeAny;\n annotations: { readOnlyHint: boolean; destructiveHint: boolean };\n /** MCP App UI metadata; advertised in the tool's `_meta.ui`. */\n ui?: OpenUiMeta;\n}\n\n/** Thrown when a credential has no grant covering the requested action. */\nexport class GrantDeniedError extends Error {\n readonly code = \"GRANT_DENIED\";\n constructor(toolName: string) {\n super(`GRANT_DENIED: no grant covers ${toolName}`);\n this.name = \"GrantDeniedError\";\n }\n}\n\n/** Thrown when args fail the action's zod schema. */\nexport class ValidationError extends Error {\n readonly code = \"VALIDATION_FAILED\";\n constructor(detail: string) {\n super(`VALIDATION_FAILED: ${detail}`);\n this.name = \"ValidationError\";\n }\n}\n\n/** Thrown for a toolName with no registered provider/action. */\nexport class ActionNotFoundError extends Error {\n readonly code = \"ACTION_NOT_FOUND\";\n constructor(toolName: string) {\n super(`ACTION_NOT_FOUND: ${toolName}`);\n this.name = \"ActionNotFoundError\";\n }\n}\n\ninterface RegisteredProvider {\n declaration: OpenProviderDeclaration;\n actions: Map<string, OpenActionDeclaration>;\n}\n\n/** Effective MCP tool name: explicit override, else `{domain}_{name}`. */\nfunction effectiveToolName(domain: string, action: OpenActionDeclaration): string {\n return action.toolName ?? `${domain}_${action.name}`;\n}\n\n/**\n * Whether the given grants cover one action of a domain (default-deny;\n * empty/absent `items` covers every action). Shared by tool and UI-resource\n * filtering so item-level grants apply identically to both.\n */\nexport function grantCovers(\n grants: OpenGrant[],\n domain: string,\n action: string,\n): boolean {\n return grants.some(\n (g) => g.domain === domain && (!g.items || g.items.length === 0 || g.items.includes(action)),\n );\n}\n\nexport class OpenLattice {\n private providers = new Map<string, RegisteredProvider>();\n\n /** Register a provider; domain+action collisions are rejected. */\n register(declaration: OpenProviderDeclaration): void {\n const existing = this.providers.get(declaration.domain);\n if (existing) {\n throw new Error(\n `Open provider domain already registered: ${declaration.domain}`,\n );\n }\n const actions = new Map<string, OpenActionDeclaration>();\n for (const action of declaration.actions) {\n actions.set(action.name, action);\n }\n this.providers.set(declaration.domain, { declaration, actions });\n }\n\n /** Tool descriptors visible under the given grants (default-deny). */\n async catalogFor(grants: OpenGrant[], ctx?: OpenCatalogContext): Promise<OpenToolDescriptor[]> {\n const catalog: OpenToolDescriptor[] = [];\n for (const [domain, entry] of this.providers) {\n // Static actions.\n for (const [actionName, action] of entry.actions) {\n if (!grantCovers(grants, domain, actionName)) continue;\n catalog.push({\n toolName: effectiveToolName(domain, action),\n domain,\n action: actionName,\n description: action.description,\n schema: action.schema,\n annotations: action.annotations,\n ui: action.ui,\n });\n }\n // Instance-derived actions (e.g. agent: one tool per granted assistant).\n if (entry.declaration.instanceActions) {\n const instances = await entry.declaration.instanceActions(grants, ctx);\n for (const action of instances) {\n catalog.push({\n toolName: effectiveToolName(domain, action),\n domain,\n action: action.name,\n description: action.description,\n schema: action.schema,\n annotations: action.annotations,\n ui: action.ui,\n });\n }\n }\n }\n return catalog;\n }\n\n /**\n * Full grantable catalog (unfiltered by grants) for the management picker.\n * Instance domains (agent) return an empty item list — the catalog service\n * fills their per-tenant instances.\n */\n describeCatalog(): OpenCatalogDomain[] {\n const domains: OpenCatalogDomain[] = [];\n for (const [domain, entry] of this.providers) {\n const declaration = entry.declaration;\n const items: OpenCatalogItem[] = [];\n if ((declaration.itemKind ?? \"action\") === \"action\") {\n for (const [actionName, action] of entry.actions) {\n items.push({\n id: actionName,\n toolName: `${domain}_${actionName}`,\n label: action.label ?? actionName,\n description: action.description,\n annotations: action.annotations,\n });\n }\n }\n domains.push({\n domain,\n label: declaration.label ?? domain,\n source: declaration.source ?? \"builtin\",\n scopeKind: declaration.scopeKind ?? \"tenant\",\n itemKind: declaration.itemKind ?? \"action\",\n items,\n });\n }\n return domains;\n }\n\n private async resolveAction(\n grants: OpenGrant[],\n toolName: string,\n ctx?: OpenCatalogContext,\n ): Promise<{\n domain: string;\n entry: RegisteredProvider;\n action: OpenActionDeclaration;\n /** Grant-matching id: the action name (assistant id for agent instances). */\n actionName: string;\n } | null> {\n for (const [domain, entry] of this.providers) {\n for (const [actionName, action] of entry.actions) {\n if (effectiveToolName(domain, action) === toolName) {\n return { domain, entry, action, actionName };\n }\n }\n if (entry.declaration.instanceActions) {\n const instances = await entry.declaration.instanceActions(grants, ctx);\n for (const action of instances) {\n if (effectiveToolName(domain, action) === toolName) {\n return { domain, entry, action, actionName: action.name };\n }\n }\n }\n }\n return null;\n }\n\n /** Whether the given grants cover a tool (`{domain}_{action}`). */\n isAllowed(grants: OpenGrant[], toolName: string): boolean {\n const sep = toolName.indexOf(\"_\");\n const domain = sep > 0 ? toolName.slice(0, sep) : toolName;\n const action = sep > 0 ? toolName.slice(sep + 1) : \"\";\n return grantCovers(grants, domain, action);\n }\n\n /** The single credential-driven execution path. */\n async invoke(\n grants: OpenGrant[],\n ctx: OpenExecutionContext,\n toolName: string,\n args: unknown,\n ): Promise<OpenExecutionResult> {\n const resolved = await this.resolveAction(grants, toolName, { tenantId: ctx.tenantId });\n if (!resolved) {\n throw new ActionNotFoundError(toolName);\n }\n if (!grantCovers(grants, resolved.domain, resolved.actionName)) {\n throw new GrantDeniedError(toolName);\n }\n const resolvedSchema = resolved.action.schema;\n const parsed = (\n \"safeParse\" in resolvedSchema\n ? (resolvedSchema as z.ZodTypeAny).safeParse(args)\n : z.object(resolvedSchema as z.ZodRawShape).safeParse(args)\n );\n if (!parsed.success) {\n throw new ValidationError(parsed.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \"));\n }\n return resolved.entry.declaration.execute(resolved.actionName, parsed.data, ctx);\n }\n}\n\n/** Process-wide singleton for the gateway's Open surface. */\nexport const openLattice = new OpenLattice();\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ import{l as C}from"./embed-page-chunk-SSC7ANWV.js";import"./embed-page-chunk-XVUA7UHE.js";import"./embed-page-chunk-MQDYZS3S.js";import"./embed-page-chunk-LOXLXZNP.js";import"./embed-page-chunk-KEL6XU6R.js";import"./embed-page-chunk-AC6X2XRH.js";import"./embed-page-chunk-S4XZPBRM.js";import"./embed-page-chunk-TL2AYM76.js";import{Da as T,jb as B}from"./embed-page-chunk-OBM5EUWZ.js";import{r as P}from"./embed-page-chunk-HMTKPZ5B.js";import{a as I}from"./embed-page-chunk-MB65DZAX.js";import"./embed-page-chunk-VW3NF5NT.js";import"./embed-page-chunk-5JDQ456X.js";import"./embed-page-chunk-Z7USDLHI.js";import{U as c,W as p,oa as D,va as b,xa as l}from"./embed-page-chunk-O4QK5LWZ.js";import{a as U}from"./embed-page-chunk-4BKXE5ON.js";import"./embed-page-chunk-IX4WLWCY.js";import"./embed-page-chunk-EUOOO2LS.js";import{e as u}from"./embed-page-chunk-6Y3UYJ6Z.js";var e=u(U());var t=u(I()),G={component_key:"workspace_assistants",data:{},message:"Assistants"},N=r=>{let i=r;if(typeof r=="string")try{i=JSON.parse(r)}catch{return{}}return i!==null&&typeof i=="object"&&!Array.isArray(i)?i:{}},H=({data:r})=>{let{assistantId:i,initialTab:F}=r??{},{get:m,put:f,del:A}=P(),y=T(),[g,w]=(0,e.useState)(null),[R,h]=(0,e.useState)([]),[E,v]=(0,e.useState)(!1),[L,S]=(0,e.useState)(null),d=(0,e.useCallback)(()=>{y(G)},[y]),a=(0,e.useCallback)(async()=>{v(!0),S(null);try{let s=(await m("/api/assistants")).data?.records??[];h(s),w(s.find(o=>o.id===i)??null)}catch{S("Failed to load agent")}finally{v(!1)}},[m,i]);(0,e.useEffect)(()=>{i&&a()},[a,i]);let _=(0,e.useCallback)(async(n,s)=>{let o=N(n.graphDefinition),k;try{k=await f(`/api/assistants/${n.id}`,{name:s.name!==void 0?s.name:n.name,description:s.description!==void 0?s.description:n.description,graphDefinition:{...o,...s}})}catch(z){throw l.error("Failed to save agent"),z}if(!k.success)throw l.error("Failed to save agent"),new Error("Failed to save agent");l.success("Saved"),await a()},[f,a]),j=(0,e.useCallback)(n=>{w(s=>s&&s.id===n.id?n:s),h(s=>s.map(o=>o.id===n.id?n:o))},[]),x=(0,e.useCallback)(async n=>{if(!(await A(`/api/assistants/${n}`)).success)throw new Error("Failed to delete agent");l.success("Agent deleted"),d()},[A,d]);return i?g?(0,t.jsx)("div",{style:{height:"100%",overflow:"auto"},children:(0,t.jsx)(B,{children:(0,t.jsx)(C,{assistant:g,allAssistants:R,onBack:d,onDeleted:x,onSave:_,onAssistantUpdated:j,onAgentListInvalidated:()=>void a(),initialTab:F})},g.id)}):E?(0,t.jsx)("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"100%"},children:(0,t.jsx)(b,{})}):L?(0,t.jsx)("div",{style:{padding:24},children:(0,t.jsx)(c,{type:"error",showIcon:!0,message:"Failed to load agent","data-testid":"detail-error",action:(0,t.jsxs)(D,{children:[(0,t.jsx)(p,{size:"small",onClick:()=>void a(),children:"Retry"}),(0,t.jsx)(p,{size:"small",type:"primary",onClick:d,children:"Back to list"})]})})}):(0,t.jsx)("div",{style:{padding:24},children:(0,t.jsx)(c,{type:"warning",showIcon:!0,message:"Agent not found","data-testid":"detail-not-found",action:(0,t.jsx)(p,{size:"small",type:"primary",onClick:d,children:"Back to list"})})}):(0,t.jsx)("div",{style:{padding:24},children:(0,t.jsx)(c,{type:"warning",showIcon:!0,message:"Missing agent id","data-testid":"detail-missing-id"})})};export{H as AgentDetailSideApp};
@@ -1,4 +1,4 @@
1
- import{a as Re,b as Me,c as Tt,d as It,e as Dt,f as Rt,g as Pt,h as Ft,i as Et,j as Mt,k as Nt,l as Lt}from"./embed-page-chunk-RLP3BC7G.js";import"./embed-page-chunk-LE6OFJ7R.js";import{a as Ge}from"./embed-page-chunk-Z4S4OYA4.js";import"./embed-page-chunk-ZKJ7Z7P3.js";import"./embed-page-chunk-KEL6XU6R.js";import{b as _e,e as Ve,f as At,g as Ct,h as xt,i as wt,l as vt,m as kt}from"./embed-page-chunk-AC6X2XRH.js";import{a as mt,b as gt,c as ut,d as ft,e as yt}from"./embed-page-chunk-SV2BM3WO.js";import"./embed-page-chunk-S4XZPBRM.js";import"./embed-page-chunk-I42T7B7V.js";import"./embed-page-chunk-VRV57DFE.js";import"./embed-page-chunk-4ZSGPIBZ.js";import{b as St}from"./embed-page-chunk-ZXFZANZM.js";import{C as at,Da as dt,M as ot,Ma as ct,Oa as pt,P as rt,X as st,Ya as ht,gb as bt,hb as Ke,ja as it,o as De,pa as lt}from"./embed-page-chunk-BRETUPSG.js";import{m as Qe,r as fe}from"./embed-page-chunk-T25T2YE6.js";import{a as E}from"./embed-page-chunk-MB65DZAX.js";import"./embed-page-chunk-VW3NF5NT.js";import"./embed-page-chunk-5JDQ456X.js";import"./embed-page-chunk-Z7USDLHI.js";import{Db as et,Fa as Je,Ia as Ie,Ja as Ye,La as Y,Ua as Xe,W as Z,_ as Se,aa as Te,ac as Ee,ea as Fe,ka as Oe,la as We,ma as qe,mc as tt,oa as Ze,ra as P,ta as V,wa as $e,xa as v,ya as ue,yc as nt}from"./embed-page-chunk-O4QK5LWZ.js";import{a as ge}from"./embed-page-chunk-4BKXE5ON.js";import"./embed-page-chunk-IX4WLWCY.js";import"./embed-page-chunk-EUOOO2LS.js";import{e as x}from"./embed-page-chunk-6Y3UYJ6Z.js";var u=x(ge());var X=x(ge());var J=x(ge());var Bt=x(ge());var se=x(E()),Ot=60,$t=72,ze=(0,Bt.memo)(({data:n})=>{let r=Re(n.type),p=Math.min(12+Math.sqrt(n.subAgentCount)*10,48);return(0,se.jsxs)("div",{style:{display:"flex",flexDirection:"column",alignItems:"center"},children:[(0,se.jsx)(Ve,{type:"target",position:_e.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1}),(0,se.jsx)("div",{title:n.label,style:{width:p,height:p,borderRadius:"50%",background:Me(r.color),display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:Math.max(10,p*.4),fontWeight:600,cursor:"pointer",boxShadow:"0 2px 8px rgba(0,0,0,0.15)"},children:n.label.charAt(0).toUpperCase()}),(0,se.jsx)("div",{style:{fontSize:11,maxWidth:120,textAlign:"center",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",marginTop:4},children:n.label}),(0,se.jsx)(Ve,{type:"source",position:_e.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1})]})});ze.displayName="AgentGraphNode";var Q=x(E()),sn=({assistants:n,onNodeClick:r})=>{let[p,d,g]=xt([]),[o,f,k]=wt([]),[c,S]=(0,J.useState)(null),H=(0,J.useMemo)(()=>({agent:ze}),[]),m=(0,J.useMemo)(()=>Dt(n),[n]);(0,J.useEffect)(()=>{let w=m.nodes.map(i=>({id:i.id})),F=m.edges.map(i=>({source:i.source,target:i.target})),N=new Map(m.nodes.map(i=>[i.id,i])),_=ft(w).force("link",ut(F).id(i=>i.id).distance(80)).force("charge",yt().strength(-220)).force("center",mt(0,0)).force("collide",gt(45)).stop();for(let i=0;i<300;i++)_.tick();let R=w.map(i=>({id:i.id,type:"agent",data:N.get(i.id),position:{x:i.x-Ot/2,y:i.y-$t/2}})),s=m.edges.map(i=>({id:`e${i.source}-${i.target}`,source:i.source,target:i.target,style:{stroke:"#1677ff",strokeWidth:2},type:"straight"}));d(R),f(s)},[m,d,f]);let I=(0,J.useMemo)(()=>c===null?p:p.map(w=>{let F=w.id===c||o.some(N=>N.source===c&&N.target===w.id||N.target===c&&N.source===w.id);return{...w,style:{opacity:F?1:.2,transition:"opacity 0.2s ease"}}}),[p,o,c]),K=(0,J.useMemo)(()=>c===null?o.map(w=>({...w,style:{stroke:"#1677ff",strokeWidth:1.5,opacity:.25,transition:"opacity 0.2s ease"}})):o.map(w=>{let F=w.source===c||w.target===c;return{...w,style:{stroke:"#1677ff",strokeWidth:F?2.5:1,opacity:F?1:.04,transition:"opacity 0.2s ease"}}}),[o,c]);return(0,Q.jsx)("div",{style:{width:"100%",height:"100%",background:"#fafafa",position:"relative"},children:(0,Q.jsxs)(Ct,{nodes:I,edges:K,onNodesChange:g,onEdgesChange:k,onNodeMouseEnter:(w,F)=>S(F.id),onNodeMouseLeave:()=>S(null),onNodeClick:(w,F)=>r?.(String(F.id)),nodeTypes:H,fitView:!0,fitViewOptions:{padding:.25},children:[(0,Q.jsx)(vt,{color:"#eee",gap:20}),(0,Q.jsx)(kt,{})]})})},Kt=n=>(0,Q.jsx)(At,{children:(0,Q.jsx)(sn,{...n})});var M=x(E()),ln=n=>{if(!n)return"\u2014";let r=Date.now()-new Date(n).getTime(),p=Math.floor(r/6e4);if(p<1)return"just now";if(p<60)return`${p}m ago`;let d=Math.floor(p/60);return d<24?`${d}h ago`:`${Math.floor(d/24)}d ago`},dn=n=>n===null?"#d9d9d9":n>=80?"#22c55e":n>=50?"#f59e0b":"#ef4444",cn=ct(({css:n})=>({row:n`
1
+ import{a as Re,b as Me,c as Tt,d as It,e as Dt,f as Rt,g as Pt,h as Ft,i as Et,j as Mt,k as Nt,l as Lt}from"./embed-page-chunk-SSC7ANWV.js";import"./embed-page-chunk-XVUA7UHE.js";import{a as Ge}from"./embed-page-chunk-MQDYZS3S.js";import"./embed-page-chunk-LOXLXZNP.js";import"./embed-page-chunk-KEL6XU6R.js";import{b as _e,e as Ve,f as At,g as Ct,h as xt,i as wt,l as vt,m as kt}from"./embed-page-chunk-AC6X2XRH.js";import{a as mt,b as gt,c as ut,d as ft,e as yt}from"./embed-page-chunk-SV2BM3WO.js";import"./embed-page-chunk-S4XZPBRM.js";import"./embed-page-chunk-TL2AYM76.js";import{$ as it,Da as ht,G as ot,J as rt,P as st,Pa as bt,Qa as Ke,da as lt,jb as St,k as De,oa as dt,va as ct,w as at,wa as pt}from"./embed-page-chunk-OBM5EUWZ.js";import{m as Qe,r as fe}from"./embed-page-chunk-HMTKPZ5B.js";import{a as E}from"./embed-page-chunk-MB65DZAX.js";import"./embed-page-chunk-VW3NF5NT.js";import"./embed-page-chunk-5JDQ456X.js";import"./embed-page-chunk-Z7USDLHI.js";import{Db as et,Fa as Je,Ia as Ie,Ja as Ye,La as Y,Ua as Xe,W as Z,_ as Se,aa as Te,ac as Ee,ea as Fe,ka as Oe,la as We,ma as qe,mc as tt,oa as Ze,ra as P,ta as V,wa as $e,xa as v,ya as ue,yc as nt}from"./embed-page-chunk-O4QK5LWZ.js";import{a as ge}from"./embed-page-chunk-4BKXE5ON.js";import"./embed-page-chunk-IX4WLWCY.js";import"./embed-page-chunk-EUOOO2LS.js";import{e as x}from"./embed-page-chunk-6Y3UYJ6Z.js";var u=x(ge());var X=x(ge());var J=x(ge());var Bt=x(ge());var se=x(E()),Ot=60,$t=72,ze=(0,Bt.memo)(({data:n})=>{let r=Re(n.type),p=Math.min(12+Math.sqrt(n.subAgentCount)*10,48);return(0,se.jsxs)("div",{style:{display:"flex",flexDirection:"column",alignItems:"center"},children:[(0,se.jsx)(Ve,{type:"target",position:_e.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1}),(0,se.jsx)("div",{title:n.label,style:{width:p,height:p,borderRadius:"50%",background:Me(r.color),display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:Math.max(10,p*.4),fontWeight:600,cursor:"pointer",boxShadow:"0 2px 8px rgba(0,0,0,0.15)"},children:n.label.charAt(0).toUpperCase()}),(0,se.jsx)("div",{style:{fontSize:11,maxWidth:120,textAlign:"center",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",marginTop:4},children:n.label}),(0,se.jsx)(Ve,{type:"source",position:_e.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1})]})});ze.displayName="AgentGraphNode";var Q=x(E()),sn=({assistants:n,onNodeClick:r})=>{let[p,d,g]=xt([]),[o,f,k]=wt([]),[c,S]=(0,J.useState)(null),H=(0,J.useMemo)(()=>({agent:ze}),[]),m=(0,J.useMemo)(()=>Dt(n),[n]);(0,J.useEffect)(()=>{let w=m.nodes.map(i=>({id:i.id})),F=m.edges.map(i=>({source:i.source,target:i.target})),N=new Map(m.nodes.map(i=>[i.id,i])),_=ft(w).force("link",ut(F).id(i=>i.id).distance(80)).force("charge",yt().strength(-220)).force("center",mt(0,0)).force("collide",gt(45)).stop();for(let i=0;i<300;i++)_.tick();let R=w.map(i=>({id:i.id,type:"agent",data:N.get(i.id),position:{x:i.x-Ot/2,y:i.y-$t/2}})),s=m.edges.map(i=>({id:`e${i.source}-${i.target}`,source:i.source,target:i.target,style:{stroke:"#1677ff",strokeWidth:2},type:"straight"}));d(R),f(s)},[m,d,f]);let I=(0,J.useMemo)(()=>c===null?p:p.map(w=>{let F=w.id===c||o.some(N=>N.source===c&&N.target===w.id||N.target===c&&N.source===w.id);return{...w,style:{opacity:F?1:.2,transition:"opacity 0.2s ease"}}}),[p,o,c]),K=(0,J.useMemo)(()=>c===null?o.map(w=>({...w,style:{stroke:"#1677ff",strokeWidth:1.5,opacity:.25,transition:"opacity 0.2s ease"}})):o.map(w=>{let F=w.source===c||w.target===c;return{...w,style:{stroke:"#1677ff",strokeWidth:F?2.5:1,opacity:F?1:.04,transition:"opacity 0.2s ease"}}}),[o,c]);return(0,Q.jsx)("div",{style:{width:"100%",height:"100%",background:"#fafafa",position:"relative"},children:(0,Q.jsxs)(Ct,{nodes:I,edges:K,onNodesChange:g,onEdgesChange:k,onNodeMouseEnter:(w,F)=>S(F.id),onNodeMouseLeave:()=>S(null),onNodeClick:(w,F)=>r?.(String(F.id)),nodeTypes:H,fitView:!0,fitViewOptions:{padding:.25},children:[(0,Q.jsx)(vt,{color:"#eee",gap:20}),(0,Q.jsx)(kt,{})]})})},Kt=n=>(0,Q.jsx)(At,{children:(0,Q.jsx)(sn,{...n})});var M=x(E()),ln=n=>{if(!n)return"\u2014";let r=Date.now()-new Date(n).getTime(),p=Math.floor(r/6e4);if(p<1)return"just now";if(p<60)return`${p}m ago`;let d=Math.floor(p/60);return d<24?`${d}h ago`:`${Math.floor(d/24)}d ago`},dn=n=>n===null?"#d9d9d9":n>=80?"#22c55e":n>=50?"#f59e0b":"#ef4444",cn=ct(({css:n})=>({row:n`
2
2
  display: flex;
3
3
  justify-content: space-between;
4
4
  align-items: flex-end;
@@ -0,0 +1,6 @@
1
+ import{c as W,d as V}from"./embed-page-chunk-KEL6XU6R.js";import{b as N,d as U,e as k}from"./embed-page-chunk-AC6X2XRH.js";import"./embed-page-chunk-S4XZPBRM.js";import{Fa as b,Ha as z,Ia as F,Ja as H,Ka as L,Wa as R,Xa as $,Ya as J}from"./embed-page-chunk-OBM5EUWZ.js";import"./embed-page-chunk-HMTKPZ5B.js";import{a as g}from"./embed-page-chunk-MB65DZAX.js";import"./embed-page-chunk-VW3NF5NT.js";import"./embed-page-chunk-5JDQ456X.js";import"./embed-page-chunk-Z7USDLHI.js";import{Dc as D,Ia as O,Rc as G,Sc as w,Vc as _,W as v,aa as M,gb as P,lb as B,nc as E}from"./embed-page-chunk-O4QK5LWZ.js";import{a as C}from"./embed-page-chunk-4BKXE5ON.js";import"./embed-page-chunk-IX4WLWCY.js";import"./embed-page-chunk-EUOOO2LS.js";import{e as p}from"./embed-page-chunk-6Y3UYJ6Z.js";var s=p(C());var S=p(C());var o=p(g());var se="tracePulse 1.4s ease-in-out infinite",ie={running:(0,o.jsx)(E,{style:{color:"#1890ff"}}),success:(0,o.jsx)(P,{style:{color:"#52c41a"}}),error:(0,o.jsx)(B,{style:{color:"#ff4d4f"}})};function ae({kind:e}){switch(e){case"human":return(0,o.jsx)(_,{});case"agent":return(0,o.jsx)(G,{});case"tool":return(0,o.jsx)(w,{});case"ai":return(0,o.jsx)(D,{});default:return(0,o.jsx)(w,{})}}var I=S.default.createContext({}),le=()=>S.default.useContext(I),de=({data:e,selected:i})=>{let{onJumpToMessage:a}=le(),t=e.isAnswer===!0,r=e.status==="running",d=(e.parallelCount??1)>1,m=!!(a&&e.messageId&&!e.messageId.startsWith("summary:")),f=e.toolCall?F(e.toolCall.name):e.label,y=()=>{if((e.kind==="tool"||e.kind==="agent")&&e.toolCall){let h=H(e.toolCall.response);return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(z,{data:{name:e.toolCall.name,parameters:e.toolCall.args,type:"tool_call"},component_key:`${e.toolCall.id}-params`,interactive:!1}),h&&(0,o.jsx)("div",{style:{marginTop:8},children:(0,o.jsx)(b,{content:h})}),(0,o.jsx)(L,{ui:e.toolCall.ui})]})}return e.content?(0,o.jsx)(b,{content:e.content}):(0,o.jsx)("span",{style:{color:"#8c8c8c"},children:e.label})};return(0,o.jsxs)("div",{"data-testid":"trace-card",style:{height:"100%",display:"flex",flexDirection:"column",border:`1px solid ${t||i?"#6366f1":r?"#91caff":"#e5e7eb"}`,borderRadius:12,background:t?"#eef2ff":"#fff",boxShadow:r?"0 0 0 2px rgba(24,144,255,0.18)":i?"0 0 0 2px rgba(99,102,241,0.2)":"none",animation:r?se:void 0,overflow:"hidden",fontSize:13},children:[(0,o.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"8px 12px",borderBottom:"1px solid #f0f0f0",background:"rgba(0,0,0,0.02)"},children:[(0,o.jsx)(ae,{kind:e.kind}),(0,o.jsx)("span",{style:{fontWeight:t?700:600,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:f}),d&&(0,o.jsxs)(O,{color:"purple",style:{marginInlineEnd:0,fontSize:10},children:["\u5E76\u53D1 \xD7",e.parallelCount]}),ie[e.status],m&&(0,o.jsx)(v,{type:"text",size:"small",onClick:()=>a?.(e.messageId),children:"\u5BF9\u8BDD"})]}),(0,o.jsx)("div",{style:{flex:1,minHeight:0,overflow:"auto",padding:12},children:y()})]})},ce=({data:e,selected:i})=>(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(k,{type:"target",position:N.Top}),(0,o.jsx)(de,{data:e,selected:i}),(0,o.jsx)(k,{type:"source",position:N.Bottom})]}),K={trace:ce};var Y=p(C());var u=p(g()),pe={running:"#1890ff",success:"#52c41a",error:"#ff4d4f"},Z=({graph:e,activeNodeId:i,onSelectNode:a})=>{let t=Y.default.useMemo(()=>new Map(e.nodes.map(r=>[r.id,r])),[e.nodes]);return(0,u.jsx)("div",{"data-testid":"trace-overview-rail",style:{display:"flex",flexDirection:"column",gap:10,width:160,padding:8,overflowY:"auto",borderRight:"1px solid #f0f0f0"},children:e.phases.map(r=>(0,u.jsxs)("div",{"data-testid":"trace-rail-phase",children:[(0,u.jsx)("div",{style:{fontSize:12,color:"#8c8c8c",marginBottom:4},children:r.title}),(0,u.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:r.nodeIds.map(d=>{let m=t.get(d);if(!m)return null;let f=d===i;return(0,u.jsx)(M,{title:m.data.label,children:(0,u.jsx)("button",{type:"button","data-testid":"trace-rail-tick",onClick:()=>a?.(d),style:{width:f?12:8,height:f?12:8,borderRadius:"50%",border:"none",padding:0,cursor:"pointer",background:pe[m.data.status],outline:f?"2px solid #6366f1":"none"}})},d)})})]},r.id))})};var l=p(g()),j=3,q=()=>{},fe=`
2
+ @keyframes tracePulse {
3
+ 0%, 100% { box-shadow: 0 0 0 2px rgba(24,144,255,0.18); }
4
+ 50% { box-shadow: 0 0 0 6px rgba(24,144,255,0.05); }
5
+ }
6
+ `;function ue(e){let i=e.nodes.map(t=>({id:t.id,...R[t.data.kind]})),a=e.edges.map(t=>({from:t.from,to:t.to}));return W(i,a,{nodesep:48,ranksep:80,rankdir:"TB"})}function me({focusNodeId:e,follow:i}){let a=U();return(0,s.useEffect)(()=>{if(!i||!e)return;let t=a.getNode(e);if(!t)return;let r=t.style?.width??0,d=t.style?.height??0;a.setCenter(t.position.x+r/2,t.position.y+d/2,{zoom:1,duration:300})},[e,i,a]),null}var Be=({messages:e,isLoading:i,onJumpToMessage:a})=>{let[t,r]=(0,s.useState)(),[d,m]=(0,s.useState)(!1),[f,y]=(0,s.useState)(!0),h=(0,s.useDeferredValue)(e),T=(0,s.useMemo)(()=>$(h,{isLoading:i}),[h,i]),c=(0,s.useMemo)(()=>d?T:J(T,j),[T,d]),Q=(0,s.useMemo)(()=>`${c.nodes.map(n=>n.id).join(",")}|${c.edges.map(n=>n.id).join(",")}`,[c]),A=(0,s.useMemo)(()=>ue(c),[Q]),X=(0,s.useMemo)(()=>c.nodes.map(n=>{let x=R[n.data.kind];return{id:n.id,type:"trace",position:A.get(n.id)??{x:0,y:0},data:n.data,draggable:!1,style:{width:x.width,height:x.height}}}),[c,A]),ee=(0,s.useMemo)(()=>c.edges.map(n=>({id:n.id,source:n.from,target:n.to,animated:n.kind==="invoke",style:{stroke:n.kind==="invoke"?"#6366f1":n.kind==="result"?"#a5b4fc":"#d9d9d9"}})),[c]),oe=c.nodes[c.nodes.length-1]?.id,te=t??oe,ne=T.phases.length>j,re=(0,s.useMemo)(()=>({onJumpToMessage:a}),[a]);return(0,l.jsxs)(I.Provider,{value:re,children:[(0,l.jsx)("style",{children:fe}),(0,l.jsxs)("div",{style:{display:"flex",height:"100%",minHeight:0,width:"100%"},children:[(0,l.jsx)(Z,{graph:c,activeNodeId:t,onSelectNode:r}),(0,l.jsxs)("div",{style:{flex:1,minWidth:0,minHeight:0,display:"flex",flexDirection:"column"},children:[(0,l.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",alignItems:"center",gap:4,padding:"4px 8px"},children:[!f&&(0,l.jsx)(v,{size:"small",type:"text",onClick:()=>{r(void 0),y(!0)},children:"\u56DE\u5230\u5F53\u524D"}),ne&&(0,l.jsx)(v,{size:"small",type:"text",onClick:()=>m(n=>!n),children:d?"\u6536\u8D77\u66F4\u65E9":"\u5C55\u5F00\u5168\u90E8"})]}),(0,l.jsx)("div",{style:{flex:1,minHeight:0},children:(0,l.jsx)(V,{nodes:X,edges:ee,nodeTypes:K,onNodesChange:q,onEdgesChange:q,nodesDraggable:!1,nodesConnectable:!1,fitView:!0,miniMap:{pannable:!0,zoomable:!0},onMoveStart:()=>y(!1),onNodeClick:(n,x)=>{r(x.id),y(!0)},children:(0,l.jsx)(me,{focusNodeId:te,follow:f})})})]})]})]})};export{Be as MessageGraph};
@@ -1 +1 @@
1
- .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}.x-markdown-debug-panel{position:fixed;z-index:9999;right:0;background:#000000d9;border-radius:8px;padding:12px;font-family:SF Mono,Monaco,Inconsolata,Fira Mono,Droid Sans Mono,Source Code Pro,monospace;font-size:12px;color:#fff;width:180px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(8px);user-select:none;transition:box-shadow .2s}.x-markdown-debug-panel:hover{box-shadow:0 4px 12px #00000040}.x-markdown-debug-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}.x-markdown-debug-row:last-child{margin-bottom:0}.x-markdown-debug-label{color:#ffffffa6;font-weight:500;min-width:60px}.x-markdown-debug-value{font-weight:600;min-width:50px;text-align:right}.x-markdown-debug-chart{margin-left:auto}.x-markdown-debug-actions{display:flex;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid rgba(255,255,255,.1)}.x-markdown-debug-action{flex:1;padding:6px 12px;background:#ffffff1a;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#fff;font-size:11px;font-family:inherit;cursor:pointer;transition:all .2s;font-weight:500}.x-markdown-debug-action:hover{background:#ffffff26;border-color:#ffffff4d}.x-markdown-debug-action:active{transform:scale(.98)}.x-markdown-debug-record-btn.recording{background:#ff4d4f33;border-color:#ff4d4f;animation:recording-pulse 1.5s ease-in-out infinite}@keyframes recording-pulse{0%,to{box-shadow:0 0 #ff4d4f66}50%{box-shadow:0 0 0 8px #ff4d4f00}}.x-markdown-debug-modal-overlay{position:fixed;inset:0;background:#000000bf;backdrop-filter:blur(4px);z-index:10000;display:flex;align-items:center;justify-content:center;animation:fadeIn .2s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.x-markdown-debug-modal{background:#1e1e1ef2;border-radius:12px;box-shadow:0 8px 32px #0006;max-width:90vw;max-height:90vh;overflow:auto;animation:slideIn .3s ease-out;border:1px solid rgba(255,255,255,.1)}@keyframes slideIn{0%{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}}.x-markdown-debug-modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid rgba(255,255,255,.1)}.x-markdown-debug-close-btn{width:32px;height:32px;border-radius:6px;background:#ffffff1a;border:none;color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.x-markdown-debug-close-btn:hover{background:#ff4d4f4d}.x-markdown-debug-modal-content{padding:24px}.x-markdown-debug-stats-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}.x-markdown-debug-stat-item{background:#ffffff0d;border-radius:8px;padding:16px;border:1px solid rgba(255,255,255,.1)}.x-markdown-debug-stat-label{font-size:11px;color:#fff9;margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}.x-markdown-debug-stat-value{font-size:20px;font-weight:700;color:#fff}.x-markdown-debug-chart-full{background:#ffffff05;border-radius:8px;border:1px solid rgba(255,255,255,.1)}.x-markdown-debug-chart-full .fps-line,.x-markdown-debug-chart-full .memory-line{filter:drop-shadow(0 0 4px currentColor)}.x-markdown-debug-legend{display:flex;gap:24px;justify-content:center;margin-top:16px}.x-markdown-debug-legend-item{display:flex;align-items:center;gap:8px;font-size:13px;color:#fffc}.x-markdown-debug-legend-color{width:12px;height:12px;border-radius:2px}@media (max-width: 768px){.x-markdown-debug-stats-summary{grid-template-columns:repeat(2,1fr)}}@keyframes x-markdown-fade-in{0%{opacity:0}to{opacity:1}}.x-markdown{--text-color: inherit;--font-size: inherit;--margin-block: 0 0 1em 0;--td-th-padding: .85em 1em;--pre-th-td-padding: 2px 0;--border-font-weight: 600;--padding-ul-ol: 0 0 0 1em;--margin-ul-ol: 0 0 1em 1.8em;--margin-li: .25em 0;--margin-pre: 1em 0;--padding-code-inline: .2em .4em;--margin-code-inline: 0 .2em;--code-inline-text: .85em;--small-border-radius: 2px;--image-margin: .5em 0;--hr-margin: 1.5em 0;--table-margin: 1em 0;font-size:var(--font-size);line-height:1.5714285714285714;width:100%;color:var(--text-color)}.x-markdown p,.x-markdown div,.x-markdown span,.x-markdown li{word-break:break-word;overflow-wrap:break-word}.x-markdown pre,.x-markdown code{word-break:break-word;overflow-wrap:break-word;white-space:pre-wrap}.x-markdown th,.x-markdown td{padding:var(--td-th-padding)}.x-markdown th{font-weight:var(--border-font-weight)}.x-markdown pre table{box-shadow:none}.x-markdown pre td,.x-markdown pre th{padding:var(--pre-th-td-padding);border:none;text-align:left}.x-markdown p{margin:var(--margin-block)}.x-markdown p:first-child{margin-top:0}.x-markdown p:last-child{margin-bottom:0}.x-markdown ul,.x-markdown ol{margin:var(--margin-ul-ol);padding:var(--padding-ul-ol)}.x-markdown ul:first-child,.x-markdown ol:first-child{margin-top:0}.x-markdown ul:last-child,.x-markdown ol:last-child{margin-bottom:0}.x-markdown ol>li{list-style:decimal}.x-markdown ul>li{list-style:disc}.x-markdown li{margin:var(--margin-li)}.x-markdown li:first-child{margin-top:0}.x-markdown li:last-child{margin-bottom:0}.x-markdown pre{margin:var(--margin-pre);overflow-x:auto}.x-markdown pre:first-child{margin-top:0}.x-markdown pre:last-child{margin-bottom:0}.x-markdown code{padding:var(--padding-code-inline);margin:var(--margin-code-inline);font-size:var(--code-inline-text);border-radius:var(--small-border-radius)}.x-markdown pre code{padding:0;margin:0;font-size:inherit;border-radius:0;line-height:2}.x-markdown img{max-width:100%;height:auto;margin:var(--image-margin)}.x-markdown hr{margin:var(--hr-margin)}.x-markdown table:not(pre){margin:var(--table-margin);border-collapse:collapse;display:block;width:max-content;max-width:100%;overflow:auto}.x-markdown table:not(pre):first-child{margin-top:0}.x-markdown table:not(pre):last-child{margin-bottom:0}.x-markdown .inline-katex .katex-display{display:inline-block;margin:0;text-align:initial;vertical-align:middle}.x-markdown .inline-katex .katex-display>.katex{display:inline-block;text-align:initial;white-space:normal}.x-markdown .inline-katex .katex-display>.katex>.katex-html{display:inline-block;position:static}.x-markdown .inline-katex .katex-display>.katex>.katex-html>.tag{position:static}.diff-container{border-collapse:collapse;background:var(--diffViewerBackground);color:var(--diffViewerColor);width:100%}.diff-container pre{white-space:pre-wrap;margin:0;line-height:25px}.diff-container.light-theme{--diffViewerBackground: #fff;--diffViewerColor: #212529;--addedBackground: #e6ffed;--addedColor: #24292e;--removedBackground: #ffeef0;--removedColor: #24292e;--wordAddedBackground: #acf2bd;--wordRemovedBackground: #fdb8c0;--addedGutterBackground: #cdffd8;--removedGutterBackground: #ffdce0;--gutterBackground: #f7f7f7;--gutterBackgroundDark: #f3f1f1;--highlightBackground: #fffbdd;--highlightGutterBackground: #fff5b1;--codeFoldGutterBackground: #dbedff;--codeFoldBackground: #f1f8ff;--emptyLineBackground: #fafbfc;--gutterColor: #212529;--addedGutterColor: #212529;--removedGutterColor: #212529;--codeFoldContentColor: #212529;--diffViewerTitleBackground: #fafbfc;--diffViewerTitleColor: #212529;--diffViewerTitleBorderColor: #eee}.diff-container.dark-theme{--diffViewerBackground: #2e303c;--diffViewerColor: #fff;--addedBackground: #044b53;--addedColor: white;--removedBackground: #632f34;--removedColor: white;--wordAddedBackground: #055d67;--wordRemovedBackground: #7d383f;--addedGutterBackground: #034148;--removedGutterBackground: #632b30;--gutterBackground: #2c2f3a;--gutterBackgroundDark: #262933;--highlightBackground: #2a3967;--highlightGutterBackground: #2d4077;--codeFoldGutterBackground: #21232b;--codeFoldBackground: #262831;--emptyLineBackground: #363946;--gutterColor: #464c67;--addedGutterColor: #8c8c8c;--removedGutterColor: #8c8c8c;--codeFoldContentColor: #555a7b;--diffViewerTitleBackground: #2f323e;--diffViewerTitleColor: #555a7b;--diffViewerTitleBorderColor: #353846}.diff-container .gutter{background-color:var(--gutterBackground)}.diff-container .gutter:hover{background-color:var(--gutterBackgroundDark)}.diff-container .diff-added{background-color:var(--addedBackground);color:var(--addedColor)}.diff-container .diff-added pre{color:var(--addedColor)}.diff-container .diff-removed{background-color:var(--removedBackground);color:var(--removedColor)}.diff-container .diff-removed pre{color:var(--removedColor)}.diff-container .gutter.diff-added{background-color:var(--addedGutterBackground)}.diff-container .gutter.diff-added .line-number{color:var(--addedGutterColor)}.diff-container .gutter.diff-removed{background-color:var(--removedGutterBackground)}.diff-container .gutter.diff-removed .line-number{color:var(--removedGutterColor)}.diff-container .line-number{color:var(--gutterColor)}.diff-container .word-diff.word-added{background-color:var(--wordAddedBackground)}.diff-container .word-diff.word-removed{background-color:var(--wordRemovedBackground)}.diff-container .highlighted-line{background-color:var(--highlightBackground)}.diff-container .highlighted-gutter{background-color:var(--highlightGutterBackground)!important}.diff-container .code-fold-gutter{background-color:var(--codeFoldGutterBackground)}.diff-container .code-fold{background-color:var(--codeFoldBackground)}.diff-container .code-fold .code-fold-content{color:var(--codeFoldContentColor)}.diff-container .empty-line{background-color:var(--emptyLineBackground)}.diff-container .title-block{background-color:var(--diffViewerTitleBackground);border-bottom-color:var(--diffViewerTitleBorderColor)}.diff-container .title-block .content-text{color:var(--diffViewerTitleColor)}.diff-container .title-block:last-child{border-left-color:var(--diffViewerTitleBorderColor)}.diff-container .line{vertical-align:baseline}.diff-container .content{width:100%}.diff-container .split-view .content{width:50%}.diff-container .gutter{user-select:none;text-align:right;min-width:50px;padding:0 10px}.diff-container .gutter:hover{cursor:pointer}.diff-container .gutter:hover pre{opacity:1}.diff-container .gutter pre{opacity:.5}.diff-container .empty-gutter .gutter:hover{background:inherit;cursor:initial}.diff-container .marker{user-select:none;width:25px;padding-left:10px;padding-right:10px}.diff-container .word-diff{display:inline-flex;border-radius:1px;padding:2px}.diff-container .code-fold{height:40px;font-size:14px;font-weight:700}.diff-container .code-fold a{cursor:pointer;text-decoration:underline!important}.diff-container .code-fold a pre{display:inline}.diff-container .title-block{border-bottom:1px solid;padding:10px}.diff-container .title-block:last-child{border-left:1px solid}.diff-container .highlighted-line .word-diff.word-added{background-color:var(--wordAddedBackground)}.diff-container .highlighted-line .word-diff.word-removed{background-color:var(--wordRemovedBackground)}
1
+ .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}.x-markdown-debug-panel{position:fixed;z-index:9999;right:0;background:#000000d9;border-radius:8px;padding:12px;font-family:SF Mono,Monaco,Inconsolata,Fira Mono,Droid Sans Mono,Source Code Pro,monospace;font-size:12px;color:#fff;width:180px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(8px);user-select:none;transition:box-shadow .2s}.x-markdown-debug-panel:hover{box-shadow:0 4px 12px #00000040}.x-markdown-debug-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}.x-markdown-debug-row:last-child{margin-bottom:0}.x-markdown-debug-label{color:#ffffffa6;font-weight:500;min-width:60px}.x-markdown-debug-value{font-weight:600;min-width:50px;text-align:right}.x-markdown-debug-chart{margin-left:auto}.x-markdown-debug-actions{display:flex;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid rgba(255,255,255,.1)}.x-markdown-debug-action{flex:1;padding:6px 12px;background:#ffffff1a;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#fff;font-size:11px;font-family:inherit;cursor:pointer;transition:all .2s;font-weight:500}.x-markdown-debug-action:hover{background:#ffffff26;border-color:#ffffff4d}.x-markdown-debug-action:active{transform:scale(.98)}.x-markdown-debug-record-btn.recording{background:#ff4d4f33;border-color:#ff4d4f;animation:recording-pulse 1.5s ease-in-out infinite}@keyframes recording-pulse{0%,to{box-shadow:0 0 #ff4d4f66}50%{box-shadow:0 0 0 8px #ff4d4f00}}.x-markdown-debug-modal-overlay{position:fixed;inset:0;background:#000000bf;backdrop-filter:blur(4px);z-index:10000;display:flex;align-items:center;justify-content:center;animation:fadeIn .2s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.x-markdown-debug-modal{background:#1e1e1ef2;border-radius:12px;box-shadow:0 8px 32px #0006;max-width:90vw;max-height:90vh;overflow:auto;animation:slideIn .3s ease-out;border:1px solid rgba(255,255,255,.1)}@keyframes slideIn{0%{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}}.x-markdown-debug-modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid rgba(255,255,255,.1)}.x-markdown-debug-close-btn{width:32px;height:32px;border-radius:6px;background:#ffffff1a;border:none;color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.x-markdown-debug-close-btn:hover{background:#ff4d4f4d}.x-markdown-debug-modal-content{padding:24px}.x-markdown-debug-stats-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}.x-markdown-debug-stat-item{background:#ffffff0d;border-radius:8px;padding:16px;border:1px solid rgba(255,255,255,.1)}.x-markdown-debug-stat-label{font-size:11px;color:#fff9;margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}.x-markdown-debug-stat-value{font-size:20px;font-weight:700;color:#fff}.x-markdown-debug-chart-full{background:#ffffff05;border-radius:8px;border:1px solid rgba(255,255,255,.1)}.x-markdown-debug-chart-full .fps-line,.x-markdown-debug-chart-full .memory-line{filter:drop-shadow(0 0 4px currentColor)}.x-markdown-debug-legend{display:flex;gap:24px;justify-content:center;margin-top:16px}.x-markdown-debug-legend-item{display:flex;align-items:center;gap:8px;font-size:13px;color:#fffc}.x-markdown-debug-legend-color{width:12px;height:12px;border-radius:2px}@media (max-width: 768px){.x-markdown-debug-stats-summary{grid-template-columns:repeat(2,1fr)}}@keyframes x-markdown-fade-in{0%{opacity:0}to{opacity:1}}.x-markdown{--text-color: inherit;--font-size: inherit;--margin-block: 0 0 1em 0;--td-th-padding: .85em 1em;--pre-th-td-padding: 2px 0;--border-font-weight: 600;--padding-ul-ol: 0 0 0 1em;--margin-ul-ol: 0 0 1em 1.8em;--margin-li: .25em 0;--margin-pre: 1em 0;--padding-code-inline: .2em .4em;--margin-code-inline: 0 .2em;--code-inline-text: .85em;--small-border-radius: 2px;--image-margin: .5em 0;--hr-margin: 1.5em 0;--table-margin: 1em 0;font-size:var(--font-size);line-height:1.5714285714285714;width:100%;color:var(--text-color)}.x-markdown p,.x-markdown div,.x-markdown span,.x-markdown li{word-break:break-word;overflow-wrap:break-word}.x-markdown pre,.x-markdown code{word-break:break-word;overflow-wrap:break-word;white-space:pre-wrap}.x-markdown th,.x-markdown td{padding:var(--td-th-padding)}.x-markdown th{font-weight:var(--border-font-weight)}.x-markdown pre table{box-shadow:none}.x-markdown pre td,.x-markdown pre th{padding:var(--pre-th-td-padding);border:none;text-align:left}.x-markdown p{margin:var(--margin-block)}.x-markdown p:first-child{margin-top:0}.x-markdown p:last-child{margin-bottom:0}.x-markdown ul,.x-markdown ol{margin:var(--margin-ul-ol);padding:var(--padding-ul-ol)}.x-markdown ul:first-child,.x-markdown ol:first-child{margin-top:0}.x-markdown ul:last-child,.x-markdown ol:last-child{margin-bottom:0}.x-markdown ol>li{list-style:decimal}.x-markdown ul>li{list-style:disc}.x-markdown li{margin:var(--margin-li)}.x-markdown li:first-child{margin-top:0}.x-markdown li:last-child{margin-bottom:0}.x-markdown pre{margin:var(--margin-pre);overflow-x:auto}.x-markdown pre:first-child{margin-top:0}.x-markdown pre:last-child{margin-bottom:0}.x-markdown code{padding:var(--padding-code-inline);margin:var(--margin-code-inline);font-size:var(--code-inline-text);border-radius:var(--small-border-radius)}.x-markdown pre code{padding:0;margin:0;font-size:inherit;border-radius:0;line-height:2}.x-markdown img{max-width:100%;height:auto;margin:var(--image-margin)}.x-markdown hr{margin:var(--hr-margin)}.x-markdown table:not(pre){margin:var(--table-margin);border-collapse:collapse;display:block;width:max-content;max-width:100%;overflow:auto}.x-markdown table:not(pre):first-child{margin-top:0}.x-markdown table:not(pre):last-child{margin-bottom:0}.x-markdown .inline-katex .katex-display{display:inline-block;margin:0;text-align:initial;vertical-align:middle}.x-markdown .inline-katex .katex-display>.katex{display:inline-block;text-align:initial;white-space:normal}.x-markdown .inline-katex .katex-display>.katex>.katex-html{display:inline-block;position:static}.x-markdown .inline-katex .katex-display>.katex>.katex-html>.tag{position:static}.open-grants-picker{display:flex;border:1px solid var(--axiom-border-color, #f0f0f0);border-radius:10px;overflow:hidden}.open-grants-picker__loading{display:flex;align-items:center;padding:16px 0}.open-grants-picker__nav{width:190px;flex-shrink:0;border-right:1px solid var(--axiom-border-color, #f0f0f0);background:var(--axiom-fill-tertiary, #fafafa);padding:8px;overflow-y:auto}.open-grants-picker__nav-item{display:flex;align-items:center;justify-content:space-between;width:100%;padding:8px 10px;border:none;border-radius:8px;background:transparent;cursor:pointer;text-align:left;font-size:13px;color:var(--axiom-text-color, rgba(0, 0, 0, .88));transition:background .15s ease}.open-grants-picker__nav-item:hover{background:var(--axiom-fill-secondary, #f5f5f5)}.open-grants-picker__nav-item--active{background:var(--axiom-primary-bg, #eef2ff);color:#6366f1;font-weight:600}.open-grants-picker__nav-label{display:inline-flex;align-items:center;gap:8px;min-width:0}.open-grants-picker__content{flex:1;min-width:0;padding:12px;overflow-y:auto}.open-grants-picker__content-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.open-grants-picker__content-meta{display:inline-flex;align-items:center}.open-grants-picker__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px}.open-grants-picker__card--selected{border-color:#6366f1!important;background:var(--axiom-primary-bg, #eef2ff)}.open-grants-picker__desc{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;color:var(--axiom-text-color-secondary, rgba(0, 0, 0, .45))}.open-grants-picker__hint{display:flex;align-items:center;gap:8px;margin-top:10px}.key-exposure{display:flex;flex-direction:column;gap:16px;max-height:70vh;overflow-y:auto}.key-exposure__loading{display:flex;justify-content:center;padding:24px 0}.key-exposure__endpoint{padding:10px 12px;background:var(--axiom-fill-tertiary, #fafafa);border-radius:10px}.key-exposure__endpoint-line{display:flex;align-items:center;gap:8px;margin-top:6px;overflow-wrap:anywhere}.key-exposure__section-title{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}.key-exposure__domain+.key-exposure__domain{margin-top:12px}.key-exposure__domain-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.key-exposure__tool{padding:6px 0 6px 21px;border-bottom:1px solid var(--axiom-border-color, #f5f5f5)}.key-exposure__tool-desc{font-size:12px;color:var(--axiom-text-color-secondary, rgba(0, 0, 0, .45));margin-top:2px}.key-exposure__agent{padding:10px 12px;border:1px solid var(--axiom-border-color, #f0f0f0);border-radius:10px;margin-bottom:8px}.key-exposure__agent-header{display:flex;align-items:center;gap:6px}.key-exposure__agent-desc{font-size:12px;color:var(--axiom-text-color-secondary, rgba(0, 0, 0, .45));margin:4px 0}.key-exposure__agent-lines{display:flex;flex-direction:column;gap:2px;margin:4px 0;overflow-wrap:anywhere}.key-exposure__skills{display:flex;flex-wrap:wrap;gap:4px;margin:4px 0}.key-exposure__tab{display:flex;flex-direction:column;gap:16px}.key-exposure__scroll{max-height:calc(82vh - 130px);overflow-y:auto;padding-right:4px}.agent-card{border-radius:14px!important;margin-bottom:12px}.agent-card__header{display:flex;gap:12px;align-items:flex-start}.agent-card__avatar{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;flex-shrink:0;border-radius:10px;background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff}.agent-card__name{font-size:15px;font-weight:600;line-height:1.3}.agent-card__desc{font-size:12px;color:var(--axiom-text-color-secondary, rgba(0, 0, 0, .45));margin-top:2px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.agent-card__block{margin-top:12px}.agent-card__skills{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.agent-card__endpoints{display:flex;flex-direction:column;gap:4px;margin-top:6px}.agent-card__endpoint{display:flex;align-items:center;gap:8px;overflow-wrap:anywhere}.agent-card__modes{margin-top:12px}.diff-container{border-collapse:collapse;background:var(--diffViewerBackground);color:var(--diffViewerColor);width:100%}.diff-container pre{white-space:pre-wrap;margin:0;line-height:25px}.diff-container.light-theme{--diffViewerBackground: #fff;--diffViewerColor: #212529;--addedBackground: #e6ffed;--addedColor: #24292e;--removedBackground: #ffeef0;--removedColor: #24292e;--wordAddedBackground: #acf2bd;--wordRemovedBackground: #fdb8c0;--addedGutterBackground: #cdffd8;--removedGutterBackground: #ffdce0;--gutterBackground: #f7f7f7;--gutterBackgroundDark: #f3f1f1;--highlightBackground: #fffbdd;--highlightGutterBackground: #fff5b1;--codeFoldGutterBackground: #dbedff;--codeFoldBackground: #f1f8ff;--emptyLineBackground: #fafbfc;--gutterColor: #212529;--addedGutterColor: #212529;--removedGutterColor: #212529;--codeFoldContentColor: #212529;--diffViewerTitleBackground: #fafbfc;--diffViewerTitleColor: #212529;--diffViewerTitleBorderColor: #eee}.diff-container.dark-theme{--diffViewerBackground: #2e303c;--diffViewerColor: #fff;--addedBackground: #044b53;--addedColor: white;--removedBackground: #632f34;--removedColor: white;--wordAddedBackground: #055d67;--wordRemovedBackground: #7d383f;--addedGutterBackground: #034148;--removedGutterBackground: #632b30;--gutterBackground: #2c2f3a;--gutterBackgroundDark: #262933;--highlightBackground: #2a3967;--highlightGutterBackground: #2d4077;--codeFoldGutterBackground: #21232b;--codeFoldBackground: #262831;--emptyLineBackground: #363946;--gutterColor: #464c67;--addedGutterColor: #8c8c8c;--removedGutterColor: #8c8c8c;--codeFoldContentColor: #555a7b;--diffViewerTitleBackground: #2f323e;--diffViewerTitleColor: #555a7b;--diffViewerTitleBorderColor: #353846}.diff-container .gutter{background-color:var(--gutterBackground)}.diff-container .gutter:hover{background-color:var(--gutterBackgroundDark)}.diff-container .diff-added{background-color:var(--addedBackground);color:var(--addedColor)}.diff-container .diff-added pre{color:var(--addedColor)}.diff-container .diff-removed{background-color:var(--removedBackground);color:var(--removedColor)}.diff-container .diff-removed pre{color:var(--removedColor)}.diff-container .gutter.diff-added{background-color:var(--addedGutterBackground)}.diff-container .gutter.diff-added .line-number{color:var(--addedGutterColor)}.diff-container .gutter.diff-removed{background-color:var(--removedGutterBackground)}.diff-container .gutter.diff-removed .line-number{color:var(--removedGutterColor)}.diff-container .line-number{color:var(--gutterColor)}.diff-container .word-diff.word-added{background-color:var(--wordAddedBackground)}.diff-container .word-diff.word-removed{background-color:var(--wordRemovedBackground)}.diff-container .highlighted-line{background-color:var(--highlightBackground)}.diff-container .highlighted-gutter{background-color:var(--highlightGutterBackground)!important}.diff-container .code-fold-gutter{background-color:var(--codeFoldGutterBackground)}.diff-container .code-fold{background-color:var(--codeFoldBackground)}.diff-container .code-fold .code-fold-content{color:var(--codeFoldContentColor)}.diff-container .empty-line{background-color:var(--emptyLineBackground)}.diff-container .title-block{background-color:var(--diffViewerTitleBackground);border-bottom-color:var(--diffViewerTitleBorderColor)}.diff-container .title-block .content-text{color:var(--diffViewerTitleColor)}.diff-container .title-block:last-child{border-left-color:var(--diffViewerTitleBorderColor)}.diff-container .line{vertical-align:baseline}.diff-container .content{width:100%}.diff-container .split-view .content{width:50%}.diff-container .gutter{user-select:none;text-align:right;min-width:50px;padding:0 10px}.diff-container .gutter:hover{cursor:pointer}.diff-container .gutter:hover pre{opacity:1}.diff-container .gutter pre{opacity:.5}.diff-container .empty-gutter .gutter:hover{background:inherit;cursor:initial}.diff-container .marker{user-select:none;width:25px;padding-left:10px;padding-right:10px}.diff-container .word-diff{display:inline-flex;border-radius:1px;padding:2px}.diff-container .code-fold{height:40px;font-size:14px;font-weight:700}.diff-container .code-fold a{cursor:pointer;text-decoration:underline!important}.diff-container .code-fold a pre{display:inline}.diff-container .title-block{border-bottom:1px solid;padding:10px}.diff-container .title-block:last-child{border-left:1px solid}.diff-container .highlighted-line .word-diff.word-added{background-color:var(--wordAddedBackground)}.diff-container .highlighted-line .word-diff.word-removed{background-color:var(--wordRemovedBackground)}